svc/conntrack.in: Add IPv6 support.
authorMark Wooding <mdw@distorted.org.uk>
Fri, 29 Sep 2017 08:25:48 +0000 (09:25 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 28 Jun 2018 23:29:24 +0000 (00:29 +0100)
This is now a simple matter of implementing an `Inet6Address' class and
tweaking the `parse_address' function.

svc/conntrack.8.in
svc/conntrack.in

index 940097a..b38f668 100644 (file)
@@ -94,14 +94,15 @@ networks indicated by
 .IB network / mask \fR.  
 Here, a
 .I network
-is an IP address in dotted-quad form, and
+is an IPv4 or IPv6 address in dotted-quad form, and
 .I mask
-is a netmask, either in dotted-quad form, or as a number of 1-bits.
-Only one peer in each group may be connected at any given time; if a
-change is needed, any existing peer in the group is killed before
-connecting the new one.  If no match is found in a particular group,
-then no peers in the group are connected.  Strange and unhelpful things
-will happen if you put the same peer in several different groups.
+is a netmask, either in dotted-quad form (for IPv4), or as a prefix
+length (i.e., the number of initial 1-bits).  Only one peer in each
+group may be connected at any given time; if a change is needed, any
+existing peer in the group is killed before connecting the new one.  If
+no match is found in a particular group, then no peers in the group are
+connected.  Strange and unhelpful things will happen if you put the same
+peer in several different groups.
 .PP
 The tags
 .B down
@@ -114,14 +115,17 @@ is useful for detecting a `home' network, where a VPN is unnecessary
 The notion of `current IP address' is somewhat vague.  The
 .B conntrack
 service calculates it as the source address that the host would put on
-an IP packet sent to an arbitrarily chosen remote address.  The default
-remote address is 1.2.3.4 (which is unlikely ever to be assigned); this
-should determine an IP address on the network interface closest to the
-default gateway.  You can influence this process in two ways.  Firstly,
-you can change the default remote address used by adding a line
+an IP packet sent to a particular remote address; note that this is
+entirely hypothetical, and no actual packets are transmitted.  The
+default remote addresses are 1.2.3.4 (for IPv4, which is unlikely ever
+to be assigned), and 2001::1 (for IPv6); this should determine an IP
+address on the network interface closest to the default gateway.  You
+can influence this process in two ways.  Firstly, you can change the
+default remote address used by adding one or more lines
 .IP
 .B "test-addr ="
 .I remote-addr
+\&...
 .PP
 before the first peer group section.  Secondly, you can specify a
 particular
@@ -129,7 +133,11 @@ particular
 to use when checking whether a particular peer is applicable.
 .PP
 The peer definitions in each group are checked in the order given, and
-searching stops as soon as a match is found.
+searching stops as soon as a match is found.  (In older versions of
+.BR conntrack ,
+definitions were processed according to a most-specific-first order, but
+that doesn't provide an ordering between IPv4 and IPv6 networks, which
+is important; so this has been changed.)
 .PP
 Peers are connected using the
 .BR connect (8)
index bfdd7b8..28e4b0b 100644 (file)
@@ -143,8 +143,44 @@ class InetAddress (BaseAddress):
     addr, port = (lambda a, p: (a, p))(*sa)
     return cls(addr), port
 
+class Inet6Address (BaseAddress):
+  AF = S.AF_INET6
+  AFNAME = 'IPv6'
+  NBITS = 128
+  def _setaddr(me, addrstr):
+    pc = addrstr.find('%')
+    if pc == -1:
+      me.addr = me._addrstr_to_int(addrstr)
+      me.scope = 0
+    else:
+      me.addr = me._addrstr_to_int(addrstr[:pc])
+      ais = S.getaddrinfo(addrstr, 0, S.AF_INET6, S.SOCK_DGRAM, 0,
+                          S.AI_NUMERICHOST | S.AI_NUMERICSERV)
+      me.scope = ais[0][4][3]
+  def _addrstr(me):
+    addrstr = me._int_to_addrstr(me.addr)
+    if me.scope == 0:
+      return addrstr
+    else:
+      name, _ = S.getnameinfo((addrstr, 0, 0, me.scope),
+                              S.NI_NUMERICHOST | S.NI_NUMERICSERV)
+      return name
+  def _sockaddr(me, port = 0):
+    return (me._addrstr(), port, 0, me.scope)
+  @classmethod
+  def from_sockaddr(cls, sa):
+    addr, port, _, scope = (lambda a, p, f = 0, s = 0: (a, p, f, s))(*sa)
+    me = cls(addr)
+    me.scope = scope
+    return me, port
+  def _withinp(me, net):
+    return net.scope == 0 or me.scope == net.scope
+  def _eq(me, other):
+    return me.scope == other.scope
+
 def parse_address(addrstr, maskstr = None):
-  return InetAddress(addrstr, maskstr)
+  if addrstr.find(':') >= 0: return Inet6Address(addrstr, maskstr)
+  else: return InetAddress(addrstr, maskstr)
 
 def parse_net(netstr):
   try: sl = netstr.index('/')
@@ -161,7 +197,7 @@ def straddr(a): return a is None and '#<none>' or str(a)
 ## this service are largely going to be satellite notes, I don't think
 ## scalability's going to be a problem.
 
-TESTADDRS = [InetAddress('1.2.3.4')]
+TESTADDRS = [InetAddress('1.2.3.4'), Inet6Address('2001::1')]
 
 CONFSYNTAX = [
   ('COMMENT', RX.compile(r'^\s*($|[;#])')),