在我的开发盒上有这种限制是非常令人讨厌的,因为除了我之外再也没有其他用户了。

我知道一些标准的变通办法,但没有一个能完全满足我的要求:

authbind (Debian测试中的版本,1.0,仅支持IPv4) 使用iptables REDIRECT目标将低端口重定向到高端口(iptables的IPv6版本ip6tables尚未实现“nat”表) sudo(作为根是我试图避免的) SELinux(或类似的)。(这只是我的开发框,我不想引入很多额外的复杂性。)

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

编辑:在某些情况下,您可以使用功能来做到这一点。


当前回答

使用privbind实用程序:它允许非特权应用程序绑定到预留端口。

其他回答

我知道这是一个老问题,但是现在有了最新的(>= 4.3)内核,这个问题终于有了一个很好的答案——环境能力。

快速的答案是从git中获取libcap的最新(尚未发布的)版本的副本并编译它。将生成的progs/capsh二进制文件复制到某个地方(/usr/local/bin是一个不错的选择)。然后,作为根用户,使用

/usr/local/bin/capsh --keep=1 --user='your-service-user-name' \
    --inh='cap_net_bind_service' --addamb='cap_net_bind_service' \ 
    -- -c 'your-program'

按顺序,我们是

声明当切换用户时,我们希望保持当前的功能集 切换用户和组到“your-service-user-name” 将cap_net_bind_service功能添加到继承的&环境集 派生bash -c 'your-command'(因为capsh会自动用——后面的参数启动bash)

这里隐藏着很多秘密。

Firstly, we are running as root, so by default, we get a full set of capabilities. Included in this is the ability to switch uid & gid with the setuid and setgid syscalls. However, ordinarily when a program does this, it loses its set of capabilities - this is so that the old way of dropping root with setuid still works. The --keep=1 flag tells capsh to issue the prctl(PR_SET_KEEPCAPS) syscall, which disables the dropping of capabilities when changing user. The actual changing of users by capsh happens with the --user flag, which runs setuid and setgid.

The next problem we need to solve is how to set capabilities in a way that carries on after we exec our children. The capabilities system has always had an 'inherited' set of capabilities, which is " a set of capabilities preserved across an execve(2)" [capabilities(7)]. Whilst this sounds like it solves our problem (just set the cap_net_bind_service capability to inherited, right?), this actually only applies for privileged processes - and our process is not privileged anymore, because we already changed user (with the --user flag).

新的环境能力集解决了这个问题——它是“在一个没有特权的程序的执行中保存的一组能力。”通过将cap_net_bind_service放在环境集中,当capsh exec执行我们的服务器程序时,我们的程序将继承此功能,并能够将侦听器绑定到低端口。

如果您有兴趣了解更多信息,功能手册页详细解释了这一点。通过strace运行capsh也是非常有用的!

将8080端口绑定为80端口,开放80端口:

sudo iptables -t nat -A OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

然后以普通用户身份在8080端口上运行程序。

然后,您将能够在端口80上访问http://127.0.0.1

我的“标准解决方案”使用socat作为用户空间重定向器:

socat tcp6-listen:80,fork tcp6:8080

注意,这不会扩展,分叉是昂贵的,但这是socat工作的方式。

在libcap网站上有一个文件共享库链接到非特权应用程序的实例。最近在回答一个关于向共享库添加功能的问题时提到了它。

另外两种简单的可能性:Daemon和Proxy

守护进程

对于“一个绑定在低端口上的守护进程并将控制权交给您的守护进程”,有一个旧的(不流行的)解决方案。它被称为inetd(或xinetd)。

缺点是:

你的守护进程需要在stdin/stdout上对话(如果你不控制守护进程——如果你没有源代码——那么这可能是一个showstopper,尽管一些服务可能有inetd兼容性标志) 每个连接都会生成一个新的守护进程 这是链条上的一环

优点:

可以在任何旧的UNIX上使用 一旦系统管理员设置了配置,就可以开始开发了(当重新构建守护进程时,可能会失去setcap功能吗?然后你就得回到你的管理员那里,“请,先生……”) Daemon不需要担心网络的问题,只需要在stdin/stdout上进行对话 是否可以按照请求配置为以非根用户执行守护进程

代理

另一种替代方案:从特权端口到任意高编号端口(您可以在其中运行目标守护进程)的经过修改的代理(netcat或更健壮的代理)。(Netcat显然不是一个生产解决方案,但“只是我的开发盒”,对吧?)通过这种方式,您可以继续使用服务器的网络支持版本,只需要root/sudo启动代理(在引导时),而不依赖复杂/潜在的脆弱功能。