One day I was digging in my router / firewall web administration page and I found
a configuration setting related to SNMP (Simple Network Management Protocol). So I had a look at what was available through SNMP and found my router also has
a complete CLI administration interface (CLI stands for Command Line Interface).
Then, some times after, I was in the need of resetting router manually, without
physically having access to it.
Telnet command line was very helpful with this.
These are simple steps I had to
accomplish to reset my router:
- open a Telnet channel with router
- wait welcome message and login request
- send username
- send password
- if correctly logged in, send restart command.
So I started delving in Telnet protocol, reading related RFCs (854, 855, 857). Those
gave me a relatively clear idea of what should I expect connecting to a Telnet Server.
Implementing Telnet client is not very hard, at least not in this case, cause we
only have to know simple commands and options.
All Telnet related implementation is in
TelnetClient class.
Basically it uses TcpClient and NetworkStream to send and read byte stream from
network. Telnet client is very similar to raw messages, apart from initial commands
between server and client. A server sends commands about how it wants to
communicate; client is responsible for accepting or refusing those proposals.
In this particular case, my router says it will echo chars: client replies it would echo by itself and asks server to suppress go-ahead messages
(this avoid server asking for particular commands at every messages).
After this first handshaking, normal communication can take place: server asks client to authenticate, sending username and password.
When login pocedure is complete we can fetch "
system restart" command to
request a warm reboot (restart keeping current configuration).
So client get disconnected and we eventually start a loop to check when router comes
back online. I also added a ping test, using an out of the box solution from CodeProject:
C# Ping Component by Wesley Brown.
Router can be online,
but network could not be connected yet, so we delay our request until a default site
can be successfully pinged.
Network connection, bytes stream and server response are used here as synchronous.
This is done to keep code as simple as possibile and cause Telnet commands only requires few bytes.
Dealing with router in Release mode (I mean, without having a debugger binded to
application) leads to some synchronization problems, cause some command requires
seconds to be invoked. This refers particularly to login procedure, so we have to
wait some time before reading receive buffer, after sending login data.
This is implemented using a
Thread.Sleep and timeout can be customized on
UI.
Keep in mind this one works on my case, but relies on particular server implementation.
I think this can be used as an example implementation, but surely requires some
adaptation and debugging on your own case.
Relevant RFCs are provided in attached source code.
If compiled in debug mode, application produces verbose messages to Debug Console,
using method
GetResponseDescription which tries to decode Telnet byte commands according to RFC specs.