解决Nginx代理TCP获取不到客户端真实IP的问题_proxy_protocol on-程序员宅基地

技术标签: nginx  # Netty  杂谈  # Nginx  netty  

今天记录一下,Nginx在代理TCP时,服务端只能获取到Nginx代理服务器IP,而获取不到真实客户端ip的问题。

 

如果大家之前有用过Nginx的话,应该知道Nginx在代理http服务时,可以通过配置X-Forwarded-For的方式进行处理。

但是在代理TCP的时候就不起作用了,这里需要用到另一个配置(低版本可能没有,本人用的nginx1.18.0版本)

proxy_protocol on;

添加这个配置后Nginx建立TCP连接时会主动发送一段报文,会包含客户端真实Ip,类似下图

转成字符串就是

PROXY TCP4 192.2.12.67 192.2.12.67 10822 15600/r/n

PS:此报文是需要额外写代码去进行解析的

如果服务器框架用到的是Netty的话,可以参考以下代码


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 处理nginx使用proxy_protocol参数解决获取真实ip的问题
 *
 * @author 刘朋
 * <br/>date 2019-11-25
 */
@Slf4j
public class NginxProxyProtocolHandler extends ChannelInboundHandlerAdapter {

    public static Map<String, AddressInfo> addressInfoMap = new ConcurrentHashMap<>();

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in =(ByteBuf) msg;

        String channelId = ctx.channel().id().asLongText();

        //判断是否已经存在
        if (addressInfoMap.containsKey(channelId)) {
            ctx.fireChannelRead(msg);
            return;
        }


        byte[] head = {0x50, 0x52, 0x4f, 0x58, 0x59, 0x20, 0x54, 0x43, 0x50, 0x34, 0x20};

        for (int i = 0; i < head.length; i++) {
            if (in.getByte(i) != head[i]) {
                //报文头不符合nginx的报文头格式
                log.info("不符合Nginx的报文头格式!");
//                ctx.close();
                ctx.fireChannelRead(msg);
                return ;
            }
        }
        byte[] dataHead = new byte[head.length];
        in.readBytes(dataHead);

        List<String> addressInfoList = new ArrayList<>();
        StringBuilder info = new StringBuilder();
        byte lastB = 0;
        byte b = in.readByte();
        //找到以0d0a结尾
        while (b != 0x0a || lastB != 0x0d) {
            if (b == 0x20 || b == 0x0d) {
                addressInfoList.add(info.toString());
                info = new StringBuilder();
            } else {
                info.append((char) b);
            }
            lastB = b;
            b = in.readByte();
        }

        AddressInfo addressInfo = new AddressInfo(addressInfoList.get(0), addressInfoList.get(2), addressInfoList.get(1), addressInfoList.get(3));

        addressInfoMap.put(channelId, addressInfo);
        log.info("有新的nginx连接:{}",addressInfo);
    }


    @Data
    public class AddressInfo {

        private String clientIp;
        private String clientPort;
        private String targetIp;
        private String targetPort;

        public AddressInfo(String clientIp, String clientPort, String targetIp, String targetPort) {
            this.clientIp = clientIp;
            this.clientPort = clientPort;
            this.targetIp = targetIp;
            this.targetPort = targetPort;
        }
    }

}

参考文章:

TCP四层代理透传客户端真实IP - 简书

proxy protocol介绍及nginx配置 - 简书

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lp840312696/article/details/114976322

智能推荐

jmp指令_汇编 *-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏19次。最近看链接器源码中,对位置无关代码PIC(共享库)的链接问题,发现对call和jmp很多不常用的用法,这里试验并总结了一下各种用法。我们最常用的jmp形式,就是 jmp后面跟个标签!这个没什么可说的! 假如标签叫做mylabel,它的地址是0x8048377,而且有个全局变量b,b存储的内容就是mylabel的地址,而b的地址是0x80494A8。即有这样的赋值(加载)语句:movl$mylabel,%eax//把mylabel的地址加载到eax寄存器中movl%eax,b//把my_汇编 *

kafka查看broker上主副本_Kafka Broker配置-程序员宅基地

文章浏览阅读1.1k次。zookeeper.connectzookeeper host stringstring高advertised.host.name过时的:当advertised.listeners或listeners没设置时候才使用。请改用advertised.listeners。Hostname发布到Zookeeper供客户端使用。在IaaS环境中,Broker可能需要绑定不同的接口。如果没有设置,将会使用ho..._kafka 查看broker

nas文件服务器web接口,nas配置web服务器-程序员宅基地

文章浏览阅读1.4k次。nas配置web服务器 内容精选换一换通过Web浏览器登录资源,会话页面载入失败,提示由于服务器长时间无响应,连接已断开,请检查您的网络并重试(Code:T_514)。云堡垒机系统与资源服务器之间网络连接不稳定,导致连接断开。云堡垒机系统到资源服务器的网络被设置拦截,导致网络不通畅。资源服务器异常无响应,导致连接断开。以下排查思路按照Code:T_514问题的状态进行逐层细化DNS服务器用于解析弹..._webnas

linux免安装mysql_linux上免安装版MySQL5.7.18的教程详解-程序员宅基地

文章浏览阅读164次。1. 下载mysql从官网下载mysql的压缩包 mysql-5.7.18-linux-glibc2.5-x86_64.tar.gz2 把下载的包上传到linux上,先安装下依赖包:Ubuntu用 apt-get install libaio* centOS用yum install libaio*3 用tar -xzvf mysql-5.7.18-linux-glibc2.5-x86_..._linux mysql5.7.18 免安装版 安装

桔梗网导航怎么取消删除?分享三种方法...-程序员宅基地

文章浏览阅读8.3w次,点赞9次,收藏10次。前言:相信很多网友都遇到过安装某某软件后主页被“桔梗网”篡改劫持主页的情况;这种情况大部分原因是安装桔梗网的软件下载器所导致的,所以大家记住以后下载软件尽量不要使用网站推荐的软件下载器,即所谓的“高速下载”下载自己需要的软件,因为除了修改你的主页,还会给捆绑安装很多垃圾软件;尽量选择官网或者软件管家里下载软件。下面进入正题,教大家手动修改被篡改的浏览器主页。(注意:修改浏览器快捷方式会被安全软件阻止,建议修改快捷方式前请暂时关闭安全软件。)第一种方法:右键查看浏览器属性-目标栏是否有后缀网址;如果有_桔梗网

oracle 日志丢失,Oracle日志文件丢失的解决方法-程序员宅基地

文章浏览阅读481次。如果Oracle日志文件丢失,应该怎么办呢?下面就将为您介绍一个Oracle日志文件丢失的处理方法,希望对您能够有所启迪。因不慎操作,将日志组中的第三个Oracle日志文件丢失.SQL> conn /as sysdba已连接。SQL> startupORACLE 例程已经启动。Total System Global Area 85006980 bytesFixed Size..._oracle 启动 不恢复日志

随便推点

Flutter中文文档-程序员宅基地

文章浏览阅读4.9k次。Flutter中文文档Flutter是什么Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。Flutter文档英文好的同学可以直接去flutter官网查看文档,现在已经有Flutter中文网了,向..._flutter中文文档

分区命令详解:用Fdisk命令硬盘分区_fdisk命令分区-程序员宅基地

文章浏览阅读552次。http://www.sina.com.cn 2004/01/17 10:58 天极网   对硬盘进行分区、格式化,是每个硬盘都必须经过的步骤。在这里我就来具体讲解一下怎样使用Fdisk进行硬盘分区。  Fdisk程序是DOS和Windows系统自带的分区软件,虽然其功能比不上有些软件,但用它分区是十分安全的。一下就是具体的操作步骤:_fdisk命令分区

H5测试点汇总整理,搞定面试不受虐_h5的demo评测看哪些功能-程序员宅基地

文章浏览阅读3.9k次,点赞6次,收藏77次。一 测试点1.1.返回功能通过H5页面(非手机自带返回键)的返回功能键返回,可以返回到正确的页面(上一级/退出h5)1.2.屏幕切换横屏竖屏相互切换,能适应,布局不乱,或页面只支持横或竖屏限制1.3.分辨率适配更好建议采用响应式设计(如:offerlist页面大屏显示3行,小屏显示2行)1.4.页面打开形式建议页面在手机上从list点击进入detail页面,要在原窗口打开,通过页面..._h5的demo评测看哪些功能

基于S32K的MBD开发环境搭建_motor control development toolbox for s32k v1.0.0-程序员宅基地

文章浏览阅读5.5k次,点赞11次,收藏65次。目录1.概念简介1.1 toolbox的下载1.2 MCD toolbox描述1.3 MBD toolbox描述1.4 MCD工具箱和MBD工具箱的关系1.5 在线调试工具FreeMaster2.MBD开发环境搭建2.1 安装setup.exe2.2 安装freeMaster2.3 注册并安装许可证2.4 设置目标编译器2.5 为MBD toolbox设置matlab路径3.MBD开发示例3.1 认识S32 MBD库3.2 开发板设置3...._motor control development toolbox for s32k v1.0.0

脚本修改Makefile格式,确定命令前是tab键_使用sed命令修改makefile某一行保留tab-程序员宅基地

文章浏览阅读2.3k次。先备份当前目录下的makefile文件然后逐行判断是否commd,统一修改前面的空位(tab 空格)为 tab键然后取出文件每一行末尾多余的空格,tab键#!/bin/bashcur=`pwd`time=`date "+%Y_%m_%d_%H_%M_%S"` file=`find $cur -iname makefile | head -1`bakfile=$file"_bak_"$time#_使用sed命令修改makefile某一行保留tab

python tkinter教程-事件绑定_python bind中所有键的名称-程序员宅基地

文章浏览阅读4.6w次,点赞22次,收藏95次。一个Tkinter主要跑在mainloop进程里。Events可能来自多个地方,比如按键,鼠标,或是系统事件。 Tkinter提供了丰富的方法来处理这些事件。对于每一个控件Widge,你都可以为其绑定方法function。widget.bind(event,handler)如果相应的event发生了,就会调用handler处理事件。举个例子: 捕获鼠标点击事件:from Tkinter impo_python bind中所有键的名称

推荐文章

热门文章

相关标签