1#!/usr/local/bin/python3
2
3import os
4import threading
5from addr import *
6from scapy.all import *
7
8class Sniff1(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(Sniff1, self).__init__()
16	def run(self):
17		self.captured = sniff(iface=LOCAL_IF, filter=self.filter,
18		    count=1, 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, TCP data will not match outgoing ICMP6 packet
47sniffer = Sniff1()
48sniffer.filter = \
49    "ip6 and src %s and tcp port %u and dst %s and tcp port %u" % \
50    (ip6.dst, syn.dport, ip6.src, syn.sport)
51sniffer.start()
52time.sleep(1)
53
54print("Send ICMP6 packet too big packet with MTU 1300.")
55icmp6=ICMPv6PacketTooBig(mtu=1300)/data.payload
56sendp(e/IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/icmp6, iface=LOCAL_IF)
57
58print("Path MTU discovery will resend first data with length 1300.")
59sniffer.join(timeout=5)
60ans = sniffer.packet
61
62if len(ans) == 0:
63	print("ERROR: No data retransmit from chargen server received.")
64	exit(1)
65data=ans[0]
66
67print("Cleanup the other's socket with a reset packet.")
68rst=TCP(sport=synack.dport, dport=synack.sport, seq=2, flags='AR',
69    ack=synack.seq+1)
70sendp(e/ip6/rst, iface=LOCAL_IF)
71
72len = data.plen + len(IPv6())
73print("len=%d" % len)
74if len != 1300:
75	print("ERROR: TCP data packet len is %d, expected 1300." % len)
76	exit(1)
77
78exit(0)
79