協議誕生背景
在Web分布式系統中,一般會搭建復雜的load blance系統來提供高性能的web服務。
7層的SLB 有基於nginx/淘寶變種tengine的。后端RS會無法獲取真實客戶端IP。
為了解決此問題,HAProxy的作者Willy Tarreau於2010年開發和設計的一個Internet協議,通過為tcp添加一個很小的頭信息,來方便的傳遞客戶端信息(協議棧、源IP、目的IP、源端口、目的端口等),在網絡情況復雜又需要獲取用戶真實IP時非常有用。其本質是在三次握手結束后由代理在連接中插入了一個攜帶了原始連接四元組信息的數據包。
截止2018年10月份 proxy protocol有兩個版本,v1僅支持human-readable報頭格式(ASCIII碼),v2需同時支持human-readable和二進制格式,即需要兼容v1格式。
proxy protocol的接收端必須在接收到完整有效的 proxy protocol 頭部后才能開始處理連接數據。因此對於服務器的同一個監聽端口,不存在兼容帶proxy protocol包的連接和不帶proxy protocol包的連接。如果服務器接收到的第一個數據包不符合proxy protocol的格式,那么服務器會直接終止連接。
協議實現
在三次握手之后,會增加一個TCP payload包,包payload長度48字節。如圖:
示例,如下圖所示的第四個包就是proxy protocol的包。
proxy protocol 格式
version 1 header
-
- 每個字段中間為空格(\x20)
// PROXY AF L3_SADDR L3_DADDR L4_SADDR L4_DADDR\r\n PROXY TCP4 202.112.144.236 10.210.12.10 5678 80\r\n PROXY TCP6 2001:da8:205::100 2400:89c0:2110:1::21 6324 80\r\n PROXY UKNOWN\r\n
version 2 header
-
- 12字節的固定signature
-
\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A
-
- 4bits 協議版本號
-
\x2 // v2
-
- 4bits
-
\x0 // LOCAL \x1 // PROXY
-
- 4bits 地址族
-
\x0 // AF_UNSPEC \x1 // AF_INET \x2 // AF_INET6 \x3 // AF_UNIX
-
- 4bits transport protocol
-
\x0 // UNSPEC \x1 // STREAM \x2 // DGRAM
-
-
2字節地址長度字段(網絡字節序),指接下來剩余的報頭長度
-
L3 S_ADDR
-
L3 D_ADDR
-
L4 S_ADDR (如果有)
-
L4 D_ADDR (如果有)
-
Tips
-
- 目前nginx的v2版本的讀取只支持 cmd 為 PROXY,transport protocol 為 STREAM
- v2版本支持了很多新特性,詳情可參考官方文檔(見reference)
nginx proxy protocol 配置
- 1.5.12 support accept for http
- 1.9.3 support TCP write
- 1.11.4 support accept for tcp
- 1.13.11 support v2 read
proxy protocol 插入配置
stream { server { listen 12345; proxy_pass backend.example.com:8080; proxy_protocol on; } }
proxy protocol 接收配置
http { log_format elb_log '$proxy_protocol_addr'; server { listen 8080 proxy_protocol; root /usr/local/nginx/html; index index.html index.htm; server_name hello-world.com; set_real_ip_from 192.168.10.0/24; real_ip_header proxy_protocol; } location / { try_files $uri $uri/ /index.html; proxy_pass http://backend.example2.com:8088; proxy_set_header X-Forwarded-For $proxy_protocol_addr; } access_log /usr/local/nginx/stream.log elb_log; }
參考簡書:https://www.jianshu.com/p/cc8d592582c9
參考:https://www.cnblogs.com/hugetong/p/10901359.html