通过特定接口为 linux 中的进程路由流量

Sur*_*esh 27 networking linux routing process

是否可以通过特定接口路由进程使用的流量?

例如,下载应用程序的网络流量应始终使用该接口,wlan0而计算机上的所有其他应用程序应使用eth0.

在 Linux 中可能有这种规则吗?

chr*_*ell 23

它可以使用 Linux 网络命名空间来完成。

这是一篇文章解释如何操作。基本上,您创建一个具有不同默认路由的网络命名空间,并在那里运行需要它的进程。您可以使用网桥将新创建的网络命名空间连接到物理适配器(当然其他解决方案也是可能的)。

更新:从内核 3.14 开始,使用控制组更容易,如中所述 本文所述。你必须:

1) 定义一个 net_cls 控制组,以使用 classid(或进程组,注意它们之间没有任何父子关系)来注释来自给定进程的数据包

2) 使用 iptables cgroup 模块(在 Linux 3.14 中添加)对数据包进行 fwmark

3)使用策略路由(ip rule add fwmark ....)为标记的数据包创建一个新的路由表

优点是我们不必做桥接的事情,由于 cgroups,一切都变得更加动态。


Kri*_*Dev 23

我一直在努力解决这个问题,所以这里有一个完整的解决方案。它在 Ubuntu 15 到 19.10 上进行了测试。您尤其可以将它与 OpenVPN 结合使用,以在 VPN 隧道接口之外路由某些应用程序。

完整的“cgroup”解决方案

那是怎么工作的?

  • Linux 内核会将应用程序放入一个控制组。来自此 cgroup 中的应用程序的网络流量将在网络控制器级别由它们的类 ID 标识。
  • iptables 将标记此流量并强制它以正确的 IP 退出
  • ip route 将处理不同路由表中标记的流量,默认路由到您想要的任何网关 IP。

自动化脚本

我制作了一个novpn.sh脚本来自动安装和运行依赖项。在 Ubuntu 15 到 19.10 上测试。

首先启动您的VPN。

wget https://gist.githubusercontent.com/kriswebdev/a8d291936fe4299fb17d3744497b1170/raw/novpn.sh
# If you don't use eth0, edit the script setting.
sudo chmod +x novpn.sh
./novpn.sh traceroute www.google.com
./novpn.sh --help
Run Code Online (Sandbox Code Playgroud)

手册操作方法

首先,安装 cgroup 支持和工具:

sudo apt-get install cgroup-lite cgroup-tools
Run Code Online (Sandbox Code Playgroud)

你需要 iptables 1.6 .0+。获取 iptables 1.6.0 release source,提取它,然后--disable-nftables从 iptables 源目录运行这个(标志将避免错误):

iptables --version
sudo apt-get install dh-autoreconf bison flex
./configure --prefix=/usr      \
            --sbindir=/sbin    \
            --disable-nftables \
            --enable-libipq    \
            --with-xtlibdir=/lib/xtables
make
sudo make install
iptables --version
Run Code Online (Sandbox Code Playgroud)

现在,真正的配置。定义一个名为 的控制组novpn。此 cgroup 中的进程将具有0x00110011(11:11)的 classid 。

sudo su
mkdir /sys/fs/cgroup/net_cls/novpn
cd /sys/fs/cgroup/net_cls/novpn
echo 0x00110011 > net_cls.classid
Run Code Online (Sandbox Code Playgroud)

现在,我们假设您要用于特定应用程序的真实接口eth0的网关 IP 为10.0.0.1. 用你真正想要的东西替换它们(从 中获取信息ip route),尤其是在较新的 Ubuntu 版本中,接口具有奇怪的名称。仍然以 root 身份运行:

# Add mark 11 on packets of classid 0x00110011
iptables -t mangle -A OUTPUT -m cgroup --cgroup 0x00110011 -j MARK --set-mark 11

# Force the packets to exit through eth0 with NAT
iptables -t nat -A POSTROUTING -m cgroup --cgroup 0x00110011 -o eth0 -j MASQUERADE

# Define a new "novpn" routing table
# DO THIS JUST ONCE !
echo 11 novpn >> /etc/iproute2/rt_tables

# Packets with mark 11 will use novpn
ip rule add fwmark 11 table novpn

# Novpn has a default gateway to the interface you want to use
ip route add default via 10.0.0.1 table novpn

# Unset reverse path filtering for all interfaces, or at least for "eth0" and "all"
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done
Run Code Online (Sandbox Code Playgroud)

最后,在特定界面上运行您的应用程序:

exit
sudo cgcreate -t $USER:$USER -a $USER:$USER -g net_cls:novpn
cgexec -g net_cls:novpn traceroute www.google.com
# Close all Firefox windows first
killall firefox; cgexec -g net_cls:novpn firefox
Run Code Online (Sandbox Code Playgroud)

或者,如果您想将已经运行的进程移动到 cgroup,那么……您不能!这似乎是由于 NAT(伪装)功能:iptables -nvL -t nat切换 cgroup 时iptables -nvL -t mangle不匹配,但确实匹配。

# Get PID of the process (we'll then suppose it's 1234)
pidof firefox
# Add to cgroup - THIS DOESN'T WORK! Silently fails to produce the final result.
sudo echo 1234 > /sys/fs/cgroup/net_cls/novpn/tasks
# Remove - but this works...
sudo echo 1234 > /sys/fs/cgroup/net_cls
Run Code Online (Sandbox Code Playgroud)

积分: 没有答案按预期工作,但它们的组合做到了: chripell answer evolware 文章Per process routing take 2: using cgroups, iptables and policy routing如何使特定进程不通过 OpenVPN 连接?,基于iptables的OpenVPN的kill switch

相关问题:iptables and cgroups v2 (netfilter's xt_cgroup)

  • 通过直接从终端运行 `apache2`,你会得到同样的错误。那是因为 `apache2` 通常作为服务启动,使用 `systemctl start apache2`。但是,这不适用于 `cgexec`。被调用的程序必须是要传播的 net_cls cgroup 所需(`apache2`)进程的父进程。所以你需要找到启动脚本。在这种情况下,它是`sudo cgexec -g net_cls:novpn /usr/sbin/apache2ctl start`。检查`./novpn.sh --list`。 (2认同)
  • 我在 Ubuntu 16.04 上使用它,它运行良好。Ubuntu 16 中的接口名称已更改,您可能需要将“eth0”替换为“enp7s0”之类的内容。从`ifconfig` 命令获取信息。 (2认同)

use*_*686 5

有些人编写了使用 Linux 的 LD_PRELOAD 功能来实现此目的的垫片: