Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/common/sender.py
39536 views
1
#!/usr/bin/env python
2
# -
3
# SPDX-License-Identifier: BSD-2-Clause
4
#
5
# Copyright (c) 2020 Alexander V. Chernikov
6
#
7
# Redistribution and use in source and binary forms, with or without
8
# modification, are permitted provided that the following conditions
9
# are met:
10
# 1. Redistributions of source code must retain the above copyright
11
# notice, this list of conditions and the following disclaimer.
12
# 2. Redistributions in binary form must reproduce the above copyright
13
# notice, this list of conditions and the following disclaimer in the
14
# documentation and/or other materials provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
# SUCH DAMAGE.
27
#
28
#
29
30
31
from functools import partial
32
import socket
33
import logging
34
logging.getLogger("scapy").setLevel(logging.CRITICAL)
35
import scapy.all as sc
36
import argparse
37
import time
38
39
40
def parse_args():
41
parser = argparse.ArgumentParser(description='divert socket tester')
42
parser.add_argument('--dip', type=str, help='destination packet IP')
43
parser.add_argument('--sip', type=str, help='source packet IP')
44
parser.add_argument('--dmac', type=str, help='packet dst mac')
45
parser.add_argument('--smac', type=str, help='packet src mac')
46
parser.add_argument('--iface', type=str, help='interface to use')
47
parser.add_argument('--test_name', type=str, required=True,
48
help='test name to run')
49
return parser.parse_args()
50
51
52
def send_packet(args, pkt):
53
sc.sendp(pkt, iface=args.iface, verbose=False)
54
55
56
def is_icmp6_echo_request(pkt):
57
return pkt.type == 0x86DD and pkt.payload.nh == 58 and \
58
pkt.payload.payload.type == 128
59
60
61
def check_forwarded_ip_packet(orig_pkt, fwd_pkt):
62
"""
63
Checks that forwarded ICMP packet @fwd_ptk is the same as
64
@orig_pkt. Assumes router-on-the-stick forwarding behaviour:
65
* src/dst macs are swapped
66
* TTL is decremented
67
"""
68
# Check ether fields
69
assert orig_pkt.src == fwd_pkt.dst
70
assert orig_pkt.dst == fwd_pkt.src
71
assert len(orig_pkt) == len(fwd_pkt)
72
# Check IP
73
fwd_ip = fwd_pkt[sc.IP]
74
orig_ip = orig_pkt[sc.IP]
75
assert orig_ip.src == orig_ip.src
76
assert orig_ip.dst == fwd_ip.dst
77
assert orig_ip.ttl == fwd_ip.ttl + 1
78
# Check ICMP
79
fwd_icmp = fwd_ip[sc.ICMP]
80
orig_icmp = orig_ip[sc.ICMP]
81
assert bytes(orig_ip.payload) == bytes(fwd_ip.payload)
82
83
84
def fwd_ip_icmp_fast(args):
85
"""
86
Sends ICMP packet via args.iface interface.
87
Receives and checks the forwarded packet.
88
Assumes forwarding router decrements TTL
89
"""
90
91
def filter_f(x):
92
return x.src == args.dmac and x.type == 0x0800
93
94
e = sc.Ether(src=args.smac, dst=args.dmac)
95
ip = sc.IP(src=args.sip, dst=args.dip)
96
icmp = sc.ICMP(type='echo-request')
97
pkt = e / ip / icmp
98
99
send_cb = partial(send_packet, args, pkt)
100
packets = sc.sniff(iface=args.iface, started_callback=send_cb,
101
stop_filter=filter_f, lfilter=filter_f, timeout=5)
102
assert len(packets) > 0
103
fwd_pkt = packets[-1]
104
try:
105
check_forwarded_ip_packet(pkt, fwd_pkt)
106
except Exception as e:
107
print('Original packet:')
108
pkt.show()
109
print('Forwarded packet:')
110
fwd_pkt.show()
111
for a_packet in packets:
112
a_packet.summary()
113
raise Exception from e
114
115
116
def fwd_ip_icmp_slow(args):
117
"""
118
Sends ICMP packet via args.iface interface.
119
Forces slow path processing by introducing IP option.
120
Receives and checks the forwarded packet.
121
Assumes forwarding router decrements TTL
122
"""
123
124
def filter_f(x):
125
return x.src == args.dmac and x.type == 0x0800
126
127
e = sc.Ether(src=args.smac, dst=args.dmac)
128
# Add IP option to switch to 'normal' IP processing
129
stream_id = sc.IPOption_Stream_Id(security=0xFFFF)
130
ip = sc.IP(src=args.sip, dst=args.dip,
131
options=[sc.IPOption_Stream_Id(security=0xFFFF)])
132
icmp = sc.ICMP(type='echo-request')
133
pkt = e / ip / icmp
134
135
send_cb = partial(send_packet, args, pkt)
136
packets = sc.sniff(iface=args.iface, started_callback=send_cb,
137
stop_filter=filter_f, lfilter=filter_f, timeout=5)
138
assert len(packets) > 0
139
check_forwarded_ip_packet(pkt, packets[-1])
140
141
142
def check_forwarded_ip6_packet(orig_pkt, fwd_pkt):
143
"""
144
Checks that forwarded ICMP packet @fwd_ptk is the same as
145
@orig_pkt. Assumes router-on-the-stick forwarding behaviour:
146
* src/dst macs are swapped
147
* TTL is decremented
148
"""
149
# Check ether fields
150
assert orig_pkt.src == fwd_pkt.dst
151
assert orig_pkt.dst == fwd_pkt.src
152
assert len(orig_pkt) == len(fwd_pkt)
153
# Check IP
154
fwd_ip = fwd_pkt[sc.IPv6]
155
orig_ip = orig_pkt[sc.IPv6]
156
assert orig_ip.src == orig_ip.src
157
assert orig_ip.dst == fwd_ip.dst
158
assert orig_ip.hlim == fwd_ip.hlim + 1
159
# Check ICMPv6
160
assert bytes(orig_ip.payload) == bytes(fwd_ip.payload)
161
162
163
def fwd_ip6_icmp(args):
164
"""
165
Sends ICMPv6 packet via args.iface interface.
166
Receives and checks the forwarded packet.
167
Assumes forwarding router decrements TTL
168
"""
169
170
def filter_f(x):
171
return x.src == args.dmac and is_icmp6_echo_request(x)
172
173
e = sc.Ether(src=args.smac, dst=args.dmac)
174
ip = sc.IPv6(src=args.sip, dst=args.dip)
175
icmp = sc.ICMPv6EchoRequest()
176
pkt = e / ip / icmp
177
178
send_cb = partial(send_packet, args, pkt)
179
packets = sc.sniff(iface=args.iface, started_callback=send_cb,
180
stop_filter=filter_f, lfilter=filter_f, timeout=5)
181
assert len(packets) > 0
182
fwd_pkt = packets[-1]
183
try:
184
check_forwarded_ip6_packet(pkt, fwd_pkt)
185
except Exception as e:
186
print('Original packet:')
187
pkt.show()
188
print('Forwarded packet:')
189
fwd_pkt.show()
190
for idx, a_packet in enumerate(packets):
191
print('{}: {}'.format(idx, a_packet.summary()))
192
raise Exception from e
193
194
195
def main():
196
args = parse_args()
197
test_ptr = globals()[args.test_name]
198
test_ptr(args)
199
200
201
if __name__ == '__main__':
202
main()
203
204