• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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        sys.audit("telnetlib.Telnet.open", self, host, port)
235        self.sock = socket.create_connection((host, port), timeout)
236
237    def __del__(self):
238        """Destructor -- close the connection."""
239        self.close()
240
241    def msg(self, msg, *args):
242        """Print a debug message, when the debug level is > 0.
243
244        If extra arguments are present, they are substituted in the
245        message using the standard string formatting operator.
246
247        """
248        if self.debuglevel > 0:
249            print('Telnet(%s,%s):' % (self.host, self.port), end=' ')
250            if args:
251                print(msg % args)
252            else:
253                print(msg)
254
255    def set_debuglevel(self, debuglevel):
256        """Set the debug level.
257
258        The higher it is, the more debug output you get (on sys.stdout).
259
260        """
261        self.debuglevel = debuglevel
262
263    def close(self):
264        """Close the connection."""
265        sock = self.sock
266        self.sock = None
267        self.eof = True
268        self.iacseq = b''
269        self.sb = 0
270        if sock:
271            sock.close()
272
273    def get_socket(self):
274        """Return the socket object used internally."""
275        return self.sock
276
277    def fileno(self):
278        """Return the fileno() of the socket object used internally."""
279        return self.sock.fileno()
280
281    def write(self, buffer):
282        """Write a string to the socket, doubling any IAC characters.
283
284        Can block if the connection is blocked.  May raise
285        OSError if the connection is closed.
286
287        """
288        if IAC in buffer:
289            buffer = buffer.replace(IAC, IAC+IAC)
290        sys.audit("telnetlib.Telnet.write", self, buffer)
291        self.msg("send %r", buffer)
292        self.sock.sendall(buffer)
293
294    def read_until(self, match, timeout=None):
295        """Read until a given string is encountered or until timeout.
296
297        When no match is found, return whatever is available instead,
298        possibly the empty string.  Raise EOFError if the connection
299        is closed and no cooked data is available.
300
301        """
302        n = len(match)
303        self.process_rawq()
304        i = self.cookedq.find(match)
305        if i >= 0:
306            i = i+n
307            buf = self.cookedq[:i]
308            self.cookedq = self.cookedq[i:]
309            return buf
310        if timeout is not None:
311            deadline = _time() + timeout
312        with _TelnetSelector() as selector:
313            selector.register(self, selectors.EVENT_READ)
314            while not self.eof:
315                if selector.select(timeout):
316                    i = max(0, len(self.cookedq)-n)
317                    self.fill_rawq()
318                    self.process_rawq()
319                    i = self.cookedq.find(match, i)
320                    if i >= 0:
321                        i = i+n
322                        buf = self.cookedq[:i]
323                        self.cookedq = self.cookedq[i:]
324                        return buf
325                if timeout is not None:
326                    timeout = deadline - _time()
327                    if timeout < 0:
328                        break
329        return self.read_very_lazy()
330
331    def read_all(self):
332        """Read all data until EOF; block until connection closed."""
333        self.process_rawq()
334        while not self.eof:
335            self.fill_rawq()
336            self.process_rawq()
337        buf = self.cookedq
338        self.cookedq = b''
339        return buf
340
341    def read_some(self):
342        """Read at least one byte of cooked data unless EOF is hit.
343
344        Return b'' if EOF is hit.  Block if no data is immediately
345        available.
346
347        """
348        self.process_rawq()
349        while not self.cookedq and not self.eof:
350            self.fill_rawq()
351            self.process_rawq()
352        buf = self.cookedq
353        self.cookedq = b''
354        return buf
355
356    def read_very_eager(self):
357        """Read everything that's possible without blocking in I/O (eager).
358
359        Raise EOFError if connection closed and no cooked data
360        available.  Return b'' if no cooked data available otherwise.
361        Don't block unless in the midst of an IAC sequence.
362
363        """
364        self.process_rawq()
365        while not self.eof and self.sock_avail():
366            self.fill_rawq()
367            self.process_rawq()
368        return self.read_very_lazy()
369
370    def read_eager(self):
371        """Read readily available data.
372
373        Raise EOFError if connection closed and no cooked data
374        available.  Return b'' if no cooked data available otherwise.
375        Don't block unless in the midst of an IAC sequence.
376
377        """
378        self.process_rawq()
379        while not self.cookedq and not self.eof and self.sock_avail():
380            self.fill_rawq()
381            self.process_rawq()
382        return self.read_very_lazy()
383
384    def read_lazy(self):
385        """Process and return data that's already in the queues (lazy).
386
387        Raise EOFError if connection closed and no data available.
388        Return b'' if no cooked data available otherwise.  Don't block
389        unless in the midst of an IAC sequence.
390
391        """
392        self.process_rawq()
393        return self.read_very_lazy()
394
395    def read_very_lazy(self):
396        """Return any data available in the cooked queue (very lazy).
397
398        Raise EOFError if connection closed and no data available.
399        Return b'' if no cooked data available otherwise.  Don't block.
400
401        """
402        buf = self.cookedq
403        self.cookedq = b''
404        if not buf and self.eof and not self.rawq:
405            raise EOFError('telnet connection closed')
406        return buf
407
408    def read_sb_data(self):
409        """Return any data available in the SB ... SE queue.
410
411        Return b'' if no SB ... SE available. Should only be called
412        after seeing a SB or SE command. When a new SB command is
413        found, old unread SB data will be discarded. Don't block.
414
415        """
416        buf = self.sbdataq
417        self.sbdataq = b''
418        return buf
419
420    def set_option_negotiation_callback(self, callback):
421        """Provide a callback function called after each receipt of a telnet option."""
422        self.option_callback = callback
423
424    def process_rawq(self):
425        """Transfer from raw queue to cooked queue.
426
427        Set self.eof when connection is closed.  Don't block unless in
428        the midst of an IAC sequence.
429
430        """
431        buf = [b'', b'']
432        try:
433            while self.rawq:
434                c = self.rawq_getchar()
435                if not self.iacseq:
436                    if c == theNULL:
437                        continue
438                    if c == b"\021":
439                        continue
440                    if c != IAC:
441                        buf[self.sb] = buf[self.sb] + c
442                        continue
443                    else:
444                        self.iacseq += c
445                elif len(self.iacseq) == 1:
446                    # 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]'
447                    if c in (DO, DONT, WILL, WONT):
448                        self.iacseq += c
449                        continue
450
451                    self.iacseq = b''
452                    if c == IAC:
453                        buf[self.sb] = buf[self.sb] + c
454                    else:
455                        if c == SB: # SB ... SE start.
456                            self.sb = 1
457                            self.sbdataq = b''
458                        elif c == SE:
459                            self.sb = 0
460                            self.sbdataq = self.sbdataq + buf[1]
461                            buf[1] = b''
462                        if self.option_callback:
463                            # Callback is supposed to look into
464                            # the sbdataq
465                            self.option_callback(self.sock, c, NOOPT)
466                        else:
467                            # We can't offer automatic processing of
468                            # suboptions. Alas, we should not get any
469                            # unless we did a WILL/DO before.
470                            self.msg('IAC %d not recognized' % ord(c))
471                elif len(self.iacseq) == 2:
472                    cmd = self.iacseq[1:2]
473                    self.iacseq = b''
474                    opt = c
475                    if cmd in (DO, DONT):
476                        self.msg('IAC %s %d',
477                            cmd == DO and 'DO' or 'DONT', ord(opt))
478                        if self.option_callback:
479                            self.option_callback(self.sock, cmd, opt)
480                        else:
481                            self.sock.sendall(IAC + WONT + opt)
482                    elif cmd in (WILL, WONT):
483                        self.msg('IAC %s %d',
484                            cmd == WILL and 'WILL' or 'WONT', ord(opt))
485                        if self.option_callback:
486                            self.option_callback(self.sock, cmd, opt)
487                        else:
488                            self.sock.sendall(IAC + DONT + opt)
489        except EOFError: # raised by self.rawq_getchar()
490            self.iacseq = b'' # Reset on EOF
491            self.sb = 0
492            pass
493        self.cookedq = self.cookedq + buf[0]
494        self.sbdataq = self.sbdataq + buf[1]
495
496    def rawq_getchar(self):
497        """Get next char from raw queue.
498
499        Block if no data is immediately available.  Raise EOFError
500        when connection is closed.
501
502        """
503        if not self.rawq:
504            self.fill_rawq()
505            if self.eof:
506                raise EOFError
507        c = self.rawq[self.irawq:self.irawq+1]
508        self.irawq = self.irawq + 1
509        if self.irawq >= len(self.rawq):
510            self.rawq = b''
511            self.irawq = 0
512        return c
513
514    def fill_rawq(self):
515        """Fill raw queue from exactly one recv() system call.
516
517        Block if no data is immediately available.  Set self.eof when
518        connection is closed.
519
520        """
521        if self.irawq >= len(self.rawq):
522            self.rawq = b''
523            self.irawq = 0
524        # The buffer size should be fairly small so as to avoid quadratic
525        # behavior in process_rawq() above
526        buf = self.sock.recv(50)
527        self.msg("recv %r", buf)
528        self.eof = (not buf)
529        self.rawq = self.rawq + buf
530
531    def sock_avail(self):
532        """Test whether data is available on the socket."""
533        with _TelnetSelector() as selector:
534            selector.register(self, selectors.EVENT_READ)
535            return bool(selector.select(0))
536
537    def interact(self):
538        """Interaction function, emulates a very dumb telnet client."""
539        if sys.platform == "win32":
540            self.mt_interact()
541            return
542        with _TelnetSelector() as selector:
543            selector.register(self, selectors.EVENT_READ)
544            selector.register(sys.stdin, selectors.EVENT_READ)
545
546            while True:
547                for key, events in selector.select():
548                    if key.fileobj is self:
549                        try:
550                            text = self.read_eager()
551                        except EOFError:
552                            print('*** Connection closed by remote host ***')
553                            return
554                        if text:
555                            sys.stdout.write(text.decode('ascii'))
556                            sys.stdout.flush()
557                    elif key.fileobj is sys.stdin:
558                        line = sys.stdin.readline().encode('ascii')
559                        if not line:
560                            return
561                        self.write(line)
562
563    def mt_interact(self):
564        """Multithreaded version of interact()."""
565        import _thread
566        _thread.start_new_thread(self.listener, ())
567        while 1:
568            line = sys.stdin.readline()
569            if not line:
570                break
571            self.write(line.encode('ascii'))
572
573    def listener(self):
574        """Helper for mt_interact() -- this executes in the other thread."""
575        while 1:
576            try:
577                data = self.read_eager()
578            except EOFError:
579                print('*** Connection closed by remote host ***')
580                return
581            if data:
582                sys.stdout.write(data.decode('ascii'))
583            else:
584                sys.stdout.flush()
585
586    def expect(self, list, timeout=None):
587        """Read until one from a list of a regular expressions matches.
588
589        The first argument is a list of regular expressions, either
590        compiled (re.Pattern instances) or uncompiled (strings).
591        The optional second argument is a timeout, in seconds; default
592        is no timeout.
593
594        Return a tuple of three items: the index in the list of the
595        first regular expression that matches; the re.Match object
596        returned; and the text read up till and including the match.
597
598        If EOF is read and no text was read, raise EOFError.
599        Otherwise, when nothing matches, return (-1, None, text) where
600        text is the text received so far (may be the empty string if a
601        timeout happened).
602
603        If a regular expression ends with a greedy match (e.g. '.*')
604        or if more than one expression can match the same input, the
605        results are undeterministic, and may depend on the I/O timing.
606
607        """
608        re = None
609        list = list[:]
610        indices = range(len(list))
611        for i in indices:
612            if not hasattr(list[i], "search"):
613                if not re: import re
614                list[i] = re.compile(list[i])
615        if timeout is not None:
616            deadline = _time() + timeout
617        with _TelnetSelector() as selector:
618            selector.register(self, selectors.EVENT_READ)
619            while not self.eof:
620                self.process_rawq()
621                for i in indices:
622                    m = list[i].search(self.cookedq)
623                    if m:
624                        e = m.end()
625                        text = self.cookedq[:e]
626                        self.cookedq = self.cookedq[e:]
627                        return (i, m, text)
628                if timeout is not None:
629                    ready = selector.select(timeout)
630                    timeout = deadline - _time()
631                    if not ready:
632                        if timeout < 0:
633                            break
634                        else:
635                            continue
636                self.fill_rawq()
637        text = self.read_very_lazy()
638        if not text and self.eof:
639            raise EOFError
640        return (-1, None, text)
641
642    def __enter__(self):
643        return self
644
645    def __exit__(self, type, value, traceback):
646        self.close()
647
648
649def test():
650    """Test program for telnetlib.
651
652    Usage: python telnetlib.py [-d] ... [host [port]]
653
654    Default host is localhost; default port is 23.
655
656    """
657    debuglevel = 0
658    while sys.argv[1:] and sys.argv[1] == '-d':
659        debuglevel = debuglevel+1
660        del sys.argv[1]
661    host = 'localhost'
662    if sys.argv[1:]:
663        host = sys.argv[1]
664    port = 0
665    if sys.argv[2:]:
666        portstr = sys.argv[2]
667        try:
668            port = int(portstr)
669        except ValueError:
670            port = socket.getservbyname(portstr, 'tcp')
671    with Telnet() as tn:
672        tn.set_debuglevel(debuglevel)
673        tn.open(host, port, timeout=0.5)
674        tn.interact()
675
676if __name__ == '__main__':
677    test()
678