我有一台 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 中配置同样的东西:
初始步骤:
- 启用 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 解决方案更容易理解,但本质上做同样的事情