Linux socket設(shè)置mark的必要性
Linux的Netfilter鉤子點的位置會導(dǎo)致一些奇怪的問題,比如本機發(fā)出的包無法使用基于mark的策略路由,這是因為mark一般是在Netfilter中進行的,而Linux的路由處在OUTPUT鉤子點之前,因此這是一個順序倒置的問題,如何來解決呢?只能在路由之前打上mark,而我們知道,對于外部進入的包,mark是在PREROUTING進行的,因此對于外部進入的包,策略路由是好使的,對于本機發(fā)出的包,路由之前只能是socket層了,那為何不能在傳輸層做呢?因為一來傳輸層比較雜,二來很多協(xié)議直接走到IP層,比如OSPF之類的,三來很多傳輸層協(xié)議也需要路由查找,比如TCP在connect的時候就需要查找路由以確定源IP地址(如果沒有bind的話)。
幸運的是,Linux的socket支持SO_MARK這樣一個option,可以很方便的使用:
mark = 100;
setsockopt(client_socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
1.對TRACK的影響
雖然raw表是數(shù)據(jù)包經(jīng)過的第一個表,使用SO_MARK仍然可以在整個raw表起作用之前做點mark,從而使得一個特定socket發(fā)出的包統(tǒng)統(tǒng)NOTRACK:
iptables -t raw -A OUTPUT -m mark --mark 100 -j NOTRACK
如果不這樣的話,就需要:
iptables -t raw -A OUTPUT [-s xxxx] [-d yyyy] [-p tcp|udp [--sport X] [--dport Y] ... -j MARK --set-mark 100
...[一大堆和上面類似的規(guī)則]
iptables -t raw -A OUTPUT -m mark --mark 100 -j NOTRACK
正如在PREROUTING上的raw表需要做的那樣。我們得意于OUTPUT上面是socket,是應(yīng)用程序的世界,而PREROUTING以下則是內(nèi)核以及驅(qū)動的世界了,后者太雜太亂,不便做更多的事,而前者則是我們可以掌控的范圍。
2.對策略路由的影響
SO_MARK最大的受益者就是策略路由了,如果我們這是以下的路由:
ip rule add fwmark 100 table abc
ip route add 1.2.3.4/32 via 192.168.0.254 table abc
ip route del 1.2.3.4/32 table main
不設(shè)置SO_MARK的情況下,所有的訪問1.2.3.4的流量將因為沒有路由而被丟棄,因為在進入PREROUTING前首先要查找路由,而此時還沒有打上mark,因而不會匹配到abc策略表中的那條路由,而main表中的對應(yīng)路由我們已經(jīng)刪除了...但是如果我們在應(yīng)用程序中加入:
mark = 100;
setsockopt(client_socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
訪問就可以正常了,因為在查找路由的時候,已經(jīng)有這個mark了。
【編輯推薦】