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