如何用ANSI转义码猜测telnet客户端编码?

时间:2016-01-13 04:35:36

标签: python encoding telnet ansi

由于某些telnet客户端拒绝处理CHARSET否定,并且在我请求其环境变量时也没有发送有用信息,因此我在发送一些特殊字符串后尝试使用设备状态报告。

二进制模式为ON。

首先,我用CSI + 2J清理屏幕,然后将光标设置在第一行,第一列用CSI + 1; 1H。

然后我发送字符串“\ xc3 \ xa9”,这是一个UTF8“é”,并用CSI + 6n请求光标位置。如果光标只移动了一列,我假设客户端的编码是UTF8。

否则,我发送字符串“\ x80 \ x81”。如果客户端的编码是Latin-1,则不应输出任何内容;如果客户端的编码是cp1252,则应该输出一个字符,最后如果客户端的编码是Mac_Roman,则输出2个字符。

问题在于,在所有情况下,CSI + 6n报告的是2列移动,当客户端的编码不是Mac_Roman时,这是不正确的。

我做错了什么或者它是一个已知的错误?有什么想法吗?

Edit2:这是一个工作示例代码,将python脚本作为服务器运行,然后在localhost 4242上telnet进行测试。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import SocketServer
import re

# TELNET commands we need
DO = 253
DONT = 254
WILL = 251
WONT = 252
IAC = 255
SE = 240
SB = 250
SGA = 3
ECHO = 1
BINARY = 0
NAWS = 31
LINEMODE = 34

# ANSI Escape sequence
CSI = u'\x1b['

def cmd(s):
    """Translate from TELNET commands to bytes string"""
    return b"".join([chr(x) if isinstance(x, int) else x for x in s])

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    client_charset = "ascii"

    def init_session(self):
        print "Connection from {}".format(self.client_address)
        # negotiating requested options or quit
        asking = (IAC, WILL, ECHO, IAC, WILL, SGA, IAC, DO, SGA, IAC, DO, BINARY, IAC, WILL, BINARY, IAC, WONT, LINEMODE, IAC, DONT, LINEMODE)
        waiting = set(map(cmd, [(IAC, DO, ECHO), (IAC, DO, SGA), (IAC, WILL, SGA), (IAC, WILL, BINARY), (IAC, DO, BINARY)]))
        self.request.sendall(cmd(asking))
        data = self.request.recv(1024)
        print [ord(x) for x in data]
        for x in waiting:
            if x not in data:
                return False
        # retrieve client's naws (terminal size)
        asking = (IAC, DO, NAWS)
        waiting = cmd((IAC, WILL, NAWS))
        self.request.sendall(cmd(asking))
        data = self.request.recv(1024)
        print [ord(x) for x in data]
        if waiting not in data:
            return False
        data = data.replace(chr(IAC) * 2, chr(IAC))
        waiting = cmd((IAC, SB, NAWS, r"(.)(.)(.)(.)", IAC, SE))
        r = re.search(waiting, data)
        if not r:
            return False
        a, b, c, d = ord(r.group(1)), ord(r.group(2)), ord(r.group(3)), ord(r.group(4))
        columns, rows = 256*a+b, 256*c+d
        print "%d columns, %d rows" % (columns, rows)
        self.columns, self.rows = columns, rows
        # guessing client encoding
        self.request.sendall("{0}2J{0}1;1HDeterming your encoding...".format(CSI))
        self.request.sendall("{0}2;1H\xc3\xa9{0}6n".format(CSI))
        data = self.request.recv(1024)
        row, col = map(int, data[2:-1].split(";"))
        print row, col 
        if col == 2:
            self.client_charset = "utf-8"
        else:
            self.request.sendall("{0}3;1H({1}){0}6n".format(CSI, "\x80\x81"))
            data = self.request.recv(1024)
            row, col = map(int, data[2:-1].split(";"))
            print row, col
            if col == 3:
                self.client_charset = "latin_1"
            elif col == 4:
                self.client_charset = "cp1252"
            elif col == 5:
                self.client_charset = "mac_roman"
        print self.client_charset
        return False # We don't handle any client
    def handle(self):
        if not self.init_session():
            print "Rejecting client"
        else:
            pass

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    allow_reuse_address = True

if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "", 4242

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    print "Server starting on port %d" % port

    try:
        server.serve_forever()
    except:
        print "Shutting down"
        server.shutdown()
        server.server_close()

0 个答案:

没有答案