send & receive ICMP with datalink raw socket over local interface - linux

I am learning datalink raw socket programming on Linux, and I found these helpful examples. I compiled the icmp4_ll.c, and used it to send an ICMP packet to anther computer in the same LAN. I can receive the reply from the destination computer. However, when I used it to send an ICMP packet to the local computer, that is, I set the source and destination Ethernet MAC and IP addresses to the MAC and IP address of eth0, I cannot receive the ICMP reply on either eth0 or lo interface (In Wireshark, I only noticed the ICMP request sent over eth0, but no ICMP reply on any interface.)
I think the ICMP request message is composed correctly, (otherwise the remote destination wont reply). But I don't know why the OS just doesn't reply the request. Any help or hints are appreciated.

RFC 792 defined special conditions for the ICMP messages:
No ICMP error messages are sent in response to ICMP error messages to avoid infinite repetition.
For fragmented IP datagrams, ICMP messages are only sent for errors on fragmented zero (the first fragment).
ICMP error messages are never sent in response to a datagram that is destined to a broadcast or a multicast address.
ICMP error messages are never sent in response to a datagram sent as a link layer broadcast.
ICMP error messages are never sent in response to a datagram whose source address does not represents a unique host (the source address
cannot be zero, a loopback address, a broadcast address or a multicast
address).
ICMP error messages are never sent in response to an IGMP message of any kind. When an ICMP message of unknown type is received, it must
be silently discarded.
Routers will almost always generate ICMP messages but when it comes to a destination host, the number of ICMP messages generated is implementation dependent.

Related

Can the sending address:port be set from a packet received before sending (relaying) UDP?

Similar to How to set source address when sending using and UDP socket, but not identical:
I'm writing an experimental UDP packet relay.
The code works so far, but the problem is that the relayed packets have the address and port of the relay (instead of the original sender) as sending address in the outgoing packets, so any responses would also go to the relay, and not to the original sender.
Is there a standard way (without manipulating the packets directly) to do this?
Currently it has to work for IPv4 only.

How to receive packets on an interface without IP address?

I tried to receive broadcast packets on an interface that has no IPv4 address set.
The packets are visible via tcpdump. But the network stack seems to drop the packets before they can be received via a socket.
Is this possible without libpcap?

Raw ICMP socket interaction with internal stack windows/linux

In regard to using ICMP raw socket like in this example
sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
There's some important question I didn't find an answer anywhere in the documentation. As far as I understand the ICMP protocol is implemented
on kernel level ((by %SystemRoot%\System32\Drivers\Tcpip.sys driver windows) .
So how this kernel logic interacts with the raw user space socket willing to send and receive the ICMP packets defined as in example above?
Is ICMP logic canceled since RAW socket is open and OS gives the application full control of ICMP? Or they are working in parallel (inevitably creating the mess on the network). Can I tell OS which ICMP packets I would like to handle exactly?
Answers for both linux and windows are welcome.
By using the raw socket with IPPROTO_ICMP you only get copies of the ICMP packets which arrive at your host (see How to receive ICMP request in C with raw sockets). The ICMP-logic in the network stack is still alive and will handle ICMP-messages.
So you just need to pick the ICMP packets of your interest after you received them (e.g. with the corresponding ID in the ICMP header). In the receive buffer you get filled by calling recv() you also get the complete IP header.
Under Linux there is even a socket option (ICMP_FILTER) with which you can set a receive-filter for different ICMP packets.

use scapy to send UDP ping with a high frequency, why only receive the first few ICMP port unreachable message?

In a linux system, I use scapy to send a high frequency UDP ping. For example: each 20 milliseconds, send a UDP packet; a total of 100. But I can only get the first few ICMP port unreachable answer.
pkt = IP(dst=dst)/UDP(dport=RandShort())
ans,_ = sr(pkt*100, inter=0.02, timeout=3)
I tried to use tcpdump to capture packet and found that all UDP packets have been sent to the target machine, but only a few ICMP packet came back to the source machine. What would cause this?
If I use ICMP pingļ¼Œthis does not happen.
I guess:
may be caused by the target machine's system kernel parameter which process icmp packet
may be caused by the icmp packet routing switch strategies.
The rate of ICMP packets is hard limited by the kernel to prevent DDOS attacks. Usually to only 1 packet per second. Almost impossible to get anything faster than that in any external (internet) router. Example

Minimum requirements for custom networking stack to send UDP packets?

(edit: solved -- see below)
This is my situation:
TL-MR3020 -----ethernet----- mbed
OpenWRT C/C++ custom networking stack
192.168.2.1 192.168.2.16
TL-MR3020 is a Linux embedded router
mbed is an ARM microcontroller.
On the network I just want them to exchange messages using UDP packets on port 2225. In particular, TL-MR3020 has to periodically send packets every second to 192.168.2.16:2225, while mbed has to periodically send packets every 50ms to 192.168.2.1:2225.
Everything was good untill I removed the network stack library from mbed (lwIP, not so lightweight for me) and written a new minimal stack.
My new stacks sends 5 gratuitous ARP reply just after the ethernet link gets up, then starts sending and receiving udp packets.
Now TL-MR3020 doesn't receive any UDP packet. In particular, with ifconfig I can see packets coming, but my application can't get them.
Also, if I connect my laptop instead of the TL-MR3020, I can see the UDP packets coming, using Wireshark. There's nothing wrong, except done for my application.
I have a node.js script that has to receive the packets, but it doesn't receive nothing, but if I send UDP packets from local to local, the script receives them.
I think that my application is OK also because neither SOCAT can receive the UDP packets using socat - UDP-LISTEN:2225.
I've already checked on TL-MR3020:
arp table has the correct ip-mac assiciation
destination MAC address matches the incoming interface
destination IP address matches the incoming interface
IP checksum: wireshark says good=false, bad=false
UDP checksum: wireshark says good=false, bad=false
So, I'm asking... what are the minimum requirements for a custom networking stack to send UDP packets?
SOLVED:
You need a good checksum in the IP header.
UDP checksum, my case, can be set to zero.
tcpdump is very helpful (thanks to AndrewMcDonnell)

Resources