背景: 接手别人的项目,添加子网时对子网所有地址进行 ping 测试
构造子网地址和广播地址 socket 连接时,会报PermissionError: [Errno 13] Permission denied
的错误.
关于为什么要上子网地址和广播地址我也不清楚(代码专门拼接了这两个地址,这两者和对子网所有地址进行 ping 不是重复了吗)
所有,子网地址和广播地址和应该怎么构造 icmp 的包和建立 socket 连接?
ping普通地址无权限问题
附一下代码
def init_icmp_packet(sequence):
# 把字节打包成二进制数据
data_type = 8 # ICMP Echo Request
data_code = 0 # must be zero
data_checksum = 0 # "...with value 0 substituted for this field..."
data_ID = process_id # Identifier
payload = b'abcdefghijklmnopqrstuvwabcdefghi' # data
icmp_packet = struct.pack('>BBHHH32s', data_type, data_code, data_checksum, data_ID, sequence, payload)
icmp_checksum = check_sum(icmp_packet) # 获取校验和
icmp_packet = struct.pack('>BBHHH32s', data_type, data_code, icmp_checksum, data_ID, sequence, payload)
return icmp_packet
def init_raw_socket(ip_addr, icmp_packet):
raw_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, 1)
# 服务端设置非阻塞
# raw_socket.setblocking(False)
raw_socket.sendto(icmp_packet, (ip_addr, 1)) # 报错行
return raw_socket
问题已解决.附上解决后的代码:
def init_raw_socket(ip_addr, icmp_packet):
raw_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, 1)
raw_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # 解决问题的代码,允许发送广播数据
# 服务端设置非阻塞
# raw_socket.setblocking(False)
raw_socket.sendto(icmp_packet, (ip_addr, 1))
return raw_socket
关于setsockopt
方法的用法及参数的含义参考这里
1
keakon 2023-04-17 11:04:57 +08:00
socket.SOCK_RAW 需要 root 权限,你加个 sudo 试试
|
2
yougg 2023-04-17 11:09:45 +08:00
|
3
artnowben 2023-04-17 11:11:37 +08:00
构建 icmp 报文请参考一下 测试仪项目 dperf https://github.com/baidu/dperf
具体代码: 1. raw socket 参考 https://github.com/pengjianzhang/tcping/blob/main/tcping.c 2. icmp 封装参考 https://github.com/baidu/dperf/blob/main/src/icmp.c |
4
julyclyde 2023-04-17 11:27:19 +08:00
建议还是先学学网络的基本原理,搞明白掩码到底是做啥用的
再处理权限问题 |
5
qwq11 2023-04-17 11:55:39 +08:00
楼上提到需要 root 权限,其实从内核 2.2 开始就可以单独设置这些权限。你可以用用 sudo setcap cap_net_raw+p PROGRAM 赋予你程序 socket_row 的能力
|
7
qwq11 2023-04-17 12:45:42 +08:00
@julyclyde #6 +是添加,和 chmod 里的+-=有点像
https://man7.org/linux/man-pages/man3/cap_from_text.3.html#TEXTUAL_REPRESENTATION eip 是三个文件属性,有点像 rwx 这种 https://man.archlinux.org/man/capabilities.7#File_capabilities |
8
bulay OP |
9
qbqbqbqb 2023-04-17 14:44:07 +08:00
子网地址是不能用作目标地址的
广播地址可以,但是如果要用广播地址作为目标地址的话,需要用 setsockopt 给 socket 加上 SO_BROADCAST 属性 |
10
bulay OP @qbqbqbqb 感谢大佬!就是这个问题. 另外,子网地址确实可以 ping 通.用 linux 的命令`ping -b`也是可以用子网地址作为目标地址的
|
11
julyclyde 2023-04-18 17:10:49 +08:00
你这个功能是新加的??
我还以为接手的时候已经有这个了 |