关于 iptables NAT 转发后端服务器获取客户端真实 IP 的问题。

2023-09-08 17:32:14 +08:00
 Anonym0u5

请教一个关于 iptables NAT 转发后端服务器获取客户端真实 IP 的问题。

以下与我测试的真实环境不同只有 IP 和端口,以下是一个场景:

两台服务器 A,B 均为 Linux:

需求:通过请求 A 服务器 IP 端口可以转发访问到 B 服务器 IP 端口,B 服务器服务可以获取到真实客户端的 IP 地址。 实操:在 A 服务器上做 iptable NAT 转发 8088 端口到 B 服务器 8099 端口,用了以下命令

iptables -t nat -A PREROUTING -p tcp --dport 8088 -j DNAT --to-destination 183.3.203.119:8099;
iptables -t nat -A POSTROUTING -p tcp -d 183.3.203.119 --dport 8099 -j MASQUERADE -to-source 180.101.50.242;

问题:在 B 服务器的 Nginx 里面无法获取到真实的客户端 IP ,一直获取到的是 A 服务器的 IP ,如果想要获取真实客户端 IP ,iptable 这块规则该如何处理。

说明:Nginx 相关的获取客户端 IP 配置都加过了(没有效果,大概率判断问题不在 Nginx 这一侧):

server {
    listen 80 default_server;
    server_name _;

    location / {
        default_type text/html;
        set_real_ip_from  <NAT 服务器 IP>;
        real_ip_header    X-Forwarded-For;
        real_ip_recursive on;

        # 使用$remote_addr 获取客户端真实 IP
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        content_by_lua_file /etc/nginx/print_ngx_var.lua;
    }
}
2365 次点击
所在节点    Linux
18 条回复
son012
2023-09-08 17:51:35 +08:00
转发不要做 snat 啊,你做了 snat 伪装了,肯定获取的就是 B 服务器的 IP 了
son012
2023-09-08 17:54:01 +08:00
也看不懂你既然用 nginx ,直接用 nginx 转发不好了,还要做一层 nat
Anonym0u5
2023-09-08 17:54:30 +08:00
@son012 不做 snat ,就是第二条不加?不加的话,无法访问到 B 机器的端口了。
Anonym0u5
2023-09-08 17:55:08 +08:00
@son012 是有这么个需求
son012
2023-09-08 17:57:14 +08:00
@Anonym0u5 最简单的办法,就是 a 上也加 nginx 做反向代理,两条 iptables 规则都不加
honmaple
2023-09-08 17:57:57 +08:00
iptables 用`TPROXY`,nginx 用`transparent`
fangpeishi
2023-09-08 19:09:53 +08:00
leonshaw
2023-09-08 19:52:55 +08:00
7 层方案:nginx 加头
4 层方案:A 不做 SNAT ,B 默认路由(或者基于端口策略路由)配到 A (不在一个子网还需要打个隧道)。
jakes
2023-09-08 20:12:13 +08:00
你做了 NAT ,在 B 机器看来就 A 发出的,NAT 不会修改 HTTP 请求内容,所以你在 B 用 NGINX 获取的就是 A 的 IP 。

你可以在 A 机器用代理转发流量,这个时候 A 的代理就可以加入 X-Forwarded-For 这些请求头,B 就可以知道访问者的 IP 了。
lovelylain
2023-09-08 20:40:57 +08:00
既然是 http 建议在 A 服务器上做反代,这样比较容易透传客户端 ip ,A 反代是设置 xff 就行,用 iptables 很麻烦的,而且不能跨 ipv4 v6 。
julyclyde
2023-09-08 20:46:00 +08:00
1 不要用 SNAT
2 为了让 nginx 返回的数据和收到的数据组成完整的 TCP 连接,应该把 nginx B 机器的默认网关设置为 A 。具体到你这个情况,还得设置 tunnel 。可以参考一下 LVS 的几个模式的详解
adoal
2023-09-08 21:37:26 +08:00
为什么要在 A 上做到 B 的转发?你不如讲一下你的原始问题。
tool2d
2023-09-08 21:40:45 +08:00
一般来说获取不到 nat 修改前的 ip ,楼上都说的很清楚了,可以在 http 转发时做。
如果一定要获取 nat 修改前的 ip ,那么可以搜一下 getsockopt so_original_dst ,这函数就是专门干这个的。
salmon5
2023-09-09 09:19:19 +08:00
这个简单:
A 服务器 IP 180.101.50.242 ,把这个 IP 配到 B 服务器上就行了
salmon5
2023-09-09 09:20:05 +08:00
找运营商割接下
littlezzll
2023-09-09 13:33:50 +08:00
既然是 http 服务,直接 nginx 7 层转发就是了,应用取 XFF ip
Anonym0u5
2023-09-11 10:53:42 +08:00
非常感谢大家的回答,综合了解了一下,不一一回复了。去掉 iptable ,我是可以实现需求。
Anonym0u5
2023-09-11 10:57:24 +08:00
然后公网的 IP 不能配置到其他地方,因为一个是云 ,一个是 IDC 。我试试 6 楼说的这个。其他关于设置 B 机器网关的,在我这里需要隧道,网关也要设置多个,默认还有 IDC 有内网。再次感谢各位指点和 idea 。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/972111

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX