1#!/usr/local/bin/python2.7 2 3import argparse 4import scapy.all as sp 5import sys 6from sniffer import Sniffer 7 8PAYLOAD_MAGIC = 0x42c0ffee 9 10def check_ping_request(args, packet): 11 if args.ip6: 12 return check_ping6_request(args, packet) 13 else: 14 return check_ping4_request(args, packet) 15 16def check_ping4_request(args, packet): 17 """ 18 Verify that the packet matches what we'd have sent 19 """ 20 dst_ip = args.to[0] 21 22 ip = packet.getlayer(sp.IP) 23 if not ip: 24 return False 25 if ip.dst != dst_ip: 26 return False 27 28 icmp = packet.getlayer(sp.ICMP) 29 if not icmp: 30 return False 31 if sp.icmptypes[icmp.type] != 'echo-request': 32 return False 33 34 raw = packet.getlayer(sp.Raw) 35 if not raw: 36 return False 37 if raw.load != str(PAYLOAD_MAGIC): 38 return False 39 40 # Wait to check expectations until we've established this is the packet we 41 # sent. 42 if args.expect_tos: 43 if ip.tos != int(args.expect_tos[0]): 44 print "Unexpected ToS value %d, expected %s" \ 45 % (ip.tos, args.expect_tos[0]) 46 return False 47 48 return True 49 50def check_ping6_request(args, packet): 51 """ 52 Verify that the packet matches what we'd have sent 53 """ 54 dst_ip = args.to[0] 55 56 ip = packet.getlayer(sp.IPv6) 57 if not ip: 58 return False 59 if ip.dst != dst_ip: 60 return False 61 62 icmp = packet.getlayer(sp.ICMPv6EchoRequest) 63 if not icmp: 64 return False 65 if icmp.data != str(PAYLOAD_MAGIC): 66 return False 67 68 return True 69 70def ping(send_if, dst_ip, args): 71 ether = sp.Ether() 72 ip = sp.IP(dst=dst_ip) 73 icmp = sp.ICMP(type='echo-request') 74 raw = sp.Raw(str(PAYLOAD_MAGIC)) 75 76 if args.send_tos: 77 ip.tos = int(args.send_tos[0]) 78 79 req = ether / ip / icmp / raw 80 sp.sendp(req, iface=send_if, verbose=False) 81 82def ping6(send_if, dst_ip, args): 83 ether = sp.Ether() 84 ip6 = sp.IPv6(dst=dst_ip) 85 icmp = sp.ICMPv6EchoRequest(data=PAYLOAD_MAGIC) 86 87 req = ether / ip6 / icmp 88 sp.sendp(req, iface=send_if, verbose=False) 89 90def main(): 91 parser = argparse.ArgumentParser("pft_ping.py", 92 description="Ping test tool") 93 parser.add_argument('--sendif', nargs=1, 94 required=True, 95 help='The interface through which the packet(s) will be sent') 96 parser.add_argument('--recvif', nargs=1, 97 help='The interface on which to expect the ICMP echo response') 98 parser.add_argument('--ip6', action='store_true', 99 help='Use IPv6') 100 parser.add_argument('--to', nargs=1, 101 required=True, 102 help='The destination IP address for the ICMP echo request') 103 104 # Packet settings 105 parser.add_argument('--send-tos', nargs=1, 106 help='Set the ToS value for the transmitted packet') 107 108 # Expectations 109 parser.add_argument('--expect-tos', nargs=1, 110 help='The expected ToS value in the received packet') 111 112 args = parser.parse_args() 113 114 # We may not have a default route. Tell scapy where to start looking for routes 115 sp.conf.iface6 = args.sendif[0] 116 117 sniffer = None 118 if not args.recvif is None: 119 sniffer = Sniffer(args, check_ping_request) 120 121 if args.ip6: 122 ping6(args.sendif[0], args.to[0], args) 123 else: 124 ping(args.sendif[0], args.to[0], args) 125 126 if sniffer: 127 sniffer.join() 128 129 if sniffer.foundCorrectPacket: 130 sys.exit(0) 131 else: 132 sys.exit(1) 133 134if __name__ == '__main__': 135 main() 136