From: Mark Wooding Date: Fri, 29 Sep 2017 08:15:05 +0000 (+0100) Subject: svc/conntrack.in: Contemplate multiple address families. X-Git-Tag: 1.5.0~41^2~4 X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/commitdiff_plain/e152ccf25e1047309d0649e82378c6ea86b1c270 svc/conntrack.in: Contemplate multiple address families. A number of relatively simple changes, with no overall functional change except for a few diagnostic messages. * Attach the address-family code and a name string to the `InetAddress' class. This will mean that we can add new address families without breaking things. * Make `testaddrs' (and related variables) be a dictionary, mapping address families to addresses, rather than just a lone address. * Ensure that the networks in a peer assignment belong to the same family. They will do for now, because there's only one. * Have `kickpeers' maintain a local IP address for each family, rather than just a single one. --- diff --git a/svc/conntrack.in b/svc/conntrack.in index a31b2687..cc753d40 100644 --- a/svc/conntrack.in +++ b/svc/conntrack.in @@ -58,6 +58,8 @@ class struct (object): ### Address manipulation. class InetAddress (object): + AF = S.AF_INET + AFNAME = 'IPv4' def __init__(me, addrstr, maskstr = None): me.addr = me._addrstr_to_int(addrstr) if maskstr is None: @@ -116,7 +118,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. -TESTADDR = InetAddress('1.2.3.4') +TESTADDRS = [InetAddress('1.2.3.4')] CONFSYNTAX = [ ('COMMENT', RX.compile(r'^\s*($|[;#])')), @@ -167,7 +169,7 @@ class Config (object): if T._debug: print '# reread config' ## Initial state. - testaddr = None + testaddrs = {} groups = {} grpname = None grplist = [] @@ -215,9 +217,10 @@ class Config (object): raise ConfigError(me._file, lno, "invalid IP address `%s': %s" % (astr, e)) - if testaddr is not None: - raise ConfigError(me._file, lno, 'duplicate test-address') - testaddr = a + if a.AF in testaddrs: + raise ConfigError(me._file, lno, + 'duplicate %s test-address' % a.AFNAME) + testaddrs[a.AF] = a else: raise ConfigError(me._file, lno, "unknown global option `%s'" % name) @@ -230,6 +233,7 @@ class Config (object): ## Check for an explicit target address. if i >= len(spec) or spec[i].find('/') >= 0: peer = None + af = None else: try: peer = parse_address(spec[i]) @@ -237,6 +241,7 @@ class Config (object): raise ConfigError(me._file, lno, "invalid IP address `%s': %s" % (spec[i], e)) + af = peer.AF i += 1 ## Parse the list of local networks. @@ -254,22 +259,33 @@ class Config (object): if not nets: raise ConfigError(me._file, lno, 'no networks defined') + ## Make sure that the addresses are consistent. + for net in nets: + if af is None: + af = net.AF + elif net.AF != af: + raise ConfigError(me._file, lno, + "net %s doesn't match" % net) + ## Add this entry to the list. grplist.append((name, peer, nets)) - ## Fill in the default test address if necessary. - if testaddr is None: testaddr = TESTADDR + ## Fill in the default test addresses if necessary. + for a in TESTADDRS: testaddrs.setdefault(a.AF, a) ## Done. if grpname is not None: groups[grpname] = grplist - me.testaddr = testaddr + me.testaddrs = testaddrs me.groups = groups ### This will be a configuration file. CF = None def cmd_showconfig(): - T.svcinfo('test-addr=%s' % CF.testaddr) + T.svcinfo('test-addr=%s' % + ' '.join(str(a) + for a in sorted(CF.testaddrs.itervalues(), + key = lambda a: a.AFNAME))) def cmd_showgroups(): for g in sorted(CF.groups.iterkeys()): T.svcinfo(g) @@ -288,12 +304,12 @@ def localaddr(peer): """ Return the local IP address used for talking to PEER. """ - sk = S.socket(S.AF_INET, S.SOCK_DGRAM) + sk = S.socket(peer.AF, S.SOCK_DGRAM) try: try: sk.connect(peer.sockaddr(1)) addr = sk.getsockname() - return InetAddress.from_sockaddr(addr)[0] + return type(peer).from_sockaddr(addr)[0] except S.error: return None finally: @@ -348,16 +364,18 @@ def kickpeers(): ## Find the current list of peers. peers = SM.list() - ## Work out the primary IP address. + ## Work out the primary IP addresses. + locals = {} if upness: - addr = localaddr(CF.testaddr) - if addr is None: - upness = False - else: - addr = None + for af, remote in CF.testaddrs.iteritems(): + local = localaddr(remote) + if local is not None: locals[af] = local + if not locals: upness = False if not T._debug: pass - elif addr: print '# local address = %s' % straddr(addr) - else: print '# offline' + elif not locals: print '# offline' + else: + for local in locals.itervalues(): + print '# local %s address = %s' % (local.AFNAME, local) ## Now decide what to do. changes = [] @@ -369,7 +387,8 @@ def kickpeers(): want = None matchp = False for t, p, nn in pp: - if p is None or not upness: ip = addr + af = nn[0].AF + if p is None or not upness: ip = locals.get(af) else: ip = localaddr(p) if T._debug: info = 'peer = %s; target = %s; nets = %s; local = %s' % (