def handle_packet_from_outside(self, packet): """Forwards packet to the appropriate simulation, if any.""" if len(packet) < 14: return # too small to even have an Ethernet header # determine which topology(ies) should receive this packet pkt = ProtocolHelper.Packet(packet) if pkt.is_valid_ipv4(): topos = self.resolver.resolve_ip(pkt.ip_dst, pkt.ip_src) str_addr = 'dst=%s src=%s' % (addrstr(pkt.ip_dst), addrstr(pkt.ip_src)) rewrite_dst_mac = True elif pkt.is_dst_mac_broadcast(): return # ignore broadcasts else: topos = self.resolver.resolve_mac(pkt.mac_dst) str_addr = 'dst=%s' % addrstr(pkt.mac_dst) rewrite_dst_mac = False # forward the packet to the appropriate topology(ies) if topos: logging.debug('sniffed raw packet to %s (topology %s): %s' % (str_addr, ','.join([str(t.id) for t in topos]), pktstr(packet))) for topo in topos: topo.create_job_for_incoming_packet(packet, rewrite_dst_mac) self.job_available_event.set()
def register_topology(self, topo): """Registers a topology with the resolver.""" if not topo.has_gateway(): return # it is isolated from the real world for mac in topo.get_my_mac_addrs(): try: self.m2t[mac].append(topo) logging.debug('%s: MAC registered: %s (shared)' % (topo, addrstr(mac))) except KeyError: self.m2t[mac] = [topo] logging.debug('%s: MAC registered: %s' % (topo, addrstr(mac))) for ip in topo.get_all_ip_addrs_in_my_ip_block(): # get the source filtering tree associated with the destination try: st = self.i2t[ip] logging.debug('%s: IP registered: %s (shared)' % (topo, addrstr(ip))) except KeyError: st = IterableSubnetTree() self.i2t[ip] = st logging.debug('%s: IP registered: %s' % (topo, addrstr(ip))) # register which sources this topo wants packets from for ps in topo.get_source_filters(): if st.has_exact(ps): # another topo has both this dst IP and the same source filter st[ps].append(topo) logging.debug('%s: Source filter: %s (shared)' % (topo, ps)) else: st[ps] = [topo] logging.debug('%s: Source filter: %s' % (topo, ps))
def unregister_topology(self, topo): """Unregisters a topology with the resolver.""" if not topo.has_gateway(): return # it is isolated from the real world for mac in topo.get_my_mac_addrs(): try: topos = self.m2t[mac] try: topos.remove(topo) if not topos: del self.m2t[mac] except ValueError: logging.error('%s: missing topo in list for %s' % (topo, addrstr(mac))) except KeyError: logging.error('%s: missing topo list for %s' % (topo, addrstr(mac))) for ip in topo.get_all_ip_addrs_in_my_ip_block(): # get the source filtering tree associated with the destination try: st = self.i2t[ip] except KeyError: logging.error('%s: missing subnet tree for %s' % (topo, addrstr(ip))) continue # unregister which sources this topo wants packets from for ps in topo.get_source_filters(): try: topos = st.get_exact(ps) try: topos.remove( topo) # remove this topology's registration if not topos: del st[ps] except ValueError: logging.error( '%s: missing topology in source filter %s for %s' % (topo, ps, addrstr(ip))) except KeyError: logging.error('%s: missing source filter %s for %s' % (topo, ps, addrstr(ip))) # if no topologies are still mapped to this IP, then delete this empty tree if len(st) == 0: del self.i2t[ip]
def __make_response_dynamic_body(body, pkt): """Replaces tags in a given response body with the proper values from the request packet. This is used in order to see what request ip and port the HTTPServer sees (useful for testing NAT).""" body = body.replace('%SRC_PORT%', portstr(pkt.tcp_src_port)) body = body.replace('%SRC_IP%', addrstr(pkt.ip_src)) return body
def resolve_mac(self, dst_mac): """Resolves a dst MAC address to a list of topologies to which the packet to this dst should be forwarded.""" try: topos = self.m2t[dst_mac] logging.debug('MAC %s resolved to topo %s' % (addrstr(dst_mac), ','.join([str(t.id) for t in topos]))) return topos except KeyError: # logging.debug('Ignoring packet to MAC %s' % addrstr(dst_mac)) return [] # no topology has this MAC address
def unregister_topology(self, topo): """Unregisters a topology with the resolver.""" if not topo.has_gateway(): return # it is isolated from the real world for mac in topo.get_my_mac_addrs(): try: topos = self.m2t[mac] try: topos.remove(topo) if not topos: del self.m2t[mac] except ValueError: logging.error('%s: missing topo in list for %s' % (topo, addrstr(mac))) except KeyError: logging.error('%s: missing topo list for %s' % (topo, addrstr(mac))) for ip in topo.get_all_ip_addrs_in_my_ip_block(): # get the source filtering tree associated with the destination try: st = self.i2t[ip] except KeyError: logging.error('%s: missing subnet tree for %s' % (topo, addrstr(ip))) continue # unregister which sources this topo wants packets from for ps in topo.get_source_filters(): try: topos = st.get_exact(ps) try: topos.remove(topo) # remove this topology's registration if not topos: del st[ps] except ValueError: logging.error('%s: missing topology in source filter %s for %s' % (topo, ps, addrstr(ip))) except KeyError: logging.error('%s: missing source filter %s for %s' % (topo, ps, addrstr(ip))) # if no topologies are still mapped to this IP, then delete this empty tree if len(st) == 0: del self.i2t[ip]
def resolve_mac(self, dst_mac): """Resolves a dst MAC address to a list of topologies to which the packet to this dst should be forwarded.""" try: topos = self.m2t[dst_mac] logging.debug( 'MAC %s resolved to topo %s' % (addrstr(dst_mac), ','.join([str(t.id) for t in topos]))) return topos except KeyError: # logging.debug('Ignoring packet to MAC %s' % addrstr(dst_mac)) return [] # no topology has this MAC address
def resolve_ip(self, dst_ip, src_ip=None): """Resolves a src and dst IP address pair to a list of topologies to which the packet with this src and dst should be forwarded. All parameters should be in network byte ordered byte strings. @param dst_ip_or_mac The destination IP or MAC address. @param src_ip The source IP this packet is from. It may be omitted when the source IP is not known (e.g., L2 traffic). @return An empty list is returned if no mapping exists. Otherwise, the returned list is all topologies which should receive the packet. """ try: st = self.i2t[dst_ip] except KeyError: # logging.debug('Ignoring packet to %s' % addrstr(dst_ip)) return [] # no topology has this IP address # If there is no source IP, return all of the topologies which have this # destination address. if not src_ip: logging.debug('No source IP given. All topos mapped by %s: %s' % \ (addrstr(dst_ip), ','.join([str(t.id) for t in st.values()]))) return st.values() # Figure out which topology is interested in packets from this source. try: topos = st[src_ip] logging.debug('IP pair resolved to topo: (%s->%s) -> %s' % \ (addrstr(src_ip), addrstr(dst_ip), ','.join([str(t.id) for t in topos]))) return topos except KeyError: logging.debug('IP pair ignored (not interested in the source): %s->%s' % \ (addrstr(src_ip), addrstr(dst_ip))) return [] # nobody is interested in packets from this source
def handle_packet(self, intf, packet): """Responses to ARP requests (as appropriate) and forwards IP packets.""" if len(packet) < 14: logging.debug('%s ignoring packet which is too small: %dB' % (self.di(), len(packet))) return logging.debug('%s handling packet: %s' % (self.di(), pktstr(packet))) pkt = ProtocolHelper.Packet(packet) if pkt.mac_dst != intf.mac and not (pkt.is_valid_arp() and pkt.mac_dst=='\xFF\xFF\xFF\xFF\xFF\xFF'): logging.debug('%s dropping packet (not to my mac addr %s): %s' % (self.di(), addrstr(intf.mac), pktstr(packet))) elif pkt.is_valid_ipv4(): self.handle_ipv4_packet(intf, pkt) elif pkt.is_valid_arp(): self.handle_arp_packet(intf, pkt) else: logging.debug('%s discarding packet which is neither valid IPv4 nor ARP' % self.di())
def __get_intf_str(intf): str_link = intf.link.str_half(intf) if intf.link else '' return '%s={%s,%s}%s' % (intf.name, addrstr(intf.ip), addrstr(intf.mac), str_link)