In the ol’ youthful days of Unix graybeards, ARP was used by DEC/Intel/Xerox/IBM for Ethernet, 802.3, Frame Relay, Token Ring, FDDI, X.25, NetROM. Life was good.
Then came along DARPA IP protocol version 1, 2, and 3. Nah. Version 4 works better.
While ARP works great at troubleshooting ISO Data Layer 2, something was needed for ISO Network Layer 3: ICMP was born in IPv3 (then later came IETF RFC777).
Despite IPv1 emerging first, ARP became more popular. ARP had an Ethertype of 0x0806 for CDMA/CD, Token-Ring, NetBIOS, DECNET, NetROM despite IPv4 having started firstly with 0x0800.
Then came IETF RFC826 ARP.
It is interesting to note that arp.c resides haphazardly within Linux kernel net/ipv4 repo directory despite serving so many other non-IP protocols.
The fact that Ethernet type were different, is the primary reason why abstraction of TCP/UDP and ICMP required different UNIX network function calls.
While ICMP and ARP are equally filterable by nftables, that is the Internet scope of the Linux kernel.
Whereas in the pathways of ARP and ICMP are different within the Unix/Linux kernel, ARP packet process entirely within the kernel, so does some of ICMP packets; receiving ICMP-REQUEST and spitting out ICMP-RESPONSE all done within kernel context.
Receiving an ICMP-REQUEST leverages ip_rt_put() and SKB buffers for their autonomous reply, which is in-kernel. Whereas ARP drops its packet directly (without ip_rt_put()) into the netdev xmit queue (netfilter still can arbitrate ARP below that).
When users become involved, both protocol’s REQUEST/RESPONSE reversed; arp-scan (ARP) and ping (ICMP) can be used also with a different set of kernel APIs when ARP/ICMP traversing from userland to kernel network thru these tools, of course, all required root privilege.
That said, UDP/TCP/DDCP also all have their set of own APIs, one for userland applications to use and one for system daemons to use.
ICMP didn’t get migrated with UDP/TCP/DDCP/SCTP protocol over Unix evolution because there was “no” data payload in which to send over ICMP with. This is by original and current design. Sure, we can abuse it to delivery “data”, also within root mode.
So why can’t user do the same thing?
ICMP-REQUEST also requires broadcast mode over multiplex-type physical interfaces (Ethernet, 802.3 DIX, Token Ring, X.25, Frame Relay). This is the secret sauce in getting all remote hosts to look, decide if they’re “it”, and selectively-respond accordingly thus making them look "alive".
However, broadcast mode is a common but easily abused into flooding the neighbor physical links as the early ARPA design demonstrated in 1978. Christmas Tree and Ping-of-Death are also results of broadcast-type abuse but they were not the first to abuse, just happens to be the largest and biggest denial of service kind. While PPTP is a rare exception by the virtue of its leveraging a simplex model over a multiplex-type link, a bastardization, if you will, but not enough to grant your precious user-privilege toward those same API that are providing dangerous multiplex-link-type transmit): PPtP also must run in root.
Is abuse of broadcast-mode the only reason to shield ICMP from direct non-privileged user access to thereof? No. End-users are typically not allowed to learn of its neighbors (hence, frequent disabling (chmod go-rwx /usr/bin/ping, blocking certain ARP-related /proc, and not installing arp-scan tools).
So, even if ICMP is apart from UDP, TCP, DDCP, SCTP, it must be further restricted to stay apart to ensure that:
- bridges are protected from flooding packet storms,
- route tables are shielded from corruptions, and
- nosy (but literal residential) neighbors are kept apart.
-poption.