【问题标题】:python with unprivileged ping in linux IPPROTO_ICMP在 linux IPPROTO_ICMP 中具有非特权 ping 的 python
【发布时间】:2012-12-25 00:53:48
【问题描述】:

根据 http://kernelnewbies.org/Linux_3.0#head-c5bcc118ee946645132a834a716ef0d7d05b282e 我们现在可以以非特权用户身份 ping,我可以让它工作。

使用https://github.com/jedie/python-ping我修改了第210行的样子

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

作为 root 我“echo 1000 1000 > /proc/sys/net/ipv4/ping_group_range”

我的组是 1000

我可以像普通用户一样运行 ping.py,我可以在 tcpdump 中看到 echo 请求和 echo 回复

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

但是 ping.py 没有看到回复,并说超时。

任何想法如何使这项工作?

编辑:

我正在缩小问题范围。

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

问题是 icmp_header["packet_id"] 总是 8247 而 self.own_id 是 ping.py 的 pid。 8247 是十六进制的 2037,我可以在转储中看到很多次。

这是一个完整的 ping 转储

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,icmp 标头可能打包错误。然而这只是一个狂野的刺,我稍后会盯着它看,同时,任何帮助将不胜感激。

【问题讨论】:

    标签: python sockets ping icmp


    【解决方案1】:

    有两件事你没有考虑到:

    • 在这种新型套接字上接收消息时,不包括 IP 标头。由于您正在修改的代码需要使用 RAW 套接字(确实在收到的消息中包含 IP 标头),因此您需要更改很多内容:
      • 第 306 行使用packet_data[20:28] 提取 ICMP 标头,但当然由于不包括 IP 标头,因此 20 字节偏移量没有意义。这必须变成packet_data[0:8]
      • 在第 310 行,代码尝试从数据包的开头提取 IP 标头,但它不存在。所以这段代码实际上会提取垃圾。如果您想了解 TTL 等信息,可以设置其他选项(请参阅 documentation which accompanies the patch that enabled the functionality)。
    • 有了这个新功能,内核通过套接字绑定机制控制 ICMP ID。您可以让内核选择一个 ID(隐式绑定)或设置一个 ID(显式绑定)。最好只依赖隐式绑定,因为内核会保证选择一个免费的 ID。

      在第 309 行,代码通过检查 id 与 self.own_id 来检查回复是否属于我们。但是使用隐式绑定,内核会为我们选择 ID。我们可以将self.own_id 设置为内核分配的标识符

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

      (将其放在第 221 行的 self.send_one_ping 之后)

      但事实上,检查self.own_id 是不必要的,因为内核已经确保我们只看到我们应该看到的回复。

    【讨论】:

    • 太棒了,这有很大帮助。 “如果您想了解 TTL 之类的信息,可以设置额外的选项(请参阅启用该功能的补丁随附的文档)。”这就是我目前所坚持的。
    • 是的,这很难。要访问辅助,您必须使用recvmsg 系统调用而不是recvfrom。然后,您必须使用一大堆 CMSG 宏解析数据,我相信这些宏仅在 C 中可用。This question 确认 recvmsg 在 Python 中不可用。另请参阅 Python issue 6560:添加它似乎并不简单。但是,至少这仅影响 TTL。您可以使用recvfrom 获取所有其他感兴趣的内容。
    • 好的,谢谢 Celada,你让我走上了正确的道路,从我在这里读到的stackoverflow.com/questions/9237006/…libpcap 可能是最简单的选择。
    • 好吧,libpcap 将需要 root(或至少 CAP_NET_RAW),这是您一开始就试图避免的,不是吗?您的解决方案很容易为您提供除了返回数据包上的 TTL 之外的所有内容,而 TTL 真的那么重要吗?如果你真的需要 TTL 并且你对 C 很方便,那么一个小的专用 Python C 扩展只调用 recvmsg 并将结果返回给 Python 程序可能不会那么糟糕(比如,100 行代码,包括样板用于 CPython 扩展)。圣诞快乐!
    • 圣诞快乐 Celada,感谢您分享您的专业知识。我想 ttl 没那么重要,是的,避免 root 才是重点。
    猜你喜欢
    • 1970-01-01
    • 2010-11-14
    • 2011-08-03
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    相关资源
    最近更新 更多