有没有办法让非root进程绑定到Linux上的“特权”端口?

巧了我就是萌 提交于 2020-02-28 04:19:09

在我的开发盒上有这个限制是非常烦人的,因为除了我之外不会有任何用户。

我知道标准的解决方法 ,但它们都没有完全符合我的要求:

  1. authbind (Debian测试中的版本,1.0,仅支持IPv4)
  2. 使用iptables REDIRECT目标将低端口重定向到高端口 (对于ip6tables,iptables的IPv6版本尚未实现“nat”表)
  3. sudo(以root身份运行是我想避免的)
  4. SELinux(或类似)。 (这只是我的开发盒,我不想引入很多额外的复杂性。)

是否有一些简单的sysctl变量允许非root进程绑定到Linux上的“特权”端口(端口小于1024),或者我只是运气不好?

编辑:在某些情况下,您可以使用功能来执行此操作。


#1楼

在启动时:

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080

然后,您可以绑定到前进的端口。


#2楼

您可以执行端口重定向。 这就是我在Linux机器上运行的Silverlight策略服务器所做的

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300

#3楼

您可以设置本地SSH隧道,例如,如果您希望端口80命中绑定到3000的应用程序:

sudo ssh $USERNAME@localhost -L 80:localhost:3000 -N

这具有使用脚本服务器的优点,并且非常简单。


#4楼

还有'djb方式'。 您可以使用此方法以root身份在tcpserver下的任何端口上运行启动流程,然后它将在流程启动后立即将流程控制权交给您指定的用户。

#!/bin/sh

UID=`id -u yourusername`
GID=`id -g yourusername`
exec tcpserver -u $UID -g $GID -RHl0 0 portnumber   /path/to/your/process &

有关详细信息,请参阅: http//thedjbway.b0llix.net/daemontools/uidgid.html


#5楼

TLDR:对于“答案”(如我所见),请跳到本答案的>> TLDR <<部分。

好吧,我已经弄明白了(这次是真实的),这个问题的答案,我的这个答案也是一种道歉的方式,以促进另一个答案 (在这里和在推特上)我认为是“最好的“但是在尝试之后,发现我错了。 从我的错误中学习孩子:在你真正尝试过之前不要宣传一些东西!

我再次回顾了这里的所有答案。 我尝试了其中一些 (并选择不尝试其他人,因为我根本不喜欢这些解决方案)。 我认为解决方案是使用systemd及其Capabilities=CapabilitiesBindingSet= settings。 经过一段时间的摔跤后,我发现这不是解决方案, 因为:

功能旨在限制根进程!

由于OP明智地指出,它始终是最好避免(对所有的守护程序如果可能的话!)。

您不能在systemd单元文件中使用与功能相关的选项与User=Group= ,因为在execev (或任何函数)时,功能始终会重置。 换句话说,当systemd分叉并丢弃其权限时,功能将被重置。 没有办法解决这个问题,内核中的所有绑定逻辑都是基于uid = 0的基础,而不是功能。 这意味着Capabilities不太可能成为这个问题的正确答案(至少在很短的时间内)。 顺便setcap ,正如其他人所提到的, setcap不是解决方案。 它对我不起作用,它对脚本不起作用,并且无论何时文件发生变化都会重置。

在我微薄的辩护中,我确实陈述了(在我现在删除的评论中),詹姆斯的iptables建议(OP也提到了),是“第二好的解决方案”。 :-P

>> TLDR <<

解决方案是将systemd与on-the-fly iptables命令结合使用,如下所示( 取自DNSChain ):

[Unit]
Description=dnschain
After=network.target
Wants=namecoin.service

[Service]
ExecStart=/usr/local/bin/dnschain
Environment=DNSCHAIN_SYSD_VER=0.0.1
PermissionsStartOnly=true
ExecStartPre=/sbin/sysctl -w net.ipv4.ip_forward=1
ExecStartPre=-/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
ExecStartPre=-/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
ExecStartPre=/sbin/iptables -A INPUT -p udp --dport 5333 -j ACCEPT
ExecStartPre=/sbin/iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
ExecStopPost=/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
ExecStopPost=/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
User=dns
Group=dns
Restart=always
RestartSec=5
WorkingDirectory=/home/dns
PrivateTmp=true
NoNewPrivileges=true
ReadOnlyDirectories=/etc

# Unfortunately, capabilities are basically worthless because they're designed to restrict root daemons. Instead, we use iptables to listen on privileged ports.
# Capabilities=cap_net_bind_service+pei
# SecureBits=keep-caps

[Install]
WantedBy=multi-user.target

在这里我们完成以下任务:

  • 守护进程侦听5333,但是由于iptables ,连接在53上被成功接受
  • 我们可以将命令包含在单元文件本身中,从而节省人们的头痛。 systemd为我们清理防火墙规则,确保在守护程序未运行时删除它们。
  • 我们从不以root身份运行,并且我们无法进行权限提升(至少是systemd声明),据说即使守护程序被泄露并设置uid=0

不幸的是, iptables仍然是一个非常丑陋且难以使用的实用工具。 例如,如果守护程序正在侦听eth0:0而不是eth0 ,则命令略有不同

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!