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_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 createethernet(self, tcb, from_, to): """Create ethernet header""" ether1 = ethernet.ethernet() ether1.src = tcb.ether[from_] ether1.dst = tcb.ether[to] ether1.type = 0x800 return ether1
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_icmpv6_ping(self): 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 e = ethernet() e.type = 0x0800 e.src = "\x00\x00\x00\x00\x00\x00" e.dst = "\xff\xff\xff\xff\xff\xff" e.type = 0x0800 ip = ipv6() ip.traffic_class = 1 ip.flow = 0 ip.length = 64 ip.next_header = IPV6_ICMP ip.hop = 64 ip.src = inet_pton(AF_INET6, "::1") ip.dst = inet_pton(AF_INET6, "::1") icmp = icmpv6() icmp.type = 128 icmp.code = 0 icmp.cksum = 0 ip.len = len(ip.bytes) + len(icmp.bytes) packet = Chain([e, ip, icmp]) packet.calc_checksums() packet.encode() input = PcapConnector(devname) input.setfilter("icmp6") output = PcapConnector(devname) assert (ip != None) # XXX The use of IP triggers a bpf header format bug if used # with loopback device on FreeBSD, so we use edsc(4) there. n_out = output.write(packet.bytes, 42) assert (n_out == 42) packet_in = input.read() assert (n_out == len(packet_in))
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(): from optparse import OptionParser parser = OptionParser() parser.add_option("-i", "--interface", dest="interface", default=None, help="Which interface to snarf from.") (options, args) = parser.parse_args() snarf = pcs.PcapConnector(options.interface) while 1: packet = ethernet(snarf.read()) print packet print packet.data
def receive(self, tcb, from_, to): """receive packet for this socket This method must handle timmers""" (ip, tcp) = (None, None) while 1: reply = tcb.output[from_].read() try: packet = ethernet.ethernet(reply) ip = packet.data tcp = ip.data if (tcb.ip[ from_ ]==ip.dst and \ tcb.ip[ to ]==ip.src and \ tcb.tcpport[ from_ ]==tcp.dport and \ tcb.tcpport[ to ]==tcp.sport): break except: print "packet ignored" pass return (ip, tcp)
def main(): file = pcs.PcapConnector("fxp0") # Construct a filter chain. we are only interested in 3 fields. a = ethernet.ethernet() / arp.arp() a.wildcard_mask() a.packets[0].wildcard_mask(["type"], False) a.packets[1].wildcard_mask(["pro", "op"], False) a.packets[1].pro = 0x0800 # ETHERTYPE_IP (default) a.packets[1].op = 1 # ARPOP_REQUEST print "Waiting 10 seconds to see an ARP query." try: file.expect([a], 10) except pcs.TimeoutError: print "Timed out." sys.exit(1) print "And the matching packet chain is:" print file.match sys.exit(0)
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 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))
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 test_icmpv4_ping(self): 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 e = ethernet() e.type = 0x0800 e.src = "\x00\x00\x00\x00\x00\x00" e.dst = "\xff\xff\xff\xff\xff\xff" e.type = 0x0800 ip = ipv4() ip.version = 4 ip.hlen = 5 ip.tos = 0 ip.length = 28 ip.id = 1234 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 icmp.cksum = 0 echo = icmpv4echo() echo.id = 37123 echo.sequence = 0 ip.len = len(ip.bytes) + len(icmp.bytes) + len(echo.bytes) packet = Chain([e, ip, icmp, echo]) packet.calc_checksums() packet.encode() input = PcapConnector(devname) input.setfilter("icmp") output = PcapConnector(devname) assert ip != None # XXX The use of IP triggers a bpf header format bug if used # with loopback device on FreeBSD, so we use edsc(4) there. n_out = output.write(packet.bytes, 42) assert n_out == 42 packet_in = input.read() assert n_out == len(packet_in)
def test_icmpv4_ping(self): 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 e = ethernet() e.type = 0x0800 e.src = "\x00\x00\x00\x00\x00\x00" e.dst = "\xff\xff\xff\xff\xff\xff" e.type = 0x0800 ip = ipv4() ip.version = 4 ip.hlen = 5 ip.tos = 0 ip.length = 28 ip.id = 1234 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 icmp.cksum = 0 echo = icmpv4echo() echo.id = 37123 echo.sequence = 0 ip.len = len(ip.bytes) + len(icmp.bytes) + len(echo.bytes) packet = Chain([e, ip, icmp, echo]) packet.calc_checksums() packet.encode() input = PcapConnector(devname) input.setfilter("icmp") output = PcapConnector(devname) assert (ip != None) # XXX The use of IP triggers a bpf header format bug if used # with loopback device on FreeBSD, so we use edsc(4) there. n_out = output.write(packet.bytes, 42) assert (n_out == 42) packet_in = input.read() assert (n_out == len(packet_in))