From: Mark Wooding Date: Tue, 26 Sep 2017 21:51:59 +0000 (+0100) Subject: peerdb/tripe-newpeers.in: Enhance addr-lookup syntax; return multiple addrs. X-Git-Tag: 1.5.0~41^2~62 X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/commitdiff_plain/ef7d7afbc62c58537caabba75b36d9938eb49b94 peerdb/tripe-newpeers.in: Enhance addr-lookup syntax; return multiple addrs. Keep track of multiple addresses for each host. Extend the $[...] syntax to allow substitution of all of the addresses, rather than just the first. --- diff --git a/peerdb/peers.in.5.in b/peerdb/peers.in.5.in index a07240b2..be9b8006 100644 --- a/peerdb/peers.in.5.in +++ b/peerdb/peers.in.5.in @@ -83,14 +83,19 @@ is replaced by the value assigned to the given .IR key . .hP \*o An occurrence of -.BI $[ host ] +.BI $ flags [ host ] is replaced by the IP address of the named .IR host . Note that .I host may itself contain .BI $( key ) -substitutions. +substitutions. The +.I flags +consist of zero or more of the following characters: +.RB ` * ' +returns all of the found addresses, separated by spaces, rather than +just the first one. .PP There is a simple concept of .I inheritance diff --git a/peerdb/tripe-newpeers.in b/peerdb/tripe-newpeers.in index 502492d9..1f17811e 100644 --- a/peerdb/tripe-newpeers.in +++ b/peerdb/tripe-newpeers.in @@ -63,17 +63,20 @@ class ResolverFailure (ExpectedError): class ResolvingHost (object): """ A host name which is being looked up by a bulk-resolver instance. + + Most notably, this is where the flag-handling logic lives for the + $FLAGS[HOSTNAME] syntax. """ def __init__(me, name): """Make a new resolving-host object for the host NAME.""" me.name = name - me.addr = None + me.addr = [] me.failure = None - def setaddr(me, addr): + def addaddr(me, addr): """Add the address ADDR.""" - me.addr = addr + me.addr.append(addr) def failed(me, msg): """ @@ -81,10 +84,17 @@ class ResolvingHost (object): """ me.failure = msg - def get(me): - """Return the resolved address.""" + def get(me, flags): + """Return a list of addresses according to the FLAGS string.""" if me.failure is not None: raise ResolverFailure(me.name, me.failure) - return me.addr + aa = me.addr + all = False + for ch in flags: + if ch == '*': all = True + else: raise ValueError("unknown address-resolution flag `%s'" % ch) + if not aa: raise ResolverFailure(me.name, 'no matching addresses found') + if not all: aa = [aa[0]] + return aa class BulkResolver (object): """ @@ -113,24 +123,24 @@ class BulkResolver (object): me._namemap[name] = host = ResolvingHost(name) host._resolv = M.SelResolveByName( name, - lambda cname, alias, addr: me._resolved(host, addr[0]), - lambda: me._resolved(host, None)) + lambda cname, alias, addr: me._resolved(host, addr), + lambda: me._resolved(host, [])) me._noutstand += 1 def run(me): """Run the background DNS resolver until it's finished.""" while me._noutstand: M.select() - def lookup(me, name): + def lookup(me, name, flags): """Fetch the address corresponding to the host NAME.""" - return me._namemap[name].get() + return me._namemap[name].get(flags) def _resolved(me, host, addr): - """Callback function: remember that ADDR is the address for HOST.""" - if addr is None: + """Callback function: remember that ADDRs are the addresses for HOST.""" + if not addr: host.failed('(unknown failure)') else: - host.setaddr(addr) + for a in addr: host.addaddr(a) host._resolv = None me._noutstand -= 1 @@ -158,8 +168,9 @@ RX_CONT = RX.compile(r'''(?x) ^ \s+ ## Match a $(VAR) configuration variable reference; group 1 is the VAR. RX_REF = RX.compile(r'(?x) \$ \( ([^)]+) \)') -## Match a $[HOST] name resolution reference; group 1 is the HOST. -RX_RESOLVE = RX.compile(r'(?x) \$ \[ ([^]]+) \]') +## Match a $FLAGS[HOST] name resolution reference; group 1 are the flags; +## group 2 is the HOST. +RX_RESOLVE = RX.compile(r'(?x) \$ ([*]*) \[ ([^]]+) \]') class ConfigSyntaxError (ExpectedError): def __init__(me, fname, lno, msg): @@ -237,17 +248,17 @@ class ConfigSection (object): def _expand(me, string, resolvep): """ - Expands $(...) and (optionally) $[...] placeholders in STRING. + Expands $(...) and (optionally) $FLAGS[...] placeholders in STRING. RESOLVEP is a boolean switch: do we bother to tax the resolver or not? This is turned off by MyConfigParser's resolve() method while it's collecting hostnames to be resolved. """ - string = RX_REF.sub \ - (lambda m: me.get(m.group(1), resolvep), string) + string = RX_REF.sub(lambda m: me.get(m.group(1), resolvep), string) if resolvep: - string = RX_RESOLVE.sub(lambda m: me._cp._resolver.lookup(m.group(1)), - string) + string = RX_RESOLVE.sub( + lambda m: ' '.join(me._cp._resolver.lookup(m.group(2), m.group(1))), + string) return string def _parents(me): @@ -377,8 +388,9 @@ class MyConfigParser (object): * It recognizes `$(VAR)' references to configuration variables during expansion and processes them correctly. - * It recognizes `$[HOST]' name-resolver requests and handles them - correctly. + * It recognizes `$FLAGS[HOST]' name-resolver requests and handles them + correctly. FLAGS may be empty, or `*' (all addresses, space-separated, + rather than just the first). * Its parsing behaviour is well-defined. @@ -491,7 +503,7 @@ class MyConfigParser (object): for key in sec.items(): value = sec.get(key, resolvep = False) for match in RX_RESOLVE.finditer(value): - me._resolver.prepare(match.group(1)) + me._resolver.prepare(match.group(2)) me._resolver.run() ###--------------------------------------------------------------------------