Python绑定套接字出现错误: [Errno 13] 权限被拒绝。

31

我有一个Python脚本,它从远程机器获取数据包并将它们写入tun接口gr3中(os.write(self.tun_fd.fileno(), ''.join(packet)))。

Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
inet addr:10.0.0.6  P-t-P:10.0.0.8  Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
RX packets:61 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500 
RX bytes:5124 (5.0 KiB)  TX bytes:0 (0.0 b)

我希望通过一个单独的pong脚本接收这些数据包,如下:

import threading, os, sys, fcntl, struct, socket
from fcntl import ioctl
from packet import Packet

HOST = '10.0.0.6'
PORT = 111
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
    data = conn.recv(1024)
    if not data: break
    else: print data    
    conn.sendall(data)
conn.close()

我遇到了这个错误:

s.bind((HOST, PORT))
File "<string>", line 1, in bind
socket.error: [Errno 13] Permission denied

2
你有什么问题吗?这似乎都是正常和预期的...你想知道什么?(111是一个特权端口。) - David Schwartz
6
我认为这是一个非常好的问题,包括整个代码和错误信息。只是有一些他/她不知道的东西。如果我们假设 OP 应该知道所有东西,那就没有 Stack Overflow 了。 - utdemir
我想知道我的Python正在哪个端口上写入到gr3 tun接口,以便使用pong脚本监听它。 os.write(self.tun_fd.fileno(), ''.join(packet))没有指定端口。 - NELOUNI
4个回答

82

如果作为非特权用户,您无法绑定到小于1024的端口号。

所以,您应该选择:

  • 使用大于1024的端口号(建议)
  • 或以特权用户身份运行脚本

如果确实需要从111接受连接,则更难但更安全的解决方案是:

  • 在更高端口上作为非特权用户运行,并在外部将端口111转发到它上面。

1
谢谢utdemir,但我怎么知道我的脚本正在发送这些数据包的哪个端口,因为我知道它正在写入tun接口gr3,但是我不知道在哪个端口。 - NELOUNI
其实,我不知道如何使用tun接口,这只是针对s.bind错误的答案和解决方案。 - utdemir
如果您正在使用Linux服务器,只需在命令前加上sudo即可。 - Marius Johan

1
尽管原问题中没有提到,但我想将其扩展到本地进程间通信的unix sockets情况,即AF_UNIX。如man unix 7所示:

在Linux实现中,路径名套接字遵循它们所在目录的权限。如果进程没有对创建套接字的目录具有写入和搜索(执行)权限,则创建新套接字失败。

在Linux上,连接流套接字对象需要该套接字的写入权限;同样,向数据报套接字发送数据报也需要该套接字的写入权限。POSIX不对套接字文件的权限效果做出任何声明,在某些系统(例如旧版BSD)上,套接字权限会被忽略。便携式程序不应依赖此功能进行安全性。

因此,如果使用unix sockets时在bind()上遇到PermissionError:[Errno 13] Permission denied错误,请查看套接字目录的权限。

0
您可能正在使用其他服务或保留端口,请将端口号更改为空闲端口。

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人能够确认你的答案是否正确。你可以在帮助中心找到关于如何撰写好答案的更多信息。 - Community

0

对于其他遇到同样错误的人:

你的服务器可能没有以 root 权限运行。所有低于 1024 的端口都是系统保留的。你需要从具有 root 权限的服务器获得帮助。

对于我的特定情况,解决方法是使用 Nginx 设置反向代理到我的应用程序上更高的端口。

在我的情况下,我部署的生产服务器:Waitress 没有以 root 运行,因此不支持在系统保留端口上打开端口。启动 Nginx 处理 SSL 加密并通过 http 将所有 https 请求传递到应用程序端口是对我有效的解决方案。

首先确保没有其他东西正在使用您尝试使用的端口,如果清除了,则确保已部署的服务器设置为处理该端口。

这是我找到的文档,在很多头发被拔掉后,它清楚地向我解释了这种情况:

外部绑定

Waitress 不应该以 root 用户身份运行,因为这会导致您的应用程序代码以 root 权限运行,这是不安全的。然而,这意味着将无法绑定到 80 或 443 端口。相反,应该在 Waitress 前面使用反向代理,例如 nginx 或 Apache httpd。

通过不指定 --host 选项,可以在非特权端口上绑定到所有外部 IP。当使用反向代理设置时,请勿这样做,否则将有可能绕过代理。

0.0.0.0 不是一个有效的地址,您需要在浏览器中使用特定的 IP 地址。

来源:https://flask.palletsprojects.com/en/2.2.x/deploying/waitress/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接