0433c61674
Motivation: Sometimes it is useful to detect if a ByteBuf contains a HAProxy header, for example if you want to write something like the PortUnification example. Modifications: - Add ProtocolDetectionResult which can be used as a return type for detecting different protocol. - Add new method which allows to detect HA Proxy messages. Result: Easier to detect protocol.
950 lines
35 KiB
Java
950 lines
35 KiB
Java
/*
|
|
* 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 unkown = 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(unkown));
|
|
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(unkown));
|
|
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();
|
|
}
|
|
}
|