python 绑定 socket.error: [Errno 13] 权限被拒绝

31 投票
4 回答
94813 浏览
提问于 2025-04-18 08:19

我有一个Python脚本,它可以从远程机器获取数据包,并把这些数据包写入一个叫做gr3的tun接口,具体操作是这样的:
(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

4 个回答

0

你可能正在使用一个被其他服务占用的端口,或者这个端口是被保留的。你可以换一个空闲的端口号,或者换一个你知道没有被使用的端口。

0

给遇到同样错误的朋友们:

你的服务器可能没有以管理员权限运行。所有1024以下的端口都是系统保留的。你需要一个有管理员权限的服务器来帮忙。

在我的具体情况下,我通过设置一个反向代理,用Nginx将请求转发到我应用的高端口来解决问题。

我部署的生产服务器Waitress没有以管理员身份运行,所以无法打开系统保留的端口。于是我启动了Nginx来处理SSL加密,并通过http将所有https请求转发到应用的端口,这样就成功了。

我建议你先确认一下你想用的端口没有被其他程序占用,如果没有被占用,再确保你的服务器设置能够处理这个端口。

这是我找到的文档,经过很多次的挠头后,它清楚地解释了这个情况:

外部绑定

Waitress不应该以管理员身份运行,因为这样会让你的应用代码也以管理员身份运行,这样不安全。不过,这也意味着你无法绑定到80或443端口。相反,应该在Waitress前面使用像Nginx或Apache httpd这样的反向代理。

如果不指定--host选项,你可以绑定到所有外部IP的非特权端口。但在使用反向代理的情况下,不要这样做,否则可能会绕过代理。

0.0.0.0不是一个有效的地址,你需要在浏览器中使用一个具体的IP地址。

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

1

虽然这个问题里没有提到,但我想扩展一下关于本地进程间通信的 unix sockets 的内容,也就是 AF_UNIX。在 man unix 7 中可以看到:

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

在Linux上,连接到一个流套接字对象需要对该套接字有写入权限;向数据报套接字发送数据报同样需要对该套接字有写入权限。POSIX并没有说明套接字文件的权限会有什么影响,在某些系统(例如旧版的BSD)中,套接字的权限会被忽略。可移植的程序不应该依赖这个特性来保证安全。

所以,如果在使用 bind() 创建unix套接字时遇到 PermissionError: [Errno 13] Permission denied 的错误,请检查一下套接字所在目录的权限。

84

作为普通用户,你不能绑定低于1024的端口号。

所以你可以选择:

  • 使用一个大于1024的端口号(推荐)
  • 或者以有特权的用户身份运行脚本

如果真的需要接受111端口的请求,虽然更复杂,但更安全的解决方案是:

  • 在一个更高的端口上以普通用户身份运行,然后将111端口的请求转发到这个高端口上。

撰写回答