Using socat to send arbitrary IPv4 traffic

One of the more interesting tasks I've had recently was to figure out what a firewall did when IPv4 was sent through it. Sounds simple enough right? Just place something like a web server on one side of the firewall and then use curl to access it. This does in fact send IPv4 traffic. That covers TCP. Some clever use of the netcat command can then be used to quickly test UDP connectivity as well. If you're knowledgeable of network protocols, you might also know that ICMP exists and that ping can send ICMP packets.

But what about the rest of IPv4? Wikipedia does in fact list dozens of other known protocols. Some of these are reasonably well known, like IP in IP. Others such as "UDP Lite" are completely unknown to me. The main issue with trying to test a firewall with such traffic is that even if software is well known for a particular protocol is unlikely to be as accessible as a tool like curl. After all, I don't really need to set up a proper IP encapsulation link. I just need to find out how the firewall handles packets that appear to be IP in IP encapsulation.

Using socat

As it would turn out, there is in fact a solution to this. The socat tool is designed to be a command line tool for interacting with sockets. You can send an arbitrary packet by combining some commands line tools together

echo -ne 'bob' | sudo socat - ip4-sendto:127.0.0.1:4

This particular example sends an IPv4 packet to a destination IP of 127.0.0.1 with protocol number 4. The packet contents is the string 'bob' which as you might guess does not conform to any actual protocol standards. You can actually see this with tcpdump running on your local computer

$ sudo tcpdump -i lo -n -vvvv -s 65535 -X 'ip and not icmp and not tcp and not udp'
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 65535 bytes
21:33:35.683579 IP (tos 0x0, ttl 64, id 10901, offset 0, flags [DF], proto IPIP (4), length 23)
    127.0.0.1 > 127.0.0.1: IP6, wrong link-layer encapsulation (invalid)
    0x0000:  4500 0017 2a95 4000 4004 124c 7f00 0001  E...*.@.@..L....
    0x0010:  7f00 0001 626f 62                        ....bob
^C
1 packet captured
2 packets received by filter
0 packets dropped by kernel

Since in my case I just needed to confirm the firewall behaviors in the presence of different IPv4 protocols, this worked out great. I can send basically any packet that appears to be any of the protocols. If I actually need to send a valid packet I could craft one as well

IPv6

Of course socat supports more than just IPv4. So you can use this technique to send IPv6 traffic as well.

echo -ne "Hello IPv6" | sudo socat - 'ip6-sendto:[fe80::5054:ff:feb0:d38e%enp7s0]:136'

Since the address is IPv6, it needs to be enclosed in the square brackets []. I'm also using a link local address, which means I use the percent sign % to specify what interface to communicate on. The packet sent looks like this according to tcpdump

03:45:08.016368 IP6 (flowlabel 0xc71b6, hlim 64, next-header unknown (136) payload length: 10) fe80::83eb:45ba:3eda:6a0a > fe80::5054:ff:feb0:d38e:  ip-proto-136 10
    0x0000:  600c 71b6 000a 8840 fe80 0000 0000 0000  `.q....@........
    0x0010:  83eb 45ba 3eda 6a0a fe80 0000 0000 0000  ..E.>.j.........
    0x0020:  5054 00ff feb0 d38e 4865 6c6c 6f20 4950  PT......Hello.IP
    0x0030:  7636                                     v6

Copyright Eric Urban 2024, or the respective entity where indicated