haproxy透傳用戶ip-方法和原理
參考URL: https://blog.csdn.net/frockee/article/details/78641188
為了透傳用戶ip到后端server, proxy機器需要解決兩個問題:
1.在創建到后端server的套接字時, 將用戶ip作為套接字的源ip,從而讓后端server看到;
2.后端server在回包時, 能夠將目的地為用戶ip的回包,返回給proxy機器,而proxy機器能夠將該包,從網卡驅動(鏈路層)收下來,並正確遞交給應用層的haproxy進程
為了解決這兩個問題,haproxy進程和所在機器需要做三個事情:
1.haproxy進程在創建到后端server的tcp套接字時,開啟IP_TRANSPARENT選項, 並綁定用戶ip為源ip;
2.后端server修改路由規則,將目的地為用戶ip的回包,路由給proxy機器;
3.proxy機器在處理回包時, 在ip層, 由TProxy通過結合netfilter/iptables, 對該回包做一些小動作,將該回包的skb->sk = sk(sk為haproxy進程創建的對應套接字),從而讓tcp層能夠根據skb->sk, 將該回包遞交給haroxy進程進行處理,最終返回給客戶端
上傳一個經典問題配置:
內網的客戶機通過Linux主機連入Internet,而Linux主機與Internet連接時有兩條線路,它們的網關如圖所示。現要求對內網進行策略路由,所有通過TCP協議訪問80端口的數據包都從ChinaNet線路出去,而所有訪問UDP協議53號端口的數據包都從Cernet線路出去。
這是一個策略路由的問題,為了達到目的,在對數據包進行路由前,要先根據數據包的協議和目的端口給數據包做上一種標志,然后再指定相應規則,根據數據包的標志進行策略路由。為了給特定的數據包做上標志,需要使用mangle表,mangle表共有5條鏈,由於需要在路由選擇前做標志,因此應該使用PREROUTING鏈,下面是具體的命令。
iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 -j MARK --set- mark 1 iptables -t mangle -A PREROUTING -i eth0 -p udp --dport 53 -j MARK --set- mark 2
ip rule add from all fwmark 1 table 10 ip rule add from all fwmark 2 table 20
以上兩條命令表示所有標志是1的數據包使用路由表10進行路由,而所有標志是2的數據包使用路由表20進行路由。路由表10和20分別使用了ChinaNet和Cernet線路上的網關作為默認網關,具體設置命令如下所示
ip route add default via 10.10.1.1 dev eth1 table 10 ip route add default via 10.10.2.1 dev eth2 table 20
以上兩條命令在路由表10和20上分別指定了10.10.1.1和10.10.2.1作為默認網關,它們分別位於ChinaNet和Cernet線路上。於是,使用路由表10的數據包將通過ChinaNet線路出去,而使用路由表20的數據包將通過Cernet線路出去
PS:iptables中的mangle
(修正)table 用於修改包的 IP 頭。
例如,可以修改包的 TTL,增加或減少包可以經過的跳數。
這個 table 還可以對包打只在內核內有效的“標記”(internal kernel “mark”),后 續的 table 或工具處理的時候可以用到這些標記。標記不會修改包本身,只是在包的內核 表示上做標記。
上述說明了一個問題:
報文進入主機 過prerouteing的時候先過routing decide ;也就是先過netfilter框架在走路由;但是從本機發包時是先路由再走netfilter,如果走了netfilter后還需要過route
以udp 發包為例: udp 首先路由,找到出口, 然后封裝ip 層報文, 執行 ip_local_out 發送報文此時會遇到LOCAL_OUTPUT netfilter 節點;最后執行dst_output 函數hook 也就是:ip_output
ip_route_output_flow->__ip_route_output_key->__mkroute_output,在__mkroute_output函數中設置rth->dst.output = ip_output;
ip_output中會執行NF_INET_POST_ROUTING(有的內核版本在POST ROUTing 前會執行一次重新路由,因為之前的LOCAL_OUT可能替換DIP,代碼見nf_nat_local_fn 函數)最后到ip_finish_output 發送報文 根據arp neighbor 表項組裝L2 ;然后調用dev_queue_xmit 發送到驅動;
目前遇到一個問題: 怎樣直接更改內核協議棧 支持網橋模式和路由模式混合?