1*e7abe75aSbluhm#!/usr/local/bin/python3 293a55b4aSbluhm 393a55b4aSbluhmimport os 42b21f7bdSbluhmimport threading 593a55b4aSbluhmfrom addr import * 693a55b4aSbluhmfrom scapy.all import * 793a55b4aSbluhm 82b21f7bdSbluhmclass Sniff(threading.Thread): 92b21f7bdSbluhm filter = None 102b21f7bdSbluhm captured = None 112b21f7bdSbluhm packet = None 122b21f7bdSbluhm def __init__(self): 132b21f7bdSbluhm # clear packets buffered by scapy bpf 142b21f7bdSbluhm sniff(iface=LOCAL_IF, timeout=1) 152b21f7bdSbluhm super(Sniff, self).__init__() 162b21f7bdSbluhm def run(self): 172b21f7bdSbluhm self.captured = sniff(iface=LOCAL_IF, filter=self.filter, 182b21f7bdSbluhm timeout=3) 192b21f7bdSbluhm if self.captured: 202b21f7bdSbluhm self.packet = self.captured[0] 212b21f7bdSbluhm 2293a55b4aSbluhme=Ether(src=LOCAL_MAC, dst=REMOTE_MAC) 2393a55b4aSbluhmip6=IPv6(src=FAKE_NET_ADDR6, dst=REMOTE_ADDR6) 249ae5678bSbluhmtport=os.getpid() & 0xffff 2593a55b4aSbluhm 26*e7abe75aSbluhmprint("Send SYN packet, receive SYN+ACK.") 279ae5678bSbluhmsyn=TCP(sport=tport, dport='chargen', seq=1, flags='S', window=(2**16)-1) 2893a55b4aSbluhmsynack=srp1(e/ip6/syn, iface=LOCAL_IF, timeout=5) 2993a55b4aSbluhm 3093a55b4aSbluhmif synack is None: 31*e7abe75aSbluhm print("ERROR: No SYN+ACK from chargen server received.") 3293a55b4aSbluhm exit(1) 3393a55b4aSbluhm 34*e7abe75aSbluhmprint("Send ACK packet, receive chargen data.") 3593a55b4aSbluhmack=TCP(sport=synack.dport, dport=synack.sport, seq=2, flags='A', 3693a55b4aSbluhm ack=synack.seq+1, window=(2**16)-1) 3793a55b4aSbluhmdata=srp1(e/ip6/ack, iface=LOCAL_IF, timeout=5) 3893a55b4aSbluhm 3993a55b4aSbluhmif data is None: 40*e7abe75aSbluhm print("ERROR: No data from chargen server received.") 4193a55b4aSbluhm exit(1) 4293a55b4aSbluhm 43*e7abe75aSbluhmprint("Fill our receive buffer.") 4493a55b4aSbluhmtime.sleep(1) 4593a55b4aSbluhm 462b21f7bdSbluhm# srp1 cannot be used, fragment answer will not match outgoing ICMP6 packet 472b21f7bdSbluhmsniffer = Sniff() 482b21f7bdSbluhmsniffer.filter = \ 492b21f7bdSbluhm "ip6 and src "+ip6.dst+" and dst "+ip6.src+" and proto ipv6-frag" 502b21f7bdSbluhmsniffer.start() 512b21f7bdSbluhmtime.sleep(1) 522b21f7bdSbluhm 53*e7abe75aSbluhmprint("Send ICMP6 packet too big packet with MTU 1272.") 5493a55b4aSbluhmicmp6=ICMPv6PacketTooBig(mtu=1272)/data.payload 55caed3289Sbluhmsendp(e/IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/icmp6, iface=LOCAL_IF) 5693a55b4aSbluhm 57*e7abe75aSbluhmprint("Path MTU discovery will not resend data, ICMP6 packet is ignored.") 582b21f7bdSbluhmsniffer.join(timeout=5) 5993a55b4aSbluhm 60*e7abe75aSbluhmprint("IPv6 atomic fragments must not be generated.") 6103da3b73Sbluhmfrag=None 622b21f7bdSbluhmfor a in sniffer.captured: 6393a55b4aSbluhm fh=a.payload.payload 6493a55b4aSbluhm if fh.offset != 0 or fh.nh != (ip6/syn).nh: 6593a55b4aSbluhm continue 6693a55b4aSbluhm th=fh.payload 6793a55b4aSbluhm if th.sport != syn.dport or th.dport != syn.sport: 6893a55b4aSbluhm continue 6993a55b4aSbluhm frag=a 7093a55b4aSbluhm break 7103da3b73Sbluhm 7203da3b73Sbluhmif frag is not None: 73*e7abe75aSbluhm print("ERROR: Matching IPv6 fragment TCP answer found.") 7403da3b73Sbluhm exit(1) 7503da3b73Sbluhm 76*e7abe75aSbluhmprint("Send ACK again to trigger retransmit.") 7703da3b73Sbluhmdata=srp1(e/ip6/ack, iface=LOCAL_IF, timeout=5) 7803da3b73Sbluhm 7903da3b73Sbluhmif data is None: 80*e7abe75aSbluhm print("ERROR: No data retransmit from chargen server received.") 8193a55b4aSbluhm exit(1) 8293a55b4aSbluhm 83*e7abe75aSbluhmprint("Cleanup the other's socket with a reset packet.") 8493a55b4aSbluhmrst=TCP(sport=synack.dport, dport=synack.sport, seq=2, flags='AR', 8593a55b4aSbluhm ack=synack.seq+1) 8693a55b4aSbluhmsendp(e/ip6/rst, iface=LOCAL_IF) 8793a55b4aSbluhm 8803da3b73Sbluhmlen = data.plen + len(IPv6()) 89*e7abe75aSbluhmprint("len=%d" % len) 9003da3b73Sbluhmif len != 1500: 91*e7abe75aSbluhm print("ERROR: TCP data packet len is %d, expected 1500." % len) 9293a55b4aSbluhm exit(1) 9393a55b4aSbluhm 9493a55b4aSbluhmexit(0) 95