peerdb/tripe-newpeers.in: Add support for v4 and v6 address literals.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 27 Sep 2017 08:07:20 +0000 (09:07 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 16 Jun 2018 18:14:10 +0000 (19:14 +0100)
At least they get canonified now.  I think v4 literals should have
worked before, but it seems that they didn't.  This adds a `6' flag to
request only the v6 addresses for a name, but currently you can predict
which addresses you get pretty well.

peerdb/peers.in.5.in
peerdb/tripe-newpeers.in

index 4e6d5ca..6aa8ffc 100644 (file)
@@ -97,9 +97,19 @@ consist of zero or more of the following characters:
 looks up the
 .IR host 's
 IPv4 address(es);
 looks up the
 .IR host 's
 IPv4 address(es);
+.RB ` 6 '
+looks up the
+.IR host 's
+IPv6 address(es);
+and
 .RB ` * '
 returns all of the found addresses, separated by spaces, rather than
 .RB ` * '
 returns all of the found addresses, separated by spaces, rather than
-just the first one.
+just the first one.  If neither address family is requested, then
+.RB ` 46 '
+is assumed.  Currently,
+.BR tripe-newpeers(8)
+can only resolve hostnames to IPv4 addresses, but it can `resolve'
+numeric addresses of either kind.
 .PP
 There is a simple concept of
 .I inheritance
 .PP
 There is a simple concept of
 .I inheritance
index 4476197..5f33f5b 100644 (file)
@@ -34,6 +34,7 @@ import cdb as CDB
 from sys import stdin, stdout, exit, argv
 import re as RX
 import os as OS
 from sys import stdin, stdout, exit, argv
 import re as RX
 import os as OS
+import socket as S
 from cStringIO import StringIO
 
 ###--------------------------------------------------------------------------
 from cStringIO import StringIO
 
 ###--------------------------------------------------------------------------
@@ -71,14 +72,14 @@ class ResolvingHost (object):
   def __init__(me, name):
     """Make a new resolving-host object for the host NAME."""
     me.name = name
   def __init__(me, name):
     """Make a new resolving-host object for the host NAME."""
     me.name = name
-    me.addr = { 'INET': [] }
+    me.addr = { 'INET': [], 'INET6': [] }
     me.failure = None
 
   def addaddr(me, af, addr):
     """
     Add the address ADDR with address family AF.
 
     me.failure = None
 
   def addaddr(me, af, addr):
     """
     Add the address ADDR with address family AF.
 
-    The address family must currently be `INET'.
+    The address family may be `INET' or `INET6'.
     """
     me.addr[af].append(addr)
 
     """
     me.addr[af].append(addr)
 
@@ -93,12 +94,14 @@ class ResolvingHost (object):
     if me.failure is not None: raise ResolverFailure(me.name, me.failure)
     aa = []
     a4 = me.addr['INET']
     if me.failure is not None: raise ResolverFailure(me.name, me.failure)
     aa = []
     a4 = me.addr['INET']
+    a6 = me.addr['INET6']
     all, any = False, False
     for ch in flags:
       if ch == '*': all = True
       elif ch == '4': aa += a4; any = True
     all, any = False, False
     for ch in flags:
       if ch == '*': all = True
       elif ch == '4': aa += a4; any = True
+      elif ch == '6': aa += a6; any = True
       else: raise ValueError("unknown address-resolution flag `%s'" % ch)
       else: raise ValueError("unknown address-resolution flag `%s'" % ch)
-    if not any: aa = a4
+    if not any: aa = a4 + a6
     if not aa: raise ResolverFailure(me.name, 'no matching addresses found')
     if not all: aa = [aa[0]]
     return aa
     if not aa: raise ResolverFailure(me.name, 'no matching addresses found')
     if not all: aa = [aa[0]]
     return aa
@@ -136,7 +139,15 @@ class BulkResolver (object):
     """Prime the resolver to resolve the given host NAME."""
     if name not in me._namemap:
       me._namemap[name] = host = ResolvingHost(name)
     """Prime the resolver to resolve the given host NAME."""
     if name not in me._namemap:
       me._namemap[name] = host = ResolvingHost(name)
-      me._prepare(host, name)
+      try:
+        ailist = S.getaddrinfo(name, None, S.AF_UNSPEC, S.SOCK_DGRAM, 0,
+                               S.AI_NUMERICHOST | S.AI_NUMERICSERV)
+      except S.gaierror:
+        me._prepare(host, name)
+      else:
+        for af, skty, proto, cname, sa in ailist:
+          if af == S.AF_INET: host.addaddr('INET', sa[0])
+          elif af == S.AF_INET6: host.addaddr('INET6', sa[0])
 
   def run(me):
     """Run the background DNS resolver until it's finished."""
 
   def run(me):
     """Run the background DNS resolver until it's finished."""
@@ -182,7 +193,7 @@ RX_REF = RX.compile(r'(?x) \$ \( ([^)]+) \)')
 
 ## Match a $FLAGS[HOST] name resolution reference; group 1 are the flags;
 ## group 2 is the HOST.
 
 ## Match a $FLAGS[HOST] name resolution reference; group 1 are the flags;
 ## group 2 is the HOST.
-RX_RESOLVE = RX.compile(r'(?x) \$ ([4*]*) \[ ([^]]+) \]')
+RX_RESOLVE = RX.compile(r'(?x) \$ ([46*]*) \[ ([^]]+) \]')
 
 class ConfigSyntaxError (ExpectedError):
   def __init__(me, fname, lno, msg):
 
 class ConfigSyntaxError (ExpectedError):
   def __init__(me, fname, lno, msg):
@@ -401,8 +412,9 @@ class MyConfigParser (object):
       expansion and processes them correctly.
 
     * It recognizes `$FLAGS[HOST]' name-resolver requests and handles them
       expansion and processes them correctly.
 
     * It recognizes `$FLAGS[HOST]' name-resolver requests and handles them
-      correctly.  FLAGS consists of characters `4' (IPv4 addresses), and `*'
-      (all addresses, space-separated, rather than just the first).
+      correctly.  FLAGS consists of characters `4' (IPv4 addresses), `6'
+      (IPv6 addresses), and `*' (all, space-separated, rather than just the
+      first).
 
     * Its parsing behaviour is well-defined.
 
 
     * Its parsing behaviour is well-defined.