xref: /openbsd-src/regress/sys/netinet/pmtu/tcp_connect.py (revision e7abe75af641bacab1663afa28052d03f1e67610)
1*e7abe75aSbluhm#!/usr/local/bin/python3
2b83a2f27Sbluhm
3b83a2f27Sbluhmimport os
42b21f7bdSbluhmimport threading
5b83a2f27Sbluhmfrom addr import *
6b83a2f27Sbluhmfrom scapy.all import *
7b83a2f27Sbluhm
82b21f7bdSbluhmclass Sniff1(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(Sniff1, self).__init__()
162b21f7bdSbluhm	def run(self):
172b21f7bdSbluhm		self.captured = sniff(iface=LOCAL_IF, filter=self.filter,
182b21f7bdSbluhm		    count=1, timeout=3)
192b21f7bdSbluhm		if self.captured:
202b21f7bdSbluhm			self.packet = self.captured[0]
212b21f7bdSbluhm
22b83a2f27Sbluhmip=IP(src=FAKE_NET_ADDR, dst=REMOTE_ADDR)
239ae5678bSbluhmtport=os.getpid() & 0xffff
24b83a2f27Sbluhm
25*e7abe75aSbluhmprint("Send SYN packet, receive SYN+ACK.")
269ae5678bSbluhmsyn=TCP(sport=tport, dport='chargen', seq=1, flags='S', window=(2**16)-1)
27b83a2f27Sbluhmsynack=sr1(ip/syn, iface=LOCAL_IF, timeout=5)
28b83a2f27Sbluhm
29140ee0aaSbluhmif synack is None:
30*e7abe75aSbluhm	print("ERROR: No SYN+ACK from chargen server received.")
31140ee0aaSbluhm	exit(1)
32140ee0aaSbluhm
33*e7abe75aSbluhmprint("Send ACK packet, receive chargen data.")
34b83a2f27Sbluhmack=TCP(sport=synack.dport, dport=synack.sport, seq=2, flags='A',
35b83a2f27Sbluhm    ack=synack.seq+1, window=(2**16)-1)
36b83a2f27Sbluhmdata=sr1(ip/ack, iface=LOCAL_IF, timeout=5)
37b83a2f27Sbluhm
38140ee0aaSbluhmif data is None:
39*e7abe75aSbluhm	print("ERROR: No data from chargen server received.")
40140ee0aaSbluhm	exit(1)
41140ee0aaSbluhm
42*e7abe75aSbluhmprint("Fill our receive buffer.")
43b83a2f27Sbluhmtime.sleep(1)
44b83a2f27Sbluhm
452b21f7bdSbluhm# sr1 cannot be used, TCP data will not match outgoing ICMP packet
462b21f7bdSbluhmsniffer = Sniff1()
472b21f7bdSbluhmsniffer.filter = \
482b21f7bdSbluhm    "ip and src %s and tcp port %u and dst %s and tcp port %u" % \
492b21f7bdSbluhm    (ip.dst, syn.dport, ip.src, syn.sport)
502b21f7bdSbluhmsniffer.start()
512b21f7bdSbluhmtime.sleep(1)
522b21f7bdSbluhm
53*e7abe75aSbluhmprint("Send ICMP fragmentation needed packet with MTU 1300.")
54b83a2f27Sbluhmicmp=ICMP(type="dest-unreach", code="fragmentation-needed",
55b83a2f27Sbluhm    nexthopmtu=1300)/data
56b83a2f27Sbluhmsend(IP(src=LOCAL_ADDR, dst=REMOTE_ADDR)/icmp, iface=LOCAL_IF)
57b83a2f27Sbluhm
58*e7abe75aSbluhmprint("Path MTU discovery will resend first data with length 1300.")
592b21f7bdSbluhmsniffer.join(timeout=5)
602b21f7bdSbluhmans = sniffer.packet
61b83a2f27Sbluhm
62caed3289Sbluhmif len(ans) == 0:
63*e7abe75aSbluhm	print("ERROR: No data retransmit from chargen server received.")
64140ee0aaSbluhm	exit(1)
65caed3289Sbluhmdata=ans[0]
66140ee0aaSbluhm
67*e7abe75aSbluhmprint("Cleanup the other's socket with a reset packet.")
68b83a2f27Sbluhmrst=TCP(sport=synack.dport, dport=synack.sport, seq=2, flags='AR',
69b83a2f27Sbluhm    ack=synack.seq+1)
70b83a2f27Sbluhmsend(ip/rst, iface=LOCAL_IF)
71b83a2f27Sbluhm
72b83a2f27Sbluhmlen = data.len
73*e7abe75aSbluhmprint("len=%d" % len)
74b83a2f27Sbluhmif len != 1300:
75*e7abe75aSbluhm	print("ERROR: TCP data packet len is %d, expected 1300." % len)
76b83a2f27Sbluhm	exit(1)
7703da3b73Sbluhm
78b83a2f27Sbluhmexit(0)
79