如何在 Linux 上实现 IP 直通?

如何在 Linux 上实现 IP 直通?

我有一台 Raspberry Pi,运行 Raspbian(基于 Debian),有 2 个网络接口。

其中一个接口是 WAN,来自卫星调制解调器。另一个是客户路由器,Pi 为其提供互联网。

问题是我只处理 /30,而卫星调制解调器已经拥有该 /30 上的两个 IP 之一,所以我只剩下一个 IP(1.1.1.2/30)和 2 个需要它的设备(我的 Raspberry Pi 和客户路由器)。

我知道我可以轻松进行 NAT,并为客户提供 LAN IP。我不想那样。我需要客户拥有一个公共 IP。我还知道我可以将 Pi 配置为仅作为交换机,没有自己的 IP,但 Pi 将无法访问互联网。我也不想那样。我需要 Pi 和客户路由器都能够上网。

图表

我知道这是可能的,因为我以前用过 MicroHard 蜂窝调制解调器,它就是这么做的。蜂窝调制解调器连接到蜂窝塔时会获得一个公共 IP,当您在其上启用 IP 直通模式时,插入该蜂窝调制解调器的路由器也会获得相同的公共 IP。

如果您从互联网上的端口 80、443 或 22 访问该公共 IP,您将与蜂窝调制解调器通信,但如果您访问任何其他端口,您将与蜂窝调制解调器后面的路由器通信。这正是我想要做的。我只是不确定他们究竟是如何做到的,以及我如何在 Linux 中复制它。MicroHard Cell Modems 是基于 Linux 的,因此在 Linux 上是可能的。

到目前为止,这是我的计划:

  • Raspberry Pi 的 eth0(Sat 调制解调器接口)上的静态 IP 1.1.1.2/30
  • Raspberry Pi 的 eth1(客户路由器接口)上的静态 IP 1.1.1.254/24
  • eth1 上的 DHCP 服务器为客户路由器提供:
    • 1.1.1.2/24
    • 危险品:1.1.1.254
  • 启用 net.ipv4.ip_forward
  • 由于两个接口上的两个子网明显重叠,因此使用基于策略的路由规则来告诉 Pi 何时何地发送流量

现在看起来像这样:

在此处输入图片描述

我一直在尝试让它工作,但最后一个要点显然是最难的部分。其他一切(DHCP 路由器、静态 IP、IP 转发)都已完成并正常运行。

我已经这样做了:

# Rules to prevent ARP from going out the wrong interface
$ sudo arptables -A INPUT -i eth0 --destination-ip ! 1.1.1.2 -j DROP
$ sudo arptables -A INPUT -i eth1 --destination-ip ! 1.1.1.254 -j DROP

# Create custom routing tables
$ sudo vim /etc/iproute2/rt_tables
    190 to_sat_modem
    200 to_customer_router

# Add rules to tables
$ sudo ip route add default dev eth0 table to_sat_modem
$ sudo ip route add default dev eth1 table to_customer_router

# Add policy based routing rules
$ sudo ip rule add fwmark 0x1 lookup to_sat_modem
$ sudo ip rule add fwmark 0x2 lookup to_customer_router

# Add masq rule
$ sudo iptables -t nat -A POSTROUTING -o eth0 ! -s 1.1.1.2 -j SNAT --to 1.1.1.2

# Add rules for when to use these routing tables

$ sudo iptables -t mangle -N TO_CUSTOMER_ROUTER
$ sudo iptables -t mangle -N TO_SAT_MODEM

$ sudo iptables -t mangle -A OUTPUT -d 1.1.1.2 -j TO_CUSTOMER_ROUTER        # From localhost
$ sudo iptables -t mangle -A PREROUTING -i eth0 -d 1.1.1.2 -p udp -j TO_CUSTOMER_ROUTER                                         # All UDP ports
$ sudo iptables -t mangle -A PREROUTING -i eth0 -d 1.1.1.2 -p tcp --match multiport ! --dports 22,80 -j TO_CUSTOMER_ROUTER  # Most TCP ports
$ sudo iptables -t mangle -A TO_CUSTOMER_ROUTER -j MARK --set-xmark 0x2
$ sudo iptables -t mangle -A TO_CUSTOMER_ROUTER -j ACCEPT

$ sudo iptables -t mangle -A OUTPUT -d 1.1.1.1 -j TO_SAT_MODEM      # From localhost
$ sudo iptables -t mangle -A PREROUTING -i eth1 -d 1.1.1.1 -j TO_SAT_MODEM
$ sudo iptables -t mangle -A TO_SAT_MODEM -j MARK --set-xmark 0x1
$ sudo iptables -t mangle -A TO_SAT_MODEM -j ACCEPT

我觉得我的方法是对的,但我似乎无法让它发挥作用。有什么想法吗?

附言:是的,我知道我的大多数规则在重启后都无法继续存在。一旦找到可行的解决方案,我就会解决这个问题

PPS。这是试图实现单向透明度。Sat 调制解调器只能看到其后面的单个设备 (1.1.1.2),而客户路由器将能够与 Pi (1.1.1.254) 和 Sat 调制解调器 (1.1.1.1) 通信。这应该可行,但存在掩盖整个 /24 真实公共 IP 的问题。我可以将 /24 更改为 /29 以减少影响,但它仍然会发生。最终,我想要双向透明度,这样我就可以在 Pi 的两端重复使用 /30 IP,但我认为这会更容易入手

PPPS。我知道这个问题的答案很明显是

不要这样做。做点别的。给客户一个 LAN IP,或者把你的 Pi 放在客户路由器后面并给它一个 LAN IP,或者把 pi 置于桥接模式,或者……

我不想写 10 页的解释来解释为什么需要这样做,但相信我,如果可能的话,就必须这样做,就像我说的,我很确定这是可能的,因为我见过这样做

答案1

基于我的 2 Pi 解决方案,我能够使用 Linux 网络命名空间在单个 Pi 中配置同样的东西:

单 Pi 解决方案

初始步骤:

  • 启用 IP 转发
  • 像平常一样将 eth0 设置为 1.1.1.2/30 静态 IP
    • 您可以使用 DHCP 客户端,但您需要某种钩子来为新 IP 重新配置网络

配置网络的脚本:

#!/bin/bash

###############
# Global Vars #
###############

# Sat modem IP with subnet
# Ex: 1.1.1.1
SAT_MODEM_IP="1.1.1.1"

# Router IP
# Ex: 1.1.1.2
ROUTER_IP="1.1.1.2"

# Subnet in cidr notation
# Ex: 30
SUBNET_MASK="30"

# Space separated list of ports for the Pi to intercept
PORTS="8081 8082"

#####################
# Calculated Values #
#####################

# Removes the slash, in case the user wrote "/30" instead of "30" above
SUBNET_MASK=$(echo $SUBNET_MASK | tr -d '/')

# Make sure port list is property formatted for iptables
PORTS=$(echo $PORTS | sed 's/ /,/g' | tr -s ',')

##########
# Checks #
##########

# Make sure we are running as root
if ! [ $(id -u) = 0 ]
then
    echo "Error: This script must be run as root" >&2
    exit 1
fi

# Make sure ns2 doesn't already exist
if /sbin/ip netns | grep -q '^ns2'
then
    echo "Error: ns2 already exists"
    exit 1
fi

###################
# Start of Config #
###################

# Create ns2 namespace
ip netns add ns2 

# Move eth1 to ns2 namespace
ip link set eth1 netns ns2

# Configure eth1 in ns2 namespace
ip netns exec ns2 ip address add $SAT_MODEM_IP/$SUBNET_MASK dev eth1
ip netns exec ns2 ip link set eth1 up

# Enable loopback interface in ns2 namespace
ip netns exec ns2 ip link set lo up

# Create virtual interface pair, and move one of the interfaces into
# the ns2 namespace
ip link add veth type veth peer name vpeer
ip link set vpeer netns ns2

# Set ip on virtual interfaces
ip address add 192.168.90.5/24 dev veth
ip netns exec ns2 ip address add 192.168.90.6/24 dev vpeer

# Bring up both virtual interfaces
ip link set veth up
ip netns exec ns2 ip link set vpeer up

# Add DG to ns2 namespace
ip netns exec ns2 ip route add default via 192.168.90.5

# Add root namespace iptables rules
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o veth -s $SAT_MODEM_IP -j MASQUERADE
iptables -t nat -A PREROUTING -i eth0 -p udp -j DNAT --to-destination 192.168.90.6
iptables -t nat -A PREROUTING -i eth0 -p tcp -m multiport ! --dport $PORTS -j DNAT --to-destination 192.168.90.6
iptables -t nat -A PREROUTING -i eth0 -p ICMP -j DNAT --to-destination 192.168.90.6
iptables -t nat -A PREROUTING -i veth -p udp -d 192.168.90.5 -j DNAT --to-destination $SAT_MODEM_IP
iptables -t nat -A PREROUTING -i veth -p tcp -m multiport ! --dport $PORTS -d 192.168.90.5 -j DNAT --to-destination $SAT_MODEM_IP
iptables -t nat -A PREROUTING -i veth -p ICMP -d 192.168.90.5 -j DNAT --to-destination $SAT_MODEM_IP

# Add ns2 namespace iptables rules
ip netns exec ns2 iptables -t nat -A POSTROUTING -o vpeer -j MASQUERADE
ip netns exec ns2 iptables -t nat -A POSTROUTING -o eth1 -s 192.168.90.5 -j MASQUERADE
ip netns exec ns2 iptables -t nat -A PREROUTING -i vpeer -j DNAT --to-destination $ROUTER_IP
ip netns exec ns2 iptables -t nat -A PREROUTING -i eth1 -d $SAT_MODEM_IP -j DNAT --to-destination 192.168.90.5

# Add ICMP blocking
# Note: This just prevents customers from seeing LAN IPs in a
# traceroute from site, and duplicate WAN IPs in a traceroute to
# site
iptables -A OUTPUT -p ICMP -j DROP
ip netns exec ns2 iptables -A OUTPUT -p ICMP -j DROP

注意:我以前从未使用过网络命名空间,但它们最终变得非常容易理解和使用。请参阅:https://blogs.igalia.com/dpino/2016/04/10/network-namespaces/

另请注意:您可以在 eth1 上设置 DHCP 服务器,以便为客户路由器提供 IP,而无需他们静态设置 IP,但您需要在 ns2 命名空间中的 eth1 上运行 DHCP 服务器。这超出了本问题的范围,但请查找 NetworkNamespacePath systemd 选项,并确保您知道如何正确编辑 systemd 单元文件无需与包管理器争吵。

答案2

在问题中,我开始尝试实现单向透明,因为我认为这将是一个更容易的起点,尽管我的最终目标是双向透明。

单向透明度的意思是,调制解调器只能看到其后面的单个设备(1.1.1.2),但客户路由器可以看到 Pi(位于 1.1.1.254)和位于 1.1.1.1 的调制解调器。

单向透明的问题(至少是我尝试的方式)是,我会掩盖合法的公共 IP。这显然不是理想的选择。

以下是实现双向透明性的一种方法,但它需要使用 2 个 Raspberry Pi。虽然这种方法有效,并且可能对其他人有帮助,但我需要在单个 Pi 上运行这个确切的东西,所以我将研究使用 Linux 网络命名空间在单个 Pi 上完成此操作。如果有人有在单个 Pi 上可行的解决方案,请告诉我。

2 Pi 解决方案:

在此处输入图片描述

通用步骤:

  • 在两个 Pi 上配置静态 IP
  • 在两个 Pi 上启用路由 (echo 1 > /proc/sys/net/ipv4/ip_forward)

树莓派1:

ip route add default via 1.1.1.1

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth1 -s 1.1.1.1 -j MASQUERADE

# All UDP Ports
iptables -t nat -A PREROUTING -i eth0 -p udp -j DNAT --to-destination 192.168.90.6

# Some TCP Ports
iptables -t nat -A PREROUTING -i eth0 -p tcp -m multiport ! --dport 8081,8082 -j DNAT --to-destination 192.168.90.6

树莓派2:

ip route add default via 192.168.90.5

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth1 -s 192.168.90.5 -j MASQUERADE

# Forwards EVERYTHING to Customer Router
iptables -t nat -A PREROUTING -i eth0 -j DNAT --to-destination 192.168.90.6

注意:我很快就从这个 2-pi 解决方案转向了单 pi 解决方案,因此它不如公认的单 pi 解决方案那么有效,如果有人打算使用它,可以进行一些改进。这主要仅供参考,因为它比单 pi 解决方案更容易理解,但本质上做同样的事情

相关内容