1

我正在尝试通过 cisco 终端/通信服务器连接到 cisco 节点的控制台连接。为此,我远程登录到特定端口上的 cisco 终端/通信服务器的 IP 地址,让我们说 XXXX - 端口 2068。当我通过 CLI 从我的计算机执行此操作时,它看起来像这样:

[user@computer]$ telnet X.X.X.X 2068
Trying X.X.X.X...
Connected to X.X.X.X (X.X.X.X).
Escape character is '^]'.

Username: <user>
Password: 

console-cisco-node>

所以通过我电脑上的 CLI 没问题。但是当我在我的计算机上运行下面的 Python 代码时,它似乎不起作用......

#! /usr/bin/env python

import telnetlib

tn = telnetlib.Telnet("X.X.X.X",2068)
tn.set_debuglevel(8)
data = tn.read_some()
tn.close()
if data == '':
  print 'variable data is EMPTY'
else:
  print data
  print "variable data is FILLED !!!"

当我运行这段代码时,我只能看到这个,看起来'tn.read_some()'只是永远等待,因为没有来自cisco终端/通信服务器的东西?[与 tn.read_all() 相同]

PS。我通过按 CTRL-C 停止了正在运行的代码

[user@computer]$ ./test.py   
Telnet(X.X.X.X,2068): recv '\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f'
Telnet(X.X.X.X,2068): IAC WILL 1
Telnet(X.X.X.X,2068): IAC WILL 3
Telnet(X.X.X.X,2068): IAC DO 24
Telnet(X.X.X.X,2068): IAC DO 31
Telnet(X.X.X.X,2068): recv '\xff\xfc\x01'
Telnet(X.X.X.X,2068): IAC WONT 1
Telnet(X.X.X.X,2068): recv '\xff\xfc\x03'
Telnet(X.X.X.X,2068): IAC WONT 3
Telnet(X.X.X.X,2068): recv '\xff\xfe\x18'
Telnet(X.X.X.X,2068): IAC DONT 24
Telnet(X.X.X.X,2068): recv '\xff\xfe\x1f'
Telnet(X.X.X.X,2068): IAC DONT 31

Traceback (most recent call last):
  File "./test.py", line 7, in ?
    data = tn.read_some()
  File "/usr/lib64/python2.4/telnetlib.py", line 345, in read_some
    self.fill_rawq()
  File "/usr/lib64/python2.4/telnetlib.py", line 521, in fill_rawq
    buf = self.sock.recv(50)
KeyboardInterrupt

当我将代码中的 'tn.read_some()' 更改为 'tn.read_eager()' 或 'tn.read_very_eager()' 或 'tn.read_lazy()' 或 'tn.read_very_lazy()' 并运行代码它再次向我展示了这一点:

[user@computer]$ ./test.py
variable data is EMPTY

当我将 python 代码更改为不连接到 cisco 节点的控制台连接,而是连接到 cisco 节点的管理连接(正常端口 23 上的另一个 IP 地址 YYYY)时,它工作得很好,我看到了这个输出:

[user@computer]$ ./test1.py 
Telnet(Y.Y.Y.Y,23): recv '\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f'
Telnet(Y.Y.Y.Y,23): IAC WILL 1
Telnet(Y.Y.Y.Y,23): IAC WILL 3
Telnet(Y.Y.Y.Y,23): IAC DO 24
Telnet(Y.Y.Y.Y,23): IAC DO 31
Telnet(Y.Y.Y.Y,23): recv '\r\n************************************************'

************************************************
variable data is FILLED !!!

所以我认为Python代码还可以。只是 cisco 终端/COMM 服务器 (XXXX) 的反应方式与正常情况不同,我认为 Python telnetlib 很困惑。

有没有人经历过类似的事情?

4

3 回答 3

0

我找到了另一种方法(感谢Serge Ballesta

在我的情况下,telnetlib 对象是不可能的,所以我不得不使用套接字对象通过 cisco 终端/通信服务器连接到 cisco 节点的控制台连接。在原始基本代码下方,我可以开始编写我需要的程序。

#! /usr/bin/env python

import socket
import time

try:
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   s.connect(("X.X.X.X",2068))
   data1 = s.recv(1024)
   #
   # when the connection with the server is made the server sends some (IAC) commands
   #
   #    '\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f'
   #
   # as far as I know this means the following:
   #
   #     IAC WILL ECHO
   #     IAC WILL SUPRESS GO AHEAD
   #     IAC DO   TERMINAL TYPE
   #     IAC DO   WINDOW SIZE
   #
   # WILL means the server wants to use the indicated facility if the client has the possibilty to use this facility
   # (client can reply with DO or DONT)
   #
   # DO means the server has the possibility for the indicated facility and asks the client if he wants to use this facility
   # (client can reply with WILL or WONT)
   #
   #
   # PS.
   #      WILL = xFB = 251
   #      WONT = xFC = 252
   #      DO   = xFD = 253
   #      DONT = xFE = 254
   #
   #
   #
   # Python is going to answer as follwos:
   #
   #     IAC DONT ECHO
   #     IAC DO   SUPRESS GO AHEAD
   #     IAC WONT TERMINAL TYPE
   #     IAC WONT WINDOW SIZE
   #

   s.sendall('\xff\xfe\x01\xff\xfd\x03\xff\xfc\x18\xff\xfc\x1f')

   data2 = s.recv(1024) # server sends '\xff\xfc\x01' = IAC WONT ECHO as a reply back

   # send an enter to make the hop from the terminal server to the console connection of the node we want to be on
   s.send('\r')

   data3 = ''
   while not 'Username: ' in data3:
      data3 = s.recv(2048)

   s.send('<USERNAME>\r')
   time.sleep(0.1)

   s.recv(1024)
   s.send('<PASSWORD>\r')
   time.sleep(0.1)
   data5 = s.recv(1024)
   s.send('exit\r')

   s.close()

   #print repr(data1)   # '\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f' from the server
   #print repr(data2)   # '\xff\xfc\x01' from the server
   #print data3         # banner and Username: from the console connection of the node we want to be on  

   prompt_console = data5.split()[-1]
   print 'prompt van de console = %s' %prompt_console[:len(prompt_console)-1]

except socket.error, e:
   print e

except socket.timeout, e:
   print e
于 2014-06-13T14:21:03.527 回答
0

看起来在端口 2068 上您没有真正的 telnet 协议。从 telnet man连接到非标准端口时,telnet 忽略任何自动启动 TELNET 选项。当端口号前面有一个减号时,初始选项协商完成。. 但是 telnetlib 假设如果你使用它,你需要一个 telnet 协议。正如您所说,在连接上使用wireshark 并不容易,您可以尝试使用CLI telnet 到端口-2068 来验证您是否遇到与使用telnetlib 相同的问题。

可以选择使用简单的套接字吗?

s = socket.create_connection(('X.X.X.X', 2068))
data = s.recv(1024)
...
于 2014-06-12T13:18:31.510 回答
0

我还与 Cisco(和其他路由器)进行交互。对于 telnet 通信,我扩展了 Telnet 类并添加了read如下方法:

 def read(self, timeout):
    s = time.time()
    resp = ""
    while True:
        res = self.read_eager()
        if not res and resp:
            return resp
        resp += res
        if time.time() - s >= timeout:
            return resp
        time.sleep(0.001)

所以基本上“问题”是各种read_*方法没有给出“全部”,基本上是因为没有“全部”的定义,它会返回“缓冲区”中的任何内容,或者他们会填充缓冲区然后返回内容,取决于您调用的方法。我的方法是“在仍有要阅读的内容时阅读(当我阅读“”时停止)或直到它超过timeout几秒钟。此外,您应该研究该read_until方法的工作原理与预期的差不多。

    def read_until(self, match, timeout=None):
        """Read until a given string is encountered or until timeout.

        When no match is found, return whatever is available instead,
        possibly the empty string.  Raise EOFError if the connection
        is closed and no cooked data is available.

        """
于 2017-02-08T22:13:05.273 回答