解决Nginx代理TCP获取不到客户端真实IP的问题

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

 

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

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

proxy_protocol on;

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

解决Nginx代理TCP获取不到客户端真实IP的问题_第1张图片

转成字符串就是

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 刘朋
 * 
date 2019-11-25 */ @Slf4j public class NginxProxyProtocolHandler extends ChannelInboundHandlerAdapter { public static Map 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 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配置 - 简书

你可能感兴趣的:(#,Netty,杂谈,#,Nginx,nginx,netty)