1#!/usr/local/bin/python3
2
3print("fragments of a large packet that has to be refragmented by reflector")
4
5# |--------|
6#          |------------------|
7#                              ...
8#                                 |------------------|
9#                                                    |----|
10
11import os
12from addr import *
13from scapy.all import *
14
15pid=os.getpid()
16eid=pid & 0xffff
17payload=b"ABCDEFGHIJKLMNOP" * 100
18packet=IP(src=LOCAL_ADDR, dst=REMOTE_ADDR)/ \
19    ICMP(type='echo-request', id=eid)/payload
20request_cksum=ICMP(bytes(packet.payload)).chksum
21print("request cksum=%#x" % (request_cksum))
22frag=[]
23fid=pid & 0xffff
24frag.append(IP(src=LOCAL_ADDR, dst=REMOTE_ADDR, proto=1, id=fid,
25    flags='MF')/bytes(packet)[20:36])
26offset=2
27chunk=4
28while 40+8*(offset+chunk) < len(payload):
29	frag.append(IP(src=LOCAL_ADDR, dst=REMOTE_ADDR, proto=1, id=fid,
30	    frag=offset, flags='MF')/
31	    bytes(packet)[20+(8*offset):20+8*(offset+chunk)])
32	offset+=chunk
33frag.append(IP(src=LOCAL_ADDR, dst=REMOTE_ADDR, proto=1, id=fid,
34	frag=offset)/bytes(packet)[20+(8*offset):])
35eth=[]
36for f in frag:
37	eth.append(Ether(src=LOCAL_MAC, dst=REMOTE_MAC)/f)
38
39if os.fork() == 0:
40	time.sleep(1)
41	sendp(eth, iface=LOCAL_IF)
42	os._exit(0)
43
44ans=sniff(iface=LOCAL_IF, timeout=3, filter=
45    "ip and src "+REMOTE_ADDR+" and dst "+LOCAL_ADDR+" and icmp")
46for a in ans:
47	if a and a.type == ETH_P_IP and \
48	    a.payload.proto == 1 and \
49	    a.payload.frag == 0 and a.payload.flags == 1 and \
50	    icmptypes[a.payload.payload.type] == 'echo-reply':
51		id=a.payload.payload.id
52		print("id=%#x" % (id))
53		if id != eid:
54			print("WRONG ECHO REPLY ID")
55			exit(2)
56		reply_cksum=a.payload.payload.chksum
57		print("reply cksum=%#x" % (reply_cksum))
58		# change request checksum incrementaly and check with reply
59		diff_cksum=~(~reply_cksum+~(~request_cksum+~0x0800+0x0000))
60		if diff_cksum & 0xffff != 0xffff and diff_cksum & 0xffff != 0:
61			print("CHECKSUM ERROR diff cksum=%#x" % (diff_cksum))
62			exit(1)
63		exit(0)
64print("NO ECHO REPLY")
65exit(2)
66