1#!/usr/local/bin/python3 2 3import os 4import threading 5from addr import * 6from scapy.all import * 7 8class Sniff(threading.Thread): 9 filter = None 10 captured = None 11 packet = None 12 def __init__(self): 13 # clear packets buffered by scapy bpf 14 sniff(iface=LOCAL_IF, timeout=1) 15 super(Sniff, self).__init__() 16 def run(self): 17 self.captured = sniff(iface=LOCAL_IF, filter=self.filter, 18 timeout=3) 19 if self.captured: 20 self.packet = self.captured[0] 21 22e=Ether(src=LOCAL_MAC, dst=REMOTE_MAC) 23ip6=IPv6(src=FAKE_NET_ADDR6, dst=REMOTE_ADDR6) 24tport=os.getpid() & 0xffff 25 26print("Send SYN packet, receive SYN+ACK.") 27syn=TCP(sport=tport, dport='chargen', seq=1, flags='S', window=(2**16)-1) 28synack=srp1(e/ip6/syn, iface=LOCAL_IF, timeout=5) 29 30if synack is None: 31 print("ERROR: No SYN+ACK from chargen server received.") 32 exit(1) 33 34print("Send ACK packet, receive chargen data.") 35ack=TCP(sport=synack.dport, dport=synack.sport, seq=2, flags='A', 36 ack=synack.seq+1, window=(2**16)-1) 37data=srp1(e/ip6/ack, iface=LOCAL_IF, timeout=5) 38 39if data is None: 40 print("ERROR: No data from chargen server received.") 41 exit(1) 42 43print("Fill our receive buffer.") 44time.sleep(1) 45 46# srp1 cannot be used, fragment answer will not match outgoing ICMP6 packet 47sniffer = Sniff() 48sniffer.filter = \ 49 "ip6 and src "+ip6.dst+" and dst "+ip6.src+" and proto ipv6-frag" 50sniffer.start() 51time.sleep(1) 52 53print("Send ICMP6 packet too big packet with MTU 1272.") 54icmp6=ICMPv6PacketTooBig(mtu=1272)/data.payload 55sendp(e/IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/icmp6, iface=LOCAL_IF) 56 57print("Path MTU discovery will not resend data, ICMP6 packet is ignored.") 58sniffer.join(timeout=5) 59 60print("IPv6 atomic fragments must not be generated.") 61frag=None 62for a in sniffer.captured: 63 fh=a.payload.payload 64 if fh.offset != 0 or fh.nh != (ip6/syn).nh: 65 continue 66 th=fh.payload 67 if th.sport != syn.dport or th.dport != syn.sport: 68 continue 69 frag=a 70 break 71 72if frag is not None: 73 print("ERROR: Matching IPv6 fragment TCP answer found.") 74 exit(1) 75 76print("Send ACK again to trigger retransmit.") 77data=srp1(e/ip6/ack, iface=LOCAL_IF, timeout=5) 78 79if data is None: 80 print("ERROR: No data retransmit from chargen server received.") 81 exit(1) 82 83print("Cleanup the other's socket with a reset packet.") 84rst=TCP(sport=synack.dport, dport=synack.sport, seq=2, flags='AR', 85 ack=synack.seq+1) 86sendp(e/ip6/rst, iface=LOCAL_IF) 87 88len = data.plen + len(IPv6()) 89print("len=%d" % len) 90if len != 1500: 91 print("ERROR: TCP data packet len is %d, expected 1500." % len) 92 exit(1) 93 94exit(0) 95