route, nat, iptables 網路,路由和防火牆

#GFW促進學習系列

Route

查看路由表:

#linux:
$route -n
$ip route list

#Windows:
>route PRINT

一個典型的LAN里機器的路由表:(區域網網段是192.168.0.1/24)

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.0.1   0.0.0.0         UG    0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 eth0
192.168.0.0   0.0.0.0         255.255.255.0   U     1      0        0 eth0

169.254.0.0/16是RFC定義的特殊link-local地址。

路由表的策略是: 當需要向某個IP發送數據時,將目標IP地址和路由表中每條路由項的掩碼(Genmask) 進行相與(AND)計算,如果結果匹配對應路由項的Destination,則記錄下此路由項。如果有多個匹配項,則會選擇最佳路由項(mask較為精確的優先;Metric較小的優先)。然後通過最佳路由項的interface或Gateway發送數據:如果該路由項沒有G flag (Gateway == 0.0.0.0),則將數據由對應的interface發送,否則,繼續以Gateway地址為目標IP搜索路由表,直到找到直接的路由項並由其interface發送。

連接OpenVPN並且使用”redirect-gateway def1″後增加的路由條目:

0.0.0.0         192.168.X.1   128.0.0.0       UG    0      0        0 tun0
128.0.0.0       192.168.X.1   128.0.0.0       UG    0      0        0 tun0
192.168.X.1   0.0.0.0         255.255.255.255 UH    0      0        0 tun0
A.B.C.D  192.168.0.1   255.255.255.255 UGH   0      0        0 eth0

192.168.X.1為OpenVPN添加的虛擬網段,A.B.C.D是OpenVPN伺服器的IP地址

另外,本机App主动向外发起通信建立Socket时,可以bind某个interface,则数据包直接由该interface发送,不再进行查找路由表操作。(Windows情况有所不同,特别是Vista之前)(source: On Windows, a call to bind() affects card selection only incoming traffic, not outgoing traffic. Thus, on a client running in a multi-homed system (i.e., more than one interface card), it’s the network stack that selects the card to use, and it makes its selection based solely on the destination IP, which in turn is based on the routing table. A call to bind() will not affect the choice of the card in any way.

It’s got something to do with something called a “Weak End System” (“Weak E/S”) model. Vista changed to a strong E/S model, so the issue might not arise under Vista. But all prior versions of Windows used the weak E/S model.

With a weak E/S model, it’s the routing table that decides which card is used for outgoing traffic in a multihomed system. )

NAT

NAT常用於私有地址與公網地址之間的轉換。

例如:本機IP為192.168.0.2,通過路由器192.168.0.1上網,路由器具有公網IP A.B.C.D。當本機向8.8.8.8發送DNS解析請求時:

192.168.0.2:查詢路由表,找到需要的interface eth0。
192.168.0.2:通過eth0發送udp數據包:source ip為192.168.0.2,source port為隨機打開的某個高端埠(Ephemeral port, Linux: 32768-61000, Windows: 49152-65535),destination ip為8.8.8.8,destination port為53
192.168.0.1:收到了192.168.0.2發送的數據包,SNAT,將轉換後的數據包通過internet interface發送出去。同時記錄到轉換表中
8.8.8.8:收到了A.B.C.D發送的數據包,發送響應數據。
192.168.0.1:收到了8.8.8.8的數據包,Un SNAT:根據內存中的轉換表找到目標機器192.168.0.2,替換數據包的destination,並由路由器的lan interface發送出去。
192.168.0.2:eth0收到了響應數據包。如同直接與8.8.8.8通信一樣。

SNAT轉換將數據包源地址由192.168.0.2替換為路由器公網IP A.B.C.D。並可能替換數據包的source port
Un SNAT轉換將數據包目標地址由A.B.C.D替換為192.168.0.2

Un SNAT是自動進行的。

路由器保存有當前建立的連接的「轉換表」ip_conntrack,轉換表每個條目有幾個要素:(不是標準格式!!僅用於理解SNAT)
(source ip, source port, router port, destination ip, destination port, proto)

(192.168.0.2, 32002, 32002, 8.8.8.8, 53, udp)
對SNAT而言,轉換表每個條目後四個要素不能完全相同(否則路由器就不知道從internet收到的數據包應該轉發給哪個內網機器了)。

根據轉換表Un SNAT找到數據包對應的內網IP。

iptables

查看iptables規則:

iptables -vxnL
iptables -t nat -vxnL

數據包通過iptables chains的流程可以參考這裡,解釋的很詳細。流程概述:

Receive:

某個interface收到數據包 -> PREROUTING (manage, nat) -> route ->
    是發送給本機的數據包? -> INPUT (manage, filter) -> app
    不是 -> FORWARD (manage, filter) -> POSTROUTING (manage, nat) -> 某個interface發出

Send:

app發送數據包 -> route -> OUTPUT (manage, nat, filter) -> POSTROUTING (manage, nat) -> 某個interface發出

* Receive时判断是否是发送给本机的数据包的方法是:收到数据包的destination IP是否与本机某个interface的IP相同。
* Send的OUTPUT chain除了manage和filter以外nat表也有。nat的OUTPUT位於filter的之前,用於對從本機(app)發出的(而不是收到並FORWARD的)請求做DNAT或REDIRECT。
* Send的route階段確定了數據包的source ip和source port。source ip和source port由app发送数据包时决定。如果app沒有bind某個interface并且没有设置source ip/port,則source ip时為route使用的interface ip。
* filter表的INPUT, OUTPUT和FORWARD用來過濾數據包 -j ACCEPT /DROP
* nat表的PREROUTING用來DNAT(或REDIRECT), POSTROUTING用來SNAT(或MASQUERADE)
* FORWARD (以及所有forward之後的chain)需要net.ipv4.ip_forward=1

常見路由器NAT的iptables規則:

#SNAT
#br0是路由器internet interface
#lo0是路由器lan interface
iptables -t nat -A POSTROUTING -o br0 -j MASQUERADE

#DNAT,用於如路由器埠映射
#A.B.C.D是路由器internet ip
iptables -t nat -A PREROUTING -d A.B.C.D --dport 3000:4000 -j DNAT --to 192.168.0.2

PREROUTING不能使用-o
POSTROUTING不能使用-i

關於DNAT:

內網 - firewall - 外網
    -> SNAT ->
    <- Un SNAT <-    
 
    <- DNAT
    -> Un DNAT

以上面為例:

DNAT改變數據包dst為內網地址
Un DNAT還原響應的數據包src為firewall地址

SNAT改變數據包src為firewall地址
Un SNAT還原響應的數據包dst為內網地址

首先是對初始數據包DNAT或SNAT,建立連接(established)後才能對返回數據包Un DNAT和Un SNAT。

說的有些繞 = =

關於REDIRECT:
特殊形式的DNAT
The REDIRECT target is used to redirect packets and streams to the (firewall) machine itself. It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface (locally-generated packets are mapped to the 127.0.0.1 address)

參數可以改變埠

-p tcp --to-port[s] 5409
-p tcp --to-port[s] 4000-5409

DNAT,SNAT,Un DNAT, Un SNAT:
DNAT也會對反向數據包自動Un DNAT。Un DNAT與SNAT之間沒有關聯。Un DNAT的數據包不會經過POSTROUTING,同樣Un SNAT的數據包也不會經過PREROUTING(但Un DNAT在 **相當於** POSTROUTING chain的階段執行,Un SNAT同理,參考下面的說明)。

In short, the ‘nat’ table chains only see the
first packet of a “connection”, and only if it has the state NEW (not
RELATED). All the subsequent valid packets belonging or related to that
connection (state NEW, ESTABLISHED, or RELATED) don’t go through theses
chains. The action taken by these packets is automatically determined by
the NAT operation applied to the first packet and the direction of the
packet.

For instance, with this rule :
iptables -t nat -A POSTROUTING -o eth0 -j SNAT –to 1.2.3.4

The first ‘direct’ packet of an outgoing connection on eth0 goes through
the nat POSTROUTING chains and matches this rule, so the SNAT operation
is applied. Instead of going through the POSTROUTING chain, the
subsequent direct packets (in the same direction) of the connection will
automatically be applied the same SNAT operation. The return packets (in
the opposite direction) of the connection will automatically be applied
the de-SNAT operation instead of going through the nat PREROUTING chain.
By the way, the subsequent packets of the connection don’t need to go in
or out eth0 (funny, huh ?) to be properly NATed.

De-MASQ and de-SNAT both are destination address rewrite operations, so
it is consistent that they take place in the same place as the nat
PREROUTING chain which performs DNAT. But keep in mind that they take
place *instead* of trversing the nat PREROUTING chain, so you will never
see packets being de-MASQ-ed or de-SNAT-ed in any nat chain.

舉一些例子。

用NAT在國外VPS上搭建一個twitter代理:

199.59.150.39是twitter.com的IP(被牆),A.B.C.D是VPS的IP。這樣做之後修改本地hosts將twitter.com指向A.B.C.D即可直接訪問https://twitter.com/。這種方法局限性太強,僅用於演示。

# DNAT的--to-destination 和 SNAT的--to-source可以簡寫成--to
# 通過DNAT將443埠接受到的請求轉發給twitter
iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination 199.59.150.39:443
# 同時將src改為VPS的IP,否則twitter收到的訪問請求源地址還是原始客戶端IP
# 並且由於這時twitter響應的數據包不會經過VPS,無法自動反向 DNAT
# 而原始客戶端只知道自己在和VPS的IP通信,會把twitter響應的數據包丟棄(如果能收到的話)
# 另外,如果不SNAT,很多VPS發給twitter的數據包可能中途就被路由器丟棄了(ip spoofing),如Linode就會丟棄這種。
iptables -t nat -A POSTROUTING -p tcp --dport 443 -j SNAT --to-source A.B.C.D

OpenVPN伺服器端的NAT規則:

# 這裡的192.168.0.0/24 是OpenVPN網段
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE

在網關(如路由器)上部署OpenVPN client,同時向整個區域網機器提供透明翻牆服務的NAT規則

# 這裡的192.168.0.0/24是區域網網段
# 需要"redirect-gateway def1"設置默認路由走VPN。
# 可以不加-o tun0,視具體情況。
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o tun0 -j MASQUERADE

如果運行OpenVPN Client的機器只用於自己翻牆(不提供網關服務),則不需要SNAT,也不需要開啟ip_forward,只需要”redirect-gateway def1″添加路由即可。

sysctl參數

# net.ipv4.ip_forward 非路由器默認為0
# net.ipv4.conf.all.accept_redirects 非路由器默認為1
# net.ipv4.conf.all.send_redirects 默認為1
# ipv6 同上
# rp_filter 验证incoming数据包源地址。对于openvpn(服务器端)interface应当设为0

#Read:
sysctl -n ipv4.ip_forward

#Write:
sysctl -w net.ipv4.ip_forward=1

#另一種設置方法
echo 1 > /proc/sys/net/ipv4/ip_forward
#/proc/sys/net/ipv4/conf/all/accept_redirects
#/proc/sys/net/ipv4/conf/all/send_redirects
# or per interface config
#/proc/sys/net/ipv4/conf/eth0/accept_redirects
#/proc/sys/net/ipv4/conf/eth0/send_redirects

#永久設置方法
# edit /etc/sysctl.conf, add (or edit) the follow line
#net.ipv4.ip_forward=1
# after changing, run "sysctl -p" to make changes take effect

net.ipv4.ip_forward和net.ipv4.conf.all.accept_redirects這兩個值總是相反的,設置一個會相應改變另一個。

關於ICMP Redirect:介紹

開啟ICMP Redirect後的ping結果類似這種:

[[email protected] ~]# ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.
64 bytes from 114.114.114.114: icmp_seq=1 ttl=82 time=22.2 ms
From 192.168.0.18: icmp_seq=2 Redirect Host(New nexthop: 192.168.0.1)
64 bytes from 114.114.114.114: icmp_seq=2 ttl=93 time=7.08 ms
64 bytes from 114.114.114.114: icmp_seq=3 ttl=74 time=29.1 ms
64 bytes from 114.114.114.114: icmp_seq=4 ttl=71 time=4.26 ms

192.168.0.18和192.168.0.1是兩個網關。

0 Responses to “route, nat, iptables 網路,路由和防火牆”


Comments are currently closed.