/** * */ package io.nettythrift.codec; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import io.netty.util.Attribute; import io.netty.util.AttributeKey; /** * * PROXY protocol Decoder * <p> * 判断有没有proxy信息,如果有则解析并存储到上下文属性,并且将读指针(readerIndex)设置到proxy段的末尾(/r/n位置之后) * * @see {@link http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-proxy-protocol.html#proxy-protocol * } * * @author HouKx */ public class AwsProxyProtocolDecoder extends ChannelHandlerAdapter { private static Logger logger = LoggerFactory.getLogger(AwsProxyProtocolDecoder.class); public static final AttributeKey<String> KEY_PROXY = AttributeKey.valueOf("TCP_PROXY"); @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof ByteBuf && ctx.channel().isActive()) { ByteBuf buffer = (ByteBuf) msg; decode(ctx, buffer); } ctx.fireChannelRead(msg); } private void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { if (!isProxyProtocol(buffer)) { return; } Attribute<String> attr = ctx.attr(KEY_PROXY); if (attr.get() != null) { logger.debug("ProxyProtocolDecoder: 已解析过代理"); return; } logger.debug("尝试解析代理"); int len = Math.min(buffer.readableBytes(), 10); if (len < 10) { return; } final int start = 11; if (buffer.getByte(9) == '4') {// PROXY TCP4 // System.out.println("IPV4"); int ipEnd = -1; for (int i = start + 3 * 4 + 3; i > 0; i--) { if (buffer.getByte(i) == ' ') { ipEnd = i; break; } } if (ipEnd > start) { char ip[] = new char[ipEnd - start]; for (int i = 0; i < ip.length; i++) { ip[i] = (char) buffer.getByte(start + i); } // 修改readerIndex 到字符串末尾的\r\n int i = ipEnd + 1 + (1 * 4 + 3 + 2 * 2 + 2); ipEnd = -1; for (int MAX = buffer.readerIndex() + buffer.readableBytes(); i < MAX; i++) { if (buffer.getByte(i) == '\n') { ipEnd = i; break; } } int newIndex = ipEnd + 1; if (ipEnd > 0) { buffer.readerIndex(newIndex); } String clientIp = new String(ip); logger.debug("代理IP: {}, buffer.readerIndex={}", clientIp, buffer.readerIndex()); attr.set(clientIp); } } else { System.err.println("IPV" + buffer.getByte(9) + "?"); } } private boolean isProxyProtocol(ByteBuf buffer) { int len = Math.min(buffer.readableBytes(), 10); if (len < 6) { return false; } byte[] dst = new byte[len]; buffer.getBytes(buffer.readerIndex(), dst, 0, len); if (logger.isDebugEnabled()) { logger.debug("headCode: head={}, bytes={}", new String(dst), Arrays.toString(dst)); } switch (dst[0]) { case 'P': { switch (dst[1]) { case 'R': { // PROXY protocol , see: // http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-proxy-protocol.html#proxy-protocol if (dst[2] == 'O' && dst[3] == 'X' && dst[4] == 'Y' && dst[5] == ' ' && (dst.length > 8 && (dst[6] + dst[7] + dst[8] == 'T' + 'C' + 'P'))) { return true; } } } break; } } return false; } }