今天记录一下,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;
}
}
}
参考文章:
本文介绍如何通过Nginx的proxy_protocol配置项解决TCP代理时无法获取客户端真实IP的问题,并提供了一段使用Netty解析该报文的示例代码。
2757

被折叠的 条评论
为什么被折叠?



