LINUX.ORG.RU
ФорумAdmin

Не делает SNAT после DNAT iptables.

 , , ,


0

1

Всем привет

Надо сделать так, чтобы роутер портмаппил определенный TCP траффик одинаково прозрачно для клиентов на внутренний сервер в сети одинаково прозрачно для клиентов как из интернета так и из сети.

Постараюсь нарисовать как я себе это вижу и что не работает.

Вот такая схема работает:

iptables -t nat -A PREROUTING -p tcp --dport 8000 -j DNAT --to 192.168.1.20 
iptables -t nat -A POSTROUTING -o ppp0 -j SNAT --to [Public IP]

Client      -> Router              -> Server
Internet       [192.168.1.1]          [192.168.1.20]
[to:Public IP] [DNAT->192.168.1.20]
               [From:ExternalClientIP]

Тут «внешний» клиент ломится на внешний публичный адрес роутера на порт 8000 и роутер его DNATтит в сеть, там сервер видит «внешний» адрес клиента и через MASQUERADE ему получается ответить. Это проблем не вызывает.

Теперь этот же клиент делает то же самое но будучи внутри этой самой сети как локальный.
Client      -> Router              -> Server
Internet       [192.168.1.1]          [192.168.1.20]
[to:Public IP] [DNAT->192.168.1.20]
               [From:LocalClientIP]


В таком случае пакеты на адрес 192.168.1.20 идут с адреса LocalClientIP (например 192.168.1.2) и сервер сопоставляя одно с другим не видит необходимости направлять трафик на свой шлюз и отвечает клиенту на прямую, что клиент конечно же не ожидает и ничего не работает. Это как бы тоже очевидно.

добавляю правило
iptables -t nat -I POSTROUTING -p tcp --dport 8000 -d 192.168.1.20 -j SNAT --to 192.168.1.1


ожидаю, что роутер сменит адрес отправителя после DNAT на свой, и сервер 192.168.1.20 уже ответит ему.
Да я понимаю, что это двойной трафик в сети. Да я понимаю что это приведёт к лишней нагрузке на роутер. Но сейчас это за скобкой.

Так вот это правило SNAT не обрабатывается (счётчик не увеличивается). Если верить tcpdump пакеты всё ещё уходят с адресом отправителя равным Клиентскому (да и сервер 192.168.1.20 их видит таковыми)

Так вот вопрос: почему не работает SNAT? Потому что нет как такового перекладывания из интерфейса в интерфейс? Можно как-то принудить к этому?

Помню был подобный случай только с REDIRECT когда напрявлял в locahost, там был sysctl ключик net.ipv4.conf.all.route_localnet. Я даже попробовал его в этом применении - непомогает :(



Последнее исправление: Spider55 (всего исправлений: 1)

У тебя по идее должно быть одно правило в INPUT с редиректом на хост:порт внутри сети, потому что для роутера это входящий трафик, он в цепочку filter идёт, а не в nat. Только для локальной сети надо добавить SNAT на внутренний адрес роутера, чтобы ответ правильно ушёл.

По крайней мере на домашних устройствах так сделано.

Radjah ★★★★★
()
Последнее исправление: Radjah (всего исправлений: 1)

Должен работать DNAT + SNAT
iptables -t nat -nvxL хорошо было бы посмотреть.
Вдруг где опечатка...

Если ничего не помогает, то добавляй правило

iptables -t raw -A PREROUTING -p tcp --dport 8000 -s 192.168.1.2 -j TRACE
Делай коннект с 192.168.1.2 и смотри логи.

В теме Как сделать сервер маршрутизации? (комментарий) есть перловый скрипт который упрощает чтение логов от TRACE

vel ★★★★★
()
Ответ на: комментарий от vel

Спасибо за информацию. Я оперировал действием -j LOG
И не попадает в POSTROUTING под него ничего. А вот TRACE че то подзабыл... завтра попробую глянуть что там.

Spider55
() автор топика
Ответ на: комментарий от vel

Ну сделал я TRACE и вопросов добавилось :))

С вашего позволения я пропущу на мой взгляд не значимые строки TRACE в которых очевидно, что пакет идёт по правилам и они никак на него не влияют.
Первая строка собственно «вход» пакета в систему.
В центре строка маркировки соединения - это уже я маркировал в поисках истины, но оставлю строку тут чтобы понимать что появилась маркировка.
И последняя она же последняя строка трассировки. Это строка соответствует DNAT правилу.

Вопрос. Пакет дальше типа не пошёл? Или надо ещё раз промаркировать его где-то как новую цепочку?

TRACE: raw:PREROUTING:rule:3 IN=br-lan OUT= PHYSIN=eth0 MAC=00:d0:b4:02:84:6a:fa:19:87:f0:44:2a:08:00 SRC=192.168.1.2 DST=192.168.1.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=24484 DF PROTO=TCP SPT=60378 DPT=8000 SEQ=2508694540 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B40402080A34066BD1000000000103030A)

...

TRACE: mangle:PREROUTING:rule:2 IN=br-lan OUT= PHYSIN=eth0 MAC=00:d0:b4:02:84:6a:fa:19:87:f0:44:2a:08:00 SRC=192.168.1.2 DST=192.168.1.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=24484 DF PROTO=TCP SPT=60378 DPT=8000 SEQ=2508694540 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B40402080A34066BD1000000000103030A) MARK=0x3f00

...

TRACE: nat:PREROUTING:rule:2 IN=br-lan OUT= PHYSIN=eth0 MAC=00:d0:b4:02:84:6a:fa:19:87:f0:44:2a:08:00 SRC=192.168.1.2 DST=192.168.1.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=24486 DF PROTO=TCP SPT=60378 DPT=8000 SEQ=2508694540 ACK=0 WINDOW=65535 RES=0x00 SYN URGP=0 OPT (020405B40402080A3406779F000000000103030A) MARK=0x3f00


Можно на это взглянуть из tcpdump (Это не прям эта же попытка сессия, но эквивалентная)
tcpdump -i any -n port 8000
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes

17:50:42.353685 eth0  P   IP 192.168.1.2.57132 > 192.168.1.1.8000: Flags [S], seq 3505131552, win 65535, options [mss 1460,sackOK,TS val 873934940 ecr 0,nop,wscale 10], length 0
17:50:42.409810 br-lan Out IP 192.168.1.2.57132 > 192.168.1.20.8000: Flags [S], seq 3505131552, win 65535, options [mss 1460,sackOK,TS val 873934940 ecr 0,nop,wscale 10], length 0

Spider55
() автор топика
Последнее исправление: Spider55 (всего исправлений: 1)
Ответ на: комментарий от Spider55

Гм. Дык у тебя еще и бридж есть?! Теоретически это может немного усложнять процесс если включен bridge-nf-call-iptables и nf_call_iptables.

Без полной трассировки не вижу смысла дальше говорить. Кто-то что-то не договаривает.

Смотреть лог вручную очень тяжко. Чтобы упростить задачу, нужно чтобы правило TRACE сработало всего 1-2 раза на коннект.
(Например добавить в него "--syn")

Лог лучше смотреть после скрипта который удаляет параметры которые не изменились.
Если на роутере нет перла, то перекинуть вывод dmesg в файл на машине где есть перл и указать скрипту имя этого файла.

В трассировке не видно изменение ip-адреса после SNAT в nat/POSTROUTING :(

#!/usr/bin/env perl
use strict;

my @R;
open(F,$ARGV[0] ? '<'.$ARGV[0] : "dmesg|") || die;
while(<F>) {
        next if !/TRACE:/;
        chomp; s/^\[\s+/[/;
        push @R,[grep !/^(TOS=|PREC=|MAC=|TRACE:)/, split /\s+/];
}
close(F);

my $LL = $R[$#R];
die if !$LL;
die $LL->[0] if $LL->[0] !~ /^\[\s*(\d+)\.\d+\]$/;
my $st = 0;
my @PX;
foreach my $L (@R) {
        next if !$st && $L->[1] !~ /^raw/;
        $st = 1;
        @PX = () if $L->[1] =~ /^raw/;
        my @t = splice(@$L,0,2);
        foreach my $i (@$L) {
                my $x = 0; map {$x = 1 if $i eq $_} @PX;
                if(!$x) {
                        push @PX,$i; push @t,$i;
                }
        }
        print join(" ",@t),"\n";
}
Рабочие правила: c 10.200.2.252 на 10.200.2.11:8022 перенаправляем на 10.200.2.2:22
# Generated by iptables-save v1.8.10 on Thu Mar  6 15:54:57 2025
*raw
:PREROUTING ACCEPT [405699954:431951238193]
:OUTPUT ACCEPT [7093:1386970]
-A PREROUTING -s 10.200.2.252/32 -p tcp -m tcp --dport 8022 --tcp-flags FIN,SYN,RST,ACK SYN -j TRACE
COMMIT
*nat
:PREROUTING ACCEPT [12995886:1826359846]
:INPUT ACCEPT [11231:3249909]
:OUTPUT ACCEPT [56:3795]
:POSTROUTING ACCEPT [3469884:388479430]
-A PREROUTING -s 10.200.2.252/32 -p tcp -m tcp --dport 8022 -j DNAT --to-destination 10.200.2.2:22
-A POSTROUTING -s 10.200.2.252/32 -d 10.200.2.2/32 -j SNAT --to-source 10.200.2.11
COMMIT
*filter
:INPUT ACCEPT [100940:18331163]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [87750:29098658]
-A FORWARD -s 10.200.2.0/24 -d 10.200.2.0/24 -j ACCEPT
COMMIT
Трассировка выглядит
[13684.134473] raw:PREROUTING:policy:3 IN=vlan0022 OUT= SRC=10.200.2.252 DST=10.200.2.11 LEN=60 TTL=64 ID=47815 DF PROTO=TCP SPT=50934 DPT=8022 SEQ=3472755009 ACK=0 WINDOW=64240 RES=0x00 SYN URGP=0 OPT (020405B40402080A774E41420000000001030307)
[13684.134491] nat:PREROUTING:rule:1
[13684.134531] filter:FORWARD:rule:1 OUT=vlan0022 DST=10.200.2.2 TTL=63 DPT=22
[13684.134538] nat:POSTROUTING:rule:1

vel ★★★★★
()
Ответ на: комментарий от Spider55

Поддержу vel, что мост может влиять. Попробуйте потренироваться на обычной машине, наверное в вашей локалке найдётся рабочий комп с линуксом. Чтобы моста не было и iptables пустые.

mky ★★★★★
()
Ответ на: комментарий от vel

Не вижу сложности в чтении логов TRACE. По мне так все очевидно.
То то и оно, что не доходит дело до SNAT. Цепочка обрывается на DNAT правиле.
Хотя в tcpdump все же видно пакет после DNAT, в TRACE этот пакет уже не попал.

Spider55
() автор топика
Ответ на: комментарий от Spider55

Цепочка обрывается на DNAT правиле

Есть замечательная картинка. А у тебя цепочки INPUT хоть какие-нибудь есть?
Я бы на время выключил бы bridge-nf-call-iptables и/или nf_call_iptables.

C tcpdump-ом все тоже не совсем просто. Но той картинке видно где af_packet получает пакеты.
Обрати внимание, что первым tcpdump показал входящий (?) на eth0, а исходящий ушел через br-lan.

А в бридже еще кто-то есть?

ip li && ip a посмотреть бы...

А policy routing у тебя часом не используется?

vel ★★★★★
()