def test_chain_compare(self): """Test the underlying __eq__ functionality of the packet. Two packets constructed from the same bytes should be equal and two that are not should not be equal.""" file = PcapConnector("loopping.out") packet = file.readpkt() # Create new packets don't just point to them ip1 = ipv4(packet.data.bytes) ip2 = ipv4(packet.data.bytes) assert (ip1 != None) assert (ip2 != None) ether1 = ethernet() ether1.src = "\x00\x00\x00\x00\x00\x01" ether1.dst = "\x00\x00\x00\x00\x00\x02" ether2 = ethernet() ether2.src = "\x00\x00\x00\x00\x00\x01" ether2.dst = "\x00\x00\x00\x00\x00\x02" chain1 = Chain([ether1, ip1]) chain2 = Chain([ether2, ip2]) self.assertEqual(chain1, chain2, "chains should be equal but are not") ip1.dst = 0 self.assertNotEqual(chain1, chain2, "chains compare equal but should not")
def test_chain_compare(self): """Test the underlying __eq__ functionality of the packet. Two packets constructed from the same bytes should be equal and two that are not should not be equal.""" file = PcapConnector("loopping.out") packet = file.readpkt() # Create new packets don't just point to them ip1 = ipv4(packet.data.bytes) ip2 = ipv4(packet.data.bytes) assert ip1 != None assert ip2 != None ether1 = ethernet() ether1.src = "\x00\x00\x00\x00\x00\x01" ether1.dst = "\x00\x00\x00\x00\x00\x02" ether2 = ethernet() ether2.src = "\x00\x00\x00\x00\x00\x01" ether2.dst = "\x00\x00\x00\x00\x00\x02" chain1 = Chain([ether1, ip1]) chain2 = Chain([ether2, ip2]) self.assertEqual(chain1, chain2, "chains should be equal but are not") ip1.dst = 0 self.assertNotEqual(chain1, chain2, "chains compare equal but should not")
def test_div(self): """Test the Scapy-style chain construction syntax.""" # Create a bunch of individual packets. a = ethernet.ethernet() b = ipv4.ipv4() c = udpv4.udpv4(sport=1234) d = dhcpv4.dhcpv4() # Pack them into chains, assert that their properties still hold. x = a / b self.assertEqual(len(x.packets), 2, "x does not have 2 packets") self.assertEqual(x.packets[0].type, 0x0800, "x[0].type is not ETHERTYPE_IP") # XXX The link in the existing chain must be broken for these # invariants to hold; the semantics of chains have changed therefore # these need to be updated. # y = b / c # self.assertEqual(len(y.packets), 2, "y does not have 2 packets") # self.assertEqual(y.packets[0].protocol, 17, \ # "y.packets[0].protocol is not UDP") # z = c / d # self.assertEqual(len(z.packets), 2, "z does not have 2 packets") # self.assertEqual(z.packets[0].sport, 1234, "z.packets[0].sport is not 1234") # self.assertEqual(z.packets[0].dport, 67, "z.packets[0].dport is not 67") # All together now. alpha = ethernet.ethernet() / ipv4.ipv4() / udpv4.udpv4(sport=1234) / dhcpv4.dhcpv4() self.assertEqual(len(alpha.packets), 4, "alpha does not have 4 packets") self.assertEqual(alpha.packets[0].type, 0x0800, "alpha.packets[0].type is not ETHERTYPE_IP") self.assertEqual(alpha.packets[1].protocol, 17, "alpha.packets[1].protocol is not UDP") self.assertEqual(alpha.packets[2].sport, 1234, "alpha.packets[2].sport is not 1234") self.assertEqual(alpha.packets[2].dport, 67, "alpha.packets[2].dport is not 67")
def main(): file = pcs.PcapConnector("fxp0") # First, build a chain and use it as a filter to match any IGMPv2 joins # seen on the network. m = ethernet.ethernet() / ipv4.ipv4() / \ igmp.igmp(type=IGMP_v2_HOST_MEMBERSHIP_REPORT) / igmpv2.igmpv2() t = 50 print "Waiting %d seconds to see an IGMPv2 report." % t try: file.expect([m], t) except pcs.TimeoutError: print "Timed out." sys.exit(1) # Now try it with a "contains" filter. # This will match any packet chain containing an IGMPv2 message. c = igmpv2.igmpv2() t = 50 print "Waiting %d seconds to see an IGMPv2 report using 'contains'." % t try: file.expect([c], t) except pcs.TimeoutError: print "Timed out." sys.exit(1) print "And the matching packet chain is:" print file.match # Define a match function to apply to a field. # We could really use some syntactic sugar for this... def contains_router_alert(lp, lf, rp, rf): for i in rf._options: if isinstance(i, pcs.TypeLengthValueField) and \ i.type.value == IPOPT_RA: return True return False # Create a "contains" filter consisting of a single IPv4 datagram # with a "Router Alert" option in the header. Strictly speaking the # option isn't needed, as above we define a function which is used # as a compare function for the option list field. c = ipv4.ipv4(options=[ipv4opt(IPOPT_RA)]) c.options.compare = contains_router_alert t = 50 print "Waiting %d seconds to see any IP packet containing a Router Alert option." % t try: file.expect([c], t) except pcs.TimeoutError: print "Timed out." sys.exit(1) print "And the matching packet chain is:" print file.match sys.exit(0)
def test_pcap_write(self): """Test the underlying __compare__ functionality of the packet. Two packets constructed from the same bytes should be equal and two that are not should not be equal.""" from pcs.pcap import DLT_NULL # Create a vanilla ping packet ip = ipv4() ip.version = 4 ip.hlen = 5 ip.tos = 0 ip.length = 64 ip.id = 1 ip.flags = 0 ip.offset = 0 ip.ttl = 64 ip.protocol = IPPROTO_ICMP ip.src = inet_atol("127.0.0.1") ip.dst = inet_atol("127.0.0.1") icmp = icmpv4() icmp.type = 8 icmp.code = 0 echo = icmpv4echo() echo.id = 32767 echo.seq = 1 lo = localhost() lo.type = 2 packet = Chain([lo, ip, icmp, echo]) outfile = PcapDumpConnector("pcaptest.dump", DLT_NULL) outfile.write(packet.bytes) outfile.close() infile = PcapConnector("pcaptest.dump") packet = infile.read() ipnew = ipv4(packet[infile.dloff:len(packet)]) assert (ip != None) assert (ipnew != None) self.assertEqual(ip, ipnew, "packets should be equal but are not")
def next(self, bytes): """Decode the type of a packet and return the correct higher level protocol object""" print self.type print socket.AF_INET6 ## type is the address family, and NOT an ethertype if self.type == socket.AF_INET: return ipv4.ipv4(bytes) if self.type == socket.AF_INET6: return ipv6.ipv6(bytes) return None
def next(self, bytes): """Decode the type of a packet and return the correct higher level protocol object""" ## the ethertype of the packet if self.type == ETHERTYPE_ARP: return arp(bytes) if self.type == ETHERTYPE_IP: return ipv4(bytes) if self.type == ETHERTYPE_IPV6: return ipv6(bytes) return None
def test_div(self): """Test the Scapy-style chain construction syntax.""" # Create a bunch of individual packets. a = ethernet.ethernet() b = ipv4.ipv4() c = udpv4.udpv4(sport=1234) d = dhcpv4.dhcpv4() # Pack them into chains, assert that their properties still hold. x = a / b self.assertEqual(len(x.packets), 2, "x does not have 2 packets") self.assertEqual(x.packets[0].type, 0x0800, \ "x[0].type is not ETHERTYPE_IP") # XXX The link in the existing chain must be broken for these # invariants to hold; the semantics of chains have changed therefore # these need to be updated. #y = b / c #self.assertEqual(len(y.packets), 2, "y does not have 2 packets") #self.assertEqual(y.packets[0].protocol, 17, \ # "y.packets[0].protocol is not UDP") #z = c / d #self.assertEqual(len(z.packets), 2, "z does not have 2 packets") #self.assertEqual(z.packets[0].sport, 1234, "z.packets[0].sport is not 1234") #self.assertEqual(z.packets[0].dport, 67, "z.packets[0].dport is not 67") # All together now. alpha = ethernet.ethernet() / ipv4.ipv4() / udpv4.udpv4(sport=1234) / \ dhcpv4.dhcpv4() self.assertEqual(len(alpha.packets), 4, "alpha does not have 4 packets") self.assertEqual(alpha.packets[0].type, 0x0800, \ "alpha.packets[0].type is not ETHERTYPE_IP") self.assertEqual(alpha.packets[1].protocol, 17, \ "alpha.packets[1].protocol is not UDP") self.assertEqual(alpha.packets[2].sport, 1234, \ "alpha.packets[2].sport is not 1234") self.assertEqual(alpha.packets[2].dport, 67, \ "alpha.packets[2].dport is not 67")
def test_deepcopy_chain(self): from pcs.packets.ipv4 import ipv4 c1 = Chain([ipv4()]) p1 = c1.packets[0] self.assert_(p1._head is c1) c2 = deepcopy(c1) self.assert_(c2 is not c1) p2 = c2.packets[0] self.assert_(p2 is not p1) self.assert_(p2._head is c2) self.assert_(id(p2) != id(p1)) self.assert_(id(p2._fieldnames['id']) != id(p1._fieldnames['id'])) pass
def test_deepcopy_packet(self): from pcs.packets.ipv4 import ipv4 p1 = ipv4(id=123) self.assert_(isinstance(p1, ipv4)) p2 = deepcopy(p1) self.assert_(isinstance(p2, ipv4)) self.assert_(id(p2) != id(p1)) self.assert_(id(p2._fieldnames['id']) != id(p1._fieldnames['id'])) self.assert_(p2.id == p1.id) p2.id = 456 self.assert_(id(p2._fieldnames['id']) != id(p1._fieldnames['id'])) self.assert_(p2.id != p1.id) # Copying a Packet DOES NOT copy its payload. self.assert_(p2.data == None)
def test_pcap_file(self): file = PcapConnector("loopping.out") packet = file.read() ip = ipv4(packet[file.dloff:len(packet)]) assert (ip != None) self.assertEqual(ip.version, 4, "version not equal %d" % ip.version) self.assertEqual(ip.hlen, 5, "hlen not equal %d" % ip.hlen) self.assertEqual(ip.tos, 0, "tos not equal %d" % ip.tos) self.assertEqual(ip.length, 84, "length not equal %d" % ip.length) self.assertEqual(ip.id, 59067, "id not equal %d" % ip.id) self.assertEqual(ip.flags, 0, "flags not equal %d" % ip.flags) self.assertEqual(ip.offset, 0, "offset not equal %d" % ip.offset) self.assertEqual(ip.ttl, 64, "ttl not equal %d" % ip.ttl) self.assertEqual(ip.protocol, 1, "protocol not equal %d" % ip.protocol) self.assertEqual(ip.src, inet_atol("127.0.0.1"), "src not equal %d" % ip.src) self.assertEqual(ip.dst, inet_atol("127.0.0.1"), "dst not equal %d" % ip.dst)
def ip_cksum(ip): #TODO: solve the self problem, may be adding another arg """calculate the IPv4 checksum over a packet returns the calculated checksum """ import struct total = 0 packet = ipv4.ipv4(ip.bytes) packet.checksum = 0 bytes = packet.bytes if len(bytes) % 2 == 1: bytes += "\0" for i in range(len(bytes) / 2): total += (struct.unpack("!H", bytes[2 * i:2 * i + 2])[0]) total = (total >> 16) + (total & 0xffff) total += total >> 16 return ~total & 0xffff
def main(): from pcs import PcapConnector, TimeoutError, LimitReachedError from pcs.packets.ethernet import ethernet from pcs.packets.ipv4 import ipv4 from pcs.packets.icmpv4 import icmpv4 from pcs.packets.icmpv4 import icmpv4echo from pcs.packets.icmpv4 import ICMP_ECHO #from pcs.packets.icmpv4 import ICMP_ECHOREPLY fxp0 = PcapConnector("fxp0") filter = ethernet() / ipv4() / icmpv4(type=ICMP_ECHO) / icmpv4echo() #from pcs.bpf import program #bp = fxp0.make_bpf_program(filter) #for lp in bp.disassemble(): # print lp #fxp0.setfilter('icmp') #fxp0.set_bpf_program(bp) print "Expecting at least 1 ICMP echo request within 10 seconds." try: fxp0.expect([filter], 10) except LimitReachedError: print "Limit reached." sys.exit(1) except TimeoutError: print "Timed out." sys.exit(1) nmatches = 0 if fxp0.matches is not None: nmatches = len(fxp0.matches) print "Matched", nmatches, "chain(s)." sys.exit(0)
def createip(self, tcb, from_, to): """Create ip packet tcp is also created here""" ip1 = ipv4.ipv4() ip1.version = 4 ip1.hlen = 5 ip1.tos = 0 ip1.id = tcb.ipid[from_] ip1.flags = 0 ip1.offset = 0 ip1.ttl = 64 ip1.protocol = pcs.IPPROTO_TCP ip1.src = tcb.ip[from_] ip1.dst = tcb.ip[to] ip1.length = len(ip1.bytes) # tcp here tcp1 = createtcp(self, tcb, ip1, from_, to) ip1.length = len(ip1.bytes) + len(tcp1.bytes) #ip1.checksum = ip_cksum(ip1) #doind this at checkout(createwritepacket) return (ip1, tcp1)
def test_pcap_live(self): """Test live injection and reception. This test requires threads and must be run as root to succeed.""" import threading e = ethernet() assert (e != None) e.src = "\x00\xbd\x03\x07\xfa\x00" e.dst = "\x00\xbd\x03\x07\xfa\x00" e.type = 0x0800 # Create a vanilla ping packet ip = ipv4() ip.version = 4 ip.hlen = 5 ip.tos = 0 ip.length = 64 ip.id = 1 ip.flags = 0 ip.offset = 0 ip.ttl = 64 ip.protocol = IPPROTO_ICMP ip.src = inet_atol("192.0.2.1") ip.dst = inet_atol("192.0.2.1") icmp = icmpv4() icmp.type = 8 icmp.code = 0 echo = icmpv4echo() echo.id = 54321 echo.seq = 12345 ip.length = len(ip.bytes) + len(icmp.bytes) + len(echo.bytes) packet = Chain([e, ip, icmp, echo]) packet.calc_checksums() packet.encode() import os uname = os.uname()[0] if uname == "FreeBSD": devname = "edsc0" elif uname == "Linux": devname = "lo" elif uname == "Darwin": devname = "en0" else: print "unknown host os %s" % uname return wfile = PcapConnector(devname) rfile = PcapConnector(devname) rfile.setfilter("icmp") count = wfile.write(packet.bytes, 42) assert (count == 42) got = ethernet(rfile.read()) ip = got.data ping = ip.data self.assertEqual(ping, icmp)
def main(): from optparse import OptionParser parser = OptionParser() parser.add_option("-i", "--interface", dest="interface", default=None, help="Network interface to send on.") parser.add_option("-t", "--target", dest="ip_target", default=None, help="IPv4 target address to lookup.") parser.add_option("-s", "--ip_source", dest="ip_source", default=None, help="IPv4 source address to use.") parser.add_option("-d", "--ether_destination", dest="ether_destination", default=None, help="Ethernet destination address to use.") parser.add_option("-e", "--ether_source", dest="ether_source", default=None, help="Ethernet source address to use.") parser.add_option("-o", "--source-port", dest="source_port", default=None, help="Tcp source port.") parser.add_option("-x", "--destination-port", dest="destination_port", default=None, help="Tcp destination port.") (options, args) = parser.parse_args() import random ipid = random.randrange(1, (1 << 16) - 1) tcpsport = random.randrange(50000, 60000) #int(options.source_port ) tcpsequence = random.randrange(1, (1 << 32) - 1) output = pcs.PcapConnector(options.interface) replyip = None replytcp = None reply = None packet = None # SYN what = "SYN" ip1 = ipv4.ipv4() ip1.version = 4 ip1.hlen = 5 ip1.tos = 0 ip1.id = ++ipid ip1.flags = 0 ip1.offset = 0 ip1.ttl = 64 ip1.protocol = pcs.IPPROTO_TCP ip1.src = pcs.inet_atol(options.ip_source) ip1.dst = pcs.inet_atol(options.ip_target) tcp1 = tcp.tcp() tcp1.sport = tcpsport tcp1.dport = int(options.destination_port) tcp1.sequence = tcpsequence tcpsequence = tcpsequence + 1 # SYN consumes the sequence tcp1.ack_number = 0 tcp1.offset = 5 tcp1.urgent = 0 tcp1.ack = 0 tcp1.push = 0 tcp1.reset = 0 tcp1.syn = 1 tcp1.fin = 0 tcp1.window = (1 << 16) - 1 tcp1.urg_point = 0 #tcp1.options tcp1.checksum = tcp_cksum(tcp1, ip1) ip1.length = len(ip1.bytes) + len(tcp1.bytes) # important, only calcs the ip checksum after fill length field ip1.checksum = ip_cksum(ip1) ether1 = ethernet.ethernet() ether1.src = ethernet.ether_atob(options.ether_source) ether1.dst = ethernet.ether_atob(options.ether_destination) ether1.type = 0x800 packet = pcs.Chain([ether1, ip1, tcp1]) print "\n%s---------------------------------" % what print tcp1 print "---------------------------------" out = output.write(packet.bytes, len(packet.bytes)) ## SYN # SYN+ACK what = "SYN+ACK" while 1: reply = output.read() packet = ethernet.ethernet(reply) try: replyip = packet.data replytcp = replyip.data if (ip1.src==replyip.dst and \ ip1.dst==replyip.src and \ tcp1.sport==replytcp.dport and \ tcp1.dport==replytcp.sport): break except: #it cannot be a tcp packet (without sport:) pass print "\n%s---------------------------------" % what print packet.data.data print "---------------------------------" ## SYN+ACK # ACK 134,187 what = "ACK (SYN)" ip3 = ipv4.ipv4() ip3.version = 4 ip3.hlen = 5 ip3.tos = 0 ip3.id = ++ipid ip3.flags = 0 ip3.offset = 0 ip3.ttl = 64 ip3.protocol = pcs.IPPROTO_TCP ip3.src = pcs.inet_atol(options.ip_source) ip3.dst = pcs.inet_atol(options.ip_target) tcp3 = tcp.tcp() tcp3.sport = tcpsport tcp3.dport = int(options.destination_port) tcp3.sequence = tcpsequence ##tcpsequence = tcpsequence + 1 # ACK DOES NOT consumes the sequence tcp3.ack_number = replytcp.sequence + 1 tcp3.offset = 5 tcp3.urgent = 0 tcp3.ack = 1 tcp3.push = 0 tcp3.reset = 0 tcp3.syn = 0 tcp3.fin = 0 tcp3.window = (1 << 16) - 1 tcp3.urg_point = 0 #tcp3.options tcp3.checksum = tcp_cksum(tcp3, ip3) ip3.length = len(ip3.bytes) + len(tcp3.bytes) # important, only calcs the ip checksum after fill length field ip3.checksum = ip_cksum(ip3) ether3 = ethernet.ethernet() ether3.src = ethernet.ether_atob(options.ether_source) ether3.dst = ethernet.ether_atob(options.ether_destination) ether3.type = 0x800 packet = pcs.Chain([ether3, ip3, tcp3]) print "\n%s---------------------------------" % what print tcp3 print "---------------------------------" out = output.write(packet.bytes, len(packet.bytes)) ## ACK # FIN 188,241 what = "FIN" ip4 = ipv4.ipv4() ip4.version = 4 ip4.hlen = 5 ip4.tos = 0 ip4.id = ++ipid ip4.flags = 0 ip4.offset = 0 ip4.ttl = 64 ip4.protocol = pcs.IPPROTO_TCP ip4.src = pcs.inet_atol(options.ip_source) ip4.dst = pcs.inet_atol(options.ip_target) tcp4 = tcp.tcp() tcp4.sport = tcpsport tcp4.dport = int(options.destination_port) tcp4.sequence = tcpsequence tcpsequence = tcpsequence + 1 # FIN consumes the sequence tcp4.ack_number = replytcp.sequence + 1 tcp4.offset = 5 tcp4.urgent = 0 tcp4.ack = 1 tcp4.push = 0 tcp4.reset = 0 tcp4.syn = 0 tcp4.fin = 1 tcp4.window = (1 << 16) - 1 tcp4.urg_point = 0 #tcp4.options tcp4.checksum = tcp_cksum(tcp4, ip4) ip4.length = len(ip4.bytes) + len(tcp4.bytes) # important, only calcs the ip checksum after fill length field ip4.checksum = ip_cksum(ip4) ether4 = ethernet.ethernet() ether4.src = ethernet.ether_atob(options.ether_source) ether4.dst = ethernet.ether_atob(options.ether_destination) ether4.type = 0x800 packet = pcs.Chain([ether4, ip4, tcp4]) print "\n%s---------------------------------" % what print tcp4 print "---------------------------------" out = output.write(packet.bytes, len(packet.bytes)) ## FIN # ACK (FIN) what = "ACK (FIN)" while 1: reply = output.read() packet = ethernet.ethernet(reply) try: replyip = packet.data replytcp = replyip.data if (ip1.src==replyip.dst and \ ip1.dst==replyip.src and \ tcp1.sport==replytcp.dport and \ tcp1.dport==replytcp.sport): break except: #it cannot be a tcp packet (without sport:) pass print "\n%s---------------------------------" % what print packet.data.data print "---------------------------------" ## ACK (FIN) # FIN what = "FIN" while 1: reply = output.read() packet = ethernet.ethernet(reply) try: replyip = packet.data replytcp = replyip.data if (ip1.src==replyip.dst and \ ip1.dst==replyip.src and \ tcp1.sport==replytcp.dport and \ tcp1.dport==replytcp.sport): break except: #it cannot be a tcp packet (without sport:) pass print "\n%s---------------------------------" % what print packet.data.data print "---------------------------------" ## FIN # ACK (FIN) 288,341 what = "ACK (FIN)" ip7 = ipv4.ipv4() ip7.version = 4 ip7.hlen = 5 ip7.tos = 0 ip7.id = ++ipid ip7.flags = 0 ip7.offset = 0 ip7.ttl = 64 ip7.protocol = pcs.IPPROTO_TCP ip7.src = pcs.inet_atol(options.ip_source) ip7.dst = pcs.inet_atol(options.ip_target) tcp7 = tcp.tcp() tcp7.sport = tcpsport tcp7.dport = int(options.destination_port) tcp7.sequence = tcpsequence ##tcpsequence = tcpsequence + 1 # ACK DOES NOT consumes the sequence tcp7.ack_number = replytcp.sequence + 1 tcp7.offset = 5 tcp7.urgent = 0 tcp7.ack = 1 tcp7.push = 0 tcp7.reset = 0 tcp7.syn = 0 tcp7.fin = 0 tcp7.window = (1 << 16) - 1 tcp7.urg_point = 0 #tcp7.options tcp7.checksum = tcp_cksum(tcp7, ip7) ip7.length = len(ip7.bytes) + len(tcp7.bytes) # important, only calcs the ip checksum after fill length field ip7.checksum = ip_cksum(ip7) ether7 = ethernet.ethernet() ether7.src = ethernet.ether_atob(options.ether_source) ether7.dst = ethernet.ether_atob(options.ether_destination) ether7.type = 0x800 packet = pcs.Chain([ether7, ip7, tcp7]) print "\n%s---------------------------------" % what print tcp7 print "---------------------------------" out = output.write(packet.bytes, len(packet.bytes))