近期有个想法,想自己做一个TELNET服务器,在这个服务器上可以实现一个中转机的功能,即登录上这台服务器后可以使用telnet或者ssh命令转登录到其它设备。之所以要自己实现是为了实现对中转的完全控制,我可以记录用户在这个TELNET服务器上的所有操作,包括他登录了哪些设备,在设备上执行了哪些命令,甚至可以对其执行的命令进行控制,禁止其执行某些敏感命令。经过几天的调试终于做出了一个初步可用的东西,虽然还有点瑕疵,但毕竟可用了,写出来供有兴趣的人参考。

1、首先构建一个TELNET服务器的框架,这是以后一切工作的基础。

在www.python.org上用PYPI上进行查找,找到的大多是工作在UNIX上的,为WINDOWS定制的少之又少。最后我选了telnetsrv这个库。不过这个库默认情况下在WINDOWS下也是无法运行的,需要安装几个其它的库。主要是解决curse的依赖问题,到http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses下载一个,安装之后就可以了。另外要注意在选择Handler时不要用Green,而要用Threaded,虽然Threaded只支持一个客户端连接,但这是在UNIX的情况下,在WINDOWS下我们的TelnetServer只要从SocketServer.ThreadingTCPServer派生就可以了(官方示例上是从SocketServer.TCPServer派生的,所以只支持一个客户端连接),具体代码如下:

from telnetsrv.threaded import TelnetHandler, command
import socket,threading
import SocketServer
class MyTelnetHandler(TelnetHandler):
WELCOME =
"Welcome to my server."
WELCOME =
u"欢迎访问中转机"
WELCOME=WELCOME.encode('gb2312')
PROMPT="TELNET_Server>"
authNeedUser=True
authNeedPass=True
def
session_start(self):
print self.client_address#客户端地址
@command(['echo', 'copy', 'repeat'])
def
command_echo(self, params):
'''
Echo text back to the console.
'''
self.writeresponse( ' '.join(params) )
def
authCallback(self, username, password):
print 'auth begin'
#print username
#print password
#return
auth_info={}
auth_info['test']='888888'
if auth_info.get(username) is None:
self.writeline('Wrong Username')
raise RuntimeError('Wrong Username')
if
auth_info[username]<>password:
self.writeline('Wrong password!')
raise RuntimeError('Wrong password!')
class TelnetServer(SocketServer.ThreadingTCPServer):
allow_reuse_address = False
if __name__ == '__main__':
print
"server running..."
server =
TelnetServer(("0.0.0.0", 8023), MyTelnetHandler)
server.serve_forever()
自己试运行一下,服务器监听8023端口,一个框架就这样搭建好了,很简单的
。
这里面有个小问题,就是如果输入删除键或者退格键会导致服务器出错,从而中止连接,只可能是我们的cursse不这么给力的原因,为此我们需要修改一个telnetsrv的源代码,在telnetsrvlib.py这个文件找到类TelnetHandlerBase里面有个setterm函数,在这个函数的最后加上这几句:
if self.CODES['CSRLEFT'] is None:
self.CODES['CSRLEFT']="\x1b\x5b\x31\x44"
if self.CODES['DEL'] is None:
self.CODES['DEL']=" "+self.CODES['CSRLEFT']