def __init__(self, tap=True, readSockets=[]): """ Constructor for Ether2Any. isTap defines if the managed device should be a tap (ethernet tunnel) or a tun (IP tunnel). """ self.readSockets = readSockets # create device self.dev = TapDevice(tap=tap) self.timeout = None
class TapLoop: ''' This class creates a pair of interconnected TAP interfaces. If address and netmask are provided, they get assigned to the "remote" interface. The users are supposed to call get_iface() method to obtain the name of the "local" interface. Then the users are expected to use raw sockets to send/receive traffic on that local interface, possibly to interact with the remote end. ''' def __init__(self, local_address = None, remote_address = None, netmask = None): self.t1 = TapDevice(mode = IFF_TAP) self.t2 = TapDevice(mode = IFF_TAP) if local_address != None and netmask != None: self.t1.ifconfig(address = local_address, netmask = netmask) if remote_address != None and netmask != None: self.t2.ifconfig(address = remote_address, netmask = netmask) self.t1.up() self.t2.up() self.pump1 = Pump(self.t1, self.t2) self.pump2 = Pump(self.t2, self.t1) logger.debug("Allocated TAP interfaces %s/%s" % (self.t1.name, self.t2.name)) def start(self): self.pump1.start() self.pump2.start() logger.debug("Started pump threads") def get_iface(self): return self.t1.name
def __init__(self, local_address = None, remote_address = None, netmask = None): self.t1 = TapDevice(mode = IFF_TAP) self.t2 = TapDevice(mode = IFF_TAP) if local_address != None and netmask != None: self.t1.ifconfig(address = local_address, netmask = netmask) if remote_address != None and netmask != None: self.t2.ifconfig(address = remote_address, netmask = netmask) self.t1.up() self.t2.up() self.pump1 = Pump(self.t1, self.t2) self.pump2 = Pump(self.t2, self.t1) logger.debug("Allocated TAP interfaces %s/%s" % (self.t1.name, self.t2.name))
def __init__(self, options={}): self.secret = options.get('secret','') self.port = options.get('port',11111) self.buffer = [] self.loadbalancer_pool = [] _tap = options.get('tap', True) _name = options.get('name', '') self.dev = TapDevice(tap=_tap, name=_name) asyncore.file_dispatcher.__init__(self, self.dev.getFD()) self.dev.up() if options.get('tunnel_address', False): self.dev.ifconfig(address=options.get('tunnel_address')) logging.debug('Interface ready')
class Ether2Any: """ Baseclass for writing arbitrary Ethernet/IP tunnel using a TUN/TAP device. This class handles a TUN/TAP devices and runs a select loop for it and, if given, a set of sockets. To use this class at least sendToNet() has to be implemented by a subclass. """ def __init__(self, tap=True, readSockets=[]): """ Constructor for Ether2Any. isTap defines if the managed device should be a tap (ethernet tunnel) or a tun (IP tunnel). """ self.readSockets = readSockets # create device self.dev = TapDevice(tap=tap) self.timeout = None def setupLogging(self, name): l = logging.getLogger(name) fmt = logging.Formatter("%(asctime)s - [%(levelname)s] (%(name)s) - %(message)s") ch = logging.StreamHandler() ch.setFormatter(fmt) l.addHandler(ch) return l def addSocket(self, sock): """ Add socket to readSockets set. """ self.readSockets.append(sock) def delSocket(self, socket): """ Remove socket from readSockets set. """ try: self.readSockets.remove(socket) except ValueError: pass # outgoing data def sendToNet(self, packet): """ This function has to be implemented to handle outgoing data (read from the TUN/TAP device) """ raise NotImplementedError("You need to overload sendToNet()") # incoming data def sendToDev(self, sock): """ This function has to be implemented to handle incoming data which is read from the extra sockets (self.readSockets). It will not be called when no extra readSockets are specified. """ raise NotImplementedError("You need to overload sendToDev()") def setTimeout(self, t): """ Set select timeout. """ self.timeout = t def callAfterSelect(self): """ Will be called as last operation of the mainloop when handling of the select result / the select timeout is hit. """ pass def run(self): """ Run main select-loop. """ try: while True: sockets = [self.dev.getFD()] + self.readSockets (readFDs, _, _) = select.select(sockets, [], [], self.timeout) for readFD in readFDs: if readFD == self.dev.getFD(): self.sendToNet(self.dev.read()) elif readFD in self.readSockets: self.sendToDev(readFD) self.callAfterSelect() except KeyboardInterrupt: self.quit() self.dev.close() def quit(self): """ Will be called after the run-select() and its processing is done. """ pass
class LoadbalancerControl(asyncore.file_dispatcher): shutdown = False # Loadbalancers shouldn't reconnect rr = 0 # RoundRobin iterator counter def __init__(self, options={}): self.secret = options.get('secret','') self.port = options.get('port',11111) self.buffer = [] self.loadbalancer_pool = [] _tap = options.get('tap', True) _name = options.get('name', '') self.dev = TapDevice(tap=_tap, name=_name) asyncore.file_dispatcher.__init__(self, self.dev.getFD()) self.dev.up() if options.get('tunnel_address', False): self.dev.ifconfig(address=options.get('tunnel_address')) logging.debug('Interface ready') def eth_addr (self, a) : b = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]) , ord(a[1]) , ord(a[2]), ord(a[3]), ord(a[4]) , ord(a[5])) return b def validate(self, data): eth_length = 14 eth_header = data[:eth_length] eth = struct.unpack('!6s6sH' , eth_header) eth_protocol = socket.ntohs(eth[2]) # print 'Destination MAC : ' + self.eth_addr(data[0:6]) + ' Source MAC : ' + self.eth_addr(data[6:12]) + ' Protocol : ' + str(eth_protocol) ip_header = data[eth_length:20+eth_length] iph = struct.unpack('!BBHHHBBH4s4s' , ip_header) version_ihl = iph[0] ihl = version_ihl & 0xF iph_length = ihl * 4 protocol = iph[6] s_addr = socket.inet_ntoa(iph[8]) d_addr = socket.inet_ntoa(iph[9]) # udp_header = data[iph_length+eth_length:iph_length+20+eth_length] # udph = struct.unpack('!HHLLBBHHH' , udp_header) # print "[{}] - {}:{} -> {}:{}".format(protocol, s_addr,udph[0], d_addr,udph[1]) def writable(self): return len(self.buffer) > 0 def handle_write(self): """ Write local buffer to interface """ try: packet = self.buffer.pop() logging.debug('Writing {}byte packet to device'.format(len(packet))) self.dev.write(packet) except IndexError: pass except OSError as e: if e.errno == 22: # Invalid packet logging.debug('Failed to write invalid packet "{}"'.format(packet)) else: logging.exception('Writing "{}" to device caused exception: {}'.format(packet, e.strerror)) except Exception as e: logging.exception('Writing "{}" to device caused exception: {}'.format(packet, e.strerror)) def write(self, packet): """ Forward data from loadbalancers to local buffer """ if packet: # self.validate(packet) self.buffer.append(packet) def handle_read_event(self): """ Forward received packets to loadbalancers """ packet = self.dev.read() self.balance_data_round_robin(packet) def balance_data_round_robin(self, packet): """ Use Round Robin to distribute each packet via revolving loadbalancers """ if len(self.loadbalancer_pool) == 0: return # logging.debug('Sending {}byte packet via {}'.format(len(packet), repr(self.loadbalancer_pool[self.rr]))) self.loadbalancer_pool[self.rr].send(packet) self.rr = self.rr+1 if self.rr < len(self.loadbalancer_pool)-1 else 0 def quit(self): """ Gracefully close all loadbalancers and self """ self.shutdown = True logging.debug('Closing loadbalancers...') # Loadbalancer modifies the pool in close, so make a static list for s in list(self.loadbalancer_pool): s.handle_close() if self.loadbalancer_pool: logging.debug('Waiting for loadbalancers to close...') for i in range(5): if len(self.loadbalancer_pool) == 0: break time.sleep(1) else: for s in self.loadbalancer_pool: s.close() del s logging.debug('Closing self...') self.dev.close()