iptables wybiera opcję REDIRECT na moście bez adresu IP

0

mam konfigurację typu man-in-the-middle:

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

gdzie A, B i C to komputery, a strzałki reprezentują połączenia Ethernet.

A ma IP 10.0.0.10, C ma IP 10.0.0.9

oba mają maskę sieci 255.255.255.0

Usiłuję zaimplementować zaporę ogniową na B za pomocą mostu linuksowego bez skonfigurowanego adresu IP:

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

w celu pobrania połączeń z A do CI skonfigurowanych Iptables na B w podobny sposób

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

Otworzyłem gniazdo odsłuchowe zarówno w C, jak i 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()

wtedy na AI biegła

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
>>>

sprawdzanie Iptables pod kątem liczby pakietów reguł przy odbiorze 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 jest pusty.

dlaczego nie przejmuję połączenia? UWAGA: Jestem w stanie przejąć połączenie, jeśli skonfiguruję most z adresem IP, czego wolałbym raczej uniknąć

użytkownik3076936
źródło

Odpowiedzi:

0

Znalazłem to po pewnym kopaniu jądra.

rzeczywisty kod REDIRECTing iptables jest zaimplementowany w haku filtru sieciowego jądra o nazwie nf_nat_redirect_ipv4 , w nim znajdujemy ten stosunkowo prosty kod

...
/* 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;
}
...

podzielmy to na części

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

jeśli nasz REDIRECT pochodzi z łańcucha OUTPUT, adres docelowy pakietu zmienia się na adres sprzężenia zwrotnego („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();
...

jeśli pochodzimy z innego łańcucha (tylko PREROUTING, ponieważ już obsłużyliśmy OUTPUT), ustawiamy adres docelowy pakietu jako adres naszego lokalnego urządzenia, nasz będzie wynosił 0

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

zerowy adres jest uważany za wartość błędu, a nasz pakiet jest niestety odrzucany :(

użytkownik3076936
źródło