4 signal.signal(signal.SIGINT, signal.SIG_DFL)
7 from twisted.internet import reactor
10 from ipaddress import AddressValueError
12 import hippotat.slip as slip
14 #---------- packet parsing ----------
16 def packet_addrs(packet):
17 version = packet[0] >> 4
21 factory = ipaddress.IPv4Address
25 factory = ipaddress.IPv6Address
27 raise ValueError('unsupported IP version %d' % version)
28 saddr = factory(packet[ saddroff : saddroff + addrlen ])
29 daddr = factory(packet[ saddroff + addrlen : saddroff + addrlen*2 ])
32 #---------- address handling ----------
36 r = ipaddress.IPv4Address(input)
37 except AddressValueError:
38 r = ipaddress.IPv6Address(input)
43 r = ipaddress.IPv4Network(input)
44 except NetworkValueError:
45 r = ipaddress.IPv6Network(input)
48 #---------- ipif (SLIP) subprocess ----------
50 class _IpifProcessProtocol(twisted.internet.protocol.ProcessProtocol):
51 def __init__(self, router):
54 def connectionMade(self): pass
55 def outReceived(self, data):
56 #print('RECV ', repr(data))
58 packets = slip.decode(self._buffer)
59 self._buffer = packets.pop()
60 for packet in packets:
61 if not len(packet): continue
62 (saddr, daddr) = packet_addrs(packet)
63 self._router(packet, saddr, daddr)
64 def processEnded(self, status):
65 status.raiseException()
67 def start_ipif(command, router):
69 ipif = _IpifProcessProtocol(router)
70 reactor.spawnProcess(ipif,
71 '/bin/sh',['sh','-xc', command],
72 childFDs={0:'w', 1:'r', 2:2})
74 def queue_inbound(packet):
75 ipif.transport.write(slip.delimiter)
76 ipif.transport.write(slip.encode(packet))
77 ipif.transport.write(slip.delimiter)
79 #---------- packet queue ----------
82 def __init__(self, max_queue_time):
83 self._max_queue_time = max_queue_time
84 self._pq = collections.deque() # packets
86 def append(self, packet):
87 self._pq.append((time.monotonic(), packet))
91 try: (queuetime, packet) = self._pq[0]
92 except IndexError: return False
94 age = time.monotonic() - queuetime
95 if age > self.max_queue_time:
96 # strip old packets off the front
103 # caller must have checked nonempty
104 try: (dummy, packet) = self._pq[0]
105 except IndexError: return None