解决Nginx代理TCP获取不到客户端真实IP的问题_nginx tcp 真实ip_月月大王的博客-程序员秘密

技术标签: 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

智能推荐

Android Studio 使用USB真机调试教程_fubo1990的博客-程序员秘密

       Android开发者第一步学习的应该就是真机调试了。但是很多初次接触android studio的同学还是不知道如何用真机调试,今天我就给大家写一个教程,希望可以帮到需要的人。      我使用的是一款国家电网定制机型。Android版本为:5.0.2。      1.先用usb线把你的测试手机连接到你的电脑上,并且安装驱动(由于机子型号不同,安装方式有差异,可以根据你的机子百度安装...

基于uni-app的微信小程序引入字体文件_時が止まる的博客-程序员秘密

上传字体文件至服务器或者oss(也可以引入第三方,需支持nginx跨域)引入字体文件(两种方法)css引入@font-face { font-family: 'fontFamily'; src: url("https://xxxxxxx/fontFile.ttf?_=2019121810"); /* 小程序似乎只支持线上文件的引入,文件还不能过大*/ }.test{ font-family: butterFont;/* 不需要引号 */}js引入let [err,.

威纶通HMI常见问题_威纶触摸屏下载时报错。请检查hmi的ip地址与端口号设置_机器视觉001的博客-程序员秘密

威纶通常见问题1. 如何断电保持下位机地址数据威纶通HMI断电重启后,数值元件中的数据是会归零的(RW/RW_A除外)。 可以利用断电保持的RW地址中转:比如要保存下位机地址D10中的数据,HMI断电前将D10中数据传输给RW0,HMI重启后将RW0地址中数据传输回D10。 数据传输方法:资料传输功能或者通过宏指令。2. USB连接线使用注意事项USB连接线规格:HI-SPEED USB Revision 2.0 SHIELDED 24AWG计算机的USB端口需支持标准USB2.0或U

下一代应用监控指标采集器Prometheus核心介绍_iqifenxia的博客-程序员秘密

Prometheus简介Prometheus是一个最初在SoundCloud上构建的开源系统监视和警报工具包 。自2012年成立以来,许多公司和组织都采用Prometheus,该项目拥有一个非常活跃的开发人员和用户社区。它现在是一个独立的开源项目。Prometheus于2016年加入谷歌主导的顶级开源社区云原生计算基金会(CNCF),成为第二个顶级托管项目。第一是大名鼎鼎的k8s。prometheus是属于下一代监控。可用来监控操作系统、应用、容器等。2特征普罗米修斯的主要特点是...

flash cs3打造跟随鼠标的弹性球运动小游戏_iteye_2764的博客-程序员秘密

 用Flash CS3的AS制作跟随鼠标弹性小游戏,主要是练习AS的使用。 先看演示:源文件下载:[img]/Files/BeyondPic/2007-9/28/rar.gif[/img] [url=http://www2.flash8.net/UploadTeach/200709/20070927115200359.rar]弹性小球运动.rar[/url]修改文档属性...

CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\km3000dweb\a_shengxia623的博客-程序员秘密

win7系统安装。net服务setup安装包编译错误说明: 在编译向该请求提供服务所需资源的过程中出现错误。请检查下列特定错误详细信息并适当地修改源代码。 编译器错误消息: CS0016: 未能写入输出文件“c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\km3000dweb\ada5057

随便推点

【自动驾驶】华为车BU介绍(2021-11-23晚直播记录)_华为车bu全称_ReCclay的博客-程序员秘密

文章目录一、个人调研二、关键PPT介绍三、部分部门宣传页介绍3.1、智能座舱产品部3.2、MDC 产品部3.3、融合感知产品部3.4、智能车控产品部四、部分部门HR联系方式一、个人调研华为车BU成立于2019年,最初规模400余人,截止目前人数已有最初的10余倍之多。国内工作地主要部署在上海、杭州、苏州、深圳、南京、北京和东莞七大城市。在成都没有车BU的相关部门,但是成都2012实验室有对自动驾驶的预研岗位,个人理解是车BU成立前的探索岗位。昨晚的宣讲整体听下来,感觉车BU是个仍持续投资,急需人才的部门

8月9日 华为发布了其自研的鸿蒙操作系统,华为正式发布自研操作系统鸿蒙,面向AI全场景..._流风兮回雪的博客-程序员秘密

8月9日,余承东在华为开发者大会上正式宣布鸿蒙操作系统发布8月9日-11日,2019华为开发者大会在东莞松山湖基地举行。在8月9日下午的主题演讲中,传闻已久的华为自研操作系统鸿蒙OS正式亮相。据了解,鸿蒙OS是华为自主研发的操作系统,英文名为Harmony。首款搭载该系统的设备是荣耀智慧屏系列产品,将于明日发布。鸿蒙OS能够实现模块化解耦,应用于智慧屏、穿戴设备、手机、音箱等不同设备。会上,华为消...

jvm系列(一):java类的加载机制_茅坤宝骏氹的博客-程序员秘密

转载自 jvm系列(一):java类的加载机制1、什么是类的加载类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的 Class对象, Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。...

linux安装docker_SSYYking的博客-程序员秘密

安装docker更新系统yum update安装yum-utils工具和两个驱动依赖yum install -y yum-utils device-mapper-persistent-data lvm2设置使用阿里云的yum源yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装dockeryum install docker-ce查看docker版本d

bat批量重命名文件_批量重命名 bat_Zcmmma的博客-程序员秘密

::后面的为注释,若执行时出错可以试着将::注释内容删除直接上两个例子(注意程序中的符号全部为英文符号)将所有所在文件夹下的所有.txt文件改为a.jpg(a为递增变量)@echo off ::取消回显set a=1 ::设置变量setlocal EnableDelayedExpansion ::延迟变量for %%n in (*.txt) do ( ::*为通配符,(*.txt)即所有.txt文件集合 ren "%%n" "!a!.jpg" :.

QT开发用ffmpeg将图片制作成视频_casun_li的博客-程序员秘密

继上一博文:QT打开图片文件夹快速播放图片现在要将图片做成视频1,cmd 的调用:因为什么都不懂,刚开始是想用命令行来做,在cmd下用命令能合成比较模糊的视频了      因输入文件的方式有两种调用方式:   第一种:ffmpeg -f image2 -pattern_type glob -framerate 24 -i 'IMG_*.JPG'  ./IMG_.avi