def _process_gibberish(self, packet): (_, message, data) = packet p = self._protocol show_as_text = p and p.input_packetcount==0 and all(c in string.printable for c in bytestostr(data)) if show_as_text: #looks like the first packet back is just text, print it: data = bytestostr(data) if data.find("Traceback "): for x in data.split("\n"): log.warn(x.strip("\r")) else: log.warn("Failed to connect, received: %s", repr_ellipsized(data.strip("\n").strip("\r"))) else: log.warn("Received uninterpretable nonsense: %s", message) log.warn(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data)) if str(data).find("assword")>0: self.warn_and_quit(EXIT_SSH_FAILURE, "Your ssh program appears to be asking for a password." + GOT_PASSWORD_PROMPT_SUGGESTION) elif str(data).find("login")>=0: self.warn_and_quit(EXIT_SSH_FAILURE, "Your ssh program appears to be asking for a username.\n" "Perhaps try using something like 'ssh:USER@host:display'?") else: self.quit(EXIT_PACKET_FAILURE)
def _copy_loop(self, log_name, from_conn, to_conn): #log("XpraProxy._copy_loop(%s, %s, %s)", log_name, from_conn, to_conn) try: while not self._closed: log("%s: waiting for data", log_name) buf = untilConcludes(self.is_active, noretry, from_conn.read, PROXY_BUFFER_SIZE) if not buf: log("%s: connection lost", log_name) return if SHOW_DATA: log("%s: %s bytes: %s", log_name, len(buf), repr_ellipsized(buf)) log("%s: %s", log_name, repr_ellipsized(hexstr(buf))) while buf and not self._closed: log("%s: writing %s bytes", log_name, len(buf)) written = untilConcludes(self.is_active, noretry, to_conn.write, buf) buf = buf[written:] log("%s: written %s bytes", log_name, written) log("%s copy loop ended", log_name) except Exception as e: log("%s: %s", log_name, e) finally: self.quit()
def query_xkbmap(self): ( self.xkbmap_layout, self.xkbmap_layouts, self.xkbmap_variant, self.xkbmap_variants, self.xkbmap_options, ) = self.get_layout_spec() self.xkbmap_print, self.xkbmap_query, self.xkbmap_query_struct = self.get_keymap_spec( ) self.xkbmap_keycodes = self.get_full_keymap() self.xkbmap_x11_keycodes = self.keyboard.get_x11_keymap() ( self.xkbmap_mod_meanings, self.xkbmap_mod_managed, self.xkbmap_mod_pointermissing, ) = self.keyboard.get_keymap_modifiers() self.update_hash() log("layout=%s, layouts=%s, variant=%s, variants=%s", self.xkbmap_layout, self.xkbmap_layouts, self.xkbmap_variant, self.xkbmap_variants) log("print=%s, query=%s, struct=%s", nonl(self.xkbmap_print), nonl(self.xkbmap_query), self.xkbmap_query_struct) log("keycodes=%s", repr_ellipsized(str(self.xkbmap_keycodes))) log("x11 keycodes=%s", repr_ellipsized(str(self.xkbmap_x11_keycodes))) log("mod managed: %s", self.xkbmap_mod_managed) log("mod meanings: %s", self.xkbmap_mod_meanings) log("mod pointermissing: %s", self.xkbmap_mod_pointermissing) log("hash=%s", self.hash)
def do_cmp_unmask(buf, hlen, plen): c = memoryview_to_bytes(hybi_unmask(buf, hlen, plen)) w = numpy_unmask(buf, hlen, plen) assert w == c, "expected %s got %s" % ( repr_ellipsized(binascii.hexlify(w)), repr_ellipsized(binascii.hexlify(c)), )
def __init__(self, uid, gid, env_options, session_options, socket_dir, video_encoder_modules, pings, client_conn, disp_desc, client_state, cipher, encryption_key, server_conn, caps, message_queue): ProxyInstance.__init__(self, session_options, video_encoder_modules, pings, disp_desc, cipher, encryption_key, caps) QueueScheduler.__init__(self) Process.__init__(self, name=str(client_conn)) self.client_conn = client_conn self.server_conn = server_conn self.uid = uid self.gid = gid self.env_options = env_options self.socket_dir = socket_dir self.client_state = client_state log("ProxyProcess%s", (uid, gid, env_options, session_options, socket_dir, video_encoder_modules, client_conn, disp_desc, repr_ellipsized(str(client_state)), cipher, encryption_key, server_conn, "%s: %s.." % (type(caps), repr_ellipsized(str(caps))), message_queue)) self.message_queue = message_queue #for handling the local unix domain socket: self.control_socket_cleanup = None self.control_socket = None self.control_socket_thread = None self.control_socket_path = None self.potential_protocols = [] self.max_connections = MAX_CONCURRENT_CONNECTIONS
def peek_connection(conn, timeout=PEEK_TIMEOUT_MS): log = get_network_logger() log("peek_connection(%s, %i)", conn, timeout) PEEK_SIZE = 8192 start = monotonic_time() peek_data = b"" while not peek_data and int(1000*(monotonic_time()-start))<timeout: try: peek_data = conn.peek(PEEK_SIZE) except (OSError, IOError): pass except ValueError: log("peek_connection(%s, %i) failed", conn, timeout, exc_info=True) break if not peek_data: sleep(timeout/4000.0) line1 = b"" log("socket %s peek: got %i bytes", conn, len(peek_data)) set_socket_timeout(conn, PEEK_TIMEOUT_MS*1000) if peek_data: line1 = peek_data.splitlines()[0] log("socket peek=%s", repr_ellipsized(peek_data, limit=512)) log("socket peek hex=%s", hexstr(peek_data[:128])) log("socket peek line1=%s", repr_ellipsized(bytestostr(line1))) return peek_data, line1
def _process_gibberish(self, packet): (_, message, data) = packet p = self._protocol show_as_text = p and p.input_packetcount == 0 and all( c in string.printable for c in bytestostr(data)) if show_as_text: #looks like the first packet back is just text, print it: data = bytestostr(data) if data.find("Traceback "): for x in data.split("\n"): log.warn(x.strip("\r")) else: log.warn("Failed to connect, received: %s", repr_ellipsized(data.strip("\n").strip("\r"))) else: log.warn("Received uninterpretable nonsense: %s", message) log.warn(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data)) if str(data).find("assword") > 0: self.warn_and_quit( EXIT_SSH_FAILURE, "Your ssh program appears to be asking for a password." + GOT_PASSWORD_PROMPT_SUGGESTION) elif str(data).find("login") >= 0: self.warn_and_quit( EXIT_SSH_FAILURE, "Your ssh program appears to be asking for a username.\n" "Perhaps try using something like 'ssh:USER@host:display'?") else: self.quit(EXIT_PACKET_FAILURE)
def _process_setting_change(self, packet): setting, value = packet[1:3] setting = bytestostr(setting) #convert "hello" / "setting" variable names to client variables: if setting in ( "clipboard-limits", ): pass elif setting in ( "bell", "randr", "cursors", "notifications", "dbus-proxy", "clipboard", "clipboard-direction", "session_name", "sharing", "sharing-toggle", "lock", "lock-toggle", "start-new-commands", "client-shutdown", "webcam", "bandwidth-limit", "clipboard-limits", "xdg-menu", ): setattr(self, "server_%s" % setting.replace("-", "_"), value) else: log.info("unknown server setting changed: %s=%s", setting, repr_ellipsized(bytestostr(value))) return log("_process_setting_change: %s=%s", setting, value) #xdg-menu is too big to log, and we have to update our attribute: if setting=="xdg-menu": self.server_xdg_menu = value else: log.info("server setting changed: %s=%s", setting, repr_ellipsized(value)) self.server_setting_changed(setting, value)
def _process_gibberish(self, packet): log("process_gibberish(%s)", ellipsizer(packet)) message, data = packet[1:3] p = self._protocol show_as_text = p and p.input_packetcount == 0 and len( data) < 128 and all(c in string.printable for c in bytestostr(data)) if show_as_text: #looks like the first packet back is just text, print it: data = bytestostr(data) if data.find("\n") >= 0: for x in data.splitlines(): netlog.warn(x) else: netlog.error("Error: failed to connect, received") netlog.error(" %s", repr_ellipsized(data)) else: from xpra.net.socket_util import guess_packet_type packet_type = guess_packet_type(data) log("guess_packet_type(%r)=%s", data, packet_type) if packet_type and packet_type != "xpra": netlog.error("Error: received a %s packet", packet_type) netlog.error(" this is not an xpra server?") else: netlog.error("Error: received uninterpretable nonsense: %s", message) if p: netlog.error(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data)) else: netlog.error(" data: %s", repr_ellipsized(data)) self.quit(EXIT_PACKET_FAILURE)
def start_tcp_proxy(self, proto, data): log("start_tcp_proxy(%s, %s)", proto, data[:10]) #any buffers read after we steal the connection will be placed in this temporary queue: temp_read_buffer = Queue() client_connection = proto.steal_connection(temp_read_buffer.put) try: self._potential_protocols.remove(proto) except: pass #might already have been removed by now #connect to web server: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) host, port = self._tcp_proxy.split(":", 1) try: web_server_connection = _socket_connect(sock, (host, int(port)), "web-proxy-for-%s" % proto, "tcp") except: log.warn("failed to connect to proxy: %s:%s", host, port) proto.gibberish("invalid packet header", data) return log("proxy connected to tcp server at %s:%s : %s", host, port, web_server_connection) sock.settimeout(self._socket_timeout) ioe = proto.wait_for_io_threads_exit(0.5 + self._socket_timeout) if not ioe: log.warn("proxy failed to stop all existing network threads!") self.disconnect_protocol(proto, "internal threading error") return #now that we own it, we can start it again: client_connection.set_active(True) #and we can use blocking sockets: self.set_socket_timeout(client_connection, None) #prevent deadlocks on exit: sock.settimeout(1) log("pushing initial buffer to its new destination: %s", repr_ellipsized(data)) web_server_connection.write(data) while not temp_read_buffer.empty(): buf = temp_read_buffer.get() if buf: log("pushing read buffer to its new destination: %s", repr_ellipsized(buf)) web_server_connection.write(buf) p = XpraProxy(client_connection, web_server_connection) self._tcp_proxy_clients.append(p) def run_proxy(): p.run() log("run_proxy() %s ended", p) if p in self._tcp_proxy_clients: self._tcp_proxy_clients.remove(p) t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto) t.start() log.info("client %s forwarded to proxy server %s:%s", client_connection, host, port)
def start_tcp_proxy(self, proto, data): proxylog("start_tcp_proxy(%s, '%s')", proto, repr_ellipsized(data)) try: self._potential_protocols.remove(proto) except: pass # might already have been removed by now proxylog("start_tcp_proxy: protocol state before stealing: %s", proto.get_info(alias_info=False)) # any buffers read after we steal the connection will be placed in this temporary queue: temp_read_buffer = Queue() client_connection = proto.steal_connection(temp_read_buffer.put) # connect to web server: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) host, port = self._tcp_proxy.split(":", 1) try: web_server_connection = _socket_connect(sock, (host, int(port)), "web-proxy-for-%s" % proto, "tcp") except: proxylog.warn("failed to connect to proxy: %s:%s", host, port) proto.gibberish("invalid packet header", data) return proxylog("proxy connected to tcp server at %s:%s : %s", host, port, web_server_connection) sock.settimeout(self._socket_timeout) ioe = proto.wait_for_io_threads_exit(0.5 + self._socket_timeout) if not ioe: proxylog.warn("proxy failed to stop all existing network threads!") self.disconnect_protocol(proto, "internal threading error") return # now that we own it, we can start it again: client_connection.set_active(True) # and we can use blocking sockets: self.set_socket_timeout(client_connection, None) # prevent deadlocks on exit: sock.settimeout(1) proxylog("pushing initial buffer to its new destination: %s", repr_ellipsized(data)) web_server_connection.write(data) while not temp_read_buffer.empty(): buf = temp_read_buffer.get() if buf: proxylog("pushing read buffer to its new destination: %s", repr_ellipsized(buf)) web_server_connection.write(buf) p = XpraProxy(client_connection.target, client_connection, web_server_connection) self._tcp_proxy_clients.append(p) proxylog.info( "client connection from %s forwarded to proxy server on %s:%s", client_connection.target, host, port ) p.run() proxylog("run_proxy() %s ended", p) if p in self._tcp_proxy_clients: self._tcp_proxy_clients.remove(p)
def __init__(self, uid, gid, env_options, session_options, socket_dir, video_encoder_modules, csc_modules, client_conn, disp_desc, client_state, cipher, encryption_key, server_conn, caps, message_queue): Process.__init__(self, name=str(client_conn)) self.uid = uid self.gid = gid self.env_options = env_options self.session_options = session_options self.socket_dir = socket_dir self.video_encoder_modules = video_encoder_modules self.csc_modules = csc_modules self.client_conn = client_conn self.disp_desc = disp_desc self.client_state = client_state self.cipher = cipher self.encryption_key = encryption_key self.server_conn = server_conn self.caps = caps log("ProxyProcess%s", (uid, gid, env_options, session_options, socket_dir, video_encoder_modules, csc_modules, client_conn, disp_desc, repr_ellipsized(str(client_state)), cipher, encryption_key, server_conn, "%s: %s.." % (type(caps), repr_ellipsized(str(caps))), message_queue)) self.client_protocol = None self.server_protocol = None self.exit = False self.main_queue = None self.message_queue = message_queue self.encode_queue = None #holds draw packets to encode self.encode_thread = None self.video_encoding_defs = None self.video_encoders = None self.video_encoders_last_used_time = None self.video_encoder_types = None self.video_helper = None self.lost_windows = None #for handling the local unix domain socket: self.control_socket_cleanup = None self.control_socket = None self.control_socket_thread = None self.control_socket_path = None self.potential_protocols = [] self.max_connections = MAX_CONCURRENT_CONNECTIONS self.timer_id = AtomicInteger() self.timers = {} self.timer_lock = RLock()
def show_notify(self, dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, actions, hints, expire_timeout, icon): if not self.dbus_check(dbus_id): return self.may_retry = True try: icon_string = self.get_icon_string(nid, app_icon, icon) log("get_icon_string%s=%s", (nid, app_icon, repr_ellipsized(str(icon))), icon_string) try: app_str = self.app_name_format % app_name except: app_str = app_name or "Xpra" self.last_notification = (dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, expire_timeout, icon) def NotifyReply(notification_id): log("NotifyReply(%s) for nid=%i", notification_id, nid) self.actual_notification_id[nid] = int(notification_id) dbus_hints = self.parse_hints(hints) self.dbusnotify.Notify(app_str, 0, icon_string, summary, body, actions, dbus_hints, expire_timeout, reply_handler=NotifyReply, error_handler=self.NotifyError) except: log.error("Error: dbus notify failed", exc_info=True)
def do_test_encoder(encoder, src_format, w, h, images, name="encoder", log=None, pause=0, after_encode_cb=None): start = time.time() tsize = 0 client_options = {} for i, image in enumerate(images): log("image %i of %i, calling %s compress_image(%s)", i+1, len(images), encoder.get_type(), image) c = encoder.compress_image(image) assert c is not None, "no image!" data, client_options = c if not data: assert client_options.get("delayed", 0)>0 continue tsize += len(data) log("data %6i bytes: %s" % (len(data), repr_ellipsized(str(data)))) if pause>0: time.sleep(pause) if after_encode_cb: after_encode_cb(encoder) delayed = client_options.get("delayed", 0) if delayed>0: encoder.flush(delayed) end = time.time() #log.info("%s finished encoding %s frames at %sx%s, total encoding time: %.1fms" % (name, len(images), w, h, 1000.0*(end-start))) perf = int(len(images)*w*h/(end-start)/1024/1024) tpf = int(1000*(end-start)/len(images)) sized = "%sx%s" % (w, h) fsize = tsize/len(images) log.info("%60s finished encoding %3s %7s frames at %10s: %4s MPixels/s, %4sms/frame, %8sKB/frame (%s)", encoder, len(images), src_format, sized, perf, tpf, fsize//1024, encoder.get_info().get("pixel_format"))
def invalid_header(self, proto, data): log("invalid_header(%s, %s)", proto, repr_ellipsized(data)) if proto.input_packetcount==0 and self._tcp_proxy: self.start_tcp_proxy(proto, data) return err = "invalid packet format, not an xpra client?" proto.gibberish(err, data)
def _process_gibberish(self, packet): (_, message, data) = packet p = self._protocol show_as_text = p and p.input_packetcount==0 and all(c in string.printable for c in bytestostr(data)) if show_as_text: #looks like the first packet back is just text, print it: data = bytestostr(data) if data.find("Traceback ")>=0: for x in data.split("\n"): netlog.warn(x.strip("\r")) else: netlog.warn("Failed to connect, received: %s", repr_ellipsized(data.strip("\n").strip("\r"))) else: netlog.warn("Received uninterpretable nonsense: %s", message) netlog.warn(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data)) self.quit(EXIT_PACKET_FAILURE)
def load_command_to_type(): global command_to_type if command_to_type is None: command_to_type = {} from xpra.platform.xposix.xdg_helper import load_xdg_menu_data xdg_menu = load_xdg_menu_data() categories_to_type = load_categories_to_type() log("load_command_to_type() xdg_menu=%s, categories_to_type=%s", xdg_menu, categories_to_type) if xdg_menu and categories_to_type: for category, category_props in xdg_menu.items(): log("category %s: %s", category, repr_ellipsized(str(category_props))) entries = category_props.get("Entries", {}) for name, props in entries.items(): command = props.get("TryExec") or props.get("Exec") categories = props.get("Categories") log("Entry '%s': command=%s, categories=%s", name, command, categories) if command and categories: for c in categories: ctype = categories_to_type.get(c.lower()) if not ctype: #try a more fuzzy match: for category_name,ct in categories_to_type.items(): if c.lower().find(category_name)>=0: ctype = ct break if ctype: cmd = os.path.basename(command.split(" ")[0]).encode() if cmd: command_to_type[cmd] = ctype break log("load_command_to_type()=%s", command_to_type) return command_to_type
def _process_logging(self, packet): assert not self.local_logging, "cannot receive logging packets when forwarding logging!" level, msg = packet[1:3] prefix = "server: " if len(packet) >= 4: dtime = packet[3] prefix += "@%02i.%03i " % ((dtime // 1000) % 60, dtime % 1000) def dec(x): try: return x.decode("utf8") except Exception: return bytestostr(x) try: if isinstance(msg, (tuple, list)): dmsg = " ".join(dec(x) for x in msg) else: dmsg = dec(msg) for l in dmsg.splitlines(): self.do_log(level, prefix + l) except Exception as e: log("log message decoding error", exc_info=True) log.error("Error: failed to parse logging message:") log.error(" %s", repr_ellipsized(msg)) log.error(" %s", e)
def _process_gibberish(self, packet): (_, message, data) = packet p = self._protocol show_as_text = p and p.input_packetcount==0 and all(c in string.printable for c in bytestostr(data)) if show_as_text: #looks like the first packet back is just text, print it: data = bytestostr(data) if data.find("Traceback "): for x in data.split("\n"): netlog.warn(x.strip("\r")) else: netlog.warn("Failed to connect, received: %s", repr_ellipsized(data.strip("\n").strip("\r"))) else: netlog.warn("Received uninterpretable nonsense: %s", message) netlog.warn(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data)) self.quit(EXIT_PACKET_FAILURE)
def _send_clipboard_token_handler(self, proxy, packet_data=()): if log.is_debug_enabled(): log("_send_clipboard_token_handler(%s, %s)", proxy, repr_ellipsized(packet_data)) remote = self.local_to_remote(proxy._selection) packet = ["clipboard-token", remote] if packet_data: #append 'TARGETS' unchanged: packet.append(packet_data[0]) #if present, the next element is the target data, #which we have to convert to wire format: if len(packet_data) >= 2: target, dtype, dformat, data = packet_data[1] wire_encoding, wire_data = self._munge_raw_selection_to_wire( target, dtype, dformat, data) if wire_encoding: wire_data = self._may_compress(dtype, dformat, wire_data) if wire_data: packet += [ target, dtype, dformat, wire_encoding, wire_data ] claim = proxy._can_send packet += [claim, CLIPBOARD_GREEDY] log("send_clipboard_token_handler %s to %s", proxy._selection, remote) self.send(*packet)
def __init__(self, session_options, video_encoder_modules, pings, disp_desc, cipher, encryption_key, caps): self.session_options = session_options self.video_encoder_modules = video_encoder_modules self.pings = pings self.disp_desc = disp_desc self.cipher = cipher self.encryption_key = encryption_key self.caps = caps log("ProxyInstance%s", (session_options, video_encoder_modules, disp_desc, cipher, encryption_key, "%s: %s.." % (type(caps), repr_ellipsized(str(caps))))) self.uuid = get_hex_uuid() self.client_protocol = None self.server_protocol = None #ping handling: self.client_last_ping = 0 self.server_last_ping = 0 self.client_last_ping_echo = 0 self.server_last_ping_echo = 0 self.client_last_ping_latency = 0 self.server_last_ping_latency = 0 self.client_ping_timer = None self.server_ping_timer = None self.client_challenge_packet = None self.exit = False self.lost_windows = None self.encode_queue = None #holds draw packets to encode self.encode_thread = None self.video_encoding_defs = None self.video_encoders = None self.video_encoders_last_used_time = None self.video_encoder_types = None self.video_helper = None
def log_message(self, fmt, *args): if args and len( args) == 3 and fmt == '"%s" %s %s' and args[1] == "400": fmt = '"%r" %s %s' args = list(args) args[0] = repr_ellipsized(args[0]) log(fmt, *args)
def get_text(): data_handle = GetClipboardData(win32con.CF_UNICODETEXT) if not data_handle: errback("no data handle") return data = GlobalLock(data_handle) if not data: errback("failed to lock handle") return try: wstr = cast(data, LPCWSTR) ulen = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, None, 0, None, None) if ulen>MAX_CLIPBOARD_PACKET_SIZE: errback("too much data") return buf = create_string_buffer(ulen) l = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, byref(buf), ulen, None, None) if l>0: if buf.raw[l-1:l]==b"\0": s = buf.raw[:l-1] else: s = buf.raw[:l] log("got %i bytes of data: %s", len(s), repr_ellipsized(str(s))) callback(strtobytes(s)) else: errback("failed to convert to UTF8: %s" % FormatError(get_last_error())) finally: GlobalUnlock(data)
def set_selection_response(self, requestor, target, prop, dtype, dformat, data, time=0): log("set_selection_response(%s, %s, %s, %s, %s, %r, %i)", requestor, target, prop, dtype, dformat, repr_ellipsized(bytestostr(data)), time) #answer the selection request: try: with xsync: xid = get_xwindow(requestor) if data is not None: X11Window.XChangeProperty(xid, prop, dtype, dformat, data) else: #maybe even delete the property? #X11Window.XDeleteProperty(xid, prop) prop = None X11Window.sendSelectionNotify(xid, self._selection, target, prop, time) except XError as e: log("failed to set selection", exc_info=True) log.warn("Warning: failed to set selection for target '%s'", target) log.warn(" on requestor %s", self.get_wininfo(xid)) log.warn(" property '%s'", prop) log.warn(" %s", e)
def invalid_header(self, proto, data): log("invalid_header(%s, %s)", proto, repr_ellipsized(data)) if proto.input_packetcount == 0 and self._tcp_proxy: self.start_tcp_proxy(proto, data) return err = "invalid packet format, not an xpra client?" proto.gibberish(err, data)
def _process_logging(self, proto, packet): assert self.remote_logging_receive ss = self.get_server_source(proto) if ss is None: return level, msg = packet[1:3] prefix = "client " counter = getattr(ss, "counter", 0) if counter>0: prefix += "%3i " % counter if len(packet)>=4: dtime = packet[3] prefix += "@%02i.%03i " % ((dtime//1000)%60, dtime%1000) def dec(x): try: return x.decode("utf8") except Exception: return bytestostr(x) try: if isinstance(msg, (tuple, list)): dmsg = " ".join(dec(x) for x in msg) else: dmsg = dec(msg) for l in dmsg.splitlines(): self.do_log(level, prefix+l) except Exception as e: log("log message decoding error", exc_info=True) log.error("Error: failed to parse logging message:") log.error(" %s", repr_ellipsized(msg)) log.error(" %s", e)
def get_workarea(): if not is_Wayland(): try: d = get_current_desktop() if d < 0: return None workarea = _get_X11_root_property("_NET_WORKAREA", "CARDINAL") if not workarea: return None screenlog("get_workarea() _NET_WORKAREA=%s (%s), len=%s", repr_ellipsized(workarea), type(workarea), len(workarea)) #workarea comes as a list of 4 CARDINAL dimensions (x,y,w,h), one for each desktop sizeof_long = struct.calcsize(b"@L") if len(workarea) < (d + 1) * 4 * sizeof_long: screenlog.warn("get_workarea() invalid _NET_WORKAREA value") else: cur_workarea = workarea[d * 4 * sizeof_long:(d + 1) * 4 * sizeof_long] v = struct.unpack(b"@LLLL", cur_workarea) screenlog("get_workarea() %s=%s", hexstr(cur_workarea), v) return v except Exception as e: screenlog("get_workarea()", exc_info=True) screenlog.warn("Warning: failed to query workarea: %s", e) return None
def class_run_command(cls, command, **kwargs): if "env" not in kwargs: kwargs["env"] = cls.get_default_run_env() stdout_file = stderr_file = None if isinstance(command, (list, tuple)): strcommand = " ".join("'%s'" % x for x in command) else: strcommand = command if XPRA_TEST_DEBUG: log("************************") log("class_run_command(%s, %s)", command, repr_ellipsized(str(kwargs), 80)) log("************************") else: if "stdout" not in kwargs: stdout_file = cls._temp_file(prefix="xpra-stdout-") kwargs["stdout"] = stdout_file log("stdout: %s for %s", stdout_file.name, strcommand) if "stderr" not in kwargs: stderr_file = cls._temp_file(prefix="xpra-stderr-") kwargs["stderr"] = stderr_file log("stderr: %s for %s", stderr_file.name, strcommand) try: log("class_run_command%s", (command, kwargs)) proc = subprocess.Popen(args=command, **kwargs) proc.command = command proc.stdout_file = stdout_file proc.stderr_file = stderr_file except OSError as e: log.warn("class_run_command(%s, %s) %s", command, kwargs, e) raise cls.processes.append(proc) return proc
def server_connection_established(self, caps): self.log("server_connection_established(%s)" % repr_ellipsized(caps)) self.log("traceback: %s" % (traceback.extract_stack(), )) r = super().server_connection_established(caps) self.stdscr = curses_init() self.update_screen() return r
def unexpected_packet(packet): if packet: log.warn("Warning: received an unexpected packet") log.warn(" from the proxy connection %s:", client_proto) log.warn(" %s", repr_ellipsized(packet)) client_proto.close()
def _process_gibberish(self, packet): log("process_gibberish(%s)", ellipsizer(packet)) message, data = packet[1:3] from xpra.net.socket_util import guess_packet_type #pylint: disable=import-outside-toplevel packet_type = guess_packet_type(data) p = self._protocol exit_code = EXIT_PACKET_FAILURE pcount = p.input_packetcount if p else 0 if pcount<=1: exit_code = EXIT_CONNECTION_FAILED netlog.error("Error: failed to connect") else: netlog.error("Error: received an invalid packet") if packet_type=="xpra": netlog.error(" xpra server bug or mangled packet") if packet_type and packet_type!="xpra": netlog.error(" this is a '%s' packet,", packet_type) netlog.error(" not from an xpra server?") else: netlog.error(" received uninterpretable nonsense: %r", message) data = bytestostr(data).strip("\n\r") show_as_text = pcount<=1 and len(data)<128 and all((c in string.printable) or c in ("\n\r") for c in data) if show_as_text: if data.find("\n")>=0: netlog.error(" data:") for x in data.split("\n"): netlog.error(" %r", x.split("\0")[0]) else: netlog.error(" data: %r", data) else: netlog.error(" packet no %i data: %s", pcount, nonl(repr_ellipsized(data))) self.quit(exit_code)
def invalid_header(self, _proto, data, msg="invalid packet header"): self._packet_parser = self._parse_invalid err = "%s: '%s'" % (msg, hexstr(data[:8])) if len(data) > 1: err += " read buffer=%s (%i bytes)" % (repr_ellipsized(data), len(data)) self.invalid(err, data)
def run_command(self, command, env=None, **kwargs): if env is None: env = kwargs.get("env") or self.get_run_env() kwargs["env"] = env stdout_file = stderr_file = None if isinstance(command, (list, tuple)): strcommand = " ".join("'%s'" % x for x in command) else: strcommand = command if XPRA_TEST_DEBUG: log("************************") log("run_command(%s, %s)", command, repr_ellipsized(str(env), 40)) log("************************") else: if "stdout" not in kwargs: stdout_file = self._temp_file(prefix="xpra-stdout-") kwargs["stdout"] = stdout_file log("stdout: %s for %s", stdout_file.name, strcommand) if "stderr" not in kwargs: stderr_file = self._temp_file(prefix="xpra-stderr-") kwargs["stderr"] = stderr_file log("stderr: %s for %s", stderr_file.name, strcommand) try: proc = subprocess.Popen(args=command, **kwargs) proc.command = command proc.stdout_file = stdout_file proc.stderr_file = stderr_file except OSError as e: log.warn("run_command(%s, %s, %s) %s", command, env, kwargs, e) raise self.processes.append(proc) return proc
def _process_notify_show(self, packet): if not self.notifications_enabled: log("process_notify_show: ignoring packet, notifications are disabled") return self._ui_event() dbus_id, nid, app_name, replaces_nid, app_icon, summary, body, expire_timeout = packet[1:9] icon, actions, hints = None, [], {} if len(packet)>=10: icon = packet[9] if len(packet)>=12: actions, hints = packet[10], packet[11] #note: if the server doesn't support notification forwarding, #it can still send us the messages (via xpra control or the dbus interface) log("_process_notify_show(%s) notifier=%s, server_notifications=%s", repr_ellipsized(str(packet)), self.notifier, self.server_notifications) log("notification actions=%s, hints=%s", actions, hints) assert self.notifier #this one of the few places where we actually do care about character encoding: try: summary = summary.decode("utf8") except: summary = bytestostr(summary) try: body = body.decode("utf8") except: body = bytestostr(body) app_name = bytestostr(app_name) tray = self.get_tray_window(app_name, hints) log("get_tray_window(%s)=%s", app_name, tray) self.notifier.show_notify(dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, actions, hints, expire_timeout, icon)
def test_ssl_socket(self): server = None display_no = self.find_free_display_no() display = ":%s" % display_no tcp_port = get_free_tcp_port() ssl_port = get_free_tcp_port() try: tmpdir = tempfile.mkdtemp(suffix='ssl-xpra') certfile = os.path.join(tmpdir, "self.pem") openssl_command = [ "openssl", "req", "-new", "-newkey", "rsa:4096", "-days", "2", "-nodes", "-x509", "-subj", "/C=US/ST=Denial/L=Springfield/O=Dis/CN=localhost", "-keyout", certfile, "-out", certfile, ] openssl = self.run_command(openssl_command) assert pollwait(openssl, 10)==0, "openssl certificate generation failed" cert_data = load_binary_file(certfile) log("generated cert data: %s", repr_ellipsized(cert_data)) if not cert_data: #cannot run openssl? (happens from rpmbuild) log.warn("SSL test skipped, cannot run '%s'", b" ".join(openssl_command)) return server_args = [ "--bind-tcp=0.0.0.0:%i" % tcp_port, "--bind-ssl=0.0.0.0:%i" % ssl_port, "--ssl=on", "--ssl-cert=%s" % certfile] log("starting test ssl server on %s", display) server = self.start_server(display, *server_args) #test it with openssl client: for port in (tcp_port, ssl_port): openssl_verify_command = "openssl s_client -connect 127.0.0.1:%i -CAfile %s < /dev/null" % (port, certfile) openssl = self.run_command(openssl_verify_command, shell=True) assert pollwait(openssl, 10)==0, "openssl certificate verification failed" def test_connect(uri, exit_code, *client_args): cmd = ["info", uri] + list(client_args) client = self.run_xpra(cmd) r = pollwait(client, 5) if client.poll() is None: client.terminate() assert r==exit_code, "expected info client to return %s but got %s" % (exit_code, client.poll()) noverify = "--ssl-server-verify-mode=none" #connect to ssl socket: test_connect("ssl/127.0.0.1:%i/" % ssl_port, EXIT_OK, noverify) #tcp socket should upgrade: test_connect("ssl/127.0.0.1:%i/" % tcp_port, EXIT_OK, noverify) #self signed cert should fail without noverify: test_connect("ssl/127.0.0.1:%i/" % ssl_port, EXIT_CONNECTION_LOST) test_connect("ssl/127.0.0.1:%i/" % tcp_port, EXIT_CONNECTION_LOST) finally: shutil.rmtree(tmpdir) if server: server.terminate()
def _copy_loop(self, log_name, from_conn, to_conn): #log("XpraProxy._copy_loop(%s, %s, %s)", log_name, from_conn, to_conn) try: while not self._closed: log("%s: waiting for data", log_name) buf = untilConcludes(self.is_active, from_conn.read, PROXY_BUFFER_SIZE) if not buf: log("%s: connection lost", log_name) return if SHOW_DATA: log("%s: %s bytes: %s", log_name, len(buf), repr_ellipsized(buf)) log("%s: %s", log_name, repr_ellipsized(binascii.hexlify(buf))) while buf and not self._closed: log("%s: writing %s bytes", log_name, len(buf)) written = untilConcludes(self.is_active, to_conn.write, buf) buf = buf[written:] log("%s: written %s bytes", log_name, written) except Exception as e: log("%s: %s", log_name, e) self.quit()
def __init__(self, uid, gid, env_options, session_options, socket_dir, video_encoder_modules, csc_modules, client_conn, client_state, cipher, encryption_key, server_conn, caps, message_queue): Process.__init__(self, name=str(client_conn)) self.uid = uid self.gid = gid self.env_options = env_options self.session_options = session_options self.socket_dir = socket_dir self.video_encoder_modules = video_encoder_modules self.csc_modules = csc_modules self.client_conn = client_conn self.client_state = client_state self.cipher = cipher self.encryption_key = encryption_key self.server_conn = server_conn self.caps = caps log("ProxyProcess%s", (uid, gid, env_options, session_options, socket_dir, video_encoder_modules, csc_modules, client_conn, repr_ellipsized(str(client_state)), cipher, encryption_key, server_conn, "%s: %s.." % (type(caps), repr_ellipsized(str(caps))), message_queue)) self.client_protocol = None self.server_protocol = None self.exit = False self.main_queue = None self.message_queue = message_queue self.encode_queue = None #holds draw packets to encode self.encode_thread = None self.video_encoding_defs = None self.video_encoders = None self.video_encoders_last_used_time = None self.video_encoder_types = None self.video_helper = None self.lost_windows = None #for handling the local unix domain socket: self.control_socket_cleanup = None self.control_socket = None self.control_socket_thread = None self.control_socket_path = None self.potential_protocols = [] self.max_connections = MAX_CONCURRENT_CONNECTIONS
def process_packet(self, proto, packet): command = bytestostr(packet[0]) if command==Protocol.CONNECTION_LOST: log("connection-lost: %s, calling stop", packet[1:]) self.net_stop() return elif command==Protocol.GIBBERISH: log.warn("gibberish received:") log.warn(" %s", repr_ellipsized(packet[1], limit=80)) log.warn(" stopping") self.net_stop() return elif command=="stop": log("received stop message") self.net_stop() return elif command=="exit": log("received exit message") sys.exit(0) return #make it easier to hookup signals to methods: attr = command.replace("-", "_") if self.method_whitelist is not None and attr not in self.method_whitelist: log.warn("invalid command: %s (not in whitelist: %s)", attr, self.method_whitelist) return wo = self.wrapped_object if not wo: log("wrapped object is no more, ignoring method call '%s'", attr) return method = getattr(wo, attr, None) if not method: log.warn("unknown command: '%s'", attr) log.warn(" packet: '%s'", repr_ellipsized(str(packet))) return if DEBUG_WRAPPER: log("calling %s.%s%s", wo, attr, str(tuple(packet[1:]))[:128]) self.idle_add(method, *packet[1:]) INJECT_FAULT(proto)
def t(s, ev, remainder=""): try: rv, rr = self.decode(s) #print("decode(%s)=%s (%s)" % (s, rv, type(rv))) _cmp(rv, ev) except Exception as e: print("error on decoding of '%s'" % repr_ellipsized(s)) raise e rrstr = s[rr:] assert rrstr == remainder, "expected remainder value '%s' but got %s" % (remainder, rrstr) # With gibberish added: g_str = s + "asdf" rv, rr = self.decode(g_str) _cmp(rv, ev) rrstr = g_str[rr:] assert rrstr.endswith("asdf")
def check_packet_size(size_to_check, packet_header): if self._closed: return False log( "check_packet_size(%s, 0x%s) limit is %s", size_to_check, repr_ellipsized(packet_header), self.max_packet_size, ) if size_to_check > self.max_packet_size: msg = "packet size requested is %s but maximum allowed is %s" % ( size_to_check, self.max_packet_size, ) self.invalid(msg, packet_header) return False
def invalid_header(self, proto, data): netlog( "invalid_header(%s, %s bytes: '%s') input_packetcount=%s, tcp_proxy=%s", proto, len(data or ""), repr_ellipsized(data), proto.input_packetcount, self._tcp_proxy, ) if proto.input_packetcount == 0 and self._tcp_proxy and not proto._closed: # start a new proxy in a thread def run_proxy(): self.start_tcp_proxy(proto, data) t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto) t.start() return err = "invalid packet format, not an xpra client?" proto.gibberish(err, data)
def encode(self, packet_in): """ Given a packet (tuple or list of items), converts it for the wire. This method returns all the binary packets to send, as an array of: (index, compression_level and compression flags, binary_data) The index, if positive indicates the item to populate in the packet whose index is zero. ie: ["blah", [large binary data], "hello", 200] may get converted to: [ (1, compression_level, [large binary data now zlib compressed]), (0, 0, bencoded/rencoded(["blah", '', "hello", 200])) ] """ packets = [] packet = list(packet_in) level = self.compression_level size_check = LARGE_PACKET_SIZE min_comp_size = 378 for i in range(1, len(packet)): item = packet[i] ti = type(item) if ti in (int, long, bool, dict, list, tuple): continue l = len(item) if ti == Uncompressed: # this is a marker used to tell us we should compress it now # (used by the client for clipboard data) item = item.compress() packet[i] = item ti = type(item) # (it may now be a "Compressed" item and be processed further) if ti in (Compressed, LevelCompressed): # already compressed data (usually pixels, cursors, etc) if not item.can_inline or l > INLINE_SIZE: il = 0 if ti == LevelCompressed: # unlike Compressed (usually pixels, decompressed in the paint thread), # LevelCompressed is decompressed by the network layer # so we must tell it how to do that and pass the level flag il = item.level packets.append((i, il, item.data)) packet[i] = "" else: # data is small enough, inline it: packet[i] = item.data min_comp_size += l size_check += l elif ti in (str, bytes) and level > 0 and l > LARGE_PACKET_SIZE: log.warn( "found a large uncompressed item in packet '%s' at position %s: %s bytes", packet[0], i, len(item) ) # add new binary packet with large item: cl, cdata = self._compress(item, level) packets.append((i, cl, cdata)) # replace this item with an empty string placeholder: packet[i] = "" elif ti not in (str, bytes): log.warn("unexpected data type %s in %s packet: %s", ti, packet[0], repr_ellipsized(item)) # now the main packet (or what is left of it): packet_type = packet[0] self.output_stats[packet_type] = self.output_stats.get(packet_type, 0) + 1 if USE_ALIASES and self.send_aliases and packet_type in self.send_aliases: # replace the packet type with the alias: packet[0] = self.send_aliases[packet_type] try: main_packet, proto_version = self._encoder(packet) except Exception as e: if self._closed: return [], 0 log.error("failed to encode packet: %s", packet, exc_info=True) # make the error a bit nicer to parse: undo aliases: packet[0] = packet_type self.verify_packet(packet) raise e if len(main_packet) > size_check and packet_in[0] not in self.large_packets: log.warn( "found large packet (%s bytes): %s, argument types:%s, sizes: %s, packet head=%s", len(main_packet), packet_in[0], [type(x) for x in packet[1:]], [len(str(x)) for x in packet[1:]], repr_ellipsized(packet), ) # compress, but don't bother for small packets: if level > 0 and len(main_packet) > min_comp_size: cl, cdata = self._compress(main_packet, level) packets.append((0, cl, cdata)) else: packets.append((0, 0, main_packet)) return packets, proto_version
def _process_invalid(self, packet): (_, message, data) = packet log.info("Received invalid packet: %s", message) log(" data: %s", repr_ellipsized(data)) self.quit(EXIT_PACKET_FAILURE)
def verify_hello(self, proto, c): remote_version = c.strget("version") verr = version_compat_check(remote_version) if verr is not None: self.disconnect_client(proto, VERSION_ERROR, "incompatible version: %s" % verr) proto.close() return False def auth_failed(msg): authlog.error("Error: authentication failed") authlog.error(" %s", msg) self.timeout_add(1000, self.disconnect_client, proto, msg) #authenticator: username = c.strget("username") if proto.authenticator is None and proto.auth_class: authlog("creating authenticator %s", proto.auth_class) try: auth, aclass, options = proto.auth_class ainstance = aclass(username, **options) proto.authenticator = ainstance authlog("%s=%s", auth, ainstance) except Exception as e: authlog.error("Error instantiating %s:", proto.auth_class) authlog.error(" %s", e) auth_failed("authentication failed") return False self.digest_modes = c.get("digest", ("hmac", )) #client may have requested encryption: cipher = c.strget("cipher") cipher_iv = c.strget("cipher.iv") key_salt = c.strget("cipher.key_salt") iterations = c.intget("cipher.key_stretch_iterations") padding = c.strget("cipher.padding", DEFAULT_PADDING) padding_options = c.strlistget("cipher.padding.options", [DEFAULT_PADDING]) auth_caps = {} if cipher and cipher_iv: if cipher not in ENCRYPTION_CIPHERS: authlog.warn("unsupported cipher: %s", cipher) auth_failed("unsupported cipher") return False encryption_key = self.get_encryption_key(proto.authenticator, proto.keyfile) if encryption_key is None: auth_failed("encryption key is missing") return False if padding not in ALL_PADDING_OPTIONS: auth_failed("unsupported padding: %s" % padding) return False authlog("set output cipher using encryption key '%s'", repr_ellipsized(encryption_key)) proto.set_cipher_out(cipher, cipher_iv, encryption_key, key_salt, iterations, padding) #use the same cipher as used by the client: auth_caps = new_cipher_caps(proto, cipher, encryption_key, padding_options) authlog("server cipher=%s", auth_caps) else: if proto.encryption: authlog("client does not provide encryption tokens") auth_failed("missing encryption tokens") return False auth_caps = None #verify authentication if required: if (proto.authenticator and proto.authenticator.requires_challenge()) or c.get("challenge") is not None: challenge_response = c.strget("challenge_response") client_salt = c.strget("challenge_client_salt") authlog("processing authentication with %s, response=%s, client_salt=%s, challenge_sent=%s", proto.authenticator, challenge_response, binascii.hexlify(client_salt or ""), proto.challenge_sent) #send challenge if this is not a response: if not challenge_response: if proto.challenge_sent: auth_failed("invalid state, challenge already sent - no response!") return False if proto.authenticator: challenge = proto.authenticator.get_challenge() if challenge is None: auth_failed("invalid state, unexpected challenge response") return False authlog("challenge: %s", challenge) salt, digest = challenge authlog.info("Authentication required by %s authenticator module", proto.authenticator) authlog.info(" sending challenge for '%s' using %s digest", username, digest) if digest not in self.digest_modes: auth_failed("cannot proceed without %s digest support" % digest) return False else: authlog.warn("Warning: client expects a challenge but this connection is unauthenticated") #fake challenge so the client will send the real hello: from xpra.os_util import get_hex_uuid salt = get_hex_uuid()+get_hex_uuid() digest = "hmac" proto.challenge_sent = True proto.send_now(("challenge", salt, auth_caps or "", digest)) return False if not proto.authenticator.authenticate(challenge_response, client_salt): auth_failed("invalid challenge response") return False authlog("authentication challenge passed") else: #did the client expect a challenge? if c.boolget("challenge"): authlog.warn("this server does not require authentication (client supplied a challenge)") return auth_caps
def gibberish(self, *args): log.warn("%s stopping on gibberish:", self.description) log.warn(" %s", repr_ellipsized(args[1], limit=80)) self.stop()
def _process_invalid(self, protocol, packet): (_, message, data) = packet netlog("Received invalid packet: %s", message) netlog(" data: %s", repr_ellipsized(data)) self.disconnect_client(protocol, message)
def _process_gibberish(self, proto, packet): (_, message, data) = packet netlog("Received uninterpretable nonsense from %s: %s", proto, message) netlog(" data: %s", repr_ellipsized(data)) self.disconnect_client(proto, message)
def do_read_parse_thread_loop(self): """ Process the individual network packets placed in _read_queue. Concatenate the raw packet data, then try to parse it. Extract the individual packets from the potentially large buffer, saving the rest of the buffer for later, and optionally decompress this data and re-construct the one python-object-packet from potentially multiple packets (see packet_index). The 8 bytes packet header gives us information on the packet index, packet size and compression. The actual processing of the packet is done via the callback process_packet_cb, this will be called from this parsing thread so any calls that need to be made from the UI thread will need to use a callback (usually via 'idle_add') """ read_buffer = None payload_size = -1 padding_size = 0 packet_index = 0 compression_level = False packet = None raw_packets = {} while not self._closed: buf = self._read_queue.get() if not buf: log("read thread: empty marker, exiting") self.idle_add(self.close) return if read_buffer: read_buffer = read_buffer + buf else: read_buffer = buf bl = len(read_buffer) while not self._closed: packet = None bl = len(read_buffer) if bl<=0: break if payload_size<0: if read_buffer[0] not in ("P", ord("P")): self._invalid_header(read_buffer) return if bl<8: break #packet still too small #packet format: struct.pack('cBBBL', ...) - 8 bytes _, protocol_flags, compression_level, packet_index, data_size = unpack_header(read_buffer[:8]) #sanity check size (will often fail if not an xpra client): if data_size>self.abs_max_packet_size: self._invalid_header(read_buffer) return bl = len(read_buffer)-8 if protocol_flags & FLAGS_CIPHER: if self.cipher_in_block_size==0 or not self.cipher_in_name: cryptolog.warn("received cipher block but we don't have a cipher to decrypt it with, not an xpra client?") self._invalid_header(read_buffer) return padding_size = self.cipher_in_block_size - (data_size % self.cipher_in_block_size) payload_size = data_size + padding_size else: #no cipher, no padding: padding_size = 0 payload_size = data_size assert payload_size>0, "invalid payload size: %i" % payload_size read_buffer = read_buffer[8:] if payload_size>self.max_packet_size: #this packet is seemingly too big, but check again from the main UI thread #this gives 'set_max_packet_size' a chance to run from "hello" def check_packet_size(size_to_check, packet_header): if self._closed: return False log("check_packet_size(%s, 0x%s) limit is %s", size_to_check, repr_ellipsized(packet_header), self.max_packet_size) if size_to_check>self.max_packet_size: msg = "packet size requested is %s but maximum allowed is %s" % \ (size_to_check, self.max_packet_size) self.invalid(msg, packet_header) return False self.timeout_add(1000, check_packet_size, payload_size, read_buffer[:32]) if bl<payload_size: # incomplete packet, wait for the rest to arrive break #chop this packet from the buffer: if len(read_buffer)==payload_size: raw_string = read_buffer read_buffer = '' else: raw_string = read_buffer[:payload_size] read_buffer = read_buffer[payload_size:] #decrypt if needed: data = raw_string if self.cipher_in and protocol_flags & FLAGS_CIPHER: cryptolog("received %i %s encrypted bytes with %s padding", payload_size, self.cipher_in_name, padding_size) data = self.cipher_in.decrypt(raw_string) if padding_size > 0: def debug_str(s): try: return binascii.hexlify(bytearray(s)) except: return csv(list(str(s))) # pad byte value is number of padding bytes added padtext = pad(self.cipher_in_padding, padding_size) if data.endswith(padtext): cryptolog("found %s %s padding", self.cipher_in_padding, self.cipher_in_name) else: actual_padding = data[-padding_size:] cryptolog.warn("Warning: %s decryption failed: invalid padding", self.cipher_in_name) cryptolog(" data does not end with %s padding bytes %s", self.cipher_in_padding, debug_str(padtext)) cryptolog(" but with %s (%s)", debug_str(actual_padding), type(data)) cryptolog(" decrypted data: %s", debug_str(data[:128])) return self._internal_error("%s encryption padding error - wrong key?" % self.cipher_in_name) data = data[:-padding_size] #uncompress if needed: if compression_level>0: try: data = decompress(data, compression_level) except InvalidCompressionException as e: self.invalid("invalid compression: %s" % e, data) return except Exception as e: ctype = compression.get_compression_type(compression_level) log("%s packet decompression failed", ctype, exc_info=True) msg = "%s packet decompression failed" % ctype if self.cipher_in: msg += " (invalid encryption key?)" else: #only include the exception text when not using encryption #as this may leak crypto information: msg += " %s" % e return self.gibberish(msg, data) if self.cipher_in and not (protocol_flags & FLAGS_CIPHER): self.invalid("unencrypted packet dropped", data) return if self._closed: return if packet_index>0: #raw packet, store it and continue: raw_packets[packet_index] = data payload_size = -1 packet_index = 0 if len(raw_packets)>=4: self.invalid("too many raw packets: %s" % len(raw_packets), data) return continue #final packet (packet_index==0), decode it: try: packet = decode(data, protocol_flags) except InvalidPacketEncodingException as e: self.invalid("invalid packet encoding: %s" % e, data) return except ValueError as e: etype = packet_encoding.get_packet_encoding_type(protocol_flags) log.error("Error parsing %s packet:", etype) log.error(" %s", e) if self._closed: return log("failed to parse %s packet: %s", etype, binascii.hexlify(data[:128])) log(" %s", e) log(" data: %s", repr_ellipsized(data)) log(" packet index=%i, packet size=%i, buffer size=%s", packet_index, payload_size, bl) self.gibberish("failed to parse %s packet" % etype, data) return if self._closed: return payload_size = -1 padding_size = 0 #add any raw packets back into it: if raw_packets: for index,raw_data in raw_packets.items(): #replace placeholder with the raw_data packet data: packet[index] = raw_data raw_packets = {} packet_type = packet[0] if self.receive_aliases and type(packet_type)==int and packet_type in self.receive_aliases: packet_type = self.receive_aliases.get(packet_type) packet[0] = packet_type self.input_stats[packet_type] = self.output_stats.get(packet_type, 0)+1 self.input_packetcount += 1 log("processing packet %s", packet_type) self._process_packet_cb(self, packet) packet = None INJECT_FAULT(self)
def unexpected_packet(packet): if packet: log.warn("received an unexpected packet on the proxy connection: %s", repr_ellipsized(packet))
def invalid_header(self, proto, data): err = "invalid packet header: '%s'" % binascii.hexlify(data[:8]) if len(data) > 1: err += " read buffer=%s" % repr_ellipsized(data) self.gibberish(err, data)
def unexpected_packet(packet): if packet: log.warn("Warning: received an unexpected packet on the proxy connection %s:", client_proto) log.warn(" %s", repr_ellipsized(packet))