chesty
chesty

Reputation: 83

python with unprivileged ping in linux IPPROTO_ICMP

according to http://kernelnewbies.org/Linux_3.0#head-c5bcc118ee946645132a834a716ef0d7d05b282e we can now ping as an unprivileged user, and I can sort of get it to work.

using https://github.com/jedie/python-ping I modified line 210 to look like

current_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_ICMP)

as root I "echo 1000 1000 > /proc/sys/net/ipv4/ping_group_range"

my group is 1000

and I can run ping.py as myself as an ordinary user, I can see echo requests and echo replies in tcpdump

18:33:24.840291 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 269)
    127.0.0.1 > 127.0.0.1: ICMP echo request, id 38, seq 0, length 249
18:33:24.840309 IP (tos 0x0, ttl 64, id 37939, offset 0, flags [none], proto ICMP (1), length 269)
    127.0.0.1 > 127.0.0.1: ICMP echo reply, id 38, seq 0, length 249

but ping.py doesn't see the replies, and says timeout.

Any ideas how to make this work?

edit:

I'm narrowing down the issue.

print "c", icmp_header, address, self.own_id
if icmp_header["packet_id"] == self.own_id: # Our packet

the problem is icmp_header["packet_id"] is always 8247 and self.own_id is the pid of ping.py. 8247 is 2037 in hex, which I can see quite a few time in the dump.

This is a full dump of a ping on the wire

19:25:15.513285 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 283: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 269)
  127.0.0.1 > 127.0.0.1: ICMP echo request, id 70, seq 2, length 249
    0x0000:  4500 010d 0000 4000 4001 3bee 7f00 0001  E.....@.@.;.....
    0x0010:  7f00 0001 0800 d932 0046 0002 5b36 362c  .......2.F..[66,
    0x0020:  2036 372c 2036 382c 2036 392c 2037 302c  .67,.68,.69,.70,
    0x0030:  2037 312c 2037 322c 2037 332c 2037 342c  .71,.72,.73,.74,
    0x0040:  2037 352c 2037 362c 2037 372c 2037 382c  .75,.76,.77,.78,
    0x0050:  2037 392c 2038 302c 2038 312c 2038 322c  .79,.80,.81,.82,
    0x0060:  2038 332c 2038 342c 2038 352c 2038 362c  .83,.84,.85,.86,
    0x0070:  2038 372c 2038 382c 2038 392c 2039 302c  .87,.88,.89,.90,
    0x0080:  2039 312c 2039 322c 2039 332c 2039 342c  .91,.92,.93,.94,
    0x0090:  2039 352c 2039 362c 2039 372c 2039 382c  .95,.96,.97,.98,
    0x00a0:  2039 392c 2031 3030 2c20 3130 312c 2031  .99,.100,.101,.1
    0x00b0:  3032 2c20 3130 332c 2031 3034 2c20 3130  02,.103,.104,.10
    0x00c0:  352c 2031 3036 2c20 3130 372c 2031 3038  5,.106,.107,.108
    0x00d0:  2c20 3130 392c 2031 3130 2c20 3131 312c  ,.109,.110,.111,
    0x00e0:  2031 3132 2c20 3131 332c 2031 3134 2c20  .112,.113,.114,.
    0x00f0:  3131 352c 2031 3136 2c20 3131 372c 2031  115,.116,.117,.1
    0x0100:  3138 2c20 3131 392c 2031 3230 5d         18,.119,.120]
19:25:15.513300 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 283: (tos 0x0, ttl 64, id 37971, offset 0, flags [none], proto ICMP (1), length 269)
  127.0.0.1 > 127.0.0.1: ICMP echo reply, id 70, seq 2, length 249
    0x0000:  4500 010d 9453 0000 4001 e79a 7f00 0001  E....S..@.......
    0x0010:  7f00 0001 0000 e132 0046 0002 5b36 362c  .......2.F..[66,
    0x0020:  2036 372c 2036 382c 2036 392c 2037 302c  .67,.68,.69,.70,
    0x0030:  2037 312c 2037 322c 2037 332c 2037 342c  .71,.72,.73,.74,
    0x0040:  2037 352c 2037 362c 2037 372c 2037 382c  .75,.76,.77,.78,
    0x0050:  2037 392c 2038 302c 2038 312c 2038 322c  .79,.80,.81,.82,
    0x0060:  2038 332c 2038 342c 2038 352c 2038 362c  .83,.84,.85,.86,
    0x0070:  2038 372c 2038 382c 2038 392c 2039 302c  .87,.88,.89,.90,
    0x0080:  2039 312c 2039 322c 2039 332c 2039 342c  .91,.92,.93,.94,
    0x0090:  2039 352c 2039 362c 2039 372c 2039 382c  .95,.96,.97,.98,
    0x00a0:  2039 392c 2031 3030 2c20 3130 312c 2031  .99,.100,.101,.1
    0x00b0:  3032 2c20 3130 332c 2031 3034 2c20 3130  02,.103,.104,.10
    0x00c0:  352c 2031 3036 2c20 3130 372c 2031 3038  5,.106,.107,.108
    0x00d0:  2c20 3130 392c 2031 3130 2c20 3131 312c  ,.109,.110,.111,
    0x00e0:  2031 3132 2c20 3131 332c 2031 3134 2c20  .112,.113,.114,.
    0x00f0:  3131 352c 2031 3136 2c20 3131 372c 2031  115,.116,.117,.1
    0x0100:  3138 2c20 3131 392c 2031 3230 5d         18,.119,.120]

AFAICT, the icmp header might be packed wrong. however it's just a wild stab, I will stare at it some more later, in the meantime, any help would be appreciated.

Upvotes: 6

Views: 2576

Answers (1)

Celada
Celada

Reputation: 22261

There are two things you didn't take into account:

  • When receiving messages on this new type of socket, the IP header is not included. Since the code you are modifying expects to use RAW sockets (which do include the IP header in received messages), you need to change quite a few things:
    • line 306 extracts the ICMP header with packet_data[20:28] but of course since the IP header is not included the 20 byte offset does not make sense. This has to become packet_data[0:8]
    • At line 310, the code attempts to extract the IP header from the beginning of the packet, but it's not there. So this code will actually extract garbage. There are extra options you can set if you want to know things like the TTL (see the documentation which accompanies the patch that enabled the functionality).
  • With this new functionality, the kernel controls the ICMP ID through the socket binding mechanism. You can let the kernel choose an ID (implicit bind) or set an ID (explicit bind). It's better to just rely on implicit bind because the kernel will guarantee to choose an ID that's free.

    On line 309, the code checks to see if the reply belongs to us by checking the id against self.own_id. But using implicit bind the kernel picks the ID for us. We could set self.own_id to the identifier the kernel has assigned using

    self.own_id = current_socket.getsockname()[1]
    

    (put this right after self.send_one_ping on line 221)

    But in fact the check against self.own_id is not even necessary anyway since the kernel already makes sure we only see the replies we're supposed to see.

Upvotes: 4

Related Questions