xref: /freebsd/sbin/ping/tests/injection.py (revision 61e21613)
1#! /usr/bin/env python3
2# Used to inject various malformed packets
3
4import errno
5import logging
6import subprocess
7import sys
8
9logging.getLogger("scapy").setLevel(logging.CRITICAL)
10
11from scapy.all import IP, ICMP, IPOption
12import scapy.layers.all
13from scapy.layers.inet import ICMPEcho_am
14from scapy.layers.tuntap import TunTapInterface
15
16SRC_ADDR = "192.0.2.14"
17DST_ADDR = "192.0.2.15"
18
19mode = sys.argv[1]
20ip = None
21
22# fill opts with nop (0x01)
23opts = b''
24for x in range(40):
25    opts += b'\x01'
26
27
28# Create and configure a tun interface with an RFC5737 nonrouteable address
29create_proc = subprocess.run(
30    args=["ifconfig", "tun", "create"],
31    capture_output=True,
32    check=True,
33    text=True)
34iface = create_proc.stdout.strip()
35tun = TunTapInterface(iface)
36with open("tun.txt", "w") as f:
37    f.write(iface)
38subprocess.run(["ifconfig", tun.iface, "up"])
39subprocess.run(["ifconfig", tun.iface, SRC_ADDR, DST_ADDR])
40
41ping = subprocess.Popen(
42        args=["/sbin/ping", "-v", "-c1", "-t1", DST_ADDR],
43        text=True
44)
45# Wait for /sbin/ping to ping us
46echo_req = tun.recv()
47
48# Construct the response packet
49if mode == "opts":
50    # Sending reply with IP options
51    echo_reply = IP(
52        dst=SRC_ADDR,
53        src=DST_ADDR,
54        options=IPOption(opts)
55    )/ICMP(type=0, code=0, id=echo_req.payload.id)/echo_req.payload.payload
56elif mode == "pip":
57    # packet in packet (inner has options)
58
59    inner = IP(
60        dst=SRC_ADDR,
61        src=DST_ADDR,
62        options=IPOption(opts)
63    )/ICMP(type=0, code=0, id=echo_req.payload.id)/echo_req.payload.payload
64    outer = IP(
65        dst=SRC_ADDR,
66        src=DST_ADDR
67    )/ICMP(type=3, code=1)  # host unreach
68
69    echo_reply = outer/inner
70elif mode == "reply":
71    # Sending normal echo reply
72    echo_reply = IP(
73        dst=SRC_ADDR,
74        src=DST_ADDR,
75    )/ICMP(type=0, code=0, id=echo_req.payload.id)/echo_req.payload.payload
76else:
77    print("unknown mode {}".format(mode))
78    exit(1)
79
80tun.send(echo_reply)
81outs, errs = ping.communicate()
82
83sys.exit(ping.returncode)
84