Add test cases for ping with IP options in the response

MFC after:	1 week
Reviewed by:	markj
Differential Revision: https://reviews.freebsd.org/D37210
This commit is contained in:
Alan Somers 2022-10-29 16:03:41 -06:00
parent 526f57bf85
commit e35cfc606a
3 changed files with 140 additions and 0 deletions

View file

@ -6,9 +6,13 @@ SRCS.in_cksum_test= in_cksum_test.c ../utils.c
PACKAGE= tests
ATF_TESTS_SH+= ping_test
# Exclusive because each injection test case uses the same IP addresses
TEST_METADATA.ping_test+= is_exclusive="true"
${PACKAGE}FILES+= ping_c1_s56_t1.out
${PACKAGE}FILES+= ping_6_c1_s8_t1.out
${PACKAGE}FILES+= ping_c1_s56_t1_S127.out
${PACKAGE}FILES+= ping_c1_s8_t1_S1.out
${PACKAGE}FILES+= injection.py
.include <bsd.test.mk>

View file

@ -0,0 +1,83 @@
#! /usr/bin/env python3
# Used to inject various malformed packets
import errno
import logging
import subprocess
import sys
logging.getLogger("scapy").setLevel(logging.CRITICAL)
from scapy.all import IP, ICMP, IPOption
import scapy.layers.all
from scapy.layers.inet import ICMPEcho_am
from scapy.layers.tuntap import TunTapInterface
SRC_ADDR = "192.0.2.14"
DST_ADDR = "192.0.2.15"
mode = sys.argv[1]
ip = None
# fill opts with nop (0x01)
opts = b''
for x in range(40):
opts += b'\x01'
# Create and configure a tun interface with an RFC5737 nonrouteable address
create_proc = subprocess.run(
args=["ifconfig", "tun", "create"],
capture_output=True,
check=True,
text=True)
iface = create_proc.stdout.strip()
tun = TunTapInterface(iface)
with open("tun.txt", "w") as f:
f.write(iface)
subprocess.run(["ifconfig", tun.iface, "up"])
subprocess.run(["ifconfig", tun.iface, SRC_ADDR, DST_ADDR])
ping = subprocess.Popen(
args=["/sbin/ping", "-v", "-c1", "-t1", DST_ADDR],
text=True
)
# Wait for /sbin/ping to ping us
echo_req = tun.recv()
# Construct the response packet
if mode == "opts":
# Sending reply with IP options
echo_reply = IP(
dst=SRC_ADDR,
src=DST_ADDR,
options=IPOption(opts)
)/ICMP(type=0, code=0, id=echo_req.payload.id)/echo_req.payload.payload
elif mode == "pip":
# packet in packet (inner has options)
inner = IP(
dst=SRC_ADDR,
src=DST_ADDR,
options=IPOption(opts)
)/ICMP(type=0, code=0, id=echo_req.payload.id)/echo_req.payload.payload
outer = IP(
dst=SRC_ADDR,
src=DST_ADDR
)/ICMP(type=3, code=1) # host unreach
echo_reply = outer/inner
elif mode == "reply":
# Sending normal echo reply
echo_reply = IP(
dst=SRC_ADDR,
src=DST_ADDR,
)/ICMP(type=0, code=0, id=echo_req.payload.id)/echo_req.payload.payload
else:
print("unknown mode {}".format(mode))
exit(1)
tun.send(echo_reply)
outs, errs = ping.communicate()
sys.exit(ping.returncode)

View file

@ -153,6 +153,56 @@ ping6_46_body()
ping6 -4 -6 localhost
}
atf_test_case "inject_opts" "cleanup"
inject_opts_head()
{
atf_set "descr" "Inject an ECHO REPLY with IP options"
atf_set "require.user" "root"
atf_set "require.progs" "python3" "scapy"
}
inject_opts_body()
{
atf_check -s exit:0 -o match:"wrong total length" -o match:"NOP" python3 $(atf_get_srcdir)/injection.py opts
}
inject_opts_cleanup()
{
ifconfig `cat tun.txt` destroy
}
atf_test_case "inject_pip" "cleanup"
inject_pip_head()
{
atf_set "descr" "Inject an ICMP error with a quoted packet with IP options"
atf_set "require.user" "root"
atf_set "require.progs" "python3" "scapy"
}
inject_pip_body()
{
atf_check -s exit:2 -o match:"Destination Host Unreachable" -o not-match:"01010101" python3 $(atf_get_srcdir)/injection.py pip
}
inject_pip_cleanup()
{
ifconfig `cat tun.txt` destroy
}
# This is redundant with the ping_ tests, but it serves to ensure that scapy.py
# is working correctly.
atf_test_case "inject_reply" "cleanup"
inject_reply_head()
{
atf_set "descr" "Basic ping test with packet injection"
atf_set "require.user" "root"
atf_set "require.progs" "python3" "scapy"
}
inject_reply_body()
{
atf_check -s exit:0 -o match:"1 packets transmitted, 1 packets received" python3 $(atf_get_srcdir)/injection.py reply
}
inject_reply_cleanup()
{
ifconfig `cat tun.txt` destroy
}
atf_init_test_cases()
{
atf_add_test_case ping_c1_s56_t1
@ -164,6 +214,9 @@ atf_init_test_cases()
atf_add_test_case ping6_c1t4
atf_add_test_case ping_46
atf_add_test_case ping6_46
atf_add_test_case inject_opts
atf_add_test_case inject_pip
atf_add_test_case inject_reply
}
check_ping_statistics()