/* * Copyright 2014 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package io.netty.handler.codec.haproxy; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.ProtocolDetectionResult; import io.netty.handler.codec.ProtocolDetectionState; import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol.AddressFamily; import io.netty.handler.codec.haproxy.HAProxyProxiedProtocol.TransportProtocol; import io.netty.util.CharsetUtil; import org.junit.Before; import org.junit.Test; import static io.netty.buffer.Unpooled.*; import static org.junit.Assert.*; public class HAProxyMessageDecoderTest { private EmbeddedChannel ch; @Before public void setUp() { ch = new EmbeddedChannel(new HAProxyMessageDecoder()); } @Test public void testIPV4Decode() { int startChannels = ch.pipeline().names().size(); String header = "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V1, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.TCP4, msg.proxiedProtocol()); assertEquals("192.168.0.1", msg.sourceAddress()); assertEquals("192.168.0.11", msg.destinationAddress()); assertEquals(56324, msg.sourcePort()); assertEquals(443, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testIPV6Decode() { int startChannels = ch.pipeline().names().size(); String header = "PROXY TCP6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 1050:0:0:0:5:600:300c:326b 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V1, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.TCP6, msg.proxiedProtocol()); assertEquals("2001:0db8:85a3:0000:0000:8a2e:0370:7334", msg.sourceAddress()); assertEquals("1050:0:0:0:5:600:300c:326b", msg.destinationAddress()); assertEquals(56324, msg.sourcePort()); assertEquals(443, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testUnknownProtocolDecode() { int startChannels = ch.pipeline().names().size(); String header = "PROXY UNKNOWN 192.168.0.1 192.168.0.11 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V1, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.UNKNOWN, msg.proxiedProtocol()); assertNull(msg.sourceAddress()); assertNull(msg.destinationAddress()); assertEquals(0, msg.sourcePort()); assertEquals(0, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test(expected = HAProxyProtocolException.class) public void testV1NoUDP() { String header = "PROXY UDP4 192.168.0.1 192.168.0.11 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testInvalidPort() { String header = "PROXY TCP4 192.168.0.1 192.168.0.11 80000 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testInvalidIPV4Address() { String header = "PROXY TCP4 299.168.0.1 192.168.0.11 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testInvalidIPV6Address() { String header = "PROXY TCP6 r001:0db8:85a3:0000:0000:8a2e:0370:7334 1050:0:0:0:5:600:300c:326b 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testInvalidProtocol() { String header = "PROXY TCP7 192.168.0.1 192.168.0.11 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testMissingParams() { String header = "PROXY TCP4 192.168.0.1 192.168.0.11 56324\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testTooManyParams() { String header = "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443 123\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testInvalidCommand() { String header = "PING TCP4 192.168.0.1 192.168.0.11 56324 443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testInvalidEOL() { String header = "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\nGET / HTTP/1.1\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test(expected = HAProxyProtocolException.class) public void testHeaderTooLong() { String header = "PROXY TCP4 192.168.0.1 192.168.0.11 56324 " + "00000000000000000000000000000000000000000000000000000000000000000443\r\n"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } @Test public void testIncompleteHeader() { String header = "PROXY TCP4 192.168.0.1 192.168.0.11 56324"; ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testCloseOnInvalid() { ChannelFuture closeFuture = ch.closeFuture(); String header = "GET / HTTP/1.1\r\n"; try { ch.writeInbound(copiedBuffer(header, CharsetUtil.US_ASCII)); } catch (HAProxyProtocolException ppex) { // swallow this exception since we're just testing to be sure the channel was closed } boolean isComplete = closeFuture.awaitUninterruptibly(5000); if (!isComplete || !closeFuture.isDone() || !closeFuture.isSuccess()) { fail("Expected channel close"); } } @Test public void testTransportProtocolAndAddressFamily() { final byte unknown = HAProxyProxiedProtocol.UNKNOWN.byteValue(); final byte tcp4 = HAProxyProxiedProtocol.TCP4.byteValue(); final byte tcp6 = HAProxyProxiedProtocol.TCP6.byteValue(); final byte udp4 = HAProxyProxiedProtocol.UDP4.byteValue(); final byte udp6 = HAProxyProxiedProtocol.UDP6.byteValue(); final byte unix_stream = HAProxyProxiedProtocol.UNIX_STREAM.byteValue(); final byte unix_dgram = HAProxyProxiedProtocol.UNIX_DGRAM.byteValue(); assertEquals(TransportProtocol.UNSPEC, TransportProtocol.valueOf(unknown)); assertEquals(TransportProtocol.STREAM, TransportProtocol.valueOf(tcp4)); assertEquals(TransportProtocol.STREAM, TransportProtocol.valueOf(tcp6)); assertEquals(TransportProtocol.STREAM, TransportProtocol.valueOf(unix_stream)); assertEquals(TransportProtocol.DGRAM, TransportProtocol.valueOf(udp4)); assertEquals(TransportProtocol.DGRAM, TransportProtocol.valueOf(udp6)); assertEquals(TransportProtocol.DGRAM, TransportProtocol.valueOf(unix_dgram)); assertEquals(AddressFamily.AF_UNSPEC, AddressFamily.valueOf(unknown)); assertEquals(AddressFamily.AF_IPv4, AddressFamily.valueOf(tcp4)); assertEquals(AddressFamily.AF_IPv4, AddressFamily.valueOf(udp4)); assertEquals(AddressFamily.AF_IPv6, AddressFamily.valueOf(tcp6)); assertEquals(AddressFamily.AF_IPv6, AddressFamily.valueOf(udp6)); assertEquals(AddressFamily.AF_UNIX, AddressFamily.valueOf(unix_stream)); assertEquals(AddressFamily.AF_UNIX, AddressFamily.valueOf(unix_dgram)); } @Test public void testV2IPV4Decode() { byte[] header = new byte[28]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x11; // TCP over IPv4 header[14] = 0x00; // Remaining Bytes header[15] = 0x0c; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- int startChannels = ch.pipeline().names().size(); ch.writeInbound(copiedBuffer(header)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V2, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.TCP4, msg.proxiedProtocol()); assertEquals("192.168.0.1", msg.sourceAddress()); assertEquals("192.168.0.11", msg.destinationAddress()); assertEquals(56324, msg.sourcePort()); assertEquals(443, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testV2UDPDecode() { byte[] header = new byte[28]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x12; // UDP over IPv4 header[14] = 0x00; // Remaining Bytes header[15] = 0x0c; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- int startChannels = ch.pipeline().names().size(); ch.writeInbound(copiedBuffer(header)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V2, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.UDP4, msg.proxiedProtocol()); assertEquals("192.168.0.1", msg.sourceAddress()); assertEquals("192.168.0.11", msg.destinationAddress()); assertEquals(56324, msg.sourcePort()); assertEquals(443, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testv2IPV6Decode() { byte[] header = new byte[52]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x21; // TCP over IPv6 header[14] = 0x00; // Remaining Bytes header[15] = 0x24; // ----- header[16] = 0x20; // Source Address header[17] = 0x01; // ----- header[18] = 0x0d; // ----- header[19] = (byte) 0xb8; // ----- header[20] = (byte) 0x85; // ----- header[21] = (byte) 0xa3; // ----- header[22] = 0x00; // ----- header[23] = 0x00; // ----- header[24] = 0x00; // ----- header[25] = 0x00; // ----- header[26] = (byte) 0x8a; // ----- header[27] = 0x2e; // ----- header[28] = 0x03; // ----- header[29] = 0x70; // ----- header[30] = 0x73; // ----- header[31] = 0x34; // ----- header[32] = 0x10; // Destination Address header[33] = 0x50; // ----- header[34] = 0x00; // ----- header[35] = 0x00; // ----- header[36] = 0x00; // ----- header[37] = 0x00; // ----- header[38] = 0x00; // ----- header[39] = 0x00; // ----- header[40] = 0x00; // ----- header[41] = 0x05; // ----- header[42] = 0x06; // ----- header[43] = 0x00; // ----- header[44] = 0x30; // ----- header[45] = 0x0c; // ----- header[46] = 0x32; // ----- header[47] = 0x6b; // ----- header[48] = (byte) 0xdc; // Source Port header[49] = 0x04; // ----- header[50] = 0x01; // Destination Port header[51] = (byte) 0xbb; // ----- int startChannels = ch.pipeline().names().size(); ch.writeInbound(copiedBuffer(header)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V2, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.TCP6, msg.proxiedProtocol()); assertEquals("2001:db8:85a3:0:0:8a2e:370:7334", msg.sourceAddress()); assertEquals("1050:0:0:0:5:600:300c:326b", msg.destinationAddress()); assertEquals(56324, msg.sourcePort()); assertEquals(443, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testv2UnixDecode() { byte[] header = new byte[232]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x31; // UNIX_STREAM header[14] = 0x00; // Remaining Bytes header[15] = (byte) 0xd8; // ----- header[16] = 0x2f; // Source Address header[17] = 0x76; // ----- header[18] = 0x61; // ----- header[19] = 0x72; // ----- header[20] = 0x2f; // ----- header[21] = 0x72; // ----- header[22] = 0x75; // ----- header[23] = 0x6e; // ----- header[24] = 0x2f; // ----- header[25] = 0x73; // ----- header[26] = 0x72; // ----- header[27] = 0x63; // ----- header[28] = 0x2e; // ----- header[29] = 0x73; // ----- header[30] = 0x6f; // ----- header[31] = 0x63; // ----- header[32] = 0x6b; // ----- header[33] = 0x00; // ----- header[124] = 0x2f; // Destination Address header[125] = 0x76; // ----- header[126] = 0x61; // ----- header[127] = 0x72; // ----- header[128] = 0x2f; // ----- header[129] = 0x72; // ----- header[130] = 0x75; // ----- header[131] = 0x6e; // ----- header[132] = 0x2f; // ----- header[133] = 0x64; // ----- header[134] = 0x65; // ----- header[135] = 0x73; // ----- header[136] = 0x74; // ----- header[137] = 0x2e; // ----- header[138] = 0x73; // ----- header[139] = 0x6f; // ----- header[140] = 0x63; // ----- header[141] = 0x6b; // ----- header[142] = 0x00; // ----- int startChannels = ch.pipeline().names().size(); ch.writeInbound(copiedBuffer(header)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V2, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.UNIX_STREAM, msg.proxiedProtocol()); assertEquals("/var/run/src.sock", msg.sourceAddress()); assertEquals("/var/run/dest.sock", msg.destinationAddress()); assertEquals(0, msg.sourcePort()); assertEquals(0, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testV2LocalProtocolDecode() { byte[] header = new byte[28]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x20; // v2, cmd=LOCAL header[13] = 0x00; // Unspecified transport protocol and address family header[14] = 0x00; // Remaining Bytes header[15] = 0x0c; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- int startChannels = ch.pipeline().names().size(); ch.writeInbound(copiedBuffer(header)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V2, msg.protocolVersion()); assertEquals(HAProxyCommand.LOCAL, msg.command()); assertEquals(HAProxyProxiedProtocol.UNKNOWN, msg.proxiedProtocol()); assertNull(msg.sourceAddress()); assertNull(msg.destinationAddress()); assertEquals(0, msg.sourcePort()); assertEquals(0, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testV2UnknownProtocolDecode() { byte[] header = new byte[28]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x00; // Unspecified transport protocol and address family header[14] = 0x00; // Remaining Bytes header[15] = 0x0c; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- int startChannels = ch.pipeline().names().size(); ch.writeInbound(copiedBuffer(header)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V2, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.UNKNOWN, msg.proxiedProtocol()); assertNull(msg.sourceAddress()); assertNull(msg.destinationAddress()); assertEquals(0, msg.sourcePort()); assertEquals(0, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testV2WithTLV() { ch = new EmbeddedChannel(new HAProxyMessageDecoder(4)); byte[] header = new byte[236]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x31; // UNIX_STREAM header[14] = 0x00; // Remaining Bytes header[15] = (byte) 0xdc; // ----- header[16] = 0x2f; // Source Address header[17] = 0x76; // ----- header[18] = 0x61; // ----- header[19] = 0x72; // ----- header[20] = 0x2f; // ----- header[21] = 0x72; // ----- header[22] = 0x75; // ----- header[23] = 0x6e; // ----- header[24] = 0x2f; // ----- header[25] = 0x73; // ----- header[26] = 0x72; // ----- header[27] = 0x63; // ----- header[28] = 0x2e; // ----- header[29] = 0x73; // ----- header[30] = 0x6f; // ----- header[31] = 0x63; // ----- header[32] = 0x6b; // ----- header[33] = 0x00; // ----- header[124] = 0x2f; // Destination Address header[125] = 0x76; // ----- header[126] = 0x61; // ----- header[127] = 0x72; // ----- header[128] = 0x2f; // ----- header[129] = 0x72; // ----- header[130] = 0x75; // ----- header[131] = 0x6e; // ----- header[132] = 0x2f; // ----- header[133] = 0x64; // ----- header[134] = 0x65; // ----- header[135] = 0x73; // ----- header[136] = 0x74; // ----- header[137] = 0x2e; // ----- header[138] = 0x73; // ----- header[139] = 0x6f; // ----- header[140] = 0x63; // ----- header[141] = 0x6b; // ----- header[142] = 0x00; // ----- // ---- Additional data (TLV) ---- \\ header[232] = 0x01; // Type header[233] = 0x00; // Remaining bytes header[234] = 0x01; // ----- header[235] = 0x01; // Payload int startChannels = ch.pipeline().names().size(); ch.writeInbound(copiedBuffer(header)); Object msgObj = ch.readInbound(); assertEquals(startChannels - 1, ch.pipeline().names().size()); assertTrue(msgObj instanceof HAProxyMessage); HAProxyMessage msg = (HAProxyMessage) msgObj; assertEquals(HAProxyProtocolVersion.V2, msg.protocolVersion()); assertEquals(HAProxyCommand.PROXY, msg.command()); assertEquals(HAProxyProxiedProtocol.UNIX_STREAM, msg.proxiedProtocol()); assertEquals("/var/run/src.sock", msg.sourceAddress()); assertEquals("/var/run/dest.sock", msg.destinationAddress()); assertEquals(0, msg.sourcePort()); assertEquals(0, msg.destinationPort()); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test(expected = HAProxyProtocolException.class) public void testV2InvalidProtocol() { byte[] header = new byte[28]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x41; // Bogus transport protocol header[14] = 0x00; // Remaining Bytes header[15] = 0x0c; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- ch.writeInbound(copiedBuffer(header)); } @Test(expected = HAProxyProtocolException.class) public void testV2MissingParams() { byte[] header = new byte[26]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x11; // TCP over IPv4 header[14] = 0x00; // Remaining Bytes header[15] = 0x0a; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- ch.writeInbound(copiedBuffer(header)); } @Test(expected = HAProxyProtocolException.class) public void testV2InvalidCommand() { byte[] header = new byte[28]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x22; // v2, Bogus command header[13] = 0x11; // TCP over IPv4 header[14] = 0x00; // Remaining Bytes header[15] = 0x0c; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- ch.writeInbound(copiedBuffer(header)); } @Test(expected = HAProxyProtocolException.class) public void testV2InvalidVersion() { byte[] header = new byte[28]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x31; // Bogus version, cmd=PROXY header[13] = 0x11; // TCP over IPv4 header[14] = 0x00; // Remaining Bytes header[15] = 0x0c; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- ch.writeInbound(copiedBuffer(header)); } @Test(expected = HAProxyProtocolException.class) public void testV2HeaderTooLong() { ch = new EmbeddedChannel(new HAProxyMessageDecoder(0)); byte[] header = new byte[248]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY header[13] = 0x11; // TCP over IPv4 header[14] = 0x00; // Remaining Bytes header[15] = (byte) 0xe8; // ----- header[16] = (byte) 0xc0; // Source Address header[17] = (byte) 0xa8; // ----- header[18] = 0x00; // ----- header[19] = 0x01; // ----- header[20] = (byte) 0xc0; // Destination Address header[21] = (byte) 0xa8; // ----- header[22] = 0x00; // ----- header[23] = 0x0b; // ----- header[24] = (byte) 0xdc; // Source Port header[25] = 0x04; // ----- header[26] = 0x01; // Destination Port header[27] = (byte) 0xbb; // ----- ch.writeInbound(copiedBuffer(header)); } @Test public void testV2IncompleteHeader() { byte[] header = new byte[13]; header[0] = 0x0D; // Binary Prefix header[1] = 0x0A; // ----- header[2] = 0x0D; // ----- header[3] = 0x0A; // ----- header[4] = 0x00; // ----- header[5] = 0x0D; // ----- header[6] = 0x0A; // ----- header[7] = 0x51; // ----- header[8] = 0x55; // ----- header[9] = 0x49; // ----- header[10] = 0x54; // ----- header[11] = 0x0A; // ----- header[12] = 0x21; // v2, cmd=PROXY ch.writeInbound(copiedBuffer(header)); assertNull(ch.readInbound()); assertFalse(ch.finish()); } @Test public void testDetectProtocol() { final ByteBuf validHeaderV1 = copiedBuffer("PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n", CharsetUtil.US_ASCII); ProtocolDetectionResult<HAProxyProtocolVersion> result = HAProxyMessageDecoder.detectProtocol(validHeaderV1); assertEquals(ProtocolDetectionState.DETECTED, result.state()); assertEquals(HAProxyProtocolVersion.V1, result.detectedProtocol()); validHeaderV1.release(); final ByteBuf invalidHeader = copiedBuffer("Invalid header", CharsetUtil.US_ASCII); result = HAProxyMessageDecoder.detectProtocol(invalidHeader); assertEquals(ProtocolDetectionState.INVALID, result.state()); assertNull(result.detectedProtocol()); invalidHeader.release(); final ByteBuf validHeaderV2 = buffer(); validHeaderV2.writeByte(0x0D); validHeaderV2.writeByte(0x0A); validHeaderV2.writeByte(0x0D); validHeaderV2.writeByte(0x0A); validHeaderV2.writeByte(0x00); validHeaderV2.writeByte(0x0D); validHeaderV2.writeByte(0x0A); validHeaderV2.writeByte(0x51); validHeaderV2.writeByte(0x55); validHeaderV2.writeByte(0x49); validHeaderV2.writeByte(0x54); validHeaderV2.writeByte(0x0A); result = HAProxyMessageDecoder.detectProtocol(validHeaderV2); assertEquals(ProtocolDetectionState.DETECTED, result.state()); assertEquals(HAProxyProtocolVersion.V2, result.detectedProtocol()); validHeaderV2.release(); final ByteBuf incompleteHeader = buffer(); incompleteHeader.writeByte(0x0D); incompleteHeader.writeByte(0x0A); incompleteHeader.writeByte(0x0D); incompleteHeader.writeByte(0x0A); incompleteHeader.writeByte(0x00); incompleteHeader.writeByte(0x0D); incompleteHeader.writeByte(0x0A); result = HAProxyMessageDecoder.detectProtocol(incompleteHeader); assertEquals(ProtocolDetectionState.NEEDS_MORE_DATA, result.state()); assertNull(result.detectedProtocol()); incompleteHeader.release(); } }