iptables: маскарад - хоровод


ULysses - Posted on 22 Ноябрь 2009

предлагаю рецептик, как сварить вкусный маскарадинг на несколько внешних ip без использования таргета MASQUARADE

1. выбираем несколько сочных внешних айпи и один красивый внешний ифэйс

REMOTE_IP_POOL="172.16.6.13 172.16.6.33 172.16.6.35 172.16.6.36 172.16.6.37"
REMOTE_IFACE="eth0"
REMOTE_NET_BITS="21"

2. апишники моем, чистим и фаршируем ими интерфейс

remote_ip_count=0
for ip in $REMOTE_IP_POOL
do
    ip addr add $ip/$REMOTE_NET_BITS brd + dev $REMOTE_IFACE
    remote_ip_count=$(($remote_ip_count + 1))
done

3. а сейчас - вимание! - добаляем немного магии

for ip in $REMOTE_IP_POOL
do
    $IPTABLES -t nat -A POSTROUTING -o $REMOTE_IFACE -m statistic --mode=nth --every=$remote_ip_count -j SNAT --to-source=$ip
    remote_ip_count=$(($remote_ip_count - 1))
done

вот и все, блюдо готово. кушайте на здоровье!

немного анатомии:

main ~ # ip a show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:02:2a:e1:e2:c3 brd ff:ff:ff:ff:ff:ff
    inet 172.16.6.13/21 brd 172.16.7.255 scope global eth0
    inet 172.16.6.33/21 brd 172.16.7.255 scope global secondary eth0
    inet 172.16.6.35/21 brd 172.16.7.255 scope global secondary eth0
    inet 172.16.6.36/21 brd 172.16.7.255 scope global secondary eth0
    inet 172.16.6.37/21 brd 172.16.7.255 scope global secondary eth0
main ~ # iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 12M packets, 1607M bytes)
 pkts bytes target     prot opt in     out     source               destination
 
Chain POSTROUTING (policy ACCEPT 28832 packets, 2075K bytes)
 pkts bytes target     prot opt in     out     source               destination
 206K   11M SNAT       all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           statistic mode nth every 5 to:172.16.6.13
 206K   11M SNAT       all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           statistic mode nth every 4 to:172.16.6.33
 206K   11M SNAT       all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           statistic mode nth every 3 to:172.16.6.35
 206K   11M SNAT       all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           statistic mode nth every 2 to:172.16.6.36
 206K   11M SNAT       all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           statistic mode nth every 1 to:172.16.6.37
 
Chain OUTPUT (policy ACCEPT 32669 packets, 3313K bytes)
 pkts bytes target     prot opt in     out     source               destination
main ~ # ping 172.16.3.1 > /dev/null &
[1] 21419
main ~ # tcpdump -ni eth0 icmp and host 172.16.3.1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 68 bytes
00:56:47.061670 IP 172.16.6.33 > 172.16.3.1: ICMP echo request, id 43859, seq 6, length 64
00:56:47.061842 IP 172.16.3.1 > 172.16.6.33: ICMP echo reply, id 43859, seq 6, length 64
00:56:48.061669 IP 172.16.6.35 > 172.16.3.1: ICMP echo request, id 43859, seq 7, length 64
00:56:48.061868 IP 172.16.3.1 > 172.16.6.35: ICMP echo reply, id 43859, seq 7, length 64
00:56:49.061667 IP 172.16.6.36 > 172.16.3.1: ICMP echo request, id 43859, seq 8, length 64
00:56:49.061837 IP 172.16.3.1 > 172.16.6.36: ICMP echo reply, id 43859, seq 8, length 64
00:56:50.061668 IP 172.16.6.37 > 172.16.3.1: ICMP echo request, id 43859, seq 9, length 64
00:56:50.061855 IP 172.16.3.1 > 172.16.6.37: ICMP echo reply, id 43859, seq 9, length 64
00:56:51.061665 IP 172.16.6.13 > 172.16.3.1: ICMP echo request, id 43859, seq 10, length 64
00:56:51.061852 IP 172.16.3.1 > 172.16.6.13: ICMP echo reply, id 43859, seq 10, length 64
00:56:52.061670 IP 172.16.6.33 > 172.16.3.1: ICMP echo request, id 43859, seq 11, length 64
00:56:52.061858 IP 172.16.3.1 > 172.16.6.33: ICMP echo reply, id 43859, seq 11, length 64
00:56:53.061669 IP 172.16.6.35 > 172.16.3.1: ICMP echo request, id 43859, seq 12, length 64
00:56:53.061863 IP 172.16.3.1 > 172.16.6.35: ICMP echo reply, id 43859, seq 12, length 64
00:56:54.061670 IP 172.16.6.36 > 172.16.3.1: ICMP echo request, id 43859, seq 13, length 64
00:56:54.061872 IP 172.16.3.1 > 172.16.6.36: ICMP echo reply, id 43859, seq 13, length 64
00:56:55.061668 IP 172.16.6.37 > 172.16.3.1: ICMP echo request, id 43859, seq 14, length 64
00:56:55.061868 IP 172.16.3.1 > 172.16.6.37: ICMP echo reply, id 43859, seq 14, length 64
^C
18 packets captured
18 packets received by filter
0 packets dropped by kernel

всем привет ;)

5
Ваша оценка: Ничего Рейтинг: 5 (1 vote)

>remote_ip_count=$(($remote_ip_count + 1))

((remote_ip_count++))

--
sash-kan

Подготовка:

www# cat ip.php
<?
echo $_SERVER['REMOTE_ADDR']."\n";
?>

Делаем:

iptables -t mangle -A OUTPUT -j CONNMARK --set-mark 1
iptables -t mangle -A OUTPUT -m statistic --mode nth --every 3 -j RETURN
iptables -t mangle -A OUTPUT -j CONNMARK --set-mark 2
iptables -t mangle -A OUTPUT -m statistic --mode nth --every 2 -j RETURN
iptables -t mangle -A OUTPUT -j CONNMARK --set-mark 3
 
iptables -t nat -A POSTROUTING -m connmark --mark 1 -j SNAT --to 95.239.178.214
iptables -t nat -A POSTROUTING -m connmark --mark 2 -j SNAT --to 95.239.178.220
iptables -t nat -A POSTROUTING -m connmark --mark 3 -j SNAT --to 95.239.178.221

Проверяем:

# i=1; while [ $i -lt 10 ]; do GET "http://www/ip.php"; ((i++)); done
95.239.178.220
95.239.178.214
95.239.178.221
95.239.178.220
95.239.178.214
95.239.178.221
95.239.178.220
95.239.178.214
95.239.178.220

for ip in $REMOTE_IP_POOL
do
    $IPTABLES -t nat -A POSTROUTING -o $REMOTE_IFACE -m statistic --mode=nth --every=$remote_ip_count -j SNAT --to-source=$ip
    remote_ip_count=$(($remote_ip_count - 1))
done

Расшифровываем:

iptables -t nat -A POSTROUTING -o eth0 -m statistic --mode=nth --every 5 -j SNAT --to-source 172.16.6.13
iptables -t nat -A POSTROUTING -o eth0 -m statistic --mode=nth --every 4 -j SNAT --to-source 172.16.6.33
iptables -t nat -A POSTROUTING -o eth0 -m statistic --mode=nth --every 3 -j SNAT --to-source 172.16.6.35
iptables -t nat -A POSTROUTING -o eth0 -m statistic --mode=nth --every 2 -j SNAT --to-source 172.16.6.36
iptables -t nat -A POSTROUTING -o eth0 -m statistic --mode=nth --every 1 -j SNAT --to-source 172.16.6.37

Разве последнее правило не должно срабатывать всегда?

а оно всегда и срабатывает. на том что до него добралось и предыдущие четыре правила не перехватили.
собсно в википедии есть пример с хорошими коментариями. вот цитата

iptables -t mangle -A select_prov -j CONNMARK --set-mark 1 # Ставим всем соединениям маркировку 1
iptables -t mangle -A select_prov -m statistic --mode nth --every 3 -j RETURN # Первый из трех пакетов - выходим
iptables -t mangle -A select_prov -j CONNMARK --set-mark 2 # Ставим всем оставшимся соединениям маркировку 2
iptables -t mangle -A select_prov -m statistic --mode nth --every 2 -j RETURN # Один из оставшихся двух - выходим
iptables -t mangle -A select_prov -j CONNMARK --set-mark 3 # Последний

это что же, кто-то уже придумал это и написал в вики? а можно сцылочку?

UPD:
нашел. в длинной предлинной предлинной предлинной статье по айпитейблз. но я то тоже это не вчера придумал!.. эх. жаль, что новость не получилась.

Придумал конечно не ты, но пример как раз в формате линсовета: коротко и по делу.
А ты ничего не забыл там больше? Уж больно на вики больше заморочено Ж:-)

вообще статья там какаято замороченная. сразу все в одной куче.

по поводу не забыл - понятное дело, что надо соображать, что происходит ваще - ну то есть пример рабочий на 100%, но с пререквизитами: рабочий линукс, netfilter, подсети реальные или виртуальные для тренировки, голова на плечах и руки из них же.

а в вики они там еще пакеты маркируют, чтобы
1)в таблице маршрутизации потом прописать маршруты разные для по-разному маркированных пакетов.
2)чтобы после начала tcp соединения пакеты в этом соединении всегда шли по одному маршруту

в моем случае

1) маршруты не отличаются для разных айпи, задача стояла распределить нагрузку для равномерной статистики трафика по адресам не интернет шлюзе.

2) SNAT сам пользуется базой conntrack чтобы вести соединение, так что проблем с tcp сессиями не было.

стоит еще заметить один момент, в ядрах < 2.6.10 можно было указывать несколько --to-source, и получалось то что надо. но после 2.6.10 такое делать нельзя уже


--to-source ipaddr[-ipaddr][:port[-port]]
which can specify a single new source IP address, an inclusive
range of IP addresses, and optionally, a port range (which is
only valid if the rule also specifies -p tcp or -p udp). If no
port range is specified, then source ports below 512 will be
mapped to other ports below 512: those between 512 and 1023
inclusive will be mapped to ports below 1024, and other ports
will be mapped to 1024 or above. Where possible, no port alter-
ation will

In Kernels up to 2.6.10, you can add several --to-source
options. For those kernels, if you specify more than one source
address, either via an address range or multiple --to-source
options, a simple round-robin (one after another in cycle) takes
place between these addresses. Later Kernels (>= 2.6.11-rc1)
don't have the ability to NAT to multiple ranges anymore.

я как раз про 2) и хотел спросить. спасибо, бум знать Ж:-)

интерливинг каналов?

Отправить комментарий

Google Friend Connect (leave a quick comment)
loading...
Содержание этого поля является приватным и не предназначено к показу.