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

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

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

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

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


当前回答

2017年更新:

使用authbind

免责声明(2021年更新):请注意,authbind通过LD_PRELOAD工作,这只在你的程序使用libc时使用,如果你的程序用GO编译,或任何其他避免使用c的编译器,这是(或可能)不是情况。如果你使用GO,为受保护的端口范围设置内核参数,请参阅post底部。< / EndUpdate > Authbind比CAP_NET_BIND_SERVICE或自定义内核好得多。

CAP_NET_BIND_SERVICE授予二进制文件信任,但不提供 控制每个端口的访问。 Authbind向对象授予信任 用户/组,并提供对每个端口访问的控制 支持IPv4和IPv6 (IPv6支持已添加到后期)。

安装:apt-get Install authbind 为所有用户和组配置访问相关端口,例如80和443: 触摸/etc/authbind/byport/80 触摸/etc/authbind/byport/443 Sudo chmod 777 /etc/authbind/byport/80 Sudo chmod 777 /etc/authbind/byport/443 .使用实例 通过authbind执行命令 (可选地指定——deep或其他参数,参见man authbind): Authbind——deep /path/to/binary命令行参数 如。 authbind——deep java -jar SomeServer.jar


作为Joshua关于破解内核的绝妙建议(=不推荐,除非你知道自己在做什么)的后续:

我首先把它贴在这里。

简单。对于普通内核或旧内核,则不需要。 正如其他人指出的那样,iptables可以转发端口。 正如其他人所指出的,CAP_NET_BIND_SERVICE也可以完成这项工作。 当然,如果你从脚本启动你的程序,CAP_NET_BIND_SERVICE将会失败,除非你在shell解释器上设置了上限,这是毫无意义的,你也可以作为root运行你的服务… 例如,对于Java,你必须把它应用到Java JVM上

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

显然,这意味着任何Java程序都可以绑定系统端口。 对于mono/. net也是如此。

我也很确定xinetd不是最好的主意。 但既然这两种方法都是黑客,为什么不通过解除限制来解除限制呢? 没有人说你必须运行一个普通的内核,所以你可以运行你自己的内核。

您只需下载最新内核的源代码(或您当前拥有的相同内核)。 之后,你去:

/usr/src/linux-<version_number>/include/net/sock.h:

看这条线

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK       1024

把它改成

#define PROT_SOCK 0

如果你不想有一个不安全的SSH情况,你可以这样修改:

#define PROT_SOCK 24

通常,我会使用您需要的最低设置,例如http设置为79,在端口25上使用SMTP时设置为24。

这就够了。 编译内核,并安装它。 重新引导。 完成——这个愚蠢的限制已经消失了,这也适用于脚本。

下面是编译内核的方法:

https://help.ubuntu.com/community/Kernel/Compile

# You can get the kernel-source via package `linux-source`, no manual download required
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

# Apply the changes to PROT_SOCK define in /include/net/sock.h

# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config

# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev

# Run menuconfig (optional)
make menuconfig

# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

# And wait a long long time

cd ..

简而言之,

如果你想保持安全,使用iptables, 如果您想确保这个限制不再困扰您,请编译内核。


sysctl方法

注意: 到目前为止,不再需要更新内核。 你现在可以设置

sysctl net.ipv4.ip_unprivileged_port_start=80

还是坚持

sysctl -w net.ipv4.ip_unprivileged_port_start=80.

如果产生错误,只需用nano编辑/etc/sysctl.conf,并在那里设置参数,以便在重启期间保持不变。

或者通过procfs

echo 80 | sudo tee /proc/sys/net/ipv4/ip_unprivileged_port_start

其他回答

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

守护进程

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

缺点是:

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

优点:

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

代理

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

在启动时:

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

然后可以绑定到您转发的端口。

我尝试了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上侦听的应用程序不知道传入连接的源地址(例如用于日志记录或其他识别目的)。

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

使用systemd,您只需要稍微修改您的服务以接受预激活的套接字。

稍后可以使用systemd套接字激活。

不需要任何功能、iptables或其他技巧。

这是这个简单的python http服务器示例中的相关systemd文件的内容

文件httpd-true.service

[Unit]
Description=Httpd true 

[Service]
ExecStart=/usr/local/bin/httpd-true
User=subsonic

PrivateTmp=yes

文件httpd-true.socket

[Unit]
Description=HTTPD true

[Socket]
ListenStream=80

[Install]
WantedBy=default.target