iptables 在没有 IP 的桥上重定向目标

iptables 在没有 IP 的桥上重定向目标

我有一个中间人设置,如下所示:

A <---> B <---> C

其中 A、B 和 C 是计算机,箭头代表以太网连接。

A 的 IP 为 10.0.0.10,C 的 IP 为 10.0.0.9

两者的网络掩码均为 255.255.255.0

我正在尝试使用没有配置 IP 的 Linux 桥接器在 B 上实现线内防火墙,如下所示:

brctl addbr br
brctl addif chlep1
brctl addif chlep2
ifconfig br 0.0.0.0 up

为了获取从 A 到 CI 的连接,请在 B 上配置 Iptables,如下所示

sysctl net.bridge.bridge-nf-call-arptables=1
sysctl net.bridge.bridge-nf-call-ip6tables=1
sysctl net.bridge.bridge-nf-call-iptables=1
iptables -t nat -I PREROUTING -p tcp -s 10.0.0.10 -d 10.0.0.9 -j REDIRECT --to-ports 40000
iptables -t nat -A PREROUTING -p tcp -s 10.0.0.10 -d 10.0.0.9 -j LOG
iptables -t filter -A INPUT -p tcp -s 10.0.0.10 -j LOG
iptables -t filter -A FORWARD -p tcp -s 10.0.0.10 -j LOG

我在 C 和 B 上都打开了一个监听套接字,就像这样

python
Python 2.7.5 (default, Aug  4 2017, 00:39:18)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM,0)
>>> sk.bind(('0.0.0.0',40000))
>>> sk.listen(1)
>>> conn, addr = sk.accept()

然后在AI上运行

python
Python 2.7.5 (default, Nov  6 2016, 00:28:07)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM,0)
>>> sk.connect(('10.0.0.9',40000))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 110] Connection timed out
>>>

检查 Iptables 中 BI 接收的规则数据包数量

[root@ace ~]# iptables -t nat -vL
Chain PREROUTING (policy ACCEPT 269 packets, 64867 bytes)
 pkts bytes target     prot opt in     out     source               destination
    4   240 REDIRECT   tcp  --  any    any     10.0.0.10            10.0.0.9             
redir ports 40000
    0     0 LOG        tcp  --  any    any     10.0.0.10            10.0.0.9             
LOG level warning

Chain INPUT (policy ACCEPT 22 packets, 3425 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 1 packets, 76 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 2 packets, 160 bytes)
 pkts bytes target     prot opt in     out     source               destination
[root@ace ~]#
[root@ace ~]#
[root@ace ~]#
[root@ace ~]#
[root@ace ~]# iptables -t filter -vL
Chain INPUT (policy ACCEPT 456 packets, 28706 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 LOG        tcp  --  any    any     10.0.0.10            anywhere             
LOG level warning

Chain FORWARD (policy ACCEPT 8 packets, 672 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 LOG        tcp  --  any    any     10.0.0.10            anywhere             
LOG level warning

Chain OUTPUT (policy ACCEPT 240 packets, 19382 bytes)
 pkts bytes target     prot opt in     out     source               destination

dmesg 是空的。

为什么我没有劫持连接?注意:如果我使用 IP 地址配置网桥,我就可以劫持连接,这是我宁愿避免的事情

答案1

经过一些内核挖掘后发现了这一点。

实际的 iptables REDIRECTing 代码是在内核 netfilter 钩子中实现的,名为nf_nat_redirect_ipv4,在其中我们发现了这个相对简单的代码

...
/* Local packets: make them go to loopback */
if (hooknum == NF_INET_LOCAL_OUT) {
    newdst = htonl(0x7F000001);
} else {
    struct in_device *indev;
    struct in_ifaddr *ifa;

    newdst = 0;

    rcu_read_lock();
    indev = __in_dev_get_rcu(skb->dev);
    if (indev && indev->ifa_list) {
        ifa = indev->ifa_list;
        newdst = ifa->ifa_local;
    }
    rcu_read_unlock();

    if (!newdst)
        return NF_DROP;
}
...

让我们把它拆开

...
if (hooknum == NF_INET_LOCAL_OUT) {
    newdst = htonl(0x7F000001);
}
...

如果我们的 REDIRECT 来自 OUTPUT 链,则数据包的目标地址将更改为环回地址('127.0.0.1')

...
else {
    struct in_device *indev;
    struct in_ifaddr *ifa;

    newdst = 0;

    rcu_read_lock();
    indev = __in_dev_get_rcu(skb->dev);
    if (indev && indev->ifa_list) {
        ifa = indev->ifa_list;
        newdst = ifa->ifa_local;
    }
    rcu_read_unlock();
...

如果我们来自另一个链(只有 PREROUTING 因为我们已经处理了 OUTPUT)我们将数据包的目标地址设置为本地设备的地址,我们的地址将是 0

 ...
    if (!newdst)
        return NF_DROP;
 }
 ...

零地址被视为错误值,我们的数据包不幸被丢弃:(

相关内容