1#!/usr/local/bin/python2.7 2# check wether path mtu to dst is as expected 3 4import os 5import threading 6from addr import * 7from scapy.all import * 8 9# usage: ping6_mtu src dst size icmp6-size 10 11# work around the broken sniffing of packages with bad checksum 12#a=srp1(eth, iface=SRC_IF, timeout=2) 13class Sniff1(threading.Thread): 14 filter = None 15 captured = None 16 packet = None 17 def run(self): 18 self.captured = sniff(iface=SRC_IF, filter=self.filter, 19 count=1, timeout=3) 20 if self.captured: 21 self.packet = self.captured[0] 22 23srcaddr=sys.argv[1] 24dstaddr=sys.argv[2] 25size=int(sys.argv[3]) 26expect=int(sys.argv[4]) 27eid=os.getpid() & 0xffff 28hdr=IPv6(src=srcaddr, dst=dstaddr)/ICMPv6EchoRequest(id=eid) 29payload="a" * (size - len(str(hdr))) 30ip=hdr/payload 31iplen=IPv6(str(ip)).plen 32eth=Ether(src=SRC_MAC, dst=PF_MAC)/ip 33 34sniffer = Sniff1(); 35# pcap cannot access icmp6, check for packet too big, avoid neighbor discovery 36sniffer.filter = "ip6 and dst %s and icmp6 and ip6[40] = 2 and ip6[41] = 0" \ 37 % srcaddr 38sniffer.start() 39time.sleep(1) 40sendp(eth, iface=SRC_IF) 41sniffer.join(timeout=5) 42a = sniffer.packet 43 44if a is None: 45 print "no packet sniffed" 46 exit(2) 47if a and a.type == ETH_P_IPV6 and \ 48 ipv6nh[a.payload.nh] == 'ICMPv6' and \ 49 icmp6types[a.payload.payload.type] == 'Packet too big': 50 mtu=a.payload.payload.mtu 51 print "mtu=%d" % (mtu) 52 if mtu != expect: 53 print "MTU!=%d" % (expect) 54 exit(1) 55 iip=a.payload.payload.payload 56 iiplen=iip.plen 57 if iiplen != iplen: 58 print "inner IPv6 plen %d!=%d" % (iiplen, iplen) 59 exit(1) 60 isrc=iip.src 61 if isrc != srcaddr: 62 print "inner IPv6 src %d!=%d" % (isrc, srcaddr) 63 exit(1) 64 idst=iip.dst 65 if idst != dstaddr: 66 print "inner IPv6 dst %d!=%d" % (idst, dstaddr) 67 exit(1) 68 exit(0) 69print "MTU=UNKNOWN" 70exit(2) 71