From: Mark Wooding Date: Fri, 29 Sep 2017 08:25:48 +0000 (+0100) Subject: svc/conntrack.in: Add IPv6 support. X-Git-Tag: 1.5.0~41^2~2 X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/commitdiff_plain/fb78e73aa6726c6f1c76bdd0a20b42f0eebb22de svc/conntrack.in: Add IPv6 support. This is now a simple matter of implementing an `Inet6Address' class and tweaking the `parse_address' function. --- diff --git a/svc/conntrack.8.in b/svc/conntrack.8.in index 940097af..b38f6681 100644 --- a/svc/conntrack.8.in +++ b/svc/conntrack.8.in @@ -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) diff --git a/svc/conntrack.in b/svc/conntrack.in index bfdd7b8d..28e4b0b3 100644 --- a/svc/conntrack.in +++ b/svc/conntrack.in @@ -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 '#' 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*($|[;#])')),