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


389

当我之外再也没有其他用户时,在我的开发箱上有这个限制是非常烦人的。

我知道标准的解决方法,但是它们都不能完全满足我的要求:

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

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

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


5
以我的经验,尝试这样做的原因之一是编写Web服务器,而不是使用Apache(或lighttpd)。
S.Lott

我已经将setcap的内容添加到了几乎相同的stackoverflow.com/questions/277991/…的
Paul Tomblin,2009年

15
因为在这种情况下,我使用的是IPv6,这就是为什么某些“常规”解决方法(authbind和iptables REDIRECT)对我不起作用的原因。
杰森·克赖顿


1
有几种方法可以做到这一点。请参阅允许非根进程绑定到端口80和443?在超级用户上。
jww

Answers:


392

好的,感谢指出能力系统和CAP_NET_BIND_SERVICE能力的人们。如果您使用的是最新内核,则确实可以使用它以非root用户身份启动服务,但绑定低端口。简短的答案是您这样做:

setcap 'cap_net_bind_service=+ep' /path/to/program

然后任何时间program执行,此后它将具有此CAP_NET_BIND_SERVICE功能。setcap在debian软件包中libcap2-bin

现在需要注意的是:

  1. 您将至少需要2.6.24内核
  2. 如果您的文件是脚本,则无法使用。(即,使用#!行启动解释器)。据我所知,在这种情况下,您必须将功能应用于解释器可执行文件本身,这当然是安全的噩梦,因为使用该解释器的任何程序都将具有该功能。我找不到解决此问题的任何简单明了的方法。
  3. Linux将在program具有更高特权的任何磁盘上禁用LD_LIBRARY_PATH,例如setcapsuid。因此,如果您program使用自己的.../lib/,则可能必须考虑其他选项,例如端口转发。

资源:

注意:RHEL首先在v6中添加了它


3
脚本的部分解决方法:创建解释器的副本(例如bash),为其提供功能,但将访问权限限制为需要它的用户。当然,这些用户必须受到信任,但是他们仍然可以更改脚本。
Erich Kitzmueller 09年

3
除了上述的debian(binary)套件,开发人员的网站为friedhoff.org/posixfilecaps.html相关论文/演示文稿/等...
RandomNickName42'1

1
在SUSE 11.1上,我必须将内核参数file_caps = 1添加到grub menu.lst才能正常工作。
谢伊(Shay)

2
是@ C.Ross,因为必须将其应用于/usr/bin/java然后将对系统上运行的任何Java应用程序开放该功能。也不能为每个用户设置太差的功能。
joeytwiddle

5
setcap设置是否在重新引导后仍然存在;如果没有,可以在该位置放置标准规则,以便在系统启动期间运行该规则吗?是/etc/security/capability.conf在Debian / Ubuntu的任何帮助吗?
joeytwiddle

34

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

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

5
不幸的是,这仅适用于路由连接,即不适用于本地计算机。
zbyszek'2

@joeytwiddle我认为它在运行(启动)服务器的脚本中,但是我可能错了。我也想知道:P
卡米洛·马丁

@CamiloMartin再看一遍,从问题中链接的Debian文档建议将其放在防火墙脚本中,或在中创建一个/etc/network/if-up.d/firewall
joeytwiddle

8
@zbyszek这可用于本地计算机连接,并带有附加的iptables规则:stackoverflow.com/a/31795603/1356953
00500005 2015年

在较旧的内核中,IPv6似乎不支持此功能。但显然,ip6tables v1.4.18和Linux内核v3.8支持该功能。
Craig McQueen 2015年

31

标准方法是使它们成为“ setuid”,以便它们以root身份启动,然后在绑定到端口后,但在开始接受与该端口的连接之前,就放弃该root特权。您可以在Apache和INN的源代码中看到很好的示例。有人告诉我Lighttpd是另一个很好的例子。

另一个例子是Postfix,它使用通过管道进行通信的多个守护程序,并且其中只有一个或两个(以接受或发出字节为单位,它们几乎不做任何工作)以root身份运行,其余的则以较低的特​​权运行。


1
有趣的是,在未设置CAP_SETUID的最新版本的Linux(可能只是Ubuntu)下,此方法不起作用。因此,如果您需要setuid,则无论如何都必须设置此功能。
马特(Matt)

删除root privs是执行此操作的正确方法。尽管如果您具有init / upstart / systemd启动服务,则不必设置setuid。
迈克尔·汉普顿

2
如果程序是用解释性语言或字节码解释器(例如C#(Mono),Java,Python)编写的,则这很难。(显然Perl是通过binfmt_misc它的'C'标志完成的;我不确定其他人。)
Craig McQueen 2015年

除了发出字节外,数据量很少。
瑞安

如果设置二进制setuid,它将作为根进程运行。但是,该问题询问如何在不将二进制程序作为根进程运行的情况下完成该操作。此解决方案是对另一个问题的答案,即:“非特权用户如何将进程绑定到特权端口”,但这不是问题,恕我直言?
迈克尔·比尔

24

或修补内核并删除检查。

(不建议使用最后的选择)。

在中net/ipv4/af_inet.c,删除读取的两行

      if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
              goto out;

并且内核将不再检查特权端口。


22
出于多种原因,这是一个非常糟糕的主意。
亚当·拉瑟克

24
这是个坏主意。但实际上可以。当然让我发笑。
Oto Brglez

23
当然,这是一个坏主意。这就是为什么我说不得已。开源的要点是,如果它不能按您希望的方式工作,您可以对其进行更改。
约书亚

18
我不确定你为什么被否决。恶意软件编写者不在乎他们侦听哪个端口,他们很乐意打开大于1024的端口。在我看来,所有端口都应要求特权,或者没有端口应要求特权。要求root打开低于1024的端口仅意味着您具有以root身份运行的高风险应用程序。这似乎是一个真正愚蠢的想法给我。也许我在这里错过了一些东西……
jww

9
过去,在UNIX到UNIX协议中使用端口<1024来证明另一端运行的代码以root身份运行。对于具有共同安全性的一组UNIX服务器,此功能相当有效。
2014年

22

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

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

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


1
我个人的最爱。非常容易打开和关闭,不需要系统范围的更改。好点子!
Dan Passaro

这真太了不起了。到目前为止,最简单的答案。
michaelsnowden

1
我希望这会适度昂贵,并且在任何性能受限的情况下都不是一个好主意,但是我无法确定是否需要对其进行测试。SSH加密的费用为非零。
lahwran

3
可以使用没有ssh开销的netcat来完成:sudo nc -l 80 | nc localhost 3000
Bugster,

1
您要加密+解密,仅是为了将数据移动到同一台计算机上的另一个端口?此外,这不适用于UDP流量。
Daniel F

19

2017年更新:

使用身份验证


比CAP_NET_BIND_SERVICE或自定义内核好得多。

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

    1. 安装: apt-get install authbind

    2. 为所有用户和组配置对相关端口的访问,例如80和443:

      sudo touch / etc / authbind / byport / 80
      sudo touch / etc / authbind / byport / 443
      sudo chmod 777 / etc / authbind / byport / 80
      sudo chmod 777 / etc / authbind / byport / 443

    3. 通过authbind
      (可选地指定--deep或其他参数,请参见手册页)执行命令:

      authbind --deep /path/to/binary command line args
      

      例如

      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程序都可以绑定系统端口。
Dito for 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;如果要确保此限制永远不会再困扰您,请编译内核。


反对的理由是什么?根本讨厌,还是内核编译指令不起作用?
Stefan Steiger 2015年

4
修改内核会使将来的更新更加痛苦。我不会这样做,因为我知道我太懒了,无法定期更新内核。从理论上讲这是可能的,但这在很多情况下都不是可行的选择。
kritzikratzi

也许做一个更安全的方法是改变使用chmod 777的/ etc / authbind / byport / 80搭配chmod 544的/ etc / authbind / byport / 23比CHOWN登录:组的/ etc / authbind / byport / 23
杰罗姆乙

18

文件功能不是理想的,因为它们在软件包更新后可能会中断。

理想的解决方案,恕我直言,应该具有创建具有可继承外壳的能力 CAP_NET_BIND_SERVICE集合。

这是一种有点复杂的方法:

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。这是必要的,因为capshGID保持不变,我们绝对不希望这样做。
  • 设置位“ UID更改保持功能”。
  • 将UID更改为 $DAEMONUSER
  • 删除所有大写字母(由于导致此刻所有大写字母仍然存在--keep=1cap_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"

它实际上不起作用。上限不保留在用户ID开关上。如果您想以root身份运行,但所有功能都被删除,它将可以正常工作。
Cyber​​ax

如果尝试这样做,我将得到“无法执行二进制文件”。实际上,使用或选项时,除了“无法执行二进制文件”外,我无法capsh任何其他事情。我想知道我缺少什么。--==
克雷格·麦昆

@CraigMcQueen,之后的所有内容--都会传递给/bin/bash您,因此您可能要尝试使用-c 'your command'。las,我似乎遇到了与@Cyber​​ax相同的问题,因为尝试时出现“权限被拒绝”的情况bind
阿米尔

为了在不设置文件功能(或以root用户身份运行)的情况下工作,您将需要使用Unix.SE答案中所述的环境功能。你也可以使用,而不是(或该套,和): --gidsg--user--uid--gid--groupssudo capsh --caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' --keep=1 --user="$service_user" --addamb=cap_net_bind_service -- -c 'exec $service $service_args'
Kevinoid

18

由于某种原因,没有人提及将sysctl net.ipv4.ip_unprivileged_port_start降低到所需的值。示例:我们需要将我们的应用程序绑定到443端口。

sysctl net.ipv4.ip_unprivileged_port_start=443

有人可能会说,这是一个潜在的安全问题:非特权用户现在可以绑定到其他特权端口(444-1024)。但是,通过阻止其他端口,您可以使用iptables轻松解决此问题:

iptables -I INPUT -p tcp --dport 444:1024 -j DROP
iptables -I INPUT -p udp --dport 444:1024 -j DROP

与其他方法的比较。此方法:

  • 从某种意义上讲,(IMO)比设置CAP_NET_BIND_SERVICE / setuid更安全,因为应用程序根本不设置setuid,甚至部分不设置setuid(实际上是功能)。例如,要捕获已启用功能的应用程序的核心转储,您将需要更改sysctl fs.suid_dumpable(这会导致另一个潜在的安全问题)。此外,设置CAP / suid时,/ proc / PID目录归根目录所有,因此您的非root用户将不具有正在运行的进程的完整信息/控制权,例如,该用户将无法(通常)通过/ proc / PID / fd /(netstat -aptn | grep)来确定哪些连接属于应用程序PID)。
  • 具有安全性劣势:当您的应用程序(或使用端口443-1024的任何应用程序)由于某种原因而关闭时,另一个应用程序可能占用该端口。但是这个问题也可能适用于CAP / suid(以防您在解释器上设置它,例如java / nodejs)和iptables-redirect。使用systemd-socket方法可以排除此问题。使用authbind方法仅允许特殊的用户绑定。
  • 不需要在每次部署新版本的应用程序时都设置CAP / suid。
  • 不需要系统支持/修改,例如systemd-socket方法。
  • 不需要内核重建(如果运行版本支持此sysctl设置)
  • 不会像authbind / privbind方法那样执行LD_PRELOAD,这可能会影响性能,安全性,行为(是吗?尚未测试)。其余的authbind确实是灵活和安全的方法。
  • 因为它不需要地址转换,连接状态跟踪等,所以它的性能优于iptables REDIRECT / DNAT方法。这仅在高负载系统上才明显。

根据情况,我将在sysctl,CAP,authbind和iptables-redirect之间进行选择。太好了,我们有很多选择。


2
感谢您的出色回答!似乎该功能于2017年4月首次出现在Linux 4.11中,所以在2009年我第一次提出这个问题时就没有出现。我也进行了快速测试,即使sysctl名称中包含“ ipv4”,它似乎也适用于IPV6。
杰森·克里顿

15

另外两种简单的可能性:

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

  • 您的守护程序需要在stdin / stdout上进行交谈(如果您不控制该守护程序-如果您没有源代码-则这可能是一个放映机,尽管某些服务可能具有inetd-compatibility标志)
  • 每个连接都有一个新的守护进程
  • 这是链中的一个额外链接

优点:

  • 在任何旧的UNIX上可用
  • 一旦您的系统管理员设置好配置,您就可以进行开发了(重新构建守护程序时,可能会失去setcap功能吗?然后您必须回到管理员位置,“先生。 。”)
  • 守护进程不必担心网络问题,只需要在stdin / stdout上进行讨论即可
  • 可以根据要求配置为以非root用户身份执行守护程序

另一种选择是:从特权端口到任意高编号端口(可以在其中运行目标守护程序)使用黑客入侵的代理(netcat或什至更强大的代理)。(Netcat显然不是生产解决方案,而是“只是我的开发箱”,对吧?)。这样,您可以继续使用具有网络功能的服务器版本,只需要root / sudo即可启动代理(在启动时),而不必依赖复杂/潜在的脆弱功能。


1
好建议。由于某种原因,我什至没有想到要使用inetd。除了所讨论的服务是基于UDP的服务之外,它比TCP服务要稍微复杂一些。我现在有一个使用setcap的解决方案,但是我必须考虑一下。
詹森·克赖顿

对于第二个选项,您甚至可以使用inetd启动代理...(但是IPTables可能会降低开销...)
Gert van den Berg,

14

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

socat tcp6-listen:80,fork tcp6:8080

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


13

Linux支持的功能不只是“此应用程序以root身份运行”,还支持更细粒度的权限。这些功能之一是CAP_NET_BIND_SERVICE与绑定到特权端口(<1024)有关。

不幸的是,我不知道如何利用它来以非root身份运行应用程序,同时仍然提供它CAP_NET_BIND_SERVICE(可能使用setcap,但是肯定有一个现有的解决方案)。


不适用于脚本或单个JVM / mono程序。
Stefan Steiger 2015年

13

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

快速的答案是从git获取libcap的最新版本(尚未发行)并进行编译。将生成的progs/capsh二进制文件复制到某个位置(这/usr/local/bin是一个不错的选择)。然后,以root身份启动程序

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

为了我们

  • 宣布在切换用户时,我们希望保留当前的功能集
  • 将用户和组切换为“您的服务用户名”
  • cap_net_bind_service功能添加到继承集和环境集
  • 分叉bash -c 'your-command'(因为会capsh使用后面的参数自动启动bash --

这里有很多事情要做。

首先,我们以root用户身份运行,因此默认情况下,我们获得了一整套功能。这包括使用setuidsetgid调用系统切换uid和gid的功能。但是,通常程序在执行此操作时会失去其功能集-这样一来,setuid仍然可以使用删除根目录的旧方法。该--keep=1标志指示capsh发出prctl(PR_SET_KEEPCAPS)syscall,这将在更改用户时禁用功能下降。通过用户的实际变化capsh情况与--user标志,它运行setuidsetgid

我们需要解决的下一个问题是如何以一种在我们exec孩子之后继续进行的方式来设置能力。功能系统始终具有“继承的”功能集,即“在execve(2)上保留的一组功能” [ capabilities(7) ]。虽然这听起来像解决了我们的问题(只需将cap_net_bind_service功能设置为继承,对吗?),但这实际上仅适用于特权进程-并且我们的进程不再具有特权,因为我们已经更改了用户(带有--user标志)。

新的环境功能集可解决此问题-它是“在没有特权的程序的execve(2)中保留的一组功能”。通过放入cap_net_bind_service环境集,当capshexec成为我们的服务器程序时,我们的程序将继承此功能,并能够将侦听器绑定到低端端口。

如果您想了解更多信息,功能手册页将对此进行详细说明。运行capsh经过strace也非常丰富!


--addamb标志是在libcap 2.26中引入的。我的系统有2.25,我必须从源代码构建。
ngreen

12

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

好的,我已经弄清楚了(这一次是真的),这个问题的答案,而我的这个答案也是道歉的一种方式,以推广另一个我认为是“最好的答案”(在这里和在Twitter上) ”,但尝试之后发现我误会了。向我的错误孩子们学习:在您自己亲自尝试之前,不要推广任何东西!

我再次在这里查看了所有答案。我尝试了其中的一些(并选择不尝试其他方法,因为我根本不喜欢这些解决方案)。我认为解决方案是使用systemdCapabilities=CapabilitiesBindingSet=设置。经过一段时间的努力,我发现这不是解决方案,因为:

功能旨在限制根进程!

正如OP明智地指出的那样,始终最好避免这种情况(如果可能,对于所有守护程序!)。

您不能在单元文件中User=Group=systemd单元文件中使用“功能”相关的选项,因为在调用(或调用任何功能)时始终会重置execev功能。换句话说,当systemd分叉和删除其权限时,功能将重置。没有办法解决这个问题,内核中所有绑定逻辑都是基于uid = 0,而不是功能。这意味着能力不可能永远是该问题的正确答案(至少在不久的将来)。偶然,setcap正如其他人提到的那样,这不是解决方案。它对我不起作用,它不能与脚本很好地配合使用,并且无论文件何时更改,这些脚本都将被重置。

在我微不足道的辩护中,我确实声明(在我现在删除的评论中)詹姆斯的iptables建议(OP也提到)是“第二最佳解决方案”。:-P

>> TLDR <<

解决方案是systemd与即时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上侦听,但在53上成功连接成功,原因是 iptables
  • 我们可以将命令包含在单位文件本身中,因此可以免去人们的麻烦。systemd为我们清理防火墙规则,确保在守护程序未运行时将其删除。
  • 我们永远不会以root用户身份运行,并且systemd即使在守护进程已被破坏和设置的情况下,我们也无法使特权升级(至少要求这样做)uid=0

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


2
eth0:0除非他们拥有真正的古老 Linux发行版,否则任何人都不应再使用旧式别名。他们已经过时多年,最终将消失。
迈克尔·汉普顿

1
我认为您的意思是OpenVZ。(SolusVM是控制面板。)是的,OpenVZ做错了很多事情,网络只是其中之一。
迈克尔·汉普顿

1
不,我是说SolusVM。来自/ etc / network / interfaces:# Generated by SolusVM
Greg Slepak

1
仍然不是OpenVZ ...至少我没有使用它,我的VPS也没有。
格雷格·斯莱帕克

7
感谢您指出systemd的功能。但是,当systemd直接启动二进制文件(而不是脚本)时,不需要复杂的iptables。AmbientCapabilities=CAP_NET_BIND_SERVICE结合使用设置对我来说很好User=
Ruud


10

端口重定向对我们来说最有意义,但是我们遇到了一个问题,即我们的应用程序将在本地解析一个url,该URL也需要重新路由。(这意味着您shindig)。

这也将允许您在访问本地计算机上的URL时进行重定向。

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


8

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

以后可以使用systemd socket activate

不需要功能,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

7

在启动时:

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

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


是否--to-port存在?man iptables仅提及--to-ports(复数)。
Abdull

香港专业教育学院注意到一些差异,我一直在跳来跳去
詹姆斯

有关如何与结合使用,请参见此答案systemd
格雷格·史莱帕克


3

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

#!/bin/sh

UID=$(id -u username)
GID=$(id -g username)
exec tcpserver -u "${UID}" -g "${GID}" -RHl0 0 port /path/to/binary &

有关更多信息,请参见:http : //thedjbway.b0llix.net/daemontools/uidgid.html


1

由于OP只是开发/测试,因此少于时尚的解决方案可能会有所帮助:

setcap可以在脚本的解释器上使用,以授予脚本功能。如果全局解释器二进制文件上的setcaps是不可接受的,请创建二进制文件的本地副本(任何用户都可以),并以root身份在此副本上的setcap。Python2(至少)与脚本开发树中的解释器的本地副本一起正常工作。不需要suid,因此root用户可以控制用户有权访问的功能。

如果您需要跟踪系统范围内对解释器的更新,请使用如下所示的shell脚本来运行脚本:

#!/bin/sh
#
#  Watch for updates to the Python2 interpreter

PRG=python_net_raw
PRG_ORIG=/usr/bin/python2.7

cmp $PRG_ORIG $PRG || {
    echo ""
    echo "***** $PRG_ORIG has been updated *****"
    echo "Run the following commands to refresh $PRG:"
    echo ""
    echo "    $ cp $PRG_ORIG $PRG"
    echo "    # setcap cap_net_raw+ep $PRG"
    echo ""
    exit
}

./$PRG $*

1

我尝试了iptables PREROUTING REDIRECT方法。在较早的内核中,IPv6似乎不支持这种类型的规则。但显然,现在ip6tables v1.4.18和Linux内核v3.8支持该功能。

我还发现PREROUTING REDIRECT不适用于在计算机内启动的连接。要在本地计算机上处​​理连接,还请添加一个OUTPUT规则-请参阅iptables端口重定向不适用于localhost。例如:

iptables -t nat -I OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080

我还发现PREROUTING REDIRECT 也影响转发的数据包。也就是说,如果计算机还在接口之间转发数据包(例如,如果它充当连接到以太网的Wi-Fi接入点),则iptables规则还将捕获连接的客户端与Internet目的地的连接,并将它们重定向到机器。那不是我想要的-我只想重定向定向到机器本身的连接。我发现通过添加,我可以使其只影响发送到该信箱的数据包-m addrtype --dst-type LOCAL。例如:

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


0

在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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.