0 votes
by (150 points)

Hi Lukas,

Just wanted to say that your proxy works PERFECTLY! We are using it with a proprietary app for which we don't have the source code anymore, and it seems to work exactly as on a straight Telnet server. Wanted to thank you a lot for that.

Now I'm also trying it with a 3rd party emulator (KEA) that has similar limitations (no SSH) and am facing a strange issue with the LocalEcho. Even though I set LocalEcho to false in the emulator, as soon as I connect that setting turns back to true. This doesn't happen when I use putty.

Any idea why this could be happening?

Best wishes,


related to an answer for: Create a Telnet to SSH proxy

2 Answers

0 votes
by (70.4k points)

Nice that the proxy works for you.

According to the LocalEcho issue with KEA I have one idea:

In case of disabled local echo, the Telnet client typically sends telnet option DO_ECHO to the remote host and the remote host typically responds with telnet option WILL_ECHO.

However, the proxy does not negotiate any telnet options, so the client always receive WONT_ECHO as reply. In this case, the client probably thinks that it is communicating with a server not capable to echo input, so it "falsely" turn LocalEcho back to true.
The PuTTY has three values for LocalEcho = on, off, auto. The described behavior corresponds to the auto setting.

With API for telnet option negotiation, it would be easy to handle this case. Unfortunately, we don't have such API yet.
The only option in this case is to replace WONT_ECHO to WILL_ECHO when proxying data (in TelnetServerFactory.cs file):

WONT_ECHO = { 0xFF, 0xFC, 0x01 }
WILL_ECHO = { 0xFF, 0xFB, 0x01 }
0 votes
by (70.4k points)

I have added the data analyzer routine to the TelnetServerFactory.cs file and it is working fine with PuTTY. The PuTTY is now able to automatically detect the LocalEcho settings, so I don't need to force it off manually. I believe, this will help with KEA emulator as well.

Update the DirectSocket.Send() method in the TelnetServerFactory.cs file like this:

public int Send(byte[] buffer, int offset, int count, SocketFlags socketFlags)
    int idx = IndexOf(WONT_ECHO, buffer, offset, count);
    if (idx >= 0)
        buffer[idx + 1] = 0xFB;

    return _inner.Send(buffer, offset, count, socketFlags);

private int IndexOf(byte[] value, byte[] buffer, int offset, int count)
    int maxOffset = offset + count;
    while (count >= value.Length)
        int idx = Array.IndexOf(buffer, value[0], offset, count);
        if (idx < 0)
            return -1;

        bool found = IsValueAt_SkipFirst(value, buffer, idx, maxOffset);
        if (found)
            return idx;

        int skip = idx + 1 - offset;
        offset += skip;
        count -= skip;
    return -1;

private bool IsValueAt_SkipFirst(byte[] value, byte[] buffer, int idx, int maxIdx)
    for (int i = 1; i < value.Length; i++, idx++)
        if (idx >= maxIdx || value[i] != buffer[idx])
            return false;
    return true;

And also define this:

private static readonly byte[] WONT_ECHO = { 0xFF, 0xFC, 0x01 };
by (150 points)
Wonderful! That works perfectly!

Thanks a lot for your support. No way I could have found this by myself.
by (70.4k points)
Nice, you are most welcome.