xref: /openbsd-src/regress/sys/netinet/pmtu/udp_atomicfrag6.py (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1#!/usr/local/bin/python2.7
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 1200 octets payload, receive echo."
32data=''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase +
33    string.digits) for _ in range(1200))
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 1272."
42icmp6=ICMPv6PacketTooBig(mtu=1272)/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 1200 octets payload."
56sendp(e/ip6/udp, iface=LOCAL_IF)
57
58print "Path MTU discovery will not send UDP atomic fragment."
59sniffer.join(timeout=5)
60
61print "IPv6 atomic fragments must not be generated."
62frag=None
63for a in sniffer.captured:
64	fh=a.payload.payload
65	if fh.offset != 0 or fh.nh != (ip6/udp).nh:
66		continue
67	uh=fh.payload
68	if uh.sport != udp.dport or uh.dport != udp.sport:
69		continue
70	frag=a
71	break
72
73if frag is not None:
74	print "ERROR: matching IPv6 fragment UDP answer found"
75	exit(1)
76
77print "Send echo again and expect reply without fragmentation."
78reply=srp1(e/IPv6(src=LOCAL_ADDR6, dst=REMOTE_ADDR6)/udp, iface=LOCAL_IF)
79
80print "UDP echo has IPv6 and UDP header, so expected payload len is 1248."
81elen = reply.plen + len(IPv6())
82print "rlen=%d" % elen
83if elen != 1248:
84	print "ERROR: UDP reply payload len is %d, expected 1248." % elen
85	exit(1)
86
87exit(0)
88