def handle_packet(self, incoming_intf, packet): """Forwards an IP packet from the simulated topology to the network.""" if len(packet) >= 34 and packet[12:14] == '\x08\x00': dst_ip = packet[30:34] if not MAY_FORWARD_TO_PRIVATE_IPS and self.__is_private_address(dst_ip): logging.debug('%s ignoring IP packet to private address space: %s' % (self.di(), inet_ntoa(dst_ip))) return if len(packet) >= 42 and packet[12:14] == '\x08\06' and self.topo.gw_intf_to_first_hop: pkt = ProtocolHelper.Packet(packet) if pkt.is_arp_reply() and pkt.dha == self.topo.gw_intf_to_first_hop.mac: logging.debug('%s: handling ARP reply from first hop to gateway' % self.di()) self.topo.update_arp_translation(pkt.spa, pkt.sha) return # forward packet out to the real network if self.raw_socket: try: logging.debug('%s sending packet out to the real world: %s' % (self.di(), pktstr(packet))) self.topo.stats.note_pkt_from_topo(len(packet)) self.raw_socket.send(packet) except socket.error: # this is recoverable - the network may come back up log_exception(logging.WARN, 'unable to forward packet to the real network')
def start_topology(self, tid, client_ip, user): """Handles starting up the specified topology id. Returns a 2-tuple. The first element is None and the second is a string if an error occurs; otherwise the first element is the topology.""" try: topo = DBService.run_and_wait(lambda: Topology(tid, self.raw_socket, client_ip, user)) topo.interactors = [] # list of TI connections to this topo except TopologyCreationException as e: return (None, str(e)) except db.Topology.DoesNotExist: return (None, 'topology %d does not exist' % tid) except db.IPAssignment.DoesNotExist: return (None, 'topology %d is missing an IP assignment' % tid) except db.IPBlockAllocation.DoesNotExist: return (None, 'topology %d is not allocated any IPs' % tid) except AddressAllocation.IPError: return (None, 'not enough IPs to allocate for topology %d' % tid) except: msg = 'topology instantiation unexpectedly failed' log_exception(logging.ERROR, msg) return (None, msg) if topo.has_gateway(): self.resolver.register_topology(topo) with self.topologies_lock: self.topologies[tid] = topo self.topologies_changed = True return (topo, None)
def start_topology(self, tid, client_ip, user): """Handles starting up the specified topology id. Returns a 2-tuple. The first element is None and the second is a string if an error occurs; otherwise the first element is the topology.""" try: topo = Topology(tid, self.raw_socket, client_ip, user) topo.interactors = [] # list of TI connections to this topo except TopologyCreationException as e: return (None, str(e)) except db.Topology.DoesNotExist: return (None, 'topology %d does not exist' % tid) except db.IPAssignment.DoesNotExist: return (None, 'topology %d is missing an IP assignment' % tid) except db.IPBlockAllocation.DoesNotExist: return (None, 'topology %d is not allocated any IPs' % tid) except: msg = 'topology instantiation unexpectedly failed' log_exception(logging.ERROR, msg) return (None, msg) if topo.has_gateway(): self.resolver.register_topology(topo) with self.topologies_lock: self.topologies[tid] = topo self.topologies_changed = True return (topo, None)
def handle_packet(self, incoming_intf, packet): """Forwards an IP packet from the simulated topology to the network.""" if len(packet) >= 34 and packet[12:14] == '\x08\x00': dst_ip = packet[30:34] if not MAY_FORWARD_TO_PRIVATE_IPS and self.__is_private_address(dst_ip): logging.debug('%s ignoring IP packet to private address space: %s' % (self.di(), inet_ntoa(dst_ip))) return if len(packet) >= 42 and packet[12:14] == '\x08\06' and self.topo.gw_intf_to_first_hop: pkt = ProtocolHelper.Packet(packet) if pkt.is_arp_reply() and pkt.dha == self.topo.gw_intf_to_first_hop.mac: logging.debug('%s: handling ARP reply from first hop to gateway' % self.di()) self.topo.update_arp_translation(pkt.sha) return # forward packet out to the real network if self.raw_socket: try: logging.debug('%s sending packet out to the real world: %s' % (self.di(), pktstr(packet))) self.topo.stats.note_pkt_from_topo(len(packet)) self.raw_socket.send(packet) except socket.error: # this is recoverable - the network may come back up log_exception(logging.WARN, 'unable to forward packet to the real network')
def __start_raw_socket(self, dev): """Starts a socket for sending raw Ethernet frames.""" try: self.raw_socket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) self.raw_socket.bind((dev, 0x9999)) except socket.error as e: if e.errno == errno.EPERM: extra = ' (did you forget to run me with root?)' else: extra = '' log_exception(logging.CRITICAL, 'failed to open raw socket' + extra) sys.exit(-1)
def __run_pcap(self, dev): """Start listening for packets coming in from the outside world.""" MAX_LEN = 2000 # max size of packet to capture PROMISCUOUS = 1 # promiscuous mode? READ_TIMEOUT = 100 # in milliseconds MAX_PKTS = -1 # number of packets to capture; -1 => no limit # the method which will be called when a packet is captured def ph(_, data): # thread safety: call from the main twisted event loop reactor.callFromThread(self.handle_packet_from_outside, data) # start the packet capture try: p = open_live(dev, MAX_LEN, PROMISCUOUS, READ_TIMEOUT) except PcapError: log_exception(logging.CRITICAL, 'failed to start pcap') sys.exit(-1) p.setfilter(PCAP_FILTER) logging.info("Listening on %s: net=%s, mask=%s, filter=%s" % (dev, p.getnet(), p.getmask(), PCAP_FILTER)) p.loop(MAX_PKTS, ph)