ICMP Identifier field in UDP between Linux and OSX
Ping packet is traditionally created as a raw packet and formatted into ICMP ECHO REQUEST. The problem with creating a raw socket requires root privilege. It is alright if the program is running as part of the system service under root anyway. However, running as a non privilege user, the program requires extra care by configuring the setuid bit which poses security risks e.g. the program may have memory leak which can be hijacked with shellcode.
Fortunately, there is a proper way to issue ICMP request for non privilege use, by creating a UDP socket:
socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)
This avoids escalating to root privilege. Here is a link to my ping demo code in C which sends the ICMP ECHO request as UDP and shows the identifier value in request and reply.
Make sure you have configured the group permission for creating ping sockets, otherwise you will get “Permission denied” error message in socket system call. To grant the permission, issues a sysctl command to set the kernel state. Below is an example granting to all user groups.
sysctl -w net.ipv4.ping_group_range="0 65536"
One interesting observation of ICMP as UDP packet is the behaviour of identifier field on Linux. In general, identifier is assigned as the PID value for matching against the same field in ECHO REPLY. This is necessary when multiple pings are running and looking for the correct ECHO REPLY. Since it is in UDP, this is not necessary the case anymore. In fact, the kernel will change the identifier to store for the local port. See this, and this.
Compiles the ping_demo program and runs in on Ubuntu, here is the result:
itrinegy@neone-devel:~$ ./pingdemo Sent ICMP ECHO (ident : 6789) to 22.214.171.124 Recieved ICMP REPLY - id: 6
As we can see, the ICMP ECHO request is sent with a hardcoded identifier, 6789, value, whereas the ICMP REPLY comes back with a different value. If we use tcpdump, we can see the identifier in ICMP ECHO REQUEST have been converted to 6 instead of 6789.
itrinegy@neone-devel:~$ sudo tcpdump icmp -vvv tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 21:14:33.593357 IP (tos 0x0, ttl 64, id 28437, offset 0, flags [DF], proto ICMP (1), length 33) 192.168.202.246 > lhr25s09-in-f4.1e100.net: ICMP echo request, id 6, seq 1, length 13 21:14:33.597027 IP (tos 0x0, ttl 55, id 0, offset 0, flags [none], proto ICMP (1), length 33) lhr25s09-in-f4.1e100.net > 192.168.202.246: ICMP echo reply, id 6, seq 1, length 13
Since Android is derived from Linux, it has the exact same behaviour in UDP ping.
As for OSX, the network layer is very much based on FreeBSD. The behaviour is different, the identifier value is maintained throughout the ping.
Joe-New-MBP:ping_demo Joe$ ./pingdemo Sent ICMP ECHO (ident : 6789) to 126.96.36.199 Recieved ICMP REPLY - id: 6789