1 from __future__ import print_function
3 from code import InteractiveConsole
11 from eventlet import hubs
12 from eventlet.support import greenlets, get_errno
16 except AttributeError:
20 except AttributeError:
24 class FileProxy(object):
25 def __init__(self, f):
34 def write(self, data, *a, **kw):
35 self.f.write(data, *a, **kw)
38 def readline(self, *a):
39 return self.f.readline(*a).replace('\r\n', '\n')
41 def __getattr__(self, attr):
42 return getattr(self.f, attr)
45 # @@tavis: the `locals` args below mask the built-in function. Should
47 class SocketConsole(greenlets.greenlet):
48 def __init__(self, desc, hostport, locals):
49 self.hostport = hostport
52 self.desc = FileProxy(desc)
53 greenlets.greenlet.__init__(self)
57 console = InteractiveConsole(self.locals)
63 def switch(self, *args, **kw):
64 self.saved = sys.stdin, sys.stderr, sys.stdout
65 sys.stdin = sys.stdout = sys.stderr = self.desc
66 greenlets.greenlet.switch(self, *args, **kw)
69 sys.stdin, sys.stderr, sys.stdout = self.saved
72 # restore the state of the socket
74 if len(self.hostport) >= 2:
75 host = self.hostport[0]
76 port = self.hostport[1]
77 print("backdoor closed to %s:%s" % (host, port,))
79 print('backdoor closed')
82 def backdoor_server(sock, locals=None):
83 """ Blocking function that runs a backdoor server on the socket *sock*,
84 accepting connections and running backdoor consoles for each client that
87 The *locals* argument is a dictionary that will be included in the locals()
88 of the interpreters. It can be convenient to stick important application
91 listening_on = sock.getsockname()
92 if sock.family == socket.AF_INET:
93 # Expand result to IP + port
94 listening_on = '%s:%s' % listening_on
95 elif sock.family == socket.AF_INET6:
96 ip, port, _, _ = listening_on
97 listening_on = '%s:%s' % (ip, port,)
98 # No action needed if sock.family == socket.AF_UNIX
100 print("backdoor server listening on %s" % (listening_on,))
104 socketpair = sock.accept()
105 backdoor(socketpair, locals)
106 except socket.error as e:
107 # Broken pipe means it was shutdown
108 if get_errno(e) != errno.EPIPE:
114 def backdoor(conn_info, locals=None):
115 """Sets up an interactive console on a socket with a single connected
116 client. This does not block the caller, as it spawns a new greenlet to
117 handle the console. This is meant to be called from within an accept loop
118 (such as backdoor_server).
120 conn, addr = conn_info
121 if conn.family == socket.AF_INET:
123 print("backdoor to %s:%s" % (host, port))
124 elif conn.family == socket.AF_INET6:
125 host, port, _, _ = addr
126 print("backdoor to %s:%s" % (host, port))
128 print('backdoor opened')
129 fl = conn.makefile("rw")
130 console = SocketConsole(fl, addr, locals)
132 hub.schedule_call_global(0, console.switch)
135 if __name__ == '__main__':
136 backdoor_server(eventlet.listen(('127.0.0.1', 9000)), {})