在我的开发盒上有这个限制是非常烦人的,因为除了我之外不会有任何用户。
我知道标准的解决方法 ,但它们都没有完全符合我的要求:
authbind (Debian测试中的版本,1.0,仅支持IPv4)
使用iptables REDIRECT目标将低端口重定向到高端口 (对于ip6tables,iptables的IPv6版本尚未实现“nat”表)
sudo(以root身份运行是我想避免的)
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 &
#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 ,则命令略有不同 。