本文参考:https://www.jianshu.com/p/cc8d592582c9 感谢分享
netty想要获取客户端请求的IP有两种方法:
String ip=connContext.getClientIP().replace("/","").split(":")[0];
如果使用了代理,这时获取到的IP是代理服务器的IP
nginx对TCP协议进行代理需要引入stream模块,并修改nginx配置:
stream{
upstream tcpstream{
server 10.1.11.67:10001 weight=1;
}
server{
listen 80;
proxy_connect_timeout 20s;
proxy_timeout 1m;
# 开启代理
proxy_protocol on;
proxy_pass tcpstream;
}
error_log logs/error.log;
}
proxy protocol是HAProxy的作者Willy Tarreau于2010年开发和设计的一个Internet协议,通过为tcp添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等),在网络情况复杂又需要获取用户真实IP时非常有用。其本质是在三次握手结束后由代理在连接中插入了一个携带了原始连接四元组信息的数据包。
50524f58592054435034203132372e302e302e31203132372e302e302e312036303634322038300d0a
解析结果为:
PROXY TCP4 127.0.0.1 127.0.0.1 60642 80
注意结果为PROXY TCP4 127.0.0.1 127.0.0.1 60642 80\r\n
所以上面会换行
解析代码
以上是解析只有一层代理的,如果两层代理得到的数据有是什么样的呢?
50524f585920544350342031302e312e31312e36362031302e312e31312e36382035333732382038300d0a50524f585920544350342031302e312e352e32372031302e312e31312e36362036353431312038300d0a
解析出来的结果是:
获取到数据PROXY TCP4 10.1.11.66 10.1.11.68 53728 80
PROXY TCP4 10.1.5.27 10.1.11.66 65411 80
解析代码
public class MessageDecoder extends ByteToMessageDecoder {
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
log.info("收到数据:{},{}",ctx.channel().id(),ByteBufUtil.hexDump(buffer));
if(buffer.readableBytes() < ProtocolDataHead.LENGTH){
return;
}
//protocol head
ProtocolDataHead header = ProtocolDataHead.fromData(ByteBufUtil.getBytes(buffer,0,ProtocolDataHead.LENGTH));
if(header.getStartMark().equals(ProtocolDataHead.STARTMARK)){
//本公司业务代码,不展示
} else if(header.getStartMark().equals(NginxIPConst.NGINX_IP_TWO)){
if(buffer.readableBytes()<NginxIPConst.NGINX_IP_LENGTH){
return;
}
String readData=ByteBufUtil.hexDump(buffer);
log.info("收到nginx消息:{}",ByteBufUtil.hexDump(buffer));
if(readData.indexOf(NginxIPConst.NGINX_IP_END)>0){
byte[] nginxIP=new byte[readData.indexOf(NginxIPConst.NGINX_IP_END)/2+2];
buffer.readBytes(nginxIP);
NginxUtils.checkHead(ctx.channel().id().toString(),nginxIP);
return;
}else{
buffer.clear();
}
}else{
log.info("收到数据错误:{}",ByteBufUtil.hexDump(buffer));
buffer.clear();
return;
}
}
}
public class NginxUtils {
private static ConcurrentHashMap<String,String> ipMap=new ConcurrentHashMap<>(1000);
public static void checkHead(String channelId,byte[] bytes){
String nginxIP=new String(bytes, Charset.forName("UTF-8"));
log.info("获取到数据{}",nginxIP);
String[] strs=nginxIP.split(" ");
if(strs.length>2){
ipMap.put(channelId,strs[2]);
}
}
public static String getIp(String channelId){
return ipMap.get(channelId);
}
public static String removeIp(String channelId){
return ipMap.remove(channelId);
}
}
public class NginxIPConst {
//nginx透传ip最小长度
public static final int NGINX_IP_LENGTH = 41;
//nginx透传ip前两位数据
public static final String NGINX_IP_TWO = "PR";
//nginx结尾符
public static final String NGINX_IP_END = "0d0a";
}