Page MenuHomeFreeBSD

D37210.id114543.diff
No OneTemporary

D37210.id114543.diff

diff --git a/sbin/ping/tests/Makefile b/sbin/ping/tests/Makefile
--- a/sbin/ping/tests/Makefile
+++ b/sbin/ping/tests/Makefile
@@ -6,9 +6,13 @@
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>
diff --git a/sbin/ping/tests/injection.py b/sbin/ping/tests/injection.py
new file mode 100644
--- /dev/null
+++ b/sbin/ping/tests/injection.py
@@ -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)
diff --git a/sbin/ping/tests/ping_test.sh b/sbin/ping/tests/ping_test.sh
--- a/sbin/ping/tests/ping_test.sh
+++ b/sbin/ping/tests/ping_test.sh
@@ -153,6 +153,56 @@
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_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()

File Metadata

Mime Type
text/plain
Expires
Tue, Jun 16, 10:50 AM (19 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33986307
Default Alt Text
D37210.id114543.diff (4 KB)

Event Timeline