Details

    • Type: New Feature
    • Status: Resolved
    • Priority: Minor
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.6.0
    • Labels:
      None

      Description

      Load Balancing and other higher availability services are included between client and SSHD server and works on TCP level. This makes an actual client address shown in the SSHD server to be a load balancer address, not a real client address. This makes it hard to use SSHD for multi-node production scenarios.

      There are several ways to solve the issue.
      The first one is to include complex TCP routing to have specific packets delivered correctly. This is too hard to setup

      It looks like using The PROXY Protocol is the possible, easy and more or less standard way to pass actual client/server addresses to the server over TCP. The protocol is implemented by a number of TCP-based servers (including nginx, Amazon Load Balancer, Apache, github enterprise, see the link below for details)

      Protocol specification is here
      http://www.haproxy.org/download/1.6/doc/proxy-protocol.txt

        Activity

        Hide
        lgoldstein Goldstein Lyor added a comment -

        Feel free to go ahead and publish a pull request for it - see https://github.com/apache/mina-sshd/commit/ec56d2ab6c0a0923d8310976530e7c8bf1144d13 for a mechanism I added for this very purpose. Basically, you need to write a ClientProxyConnector and ServerProxyAcceptor that implement the protocol you describe. If you do go ahead with this, then please open a separate module folder for it - e.g., sshd-haproxy (similar to sshd-ldap) since this is a "plugin" that one can use rather than a core feature.

        Show
        lgoldstein Goldstein Lyor added a comment - Feel free to go ahead and publish a pull request for it - see https://github.com/apache/mina-sshd/commit/ec56d2ab6c0a0923d8310976530e7c8bf1144d13 for a mechanism I added for this very purpose. Basically, you need to write a ClientProxyConnector and ServerProxyAcceptor that implement the protocol you describe. If you do go ahead with this, then please open a separate module folder for it - e.g., sshd-haproxy (similar to sshd-ldap ) since this is a "plugin" that one can use rather than a core feature.
        Hide
        tonyicemanz Tony Bussieres added a comment -

        Eugene Petrenko
        I've ran in the same situation. I needed to get the real IP of the client that connect to a server behind a load balancer that supports the PROXY protocol server.
        I have found this JIRA and decided to implement it.

        Feel free to use / integrate : https://gist.github.com/codingtony/a8684c9ffa08ad56899f94d3b6c2a040

        If can find some time, I can give a try to add it as a module.

        Show
        tonyicemanz Tony Bussieres added a comment - Eugene Petrenko I've ran in the same situation. I needed to get the real IP of the client that connect to a server behind a load balancer that supports the PROXY protocol server. I have found this JIRA and decided to implement it. Feel free to use / integrate : https://gist.github.com/codingtony/a8684c9ffa08ad56899f94d3b6c2a040 If can find some time, I can give a try to add it as a module.
        Hide
        jonnyzzz Eugene Petrenko added a comment -

        I have an implementation in Kotlin for that. I can share it, if it helps

        Show
        jonnyzzz Eugene Petrenko added a comment - I have an implementation in Kotlin for that. I can share it, if it helps
        Hide
        tonyicemanz Tony Bussieres added a comment -

        Sure, can you send a link to the code ?

        Show
        tonyicemanz Tony Bussieres added a comment - Sure, can you send a link to the code ?
        Hide
        jonnyzzz Eugene Petrenko added a comment -

        Let me move the code somewhere to a public place. Will do it shortly

        Show
        jonnyzzz Eugene Petrenko added a comment - Let me move the code somewhere to a public place. Will do it shortly
        Hide
        jonnyzzz Eugene Petrenko added a comment -

        I created an inheritor of `ServerSessionImpl` and override the method `readIdentification`:

         @Throws(IOException::class)
          override fun readIdentification(buffer: Buffer): Boolean {
            val rpos = buffer.rpos()
            if (!readIdentificationEx(buffer)) {
              buffer.rpos(rpos)
              return false
            } else {
              return true
            }
          }
        
          private fun readIdentificationEx(buffer: Buffer): Boolean {
            val r = ProxyProtocolReader.parsePROXY(buffer.wrap())
            when(r) {
              is ProxyProtocolReader.Result.Error -> {
                val msg = "Unsupported PROXY PROTOCOL header: " + r.message
                log.warn(msg + ". Connection will be closed")
                ioSession.write(ByteArrayBuffer(("\n" + msg + "\n").toByteArray(StandardCharsets.UTF_8))).addListener { close(true) }
                throw object:SshException(msg){}
              }
        
              is ProxyProtocolReader.Result.NotEnoughData -> {
                //wait for more data to be available
                return false
              }
        
              is ProxyProtocolReader.Result.Parsed -> {
                //instantly update session IP, can be called several times here
                myLogger.setSessionIP(this, r.fromIP)
        
                //Let SSHD parse header. Lookup if necessary
                return super.readIdentification(buffer)
              }
        
              is ProxyProtocolReader.Result.Empty -> {
                //instantly update session IP, can be called several times here
                myLogger.setSessionIP(this, "PROXY_N/A")
        
                //Let SSHD parse header. Lookup if necessary
                return super.readIdentification(buffer)
              }
            }
          }
        
        fun Buffer.wrap() = object : ProxyProtocolReader.Input {
          override val available: Int
            get() = available()
        
          override val nextChar: Char
            get() = uByte.toChar()
        }
        
        
        object ProxyProtocolReader {
          sealed class Result {
            object NotEnoughData : Result()
            class Error(val message: String) : Result()
            object Empty : Result()
            class Parsed(val fromIP: String) : Result() {
              override fun toString(): String {
                return "Parsed(fromIP='$fromIP')"
              }
            }
          }
        
          interface Input {
            val available: Int
            val nextChar: Char
          }
        
          @JvmStatic
          fun parsePROXY(b: Input): Result =
            try {
              parsePROXYImpl(b)
            } catch (t : Throwable) {
              LoggerFactory.getLogger(javaClass).warn("Crashed parsing PROXY header. ${t.message}", t)
              Result.Error("Crashed parsing header. ${t.message}")
            }
        
        
          private fun parsePROXYImpl(b: Input): Result {
            if (b.available <= 8) return Result.NotEnoughData;
        
            val proxy = readWord(b, 5)
            when (proxy) {
              is WordResult.NotEnoughData -> return Result.NotEnoughData;
              is WordResult.Error -> return Result.Error(proxy.message)
              is WordResult.Parsed -> {
                if (proxy.end) return Result.Error("Unexpected end of PROXY header")
                if (proxy.x != "PROXY") Result.Error("PROXY expected")
              }
            }
        
            val type = readWord(b, 7)
            when (type) {
              is WordResult.NotEnoughData -> return Result.NotEnoughData;
              is WordResult.Error -> return Result.Error(type.message)
              is WordResult.Parsed -> {
                if (type.end) return Result.Empty
              }
            }
        
            val source = readWord(b, 40)
            when (source) {
              is WordResult.NotEnoughData -> return Result.NotEnoughData;
              is WordResult.Error -> return Result.Error(source.message)
              is WordResult.Parsed -> {
                if (source.end) return Result.Parsed(source.x)
              }
            }
        
            for (x in arrayOf(1, 2, 3)) {
              val r = readWord(b, 40)
              when (r) {
                is WordResult.NotEnoughData -> return Result.NotEnoughData;
                is WordResult.Error -> return Result.Error(r.message)
                is WordResult.Parsed -> {
                  if (r.end) return Result.Parsed(source.x)
                }
              }
            }
            return Result.Error("Too long PROXY header")
          }
        
        
          private sealed class WordResult {
            class Parsed(val x: String, val end: Boolean) : WordResult()
            class Error(val message: String) : WordResult()
            object NotEnoughData : WordResult()
          }
        
          private fun readWord(b: Input, maxSize: Int): WordResult {
            val sb = StringBuilder()
        
            while (b.available > 0) {
              val next = b.nextChar
        
              if (next == '\r') {
                if (b.nextChar != '\n') {
                  return WordResult.Error("\\r not followed by \\n")
                }
        
                return WordResult.Parsed(sb.toString(), true)
              }
        
              if (next == ' ') {
                return WordResult.Parsed(sb.toString(), false);
              }
        
              sb.append(next.toChar())
        
              if (sb.length > maxSize) {
                return WordResult.Error("Too long string")
              }
            }
        
            return WordResult.NotEnoughData
          }
        
        
          /// PROXY [TCP4|TCP6|UNKNOWN] [IP4/IP6 source address] [IP4/IP6 destination address] [source port] [destination port]\r\n
        
        
        }

        Also I have a test for PROXY header

        @TestFor(issues = "VCS-411")
        public class PROXYProtocolReaderTest {
          @NotNull
          private ProxyProtocolReader.Input input(final byte[] input) {
            return new ProxyProtocolReader.Input() {
              private final ByteArrayInputStream bis = new ByteArrayInputStream(input);
              @Override
              public int getAvailable() {
                return bis.available();
              }
        
              @Override
              public char getNextChar() {
                int r = bis.read();
                if (r < 0) throw new Error("EOF");
                return (char)(r & 0xff);
              }
            };
          }
        
          private void doFailureTest(@NotNull final String m) {
            byte[] input = (m + "HOHOHO").getBytes(Charsets.UTF_8);
            final ProxyProtocolReader.Input b = input(input);
        
            ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(b);
            Assert.assertTrue(result instanceof ProxyProtocolReader.Result.Error);
        
            System.out.println(((ProxyProtocolReader.Result.Error)result).getMessage());
          }
        
          private void doNotEnoughDataTest(@NotNull final String m) {
            byte[] input = m.getBytes(Charsets.UTF_8);
            ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(input(input));
            Assert.assertTrue(result instanceof ProxyProtocolReader.Result.NotEnoughData);
          }
        
          private void doHeaderBlockSuccessfully(@NotNull final String m, @NotNull final String expectedIP) {
            byte[] input = (m + "HOHOHO").getBytes(Charsets.UTF_8);
        
            for (int i = 1; i < m.length() - 1; i++) {
              final ProxyProtocolReader.@NotNull Input b = input(Arrays.copyOfRange(input, 0, i));
        
              ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(b);
              Assert.assertTrue(result == ProxyProtocolReader.Result.NotEnoughData.INSTANCE);
            }
        
            ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(input(input));
        
            if (expectedIP.equals("UNKNOWN")) {
              Assert.assertTrue(result instanceof ProxyProtocolReader.Result.Empty);
            } else {
              Assert.assertTrue(result instanceof ProxyProtocolReader.Result.Parsed);
              String IP = ((ProxyProtocolReader.Result.Parsed) result).getFromIP();
              Assert.assertEquals(expectedIP, IP);
            }
          }
        
          @Test
          public void test_empty() {
            doNotEnoughDataTest("");
          }
        
          @Test
          public void test_P() {
            doNotEnoughDataTest("P");
          }
        
          @Test
          public void test_PROX() {
            doNotEnoughDataTest("PROX");
          }
        
          @Test
          public void test_PROXY_() {
            doNotEnoughDataTest("PROXY ");
          }
        
          @Test
          public void test_PROXY_IP6() {
            doNotEnoughDataTest("PROXY TCP6");
          }
        
          @Test
          public void test_PROXY_IP6_() {
            doNotEnoughDataTest("PROXY TCP6 ");
          }
        
          @Test
          public void test_PROXY_IP6_IP() {
            doNotEnoughDataTest("PROXY TCP6 123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IPnl() {
            doHeaderBlockSuccessfully("PROXY TCP6 123.231.23.23\r\n", "123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IP_nl() {
            doHeaderBlockSuccessfully("PROXY TCP6 123.231.23.23 \r\n", "123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IP_IPnl() {
            doHeaderBlockSuccessfully("PROXY TCP6 123.231.23.23 22.33.44.11\r\n", "123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IP_IP_nl() {
            doHeaderBlockSuccessfully("PROXY TCP6 123.231.23.23 22.33.44.11 \r\n", "123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IP_IP_pnl() {
            doHeaderBlockSuccessfully("PROXY TCP6 123.231.23.23 22.33.44.11 222\r\n", "123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IP_IP_p_nl() {
            doHeaderBlockSuccessfully("PROXY TCP6 123.231.23.23 22.33.44.11 222 \r\n", "123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IP_IP_p_pnl() {
            doHeaderBlockSuccessfully("PROXY TCP6 123.231.23.23 22.33.44.11 222 333\r\n", "123.231.23.23");
          }
        
          @Test
          public void test_PROXY_IP6_IP_IP_p_p_nl() {
            doFailureTest("PROXY TCP6 123.231.23.23 22.33.44.11 222 333 \r\n");
          }
        
          @Test
          public void test_PROXY_IP6_IP_IP_p_p_Enl() {
            doFailureTest("PROXY TCP6 123.231.23.23 22.33.44.11 222 333 EEE\r\n");
          }
        
          @Test
          public void test_invalid_TTT() {
            doFailureTest("TTT");
          }
        
          @Test
          public void test_invalid_TooLong() {
            doFailureTest("AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/NH/Now+6fSnESebaG4wzaYQWA1b");
          }
        
          @Test
          public void test_invalid_TooLong2() {
            doFailureTest("PROXY AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/NH/Now+6fSnESebaG4wzaYQWA1b");
          }
        
          @Test
          public void test_invalid_TooLong3() {
            doFailureTest("PROXY A A A A F P H g K 1 M e V 9 z N n o k 3 p w N J h C d 8 S O N q M g A A A A l i d W l s Z H V z Z\r\n");
          }
        
          @Test
          public void test_ip4() {
            doHeaderBlockSuccessfully("PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n", "255.255.255.255");
          }
        
          @Test
          public void test_ip4_2() {
            doHeaderBlockSuccessfully("PROXY TCP4 255.255.255.255\r\n", "255.255.255.255");
          }
        
          @Test
          public void test_ip4_example() {
            doHeaderBlockSuccessfully("PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n", "192.168.0.1");
          }
        
          @Test
          public void test_ip6() {
            doHeaderBlockSuccessfully("PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n", "ffff:f...f:ffff");
          }
        
          @Test
          public void test_unknown() {
            doHeaderBlockSuccessfully("PROXY UNKNOWN\r\n", "UNKNOWN");
          }
        
          @Test
          public void test_unknown_v6() {
            doHeaderBlockSuccessfully("PROXY UNKNOWN ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n", "ffff:f...f:ffff");
          }
        
        }

        Hope this helps

        Show
        jonnyzzz Eugene Petrenko added a comment - I created an inheritor of `ServerSessionImpl` and override the method `readIdentification`: @Throws(IOException::class) override fun readIdentification(buffer: Buffer): Boolean { val rpos = buffer.rpos() if (!readIdentificationEx(buffer)) { buffer.rpos(rpos) return false } else { return true } } private fun readIdentificationEx(buffer: Buffer): Boolean { val r = ProxyProtocolReader.parsePROXY(buffer.wrap()) when(r) { is ProxyProtocolReader.Result.Error -> { val msg = "Unsupported PROXY PROTOCOL header: " + r.message log.warn(msg + ". Connection will be closed" ) ioSession.write(ByteArrayBuffer(( "\n" + msg + "\n" ).toByteArray(StandardCharsets.UTF_8))).addListener { close( true ) } throw object:SshException(msg){} } is ProxyProtocolReader.Result.NotEnoughData -> { //wait for more data to be available return false } is ProxyProtocolReader.Result.Parsed -> { //instantly update session IP, can be called several times here myLogger.setSessionIP( this , r.fromIP) //Let SSHD parse header. Lookup if necessary return super .readIdentification(buffer) } is ProxyProtocolReader.Result.Empty -> { //instantly update session IP, can be called several times here myLogger.setSessionIP( this , "PROXY_N/A" ) //Let SSHD parse header. Lookup if necessary return super .readIdentification(buffer) } } } fun Buffer.wrap() = object : ProxyProtocolReader.Input { override val available: Int get() = available() override val nextChar: Char get() = uByte.toChar() } object ProxyProtocolReader { sealed class Result { object NotEnoughData : Result() class Error(val message: String ) : Result() object Empty : Result() class Parsed(val fromIP: String ) : Result() { override fun toString(): String { return "Parsed(fromIP='$fromIP')" } } } interface Input { val available: Int val nextChar: Char } @JvmStatic fun parsePROXY(b: Input): Result = try { parsePROXYImpl(b) } catch (t : Throwable) { LoggerFactory.getLogger(javaClass).warn( "Crashed parsing PROXY header. ${t.message}" , t) Result.Error( "Crashed parsing header. ${t.message}" ) } private fun parsePROXYImpl(b: Input): Result { if (b.available <= 8) return Result.NotEnoughData; val proxy = readWord(b, 5) when (proxy) { is WordResult.NotEnoughData -> return Result.NotEnoughData; is WordResult.Error -> return Result.Error(proxy.message) is WordResult.Parsed -> { if (proxy.end) return Result.Error( "Unexpected end of PROXY header" ) if (proxy.x != "PROXY" ) Result.Error( "PROXY expected" ) } } val type = readWord(b, 7) when (type) { is WordResult.NotEnoughData -> return Result.NotEnoughData; is WordResult.Error -> return Result.Error(type.message) is WordResult.Parsed -> { if (type.end) return Result.Empty } } val source = readWord(b, 40) when (source) { is WordResult.NotEnoughData -> return Result.NotEnoughData; is WordResult.Error -> return Result.Error(source.message) is WordResult.Parsed -> { if (source.end) return Result.Parsed(source.x) } } for (x in arrayOf(1, 2, 3)) { val r = readWord(b, 40) when (r) { is WordResult.NotEnoughData -> return Result.NotEnoughData; is WordResult.Error -> return Result.Error(r.message) is WordResult.Parsed -> { if (r.end) return Result.Parsed(source.x) } } } return Result.Error( "Too long PROXY header" ) } private sealed class WordResult { class Parsed(val x: String , val end: Boolean ) : WordResult() class Error(val message: String ) : WordResult() object NotEnoughData : WordResult() } private fun readWord(b: Input, maxSize: Int): WordResult { val sb = StringBuilder() while (b.available > 0) { val next = b.nextChar if (next == '\r') { if (b.nextChar != '\n') { return WordResult.Error( "\\r not followed by \\n" ) } return WordResult.Parsed(sb.toString(), true ) } if (next == ' ') { return WordResult.Parsed(sb.toString(), false ); } sb.append(next.toChar()) if (sb.length > maxSize) { return WordResult.Error( "Too long string" ) } } return WordResult.NotEnoughData } /// PROXY [TCP4|TCP6|UNKNOWN] [IP4/IP6 source address] [IP4/IP6 destination address] [source port] [destination port]\r\n } Also I have a test for PROXY header @TestFor(issues = "VCS-411" ) public class PROXYProtocolReaderTest { @NotNull private ProxyProtocolReader.Input input( final byte [] input) { return new ProxyProtocolReader.Input() { private final ByteArrayInputStream bis = new ByteArrayInputStream(input); @Override public int getAvailable() { return bis.available(); } @Override public char getNextChar() { int r = bis.read(); if (r < 0) throw new Error( "EOF" ); return ( char )(r & 0xff); } }; } private void doFailureTest(@NotNull final String m) { byte [] input = (m + "HOHOHO" ).getBytes(Charsets.UTF_8); final ProxyProtocolReader.Input b = input(input); ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(b); Assert.assertTrue(result instanceof ProxyProtocolReader.Result.Error); System .out.println(((ProxyProtocolReader.Result.Error)result).getMessage()); } private void doNotEnoughDataTest(@NotNull final String m) { byte [] input = m.getBytes(Charsets.UTF_8); ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(input(input)); Assert.assertTrue(result instanceof ProxyProtocolReader.Result.NotEnoughData); } private void doHeaderBlockSuccessfully(@NotNull final String m, @NotNull final String expectedIP) { byte [] input = (m + "HOHOHO" ).getBytes(Charsets.UTF_8); for ( int i = 1; i < m.length() - 1; i++) { final ProxyProtocolReader.@NotNull Input b = input(Arrays.copyOfRange(input, 0, i)); ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(b); Assert.assertTrue(result == ProxyProtocolReader.Result.NotEnoughData.INSTANCE); } ProxyProtocolReader.Result result = ProxyProtocolReader.parsePROXY(input(input)); if (expectedIP.equals( "UNKNOWN" )) { Assert.assertTrue(result instanceof ProxyProtocolReader.Result.Empty); } else { Assert.assertTrue(result instanceof ProxyProtocolReader.Result.Parsed); String IP = ((ProxyProtocolReader.Result.Parsed) result).getFromIP(); Assert.assertEquals(expectedIP, IP); } } @Test public void test_empty() { doNotEnoughDataTest(""); } @Test public void test_P() { doNotEnoughDataTest( "P" ); } @Test public void test_PROX() { doNotEnoughDataTest( "PROX" ); } @Test public void test_PROXY_() { doNotEnoughDataTest( "PROXY " ); } @Test public void test_PROXY_IP6() { doNotEnoughDataTest( "PROXY TCP6" ); } @Test public void test_PROXY_IP6_() { doNotEnoughDataTest( "PROXY TCP6 " ); } @Test public void test_PROXY_IP6_IP() { doNotEnoughDataTest( "PROXY TCP6 123.231.23.23" ); } @Test public void test_PROXY_IP6_IPnl() { doHeaderBlockSuccessfully( "PROXY TCP6 123.231.23.23\r\n" , "123.231.23.23" ); } @Test public void test_PROXY_IP6_IP_nl() { doHeaderBlockSuccessfully( "PROXY TCP6 123.231.23.23 \r\n" , "123.231.23.23" ); } @Test public void test_PROXY_IP6_IP_IPnl() { doHeaderBlockSuccessfully( "PROXY TCP6 123.231.23.23 22.33.44.11\r\n" , "123.231.23.23" ); } @Test public void test_PROXY_IP6_IP_IP_nl() { doHeaderBlockSuccessfully( "PROXY TCP6 123.231.23.23 22.33.44.11 \r\n" , "123.231.23.23" ); } @Test public void test_PROXY_IP6_IP_IP_pnl() { doHeaderBlockSuccessfully( "PROXY TCP6 123.231.23.23 22.33.44.11 222\r\n" , "123.231.23.23" ); } @Test public void test_PROXY_IP6_IP_IP_p_nl() { doHeaderBlockSuccessfully( "PROXY TCP6 123.231.23.23 22.33.44.11 222 \r\n" , "123.231.23.23" ); } @Test public void test_PROXY_IP6_IP_IP_p_pnl() { doHeaderBlockSuccessfully( "PROXY TCP6 123.231.23.23 22.33.44.11 222 333\r\n" , "123.231.23.23" ); } @Test public void test_PROXY_IP6_IP_IP_p_p_nl() { doFailureTest( "PROXY TCP6 123.231.23.23 22.33.44.11 222 333 \r\n" ); } @Test public void test_PROXY_IP6_IP_IP_p_p_Enl() { doFailureTest( "PROXY TCP6 123.231.23.23 22.33.44.11 222 333 EEE\r\n" ); } @Test public void test_invalid_TTT() { doFailureTest( "TTT" ); } @Test public void test_invalid_TooLong() { doFailureTest( "AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/NH/Now+6fSnESebaG4wzaYQWA1b" ); } @Test public void test_invalid_TooLong2() { doFailureTest( "PROXY AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/NH/Now+6fSnESebaG4wzaYQWA1b" ); } @Test public void test_invalid_TooLong3() { doFailureTest( "PROXY A A A A F P H g K 1 M e V 9 z N n o k 3 p w N J h C d 8 S O N q M g A A A A l i d W l s Z H V z Z\r\n" ); } @Test public void test_ip4() { doHeaderBlockSuccessfully( "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n" , "255.255.255.255" ); } @Test public void test_ip4_2() { doHeaderBlockSuccessfully( "PROXY TCP4 255.255.255.255\r\n" , "255.255.255.255" ); } @Test public void test_ip4_example() { doHeaderBlockSuccessfully( "PROXY TCP4 192.168.0.1 192.168.0.11 56324 443\r\n" , "192.168.0.1" ); } @Test public void test_ip6() { doHeaderBlockSuccessfully( "PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n" , "ffff:f...f:ffff" ); } @Test public void test_unknown() { doHeaderBlockSuccessfully( "PROXY UNKNOWN\r\n" , "UNKNOWN" ); } @Test public void test_unknown_v6() { doHeaderBlockSuccessfully( "PROXY UNKNOWN ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n" , "ffff:f...f:ffff" ); } } Hope this helps
        Show
        lgoldstein Goldstein Lyor added a comment - See https://github.com/apache/mina-sshd/commit/655e7dbd7fcb26956e90575bcfb66a0679ccdd48

          People

          • Assignee:
            lgoldstein Goldstein Lyor
            Reporter:
            jonnyzzz Eugene Petrenko
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development