在我的开发盒上有这种限制是非常令人讨厌的,因为除了我之外再也没有其他用户了。
我知道一些标准的变通办法,但没有一个能完全满足我的要求:
authbind (Debian测试中的版本,1.0,仅支持IPv4)
使用iptables REDIRECT目标将低端口重定向到高端口(iptables的IPv6版本ip6tables尚未实现“nat”表)
sudo(作为根是我试图避免的)
SELinux(或类似的)。(这只是我的开发框,我不想引入很多额外的复杂性。)
是否有一些简单的sysctl变量允许非根进程绑定到Linux上的“特权”端口(端口小于1024),或者我只是运气不好?
编辑:在某些情况下,您可以使用功能来做到这一点。
2015年9月:
ip6tables现在支持IPV6 NAT: http://www.netfilter.org/projects/iptables/files/changes-iptables-1.4.17.txt
您将需要内核3.7+
证明:
[09:09:23] root@X:~ ip6tables -t nat -vnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 REDIRECT tcp eth0 * ::/0 ::/0 tcp dpt:80 redir ports 8080
0 0 REDIRECT tcp eth0 * ::/0 ::/0 tcp dpt:443 redir ports 1443
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 6148 packets, 534K bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 6148 packets, 534K bytes)
pkts bytes target prot opt in out source destination
我尝试了iptables PREROUTING REDIRECT方法。在旧的内核中,IPv6似乎不支持这种类型的规则。但显然,现在ip6tables v1.4.18和Linux内核v3.8支持它。
我还发现PREROUTING REDIRECT对机器内启动的连接不起作用。要处理来自本地机器的连接,还需要添加一个OUTPUT规则-参见iptables端口重定向不适用于本地主机。例如:
iptables -t nat -I OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080
I also found that PREROUTING REDIRECT also affects forwarded packets. That is, if the machine is also forwarding packets between interfaces (e.g. if it's acting as a Wi-Fi access point connected to an Ethernet network), then the iptables rule will also catch connected clients' connections to Internet destinations, and redirect them to the machine. That's not what I wanted—I only wanted to redirect connections that were directed to the machine itself. I found I can make it only affect packets addressed to the box, by adding -m addrtype --dst-type LOCAL. E.g. something like:
iptables -A PREROUTING -t nat -p tcp --dport 80 -m addrtype --dst-type LOCAL -j REDIRECT --to-port 8080
另一种可能是使用TCP端口转发。例如使用socat:
socat TCP4-LISTEN:www,reuseaddr,fork TCP4:localhost:8080
然而,这种方法的一个缺点是,在端口8080上侦听的应用程序不知道传入连接的源地址(例如用于日志记录或其他识别目的)。
文件功能并不理想,因为它们可能在包更新后失效。
恕我直言,理想的解决方案应该是能够创建具有可继承CAP_NET_BIND_SERVICE集的shell。
这里有一个有点复杂的方法:
sg $DAEMONUSER "capsh --keep=1 --uid=`id -u $DAEMONUSER` \
--caps='cap_net_bind_service+pei' -- \
YOUR_COMMAND_GOES_HERE"
capsh实用程序可以在Debian/Ubuntu发行版的libcap2-bin包中找到。事情是这样的:
sg将生效的组ID修改为守护用户的组ID。这是必要的,因为capsh会使GID保持不变,而我们肯定不想要它。
设置位“保持UID更改的能力”。
修改UID为$DAEMONUSER
删除所有的大写(此时所有的大写仍然存在,因为——keep=1),除了可继承的cap_net_bind_service
执行命令(“——”是分隔符)
结果是一个具有指定用户和组以及cap_net_bind_service特权的进程。
例如,ejabberd启动脚本中的一行:
sg $EJABBERDUSER "capsh --keep=1 --uid=`id -u $EJABBERDUSER` --caps='cap_net_bind_service+pei' -- $EJABBERD --noshell -detached"