1#!/usr/local/bin/python3
2# $OpenBSD: sendrecv.py,v 1.3 2020/12/25 13:47:43 bluhm Exp $
3
4import os
5from scapy.all import *
6from struct import pack
7import getopt, sys
8
9def usage():
10	print("sendrecv [-hi] [-c ckoff] [-r recvsz] [-s sendsz]")
11	print("    -c ckoff   set checksum offset within payload")
12	print("    -h         help, show usage")
13	print("    -i         expect icmp6 error message as response")
14	print("    -r recvsz  expected payload size")
15	print("    -s sendsz  set payload size")
16	exit(1)
17
18opts, args = getopt.getopt(sys.argv[1:], "c:hir:s:")
19
20ip = IPv6(src="::1", dst="::1", nh=255)
21
22ckoff = None
23icmp = False
24recvsz = None
25sendsz = None
26for o, a in opts:
27	if o == "-c":
28		ckoff = int(a)
29	elif o == "-i":
30		icmp = True
31	elif o == "-r":
32		recvsz = int(a)
33	elif o == "-s":
34		sendsz = int(a)
35	else:
36		usage()
37
38payload = b"";
39if sendsz is not None:
40	for i in range(sendsz):
41		payload += pack('B', i)
42	print("payload length is", len(payload))
43
44if ckoff is not None:
45	payload = payload[:ckoff] + pack("xx") + payload[ckoff+2:]
46	cksum = in6_chksum(255, ip, payload)
47	print("calculated checksum is", cksum)
48	payload = payload[:ckoff] + pack("!H", cksum) + payload[ckoff+2:]
49
50req=ip/payload
51# As we are sending from ::1 to ::1 we sniff our own packet as answer.
52# Add a filter that matches on the expected answer using the payload size.
53if icmp:
54	filter="icmp6"
55	if recvsz is not None:
56		filter += (" and len = %d" % (4 + 40 + 8 + 40 + recvsz))
57else:
58	filter="proto 255"
59	if recvsz is not None:
60		filter += (" and len = %d" % (4 + 40 + recvsz))
61print("filter", filter)
62ans=sr(req, iface="lo0", filter=filter, timeout=10)
63print(ans)
64res=ans[0][0][1]
65res.show()
66
67print("response protocol next header is", res.nh)
68if icmp:
69	if res.nh != 58:
70		print("response wrong protocol, expected icmp6")
71		exit(1)
72	print("response icmp6 type is", res.payload.type)
73	if res.payload.type != 4:
74		print("response wrong icmp6 type, expected parameter problem")
75		exit(1)
76	exit(0)
77
78if res.nh != 255:
79	print("response with wrong protocol, expected 255, got")
80	exit(1)
81
82cksum = in6_chksum(255, res, res.payload.load)
83print("received checksum is", cksum)
84if ckoff is not None and cksum != 0:
85	print("received invalid checksum", cksum)
86	exit(1)
87
88print("received payload length is", len(res.payload.load))
89if recvsz is not None:
90	if len(res.payload.load) != recvsz:
91		print("wrong payload length, expected", recvsz)
92		exit(1)
93
94exit(0)
95