chiark / gitweb /
svc/conntrack.in: Factor out network parsing.
[tripe] / svc / conntrack.in
index a55e4c3219c62c195b6e056d581c98c45563c43f..2dc380b953800f8fdea3538fb2dd9626bd81a78c 100644 (file)
@@ -94,6 +94,30 @@ def toposort(cmp, things):
     if done:
       break
 
+###--------------------------------------------------------------------------
+### Address manipulation.
+
+def parse_address(addrstr):
+  return unpack('>L', S.inet_aton(addrstr))[0]
+
+def parse_net(netstr):
+  try: sl = netstr.index('/')
+  except ValueError: raise ValueError('missing mask')
+  addr = parse_address(netstr[:sl])
+  if netstr[sl + 1:].isdigit():
+    n = int(netstr[sl + 1:], 10)
+    mask = (1 << 32) - (1 << 32 - n)
+  else:
+    mask = parse_address(netstr[sl + 1:])
+  if addr&~mask: raise ValueError('network contains bits set beyond mask')
+  return addr, mask
+
+def straddr(a): return a is None and '#<none>' or S.inet_ntoa(pack('>L', a))
+def strmask(m):
+  for i in xrange(33):
+    if m == 0xffffffff ^ ((1 << (32 - i)) - 1): return str(i)
+  return straddr(m)
+
 ###--------------------------------------------------------------------------
 ### Parse the configuration file.
 
@@ -169,14 +193,8 @@ class Config (object):
         ## Syntax of a net is ADDRESS/MASK, where ADDRESS is a dotted-quad,
         ## and MASK is either a dotted-quad or a single integer N indicating
         ## a mask with N leading ones followed by trailing zeroes.
-        slash = net.index('/')
-        addr, = unpack('>L', S.inet_aton(net[:slash]))
-        if net[slash + 1:].isdigit():
-          n = int(net[slash + 1:], 10)
-          mask = (1 << 32) - (1 << 32 - n)
-        else:
-          mask, = unpack('>L', S.inet_aton(net[slash + 1:]))
-        pats.append((tag, peer, addr & mask, mask))
+        addr, mask = parse_net(net)
+        pats.append((tag, peer, addr, mask))
 
       ## Annoyingly, RawConfigParser doesn't preserve the order of options.
       ## In order to make things vaguely sane, we topologically sort the
@@ -194,12 +212,6 @@ class Config (object):
 ### This will be a configuration file.
 CF = None
 
-def straddr(a): return a is None and '#<none>' or S.inet_ntoa(pack('>L', a))
-def strmask(m):
-  for i in xrange(33):
-    if m == 0xffffffff ^ ((1 << (32 - i)) - 1): return str(i)
-  return straddr(m)
-
 def cmd_showconfig():
   T.svcinfo('test-addr=%s' % CF.testaddr)
 def cmd_showgroups():
@@ -229,7 +241,7 @@ def localaddr(peer):
     try:
       sk.connect((peer, 1))
       addr, _ = sk.getsockname()
-      addr, = unpack('>L', S.inet_aton(addr))
+      addr = parse_address(addr)
       return addr
     except S.error:
       return None