V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
Anonym0u5
V2EX  ›  Linux

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

  •  
  •   Anonym0u5 · 232 天前 · 1826 次点击
    这是一个创建于 232 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    • A 服务器 IP 180.101.50.242
    • B 服务器 IP 183.3.203.119

    需求:通过请求 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;
        }
    }
    
    18 条回复    2023-09-11 10:57:24 +08:00
    son012
        1
    son012  
       232 天前
    转发不要做 snat 啊,你做了 snat 伪装了,肯定获取的就是 B 服务器的 IP 了
    son012
        2
    son012  
       232 天前
    也看不懂你既然用 nginx ,直接用 nginx 转发不好了,还要做一层 nat
    Anonym0u5
        3
    Anonym0u5  
    OP
       232 天前
    @son012 不做 snat ,就是第二条不加?不加的话,无法访问到 B 机器的端口了。
    Anonym0u5
        4
    Anonym0u5  
    OP
       232 天前
    @son012 是有这么个需求
    son012
        5
    son012  
       232 天前
    @Anonym0u5 最简单的办法,就是 a 上也加 nginx 做反向代理,两条 iptables 规则都不加
    honmaple
        6
    honmaple  
       232 天前
    iptables 用`TPROXY`,nginx 用`transparent`
    fangpeishi
        7
    fangpeishi  
       232 天前
    leonshaw
        8
    leonshaw  
       232 天前 via Android
    7 层方案:nginx 加头
    4 层方案:A 不做 SNAT ,B 默认路由(或者基于端口策略路由)配到 A (不在一个子网还需要打个隧道)。
    jakes
        9
    jakes  
       232 天前
    你做了 NAT ,在 B 机器看来就 A 发出的,NAT 不会修改 HTTP 请求内容,所以你在 B 用 NGINX 获取的就是 A 的 IP 。

    你可以在 A 机器用代理转发流量,这个时候 A 的代理就可以加入 X-Forwarded-For 这些请求头,B 就可以知道访问者的 IP 了。
    lovelylain
        10
    lovelylain  
       232 天前 via Android
    既然是 http 建议在 A 服务器上做反代,这样比较容易透传客户端 ip ,A 反代是设置 xff 就行,用 iptables 很麻烦的,而且不能跨 ipv4 v6 。
    julyclyde
        11
    julyclyde  
       232 天前
    1 不要用 SNAT
    2 为了让 nginx 返回的数据和收到的数据组成完整的 TCP 连接,应该把 nginx B 机器的默认网关设置为 A 。具体到你这个情况,还得设置 tunnel 。可以参考一下 LVS 的几个模式的详解
    adoal
        12
    adoal  
       232 天前   ❤️ 1
    为什么要在 A 上做到 B 的转发?你不如讲一下你的原始问题。
    tool2d
        13
    tool2d  
       232 天前 via Android
    一般来说获取不到 nat 修改前的 ip ,楼上都说的很清楚了,可以在 http 转发时做。
    如果一定要获取 nat 修改前的 ip ,那么可以搜一下 getsockopt so_original_dst ,这函数就是专门干这个的。
    salmon5
        14
    salmon5  
       231 天前
    这个简单:
    A 服务器 IP 180.101.50.242 ,把这个 IP 配到 B 服务器上就行了
    salmon5
        15
    salmon5  
       231 天前
    找运营商割接下
    littlezzll
        16
    littlezzll  
       231 天前 via Android
    既然是 http 服务,直接 nginx 7 层转发就是了,应用取 XFF ip
    Anonym0u5
        17
    Anonym0u5  
    OP
       229 天前
    非常感谢大家的回答,综合了解了一下,不一一回复了。去掉 iptable ,我是可以实现需求。
    Anonym0u5
        18
    Anonym0u5  
    OP
       229 天前
    然后公网的 IP 不能配置到其他地方,因为一个是云 ,一个是 IDC 。我试试 6 楼说的这个。其他关于设置 B 机器网关的,在我这里需要隧道,网关也要设置多个,默认还有 IDC 有内网。再次感谢各位指点和 idea 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1205 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 23:37 · PVG 07:37 · LAX 16:37 · JFK 19:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.