def incoming_packet_handler(pktlen, data, timestamp): if not data or data[12:14] != '\x08\x00': return ip_pkt = ip.disassemble(data[14:]) udp_frag = udp.disassemble(ip_pkt.data, False) data_str = udp_frag.data.encode('hex') if udp_frag.data != '' else '-' sys.stdout.write("{} {} {} {}\n".format(ip_pkt.src, udp_frag.sport, udp_frag.dport, data_str)) sys.stdout.flush()
def testUdpPortWronlyParsed(self): ip_reply = ip.disassemble(self.pkt) icmp_reply = icmp.disassemble(ip_reply.data) #ICMP is payload of IP inner_ip = icmp_reply.get_embedded_ip() self.assertEqual('10.249.64.152', inner_ip.src) self.assertEqual('207.68.173.76', inner_ip.dst) udp_in_icmp = udp.disassemble(inner_ip.data, 0) self.assertEqual(40164, udp_in_icmp.sport) self.assertEqual(33435, udp_in_icmp.dport)
class UDPProbe(Probe): def probe_packet(self): """ Build the outgoing probe packet """ # build the packet, then set its length probe_ip = ip.Packet() probe_ip.src = self.src_addr probe_ip.dst = self.dst_addr probe_ip.p = socket.IPPROTO_UDP probe_ip.ttl = self.ttl probe_ip.df = self.dont_frag # build UPD packet as the payload of IP packet probe_udp = udp.Packet() # Because more than 1 traceroute can be running at the same time, we need to # distinguish the packets responding to this traceroute instance. We do this # by setting source port in UDP header to our process id. As ICMP will include # UDP header that triggers it in the payload, we will be able to compare the # UDP source port embedded in returned ICMP packet with our process id and # determine if the packet is of our interest. probe_udp.sport = self.src_port probe_udp.dport = self.dst_port # calculate the length of UDP data header_len = len(udp.assemble(probe_udp) + ip.assemble(probe_ip)) if self.packet_len <= header_len: raise TraceError, "packet length must be > %d" % (header_len) probe_udp.data = '\000' * (self.packet_len - header_len) probe_ip.data = udp.assemble(probe_udp) return ip.assemble(probe_ip, self.check_sum) def received(self, pkt, gateway): """ Upon received an incoming ICMP, determine if the packet is of our interest If it is, populate related fields, and return 1 otherwise return 0 """ ip_reply = ip.disassemble(pkt) if icmp.HDR_SIZE_IN_BYTES > len(ip_reply.data): return 0 #IP payload is not long enough to hold ICMP try: icmp_reply = icmp.disassemble( ip_reply.data) #ICMP is payload of IP except ValueError, msg: if DEBUG: stdout.write("Bad Packet received!") return 0 if DEBUG: stdout.write( "recvfrom %s: ICMP_type: %d ICMP_code: %d" % (gateway, icmp_reply.get_type(), icmp_reply.get_code())) # 2 conditions interest us: # 1. ICMP_TIMEEXCEED, probe packet dropped by gateway in the middle, # which then send ICMP_TIMEEXCEED back to us # 2. ICMP_UNREACH, probe packet reach destination host, which (we assume) # is not listening on the port hence send ICMP_UNREACH back to us if (isinstance(icmp_reply, icmp.TimeExceeded) \ and icmp_reply.get_code() == icmp.ICMP_TIMXCEED_INTRANS) \ or isinstance(icmp_reply, icmp.Unreachable) : inner_ip = icmp_reply.get_embedded_ip() if inner_ip.src != self.src_addr or inner_ip.dst != self.dst_addr: return 0 if udp.HDR_SIZE_IN_BYTES > len(inner_ip.data): return 0 #Not enough data for UDP udp_in_icmp = udp.disassemble(inner_ip.data, 0) if udp_in_icmp.sport == self.src_port \ and udp_in_icmp.dport == self.dst_port: self.gateway = gateway self.timestamp_received = time.time() if icmp_reply.get_type() == icmp.ICMP_UNREACH: self.dst_reached = 1 return 1 if self.verbose: # In verbose mode, ICMP packets other than IME_EXCEEDED and UNREACHABLE are listed stdout.write( "recvfrom %s: ICMP_type: %d ICMP_code: %d" % (gateway, icmp_reply.get_type(), icmp_reply.get_code())) return 0
def testSimplePacket(self): buf = udp.assemble(self.simple, 1) new = udp.disassemble(buf, 1) self.assertEqual(self.simple, new)