How to solve AireOS raw Telnet mode problem

Given that telnet sends data in clear text, we prefer to use SSH instead of telnet for security reasons. This article does not recommend using telnet to connect to AireOS WLC, but hopes that my analysis process will bring some benefits to viewers.

Problem

When we try to access AireOS WLC via Python telnetlib module, it will not be accessible. The error message is “Raw mode will not be supported, Closing connection”. Using Google, I saw that this problem was discussed as early as 2014(link1, link2), but unfortunately the solution did not work.

Refer to the official documentation, we can understand that AireOS WLC does not support raw Telnet mode.

The controller does not support raw Telnet mode.

https://www.cisco.com/c/en/us/td/docs/wireless/controller/8-1/configuration-guide/b_cg81/b_cg81_chapter_011.html

raw Telnet mode

There is a connection type called Raw on the putty terminal.

Refer to the official documentation, we can understand that the Raw connection type not using real telnet protocol, but a TCP connection using port 23.

Although the Unix telnet program provides this functionality, the protocol being used is not really Telnet. Really there is no actual protocol at all

https://documentation.help/PuTTY/using-rawprot.html

The fourth protocol, Raw, is not used for interactive login sessions; you would usually use this for debugging other Internet services

https://documentation.help/PuTTY/gs-insecure.html

Assume that WLC has a mechanism to determine whether the telnet client uses the real telnet protocol or raw Telnet mode.

Analysis

Let’s see what is the difference between the real telnet protocol and raw Telnet mode.

In the working case(via putty telnet mode), the first packet sent by the telnet client contains information such as SUPPRESS-GO-AHEAD and ECHO.

But in non-working case(via telnetlib module), the telnet client sends data directly.

Refer to the rfc854, we can understand that telnet uses “DO, DON’T, WILL, WON’T” to negotiate, and rfc858 defines the SUPPRESS-GO-AHEAD option.

but structured within the TELNET Protocol are various “options” that will be sanctioned and may be used with the “DO, DON’T, WILL, WON’T” structure (discussed below) to allow a user and server to agree to use a more elaborate (or perhaps just different) set of conventions for their TELNET connection.

https://tools.ietf.org/html/rfc854.html

Here is a really detailed explanation for the telnet negotiation process.

Solution

My next plan is let telnetlib send the SUPPRESS-GO-AHEAD option to negotiate telnet. Now Check the telnetlib source code, to understand the defined Telnet protocol characters.

I tried to send the SUPPRESS-GO-AHEAD option with the following code, but it did not work. I saw that the SUPPRESS-GO-AHEAD option was never sent to the server(in packet capture).

tn.write(telnetlib.IAC + telnetlib.WILL + telnetlib.SGA)

Fortunately I saw a solution in stackoverflow, the key point is get_socket().

import telnetlib
import time

HOST = "10.106.66.201"
user = "admin"
password = "test123"
command = "show interface summary"

tn = telnetlib.Telnet(HOST)

def write_raw_sequence(tn, seq):
    sock = tn.get_socket()
    if sock is not None:
        sock.send(seq)

write_raw_sequence(tn, telnetlib.IAC + telnetlib.WILL + telnetlib.SGA)

tn.write(user.encode('ascii') + b"\n")
tn.write(password.encode('ascii') + b"\n")
tn.write(command.encode('ascii') + b"\n")
time.sleep(1)
data = tn.read_very_eager().decode('ascii')

print(data)

Now the SUPPRESS-GO-AHEAD option was successfully sent, and the WLC did not refuse the connection, it works like a charm!

Other

Another solution is to use the telnetlib3 module. Here is a simple example.

import asyncio
import telnetlib3

host, port, username, password, command = '10.106.66.201', 23, 'admin', 'test123', 'show interface summary'


@asyncio.coroutine
def shell(reader, writer):

    while True:

        outp = yield from reader.read(1024)
        writer.write(username + '\n')
        writer.write(password + '\n')
        writer.write(command + '\n')

        if not outp:
            break
        elif 'Number of Interfaces' in outp:
            break

    print(outp)


loop = asyncio.get_event_loop()
coro = telnetlib3.open_connection(host, port, shell=shell)
reader, writer = loop.run_until_complete(coro)
loop.run_until_complete(writer.protocol.waiter_closed)

But telnetlib3 has not been widely used, there is no much information for reference, except official document.

Personally, I prefer netmiko, it is more secure (SSH) and easy to use. For example, netmiko will automatically execute “config paging disable” when connecting, which is really useful for collecting information such as “show tech”.

I hope this article is helpful to those who need to use telnetlib to connect to WLC with special needs.

References

telnetlib
telnetlib3
rfc854
rfc858
PuTTY User Manual
TELNET Negotiation
Restrictions on Telnet and SSH
How to disable telnet echo in python telnetlib?

You may also like...

2 Responses

  1. Nagyfenyvesi Viktor says:

    Thank you very much for the solution, was struggling for a week searching online to solve the problem, needed to install a virtual WLC and wireshark, then I found your post when I was searching for “Raw mode will not be supported”.

    Great help, I hope others will find your site more easily 🙂

  2. Peter Thomas says:

    Thanks also for the solution –

Leave a Reply

Your email address will not be published. Required fields are marked *