xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/telnetlib.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1r"""TELNET client class.
2
3Based on RFC 854: TELNET Protocol Specification, by J. Postel and
4J. Reynolds
5
6Example:
7
8>>> from telnetlib import Telnet
9>>> tn = Telnet('www.python.org', 79)   # connect to finger port
10>>> tn.write(b'guido\r\n')
11>>> print(tn.read_all())
12Login       Name               TTY         Idle    When    Where
13guido    Guido van Rossum      pts/2        <Dec  2 11:10> snag.cnri.reston..
14
15>>>
16
17Note that read_all() won't read until eof -- it just reads some data
18-- but it guarantees to read at least one byte unless EOF is hit.
19
20It is possible to pass a Telnet object to a selector in order to wait until
21more data is available.  Note that in this case, read_eager() may return b''
22even if there was data on the socket, because the protocol negotiation may have
23eaten the data.  This is why EOFError is needed in some cases to distinguish
24between "no data" and "connection closed" (since the socket also appears ready
25for reading when it is closed).
26
27To do:
28- option negotiation
29- timeout should be intrinsic to the connection object instead of an
30  option on one of the read calls only
31
32"""
33
34
35# Imported modules
36import sys
37import socket
38import selectors
39from time import monotonic as _time
40import warnings
41
42warnings._deprecated(__name__, remove=(3, 13))
43
44__all__ = ["Telnet"]
45
46# Tunable parameters
47DEBUGLEVEL = 0
48
49# Telnet protocol defaults
50TELNET_PORT = 23
51
52# Telnet protocol characters (don't change)
53IAC  = bytes([255]) # "Interpret As Command"
54DONT = bytes([254])
55DO   = bytes([253])
56WONT = bytes([252])
57WILL = bytes([251])
58theNULL = bytes([0])
59
60SE  = bytes([240])  # Subnegotiation End
61NOP = bytes([241])  # No Operation
62DM  = bytes([242])  # Data Mark
63BRK = bytes([243])  # Break
64IP  = bytes([244])  # Interrupt process
65AO  = bytes([245])  # Abort output
66AYT = bytes([246])  # Are You There
67EC  = bytes([247])  # Erase Character
68EL  = bytes([248])  # Erase Line
69GA  = bytes([249])  # Go Ahead
70SB =  bytes([250])  # Subnegotiation Begin
71
72
73# Telnet protocol options code (don't change)
74# These ones all come from arpa/telnet.h
75BINARY = bytes([0]) # 8-bit data path
76ECHO = bytes([1]) # echo
77RCP = bytes([2]) # prepare to reconnect
78SGA = bytes([3]) # suppress go ahead
79NAMS = bytes([4]) # approximate message size
80STATUS = bytes([5]) # give status
81TM = bytes([6]) # timing mark
82RCTE = bytes([7]) # remote controlled transmission and echo
83NAOL = bytes([8]) # negotiate about output line width
84NAOP = bytes([9]) # negotiate about output page size
85NAOCRD = bytes([10]) # negotiate about CR disposition
86NAOHTS = bytes([11]) # negotiate about horizontal tabstops
87NAOHTD = bytes([12]) # negotiate about horizontal tab disposition
88NAOFFD = bytes([13]) # negotiate about formfeed disposition
89NAOVTS = bytes([14]) # negotiate about vertical tab stops
90NAOVTD = bytes([15]) # negotiate about vertical tab disposition
91NAOLFD = bytes([16]) # negotiate about output LF disposition
92XASCII = bytes([17]) # extended ascii character set
93LOGOUT = bytes([18]) # force logout
94BM = bytes([19]) # byte macro
95DET = bytes([20]) # data entry terminal
96SUPDUP = bytes([21]) # supdup protocol
97SUPDUPOUTPUT = bytes([22]) # supdup output
98SNDLOC = bytes([23]) # send location
99TTYPE = bytes([24]) # terminal type
100EOR = bytes([25]) # end or record
101TUID = bytes([26]) # TACACS user identification
102OUTMRK = bytes([27]) # output marking
103TTYLOC = bytes([28]) # terminal location number
104VT3270REGIME = bytes([29]) # 3270 regime
105X3PAD = bytes([30]) # X.3 PAD
106NAWS = bytes([31]) # window size
107TSPEED = bytes([32]) # terminal speed
108LFLOW = bytes([33]) # remote flow control
109LINEMODE = bytes([34]) # Linemode option
110XDISPLOC = bytes([35]) # X Display Location
111OLD_ENVIRON = bytes([36]) # Old - Environment variables
112AUTHENTICATION = bytes([37]) # Authenticate
113ENCRYPT = bytes([38]) # Encryption option
114NEW_ENVIRON = bytes([39]) # New - Environment variables
115# the following ones come from
116# http://www.iana.org/assignments/telnet-options
117# Unfortunately, that document does not assign identifiers
118# to all of them, so we are making them up
119TN3270E = bytes([40]) # TN3270E
120XAUTH = bytes([41]) # XAUTH
121CHARSET = bytes([42]) # CHARSET
122RSP = bytes([43]) # Telnet Remote Serial Port
123COM_PORT_OPTION = bytes([44]) # Com Port Control Option
124SUPPRESS_LOCAL_ECHO = bytes([45]) # Telnet Suppress Local Echo
125TLS = bytes([46]) # Telnet Start TLS
126KERMIT = bytes([47]) # KERMIT
127SEND_URL = bytes([48]) # SEND-URL
128FORWARD_X = bytes([49]) # FORWARD_X
129PRAGMA_LOGON = bytes([138]) # TELOPT PRAGMA LOGON
130SSPI_LOGON = bytes([139]) # TELOPT SSPI LOGON
131PRAGMA_HEARTBEAT = bytes([140]) # TELOPT PRAGMA HEARTBEAT
132EXOPL = bytes([255]) # Extended-Options-List
133NOOPT = bytes([0])
134
135
136# poll/select have the advantage of not requiring any extra file descriptor,
137# contrarily to epoll/kqueue (also, they require a single syscall).
138if hasattr(selectors, 'PollSelector'):
139    _TelnetSelector = selectors.PollSelector
140else:
141    _TelnetSelector = selectors.SelectSelector
142
143
144class Telnet:
145
146    """Telnet interface class.
147
148    An instance of this class represents a connection to a telnet
149    server.  The instance is initially not connected; the open()
150    method must be used to establish a connection.  Alternatively, the
151    host name and optional port number can be passed to the
152    constructor, too.
153
154    Don't try to reopen an already connected instance.
155
156    This class has many read_*() methods.  Note that some of them
157    raise EOFError when the end of the connection is read, because
158    they can return an empty string for other reasons.  See the
159    individual doc strings.
160
161    read_until(expected, [timeout])
162        Read until the expected string has been seen, or a timeout is
163        hit (default is no timeout); may block.
164
165    read_all()
166        Read all data until EOF; may block.
167
168    read_some()
169        Read at least one byte or EOF; may block.
170
171    read_very_eager()
172        Read all data available already queued or on the socket,
173        without blocking.
174
175    read_eager()
176        Read either data already queued or some data available on the
177        socket, without blocking.
178
179    read_lazy()
180        Read all data in the raw queue (processing it first), without
181        doing any socket I/O.
182
183    read_very_lazy()
184        Reads all data in the cooked queue, without doing any socket
185        I/O.
186
187    read_sb_data()
188        Reads available data between SB ... SE sequence. Don't block.
189
190    set_option_negotiation_callback(callback)
191        Each time a telnet option is read on the input flow, this callback
192        (if set) is called with the following parameters :
193        callback(telnet socket, command, option)
194            option will be chr(0) when there is no option.
195        No other action is done afterwards by telnetlib.
196
197    """
198
199    def __init__(self, host=None, port=0,
200                 timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
201        """Constructor.
202
203        When called without arguments, create an unconnected instance.
204        With a hostname argument, it connects the instance; port number
205        and timeout are optional.
206        """
207        self.debuglevel = DEBUGLEVEL
208        self.host = host
209        self.port = port
210        self.timeout = timeout
211        self.sock = None
212        self.rawq = b''
213        self.irawq = 0
214        self.cookedq = b''
215        self.eof = 0
216        self.iacseq = b'' # Buffer for IAC sequence.
217        self.sb = 0 # flag for SB and SE sequence.
218        self.sbdataq = b''
219        self.option_callback = None
220        if host is not None:
221            self.open(host, port, timeout)
222
223    def open(self, host, port=0, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
224        """Connect to a host.
225
226        The optional second argument is the port number, which
227        defaults to the standard telnet port (23).
228
229        Don't try to reopen an already connected instance.
230        """
231        self.eof = 0
232        if not port:
233            port = TELNET_PORT
234        self.host = host
235        self.port = port
236        self.timeout = timeout
237        sys.audit("telnetlib.Telnet.open", self, host, port)
238        self.sock = socket.create_connection((host, port), timeout)
239
240    def __del__(self):
241        """Destructor -- close the connection."""
242        self.close()
243
244    def msg(self, msg, *args):
245        """Print a debug message, when the debug level is > 0.
246
247        If extra arguments are present, they are substituted in the
248        message using the standard string formatting operator.
249
250        """
251        if self.debuglevel > 0:
252            print('Telnet(%s,%s):' % (self.host, self.port), end=' ')
253            if args:
254                print(msg % args)
255            else:
256                print(msg)
257
258    def set_debuglevel(self, debuglevel):
259        """Set the debug level.
260
261        The higher it is, the more debug output you get (on sys.stdout).
262
263        """
264        self.debuglevel = debuglevel
265
266    def close(self):
267        """Close the connection."""
268        sock = self.sock
269        self.sock = None
270        self.eof = True
271        self.iacseq = b''
272        self.sb = 0
273        if sock:
274            sock.close()
275
276    def get_socket(self):
277        """Return the socket object used internally."""
278        return self.sock
279
280    def fileno(self):
281        """Return the fileno() of the socket object used internally."""
282        return self.sock.fileno()
283
284    def write(self, buffer):
285        """Write a string to the socket, doubling any IAC characters.
286
287        Can block if the connection is blocked.  May raise
288        OSError if the connection is closed.
289
290        """
291        if IAC in buffer:
292            buffer = buffer.replace(IAC, IAC+IAC)
293        sys.audit("telnetlib.Telnet.write", self, buffer)
294        self.msg("send %r", buffer)
295        self.sock.sendall(buffer)
296
297    def read_until(self, match, timeout=None):
298        """Read until a given string is encountered or until timeout.
299
300        When no match is found, return whatever is available instead,
301        possibly the empty string.  Raise EOFError if the connection
302        is closed and no cooked data is available.
303
304        """
305        n = len(match)
306        self.process_rawq()
307        i = self.cookedq.find(match)
308        if i >= 0:
309            i = i+n
310            buf = self.cookedq[:i]
311            self.cookedq = self.cookedq[i:]
312            return buf
313        if timeout is not None:
314            deadline = _time() + timeout
315        with _TelnetSelector() as selector:
316            selector.register(self, selectors.EVENT_READ)
317            while not self.eof:
318                if selector.select(timeout):
319                    i = max(0, len(self.cookedq)-n)
320                    self.fill_rawq()
321                    self.process_rawq()
322                    i = self.cookedq.find(match, i)
323                    if i >= 0:
324                        i = i+n
325                        buf = self.cookedq[:i]
326                        self.cookedq = self.cookedq[i:]
327                        return buf
328                if timeout is not None:
329                    timeout = deadline - _time()
330                    if timeout < 0:
331                        break
332        return self.read_very_lazy()
333
334    def read_all(self):
335        """Read all data until EOF; block until connection closed."""
336        self.process_rawq()
337        while not self.eof:
338            self.fill_rawq()
339            self.process_rawq()
340        buf = self.cookedq
341        self.cookedq = b''
342        return buf
343
344    def read_some(self):
345        """Read at least one byte of cooked data unless EOF is hit.
346
347        Return b'' if EOF is hit.  Block if no data is immediately
348        available.
349
350        """
351        self.process_rawq()
352        while not self.cookedq and not self.eof:
353            self.fill_rawq()
354            self.process_rawq()
355        buf = self.cookedq
356        self.cookedq = b''
357        return buf
358
359    def read_very_eager(self):
360        """Read everything that's possible without blocking in I/O (eager).
361
362        Raise EOFError if connection closed and no cooked data
363        available.  Return b'' if no cooked data available otherwise.
364        Don't block unless in the midst of an IAC sequence.
365
366        """
367        self.process_rawq()
368        while not self.eof and self.sock_avail():
369            self.fill_rawq()
370            self.process_rawq()
371        return self.read_very_lazy()
372
373    def read_eager(self):
374        """Read readily available data.
375
376        Raise EOFError if connection closed and no cooked data
377        available.  Return b'' if no cooked data available otherwise.
378        Don't block unless in the midst of an IAC sequence.
379
380        """
381        self.process_rawq()
382        while not self.cookedq and not self.eof and self.sock_avail():
383            self.fill_rawq()
384            self.process_rawq()
385        return self.read_very_lazy()
386
387    def read_lazy(self):
388        """Process and return data that's already in the queues (lazy).
389
390        Raise EOFError if connection closed and no data available.
391        Return b'' if no cooked data available otherwise.  Don't block
392        unless in the midst of an IAC sequence.
393
394        """
395        self.process_rawq()
396        return self.read_very_lazy()
397
398    def read_very_lazy(self):
399        """Return any data available in the cooked queue (very lazy).
400
401        Raise EOFError if connection closed and no data available.
402        Return b'' if no cooked data available otherwise.  Don't block.
403
404        """
405        buf = self.cookedq
406        self.cookedq = b''
407        if not buf and self.eof and not self.rawq:
408            raise EOFError('telnet connection closed')
409        return buf
410
411    def read_sb_data(self):
412        """Return any data available in the SB ... SE queue.
413
414        Return b'' if no SB ... SE available. Should only be called
415        after seeing a SB or SE command. When a new SB command is
416        found, old unread SB data will be discarded. Don't block.
417
418        """
419        buf = self.sbdataq
420        self.sbdataq = b''
421        return buf
422
423    def set_option_negotiation_callback(self, callback):
424        """Provide a callback function called after each receipt of a telnet option."""
425        self.option_callback = callback
426
427    def process_rawq(self):
428        """Transfer from raw queue to cooked queue.
429
430        Set self.eof when connection is closed.  Don't block unless in
431        the midst of an IAC sequence.
432
433        """
434        buf = [b'', b'']
435        try:
436            while self.rawq:
437                c = self.rawq_getchar()
438                if not self.iacseq:
439                    if c == theNULL:
440                        continue
441                    if c == b"\021":
442                        continue
443                    if c != IAC:
444                        buf[self.sb] = buf[self.sb] + c
445                        continue
446                    else:
447                        self.iacseq += c
448                elif len(self.iacseq) == 1:
449                    # 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]'
450                    if c in (DO, DONT, WILL, WONT):
451                        self.iacseq += c
452                        continue
453
454                    self.iacseq = b''
455                    if c == IAC:
456                        buf[self.sb] = buf[self.sb] + c
457                    else:
458                        if c == SB: # SB ... SE start.
459                            self.sb = 1
460                            self.sbdataq = b''
461                        elif c == SE:
462                            self.sb = 0
463                            self.sbdataq = self.sbdataq + buf[1]
464                            buf[1] = b''
465                        if self.option_callback:
466                            # Callback is supposed to look into
467                            # the sbdataq
468                            self.option_callback(self.sock, c, NOOPT)
469                        else:
470                            # We can't offer automatic processing of
471                            # suboptions. Alas, we should not get any
472                            # unless we did a WILL/DO before.
473                            self.msg('IAC %d not recognized' % ord(c))
474                elif len(self.iacseq) == 2:
475                    cmd = self.iacseq[1:2]
476                    self.iacseq = b''
477                    opt = c
478                    if cmd in (DO, DONT):
479                        self.msg('IAC %s %d',
480                            cmd == DO and 'DO' or 'DONT', ord(opt))
481                        if self.option_callback:
482                            self.option_callback(self.sock, cmd, opt)
483                        else:
484                            self.sock.sendall(IAC + WONT + opt)
485                    elif cmd in (WILL, WONT):
486                        self.msg('IAC %s %d',
487                            cmd == WILL and 'WILL' or 'WONT', ord(opt))
488                        if self.option_callback:
489                            self.option_callback(self.sock, cmd, opt)
490                        else:
491                            self.sock.sendall(IAC + DONT + opt)
492        except EOFError: # raised by self.rawq_getchar()
493            self.iacseq = b'' # Reset on EOF
494            self.sb = 0
495        self.cookedq = self.cookedq + buf[0]
496        self.sbdataq = self.sbdataq + buf[1]
497
498    def rawq_getchar(self):
499        """Get next char from raw queue.
500
501        Block if no data is immediately available.  Raise EOFError
502        when connection is closed.
503
504        """
505        if not self.rawq:
506            self.fill_rawq()
507            if self.eof:
508                raise EOFError
509        c = self.rawq[self.irawq:self.irawq+1]
510        self.irawq = self.irawq + 1
511        if self.irawq >= len(self.rawq):
512            self.rawq = b''
513            self.irawq = 0
514        return c
515
516    def fill_rawq(self):
517        """Fill raw queue from exactly one recv() system call.
518
519        Block if no data is immediately available.  Set self.eof when
520        connection is closed.
521
522        """
523        if self.irawq >= len(self.rawq):
524            self.rawq = b''
525            self.irawq = 0
526        # The buffer size should be fairly small so as to avoid quadratic
527        # behavior in process_rawq() above
528        buf = self.sock.recv(50)
529        self.msg("recv %r", buf)
530        self.eof = (not buf)
531        self.rawq = self.rawq + buf
532
533    def sock_avail(self):
534        """Test whether data is available on the socket."""
535        with _TelnetSelector() as selector:
536            selector.register(self, selectors.EVENT_READ)
537            return bool(selector.select(0))
538
539    def interact(self):
540        """Interaction function, emulates a very dumb telnet client."""
541        if sys.platform == "win32":
542            self.mt_interact()
543            return
544        with _TelnetSelector() as selector:
545            selector.register(self, selectors.EVENT_READ)
546            selector.register(sys.stdin, selectors.EVENT_READ)
547
548            while True:
549                for key, events in selector.select():
550                    if key.fileobj is self:
551                        try:
552                            text = self.read_eager()
553                        except EOFError:
554                            print('*** Connection closed by remote host ***')
555                            return
556                        if text:
557                            sys.stdout.write(text.decode('ascii'))
558                            sys.stdout.flush()
559                    elif key.fileobj is sys.stdin:
560                        line = sys.stdin.readline().encode('ascii')
561                        if not line:
562                            return
563                        self.write(line)
564
565    def mt_interact(self):
566        """Multithreaded version of interact()."""
567        import _thread
568        _thread.start_new_thread(self.listener, ())
569        while 1:
570            line = sys.stdin.readline()
571            if not line:
572                break
573            self.write(line.encode('ascii'))
574
575    def listener(self):
576        """Helper for mt_interact() -- this executes in the other thread."""
577        while 1:
578            try:
579                data = self.read_eager()
580            except EOFError:
581                print('*** Connection closed by remote host ***')
582                return
583            if data:
584                sys.stdout.write(data.decode('ascii'))
585            else:
586                sys.stdout.flush()
587
588    def expect(self, list, timeout=None):
589        """Read until one from a list of a regular expressions matches.
590
591        The first argument is a list of regular expressions, either
592        compiled (re.Pattern instances) or uncompiled (strings).
593        The optional second argument is a timeout, in seconds; default
594        is no timeout.
595
596        Return a tuple of three items: the index in the list of the
597        first regular expression that matches; the re.Match object
598        returned; and the text read up till and including the match.
599
600        If EOF is read and no text was read, raise EOFError.
601        Otherwise, when nothing matches, return (-1, None, text) where
602        text is the text received so far (may be the empty string if a
603        timeout happened).
604
605        If a regular expression ends with a greedy match (e.g. '.*')
606        or if more than one expression can match the same input, the
607        results are undeterministic, and may depend on the I/O timing.
608
609        """
610        re = None
611        list = list[:]
612        indices = range(len(list))
613        for i in indices:
614            if not hasattr(list[i], "search"):
615                if not re: import re
616                list[i] = re.compile(list[i])
617        if timeout is not None:
618            deadline = _time() + timeout
619        with _TelnetSelector() as selector:
620            selector.register(self, selectors.EVENT_READ)
621            while not self.eof:
622                self.process_rawq()
623                for i in indices:
624                    m = list[i].search(self.cookedq)
625                    if m:
626                        e = m.end()
627                        text = self.cookedq[:e]
628                        self.cookedq = self.cookedq[e:]
629                        return (i, m, text)
630                if timeout is not None:
631                    ready = selector.select(timeout)
632                    timeout = deadline - _time()
633                    if not ready:
634                        if timeout < 0:
635                            break
636                        else:
637                            continue
638                self.fill_rawq()
639        text = self.read_very_lazy()
640        if not text and self.eof:
641            raise EOFError
642        return (-1, None, text)
643
644    def __enter__(self):
645        return self
646
647    def __exit__(self, type, value, traceback):
648        self.close()
649
650
651def test():
652    """Test program for telnetlib.
653
654    Usage: python telnetlib.py [-d] ... [host [port]]
655
656    Default host is localhost; default port is 23.
657
658    """
659    debuglevel = 0
660    while sys.argv[1:] and sys.argv[1] == '-d':
661        debuglevel = debuglevel+1
662        del sys.argv[1]
663    host = 'localhost'
664    if sys.argv[1:]:
665        host = sys.argv[1]
666    port = 0
667    if sys.argv[2:]:
668        portstr = sys.argv[2]
669        try:
670            port = int(portstr)
671        except ValueError:
672            port = socket.getservbyname(portstr, 'tcp')
673    with Telnet() as tn:
674        tn.set_debuglevel(debuglevel)
675        tn.open(host, port, timeout=0.5)
676        tn.interact()
677
678if __name__ == '__main__':
679    test()
680