1#!/usr/local/bin/python3 2 3import os 4import threading 5import string 6import random 7from addr import * 8from scapy.all import * 9 10class Sniff(threading.Thread): 11 filter = None 12 captured = None 13 packet = None 14 def __init__(self): 15 # clear packets buffered by scapy bpf 16 sniff(iface=LOCAL_IF, timeout=1) 17 super(Sniff, self).__init__() 18 def run(self): 19 self.captured = sniff(iface=LOCAL_IF, filter=self.filter, 20 timeout=3) 21 if self.captured: 22 self.packet = self.captured[0] 23 24e=Ether(src=LOCAL_MAC, dst=REMOTE_MAC) 25ip6=IPv6(src=FAKE_NET_ADDR6, dst=REMOTE_ADDR6) 26uport=os.getpid() & 0xffff 27# inetd ignores UDP packets from privileged port or nfs 28if uport < 1024 or uport == 2049: 29 uport+=1024 30 31print("Send UDP packet with 1400 octets payload, receive echo.") 32data=''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + 33 string.digits) for _ in range(1400)) 34udp=UDP(sport=uport, dport='echo')/data 35echo=srp1(e/ip6/udp, iface=LOCAL_IF, timeout=5) 36 37if echo is None: 38 print("ERROR: No UDP answer from echo server received.") 39 exit(1) 40 41print("Send ICMP6 packet too big packet with MTU 1300.") 42icmp6=ICMPv6PacketTooBig(mtu=1300)/echo.payload 43sendp(e/IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/icmp6, iface=LOCAL_IF) 44 45print("Clear route cache at echo socket by sending from different address.") 46sendp(e/IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/udp, iface=LOCAL_IF) 47 48# srp1 cannot be used, fragment answer will not match on outgoing UDP packet 49sniffer = Sniff() 50sniffer.filter = \ 51 "ip6 and src "+ip6.dst+" and dst "+ip6.src+" and proto ipv6-frag" 52sniffer.start() 53time.sleep(1) 54 55print("Send UDP packet with 1400 octets payload.") 56sendp(e/ip6/udp, iface=LOCAL_IF) 57 58print("Path MTU discovery will send UDP fragment with maximum length 1300.") 59sniffer.join(timeout=5) 60 61for a in sniffer.captured: 62 fh=a.payload.payload 63 if fh.offset != 0 or fh.nh != (ip6/udp).nh: 64 continue 65 uh=fh.payload 66 if uh.sport != udp.dport or uh.dport != udp.sport: 67 continue 68 frag=a 69 break 70else: 71 print("ERROR: No matching IPv6 fragment UDP answer found.") 72 exit(1) 73 74print("UDP echo has IPv6 and UDP header, so expected payload len is 1448.") 75elen = echo.plen + len(IPv6()) 76print("elen=%d" % elen) 77if elen != 1448: 78 print("ERROR: UDP echo payload len is %d, expected 1448." % elen) 79 exit(1) 80 81print("Fragments contain multiple of 8 octets, so expected len is 1296.") 82flen = frag.plen + len(IPv6()) 83print("flen=%d" % flen) 84if flen != 1296: 85 print("ERROR: UDP fragment len is %d, expected 1296." % flen) 86 exit(1) 87 88exit(0) 89