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

2024-05-14 21:58:33 发布

您现在位置:Python中文网/ 问答频道 /正文

因为一些telnet客户端拒绝处理字符集协商,而且在我请求它们的环境变量时也没有发送有用的信息,所以我在发送一些特殊字符串之后尝试在设备状态报告中使用技巧。在

二进制模式打开。在

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

然后我发送字符串“\xc3\xa9”,这是一个UTF8“é”,并用CSI+6n请求光标位置。在

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

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

我做错什么了吗?还是已知的错误?有什么想法吗?在

Edit2:这是一个工作的示例代码,将python脚本作为服务器运行,然后在localhost4242上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()

Tags: inselfcmdclientdataifserverrequest

热门问题