美文网首页
nginx的tcp透明代理设置

nginx的tcp透明代理设置

作者: clstou | 来源:发表于2020-08-14 18:13 被阅读0次

    背景

    目前,接入层access使用nginx作为反向代理。客户端连接nginx打开的5000端口后,nginx通过客户端ip哈希的方式,将客户端的接入请求负载均衡到后台的4个access服务。
    使用nginx作为反向代理时,客户端与nginx直连,同时nginx为每一个客户端连接建立了单独的tcp连接到access服务。此时,nginx代理带来的问题是,access无法获取到客户端的真实ip,而只能拿到nginx代理服务所在机器的ip。(所有的代理都有类似的问题,因为与上游服务(例如这里的access服务)连接的实际上是代理服务器,ip包里的ip地址是代理服务器的地址)。
    但是,很时候我们需要拿到客户端的真实ip做一些业务上的判断。这个时候,就需要通过某些方式获取客户端的真实ip。如果代理服务器和上游服务之前是通过http通讯,则可以通过http的首部X-Forwarded-For将客户端的ip信息传给上游服务(nginx可以很方便的设置该首部设置)。
    对于纯tcp代理,则获取客户端ip会麻烦一些。主要有两种方式:

    1. 类似http协议,在业务服务上包装一层proxy protocol,通过proxy protocol传递客户端的ip地址。
      nginx可以通过protocol_proxy on启用proxy protocol,同时,需要上游服务也增加对proxy protocol的支持。
    2. 通过Linux 2.6.24中,socket新增的选项IP_TRANSPARENT,使socket可以接收目的地址没有配置的数据包,也可以发送源地址不是本地地址的数据包实现。使用这种方式,上游服务不需要任何修改就可以得到客户端的ip。下文主要说明这种方式。

    原理

    nginx作为上游服务的反向代理时,每个客户端的连接方式如下:

               tcp                 tcp
    client <--------->  nginx  <---------> upstream server(access)
    

    实现透明代理的原理是,nginx使用获取到的客户端ip来建立nginx与上游服务直接的tcp连接。也即:

    1. nginx与上游服务的tcp链接建立和通讯时,从nginx发布的ip数据包,源地址由nginx服务所在机器的地址替换为客户端的ip地址;
    2. 从上游服务器返回的ip数据包,目的地址也是客户端的ip地址,通过特殊的路由方式,将返回的ip数据包路由到nginx进程;
    3. 最后nginx将收到的数据发送给对应的客户端。

    设置

    服务和机器部署说明

    总共有两台服务器,内网ip地址分别为172.19.228.32172.19.228.33。两台机器部署的服务如下:

    • 172.19.228.32
      主服务器。nginx绑定5000端口。两个access服务绑定15010以及15011端口。

    • 172.19.229.33
      副服务器。两个access服务绑定15010以及15011端口。

    nginx配置

    1. nginx需要以root的用户运行,因为socket的IP_TRANSPARENT选项需要超级用户权限。
    # in the "main"  context
    use root;
    
    1. nginx在stream中设置proxy_bind,使nginx在连接上游服务器时,启用socket的IP_TRANSPARENT选项。
    # in the "stream"  context
    server {
    ...
    proxy_bind $remote_addr transparent;
    }
    

    nginx设置完成并reload配置后,所有从nginx发送到上游服务器的ip数据包将使用客户端的ip地址作为源地址。后续的设置,需要将上游服务器返回的ip数据包(其中的目的地址是客户端的ip)返回到nginx所在的机器,并投递给nginx进程。

    172.19.228.32服务器设置

    32机器上的上游服务返回ip数据包给nginx时,指定的目的ip地址是客户端的ip地址。32机器需要将这些数据返回给nginx进程。

    # 1. 将32上的上游服务回复的数据路由到nginx进程
    # 1.1 对32上的上游服务返回的ip数据设置标记1
    # NOTE: 如果32上增加access服务,需要修改这里--sport源端口,将新增的access服务端口包含进来
    iptables -t mangle -A OUTPUT -p tcp --src 172.19.228.32 --sport 15010:15011 \
             -j MARK --set-xmark 0x1/0xffffffff
             
    # 1.2 新增路由表,表id为100,将所有ip数据路由到lo网络接口         
    # NOTE: 以下两条ip命令设置的route和rule都需要保存到/etc/rc.local中,以便在开机时启动
    ip route add local 0.0.0.0/0 dev lo table 100
    # 1.3 为标记为1的ip数据使用路由表100
    ip rule add fwmark 1 lookup 100
    

    设置完成后,32上的上游服务(端口为15010以及15011)发出的ip数据包,因为被设置了标记而匹配新增的策略路由,所有ip数据被路由到lo网络接口。同时,因为这些数据包中包含的端口是nginx连接上游服务时打开的端口,所以这些数据最终被分用到nginx进程。
    这样,nginx和同在一个机器上的上游服务之间的透明代理设置完整。上游服务将可以得到客户端的ip地址,同时可以将数据返回给nginx,nginx再将返回的数据返回给对应的客户端。
    此时,如果使用lsof(1)命令查看上游服务打开的tcp链接,显示的源ip地址也将是客户端的ip地址。

    172.19.228.33服务器设置

    33上的上游服务与nginx在不同的主机上。主要设置如下:

    # 1. 允许来自局域网网络接口bond0的ip数据
    # 1.1 该设置主要避免来自32的ip数据被33屏蔽
    iptables -I INPUT -i bond0 -j ACCEPT
    
    # 1.2 禁用33主机上的reverse path filter。
    # NOTE:因为nginx启动透明代理后,
    #       33将在局域网网络接口bond0上收到源地址是客户端ip的数据(一般是公网ip), 
    #       如果不禁用reverse path filter, 则因为无法在局域网网络接口回复公网的数据包,
    #       导致33上收到的tcp sync包被33直接丢弃,导致tcp连接无法建立。
    echo "net.ipv4.conf.all.rp_filter = 0" >> /etc/sysctl.conf
    echo "net.ipv4.conf.bond0.rp_filter = 0" >> /etc/sysctl.conf
    
    # 2. 将33上的上游服务回复的数据路由到32机器
    # 2.1 对33上的上游服务发出的包设置标记1
    # NOTE: 如果33上增加access服务,需要修改这里--sport源端口,将新增的access服务端口包含进来
    iptables -t mangle -A OUTPUT -p tcp --src 172.19.228.33 --sport 15010:15011 \
             -j MARK --set-xmark 0x1/0xffffffff
    
    # 2.2 新增路由表,表id为100,将所有ip数据路由到32机器
    # NOTE: 以下两条ip命令设置的route和rule都需要保存到/etc/rc.local中,以便在开机时启动
    ip route add default via 172.19.228.32 table 100
    # 2.3 为标记为1的ip数据使用路由表100
    ip rule add fwmark 1 lookup 100
    
    # 3. 将33的上游服务返回的ip数据路由到32机器之后,再把这些数据路由到nginx进程
    # 3.1 32上收到的来自33上游服务的数据设置标记1,使这些数据可以路由到nginx进程
    # NOTE: 注意这一条命令在32主机上执行;
    #       33上的增加access服务,需要修改这里的--sport源端口,将新增的access服务端口包含进来
    # NOTE: 因为32上已经设置了对标记为1的ip数据使用策略路由表100,将其路由到lo网络接口
    #       所以只需要对33返回的数据设置标记1即可
    iptables -t mangle -A PREROUTING -p tcp --src 172.19.228.33 --sport 15010:15011 \
             -j MARK --set-xmark 0x1/0xffffffff
    

    设置完成后,33可以接收nginx发出的ip数据包,并可以将上游服务回复的ip数据路由给32机上的nginx进程。
    同时,使用lsof(1)命令查看33的上游服务打开的tcp链接,源ip将是客户端的ip。其他所有的与nginx不在同一个主机上的上游服务都可以参考这个配置设置。

    参考:
    nginx的透明代理实现
    IP Transparency and Direct Server Return with NGINX and NGINX Plus as Transparent Proxy
    Linux kernel rp_filter settings

    相关文章

      网友评论

          本文标题:nginx的tcp透明代理设置

          本文链接:https://www.haomeiwen.com/subject/wekndktx.html