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