xpra icon
Bug tracker and wiki

Ticket #1136: web-ssl.patch

File web-ssl.patch, 10.9 KB (added by Antoine Martin, 4 years ago)

attempts at preventing ssl from deadlocking - failed

  • xpra/net/websocket.py

     
    3030        server = AdHocStruct()
    3131        server.logger = log
    3232        server.run_once = True
     33        server.verbose = os.environ.get("XPRA_WEBSOCKIFY_DEBUG", "0")=="1"
    3334        WebSocketRequestHandler.__init__(self, sock, addr, server)
    3435
    3536    def new_websocket_client(self):
  • xpra/scripts/config.py

     
    340340                    "speaker"           : str,
    341341                    "sound-source"      : str,
    342342                    "html"              : str,
     343                    "ssl-cert"          : str,
     344                    "ssl-key"           : str,
    343345                    "socket-permissions": str,
    344346                    "exec-wrapper"      : str,
    345347                    "dbus-launch"       : str,
     
    523525                    "input-method"      : "none",
    524526                    "sound-source"      : "",
    525527                    "html"              : "auto",
     528                    "ssl-cert"          : "",
     529                    "ssl-key"           : "",
    526530                    "socket-permissions": "600",
    527531                    "exec-wrapper"      : "",
    528532                    "dbus-launch"       : "dbus-launch --close-stderr",
  • xpra/scripts/main.py

     
    310310                          dest="html", default=defaults.html,
    311311                          metavar="on|off|[HOST:]PORT",
    312312                          help="Enable the web server and the html5 client. Default: '%default'.")
     313        group.add_option("--ssl-cert", action="store",
     314                          dest="ssl_cert", default=defaults.ssl_cert,
     315                          metavar="/path/to/cert.pem",
     316                          help="Certificate file to use for SSL traffic. Default: '%default'.")
     317        group.add_option("--ssl-key", action="store",
     318                          dest="ssl_key", default=defaults.ssl_key,
     319                          metavar="/path/to/key.pem",
     320                          help="Key file to use for SSL traffic. Default: '%default'.")
    313321    else:
    314         ignore({"tcp_proxy" : "",
    315                 "html"      : ""})
     322        ignore({
     323                "tcp_proxy" : "",
     324                "html"      : "",
     325                "ssl-cert"  : "",
     326                "ssl-key"   : "",
     327                })
    316328    legacy_bool_parse("daemon")
    317329    if (supports_server or supports_shadow) and CAN_DAEMONIZE:
    318330        group.add_option("--daemon", action="store", metavar="yes|no",
  • xpra/server/gtk_server_base.py

     
    6666        log("do_run() end of gtk.main()")
    6767
    6868    def add_listen_socket(self, socktype, sock):
    69         sock.listen(5)
     69        sock.listen(100)
    7070        glib.io_add_watch(sock, glib.IO_IN, self._new_connection, sock)
    7171        self.socket_types[sock] = socktype
    7272
  • xpra/server/server_core.py

     
    149149        self._tcp_proxy = ""
    150150        self._html = False
    151151        self._www_dir = None
     152        self._ssl_cert = None
     153        self._ssl_key = None
    152154        self._aliases = {}
    153155        self._reverse_aliases = {}
    154156        self.socket_types = {}
     
    206208        self.init_auth(opts)
    207209
    208210    def init_html_proxy(self, opts):
     211        self._ssl_cert = opts.ssl_cert
     212        self._ssl_key = opts.ssl_key or self._ssl_cert
     213
    209214        self._tcp_proxy = opts.tcp_proxy
    210215        #opts.html can contain a boolean, "auto" or the path to the webroot
    211216        www_dir = None
     
    509514            netlog.error("too many connections (%s), ignoring new one", len(self._potential_protocols))
    510515            sock.close()
    511516            return True
     517
     518        def threaded_accept():
     519            self.accept_socket(socktype, sock, address)
     520        make_thread(threaded_accept, "%s-%s" % (socktype, address), daemon=True).start()
     521        return True
     522
     523    def accept_socket(self, socktype, sock, address):
    512524        try:
    513525            peername = sock.getpeername()
    514526        except:
     
    516528        sockname = sock.getsockname()
    517529        target = peername or sockname
    518530        sock.settimeout(self._socket_timeout)
    519         netlog("new_connection(%s) sock=%s, timeout=%s, sockname=%s, address=%s, peername=%s", args, sock, self._socket_timeout, sockname, address, peername)
     531        netlog("accept_socket(%s) timeout=%s, sockname=%s, peername=%s", (socktype, sock, address), self._socket_timeout, sockname, peername)
    520532        conn = SocketConnection(sock, sockname, address, target, socktype)
    521533        netlog("socket connection: %s", conn)
    522534        if peername:
     
    532544        if socktype=="tcp" and self._html or self._tcp_proxy:
    533545            #see if the packet data is actually xpra or something else
    534546            #that we need to handle via a tcp proxy or the websockify adapter:
    535             conn._socket.settimeout(25)
     547            sock.settimeout(5)
     548            #sock.setblocking(True)
    536549            v = conn.peek(128)
    537             netlog("peek()=%s", nonl(v))
     550            netlog("peek()=%s", repr_ellipsized(v))
    538551            if v and v[0] not in ("P", ord("P")):
     552                netlog("peek() first character=%s / %s", nonl(v[0]), hex(ord(v[0])))
     553                #SSL?
     554                ssl_sock = None
     555                if v[0] in ("\x16", "\x80", 22, 128):
     556                    netlog("peek() SSL traffic, trying cert=%s, key=%s", self._ssl_cert, self._ssl_key)
     557                    if self._ssl_cert and self._ssl_key:
     558                        try:
     559                            import ssl
     560                            ssl_sock = ssl.wrap_socket(sock, server_side=True, certfile=self._ssl_cert, keyfile=self._ssl_key)
     561                            netlog("wrapped socket %s using SSL: %s", sock, ssl_sock)
     562                            conn._socket = ssl_sock
     563                            ssl_sock.settimeout(5)
     564                            ssl_sock.do_handshake(False)
     565                            v = conn.peek(128)
     566                            netlog("handshake complete, ssl peek: %s", repr_ellipsized(v))
     567                        except Exception as e:
     568                            netlog.error("Error: cannot wrap SSL socket:")
     569                            netlog.error(" %s", e)
     570                            return
     571                    else:
     572                        log.warn("Warning: no SSL certificate configured, cannot parse this request")
     573
    539574                if self._html:
    540                     line1 = v.splitlines()[0]
    541                     if line1.find("HTTP/")>0:
     575                    line1 = ""
     576                    if v:
     577                        line1 = v.splitlines()[0]
     578                    if line1.find("HTTP/")>0 or ssl_sock:
    542579                        if line1.startswith("GET ") or line1.startswith("POST "):
    543580                            parts = line1.split(" ")
    544                             netlog.info("New http %s request received from %s for '%s'", parts[0], frominfo, parts[1])
    545                             tname = "%s-request" % parts[0]
     581                            netlog.info("New %s %s request received from %s for '%s'", ["http", "https"][ssl_sock is not None], parts[0], frominfo, parts[1])
    546582                        else:
    547                             netlog.info("New http connection received from %s", frominfo)
    548                             tname = "websockify-proxy"
    549                         def run_websockify():
    550                             self.start_websockify(conn, frominfo)
    551                         make_thread(run_websockify, "%s-for-%s" % (tname, frominfo), daemon=True).start()
    552                         return True
     583                            netlog.info("New %s connection received from %s", ["http", "https"][ssl_sock is not None], frominfo)
     584                        self.start_websockify(conn, frominfo)
     585                        return
    553586                elif self._tcp_proxy:
    554587                    netlog.info("New tcp proxy connection received from %s", frominfo)
    555588                    def run_proxy():
    556589                        self.start_tcp_proxy(conn, frominfo)
    557590                    make_thread(run_proxy, "tcp-proxy-for-%s" % frominfo, daemon=True).start()
    558                     return True
     591                    return
    559592        else:
    560593            v = conn.peek(128)
    561594        netlog("%s.peek(128)=%s", conn, v)
     
    570603                conn.close()
    571604            except Exception as e:
    572605                netlog("error sending '%s': %s", nonl(msg), e)
    573             return True
     606            return
    574607        netlog.info(info_msg)
    575         return self.make_protocol(socktype, conn, frominfo)
     608        self.make_protocol(socktype, conn, frominfo)
    576609
    577610    def make_protocol(self, socktype, conn, frominfo=""):
    578611        protocol = Protocol(self, conn, self.process_packet)
     
    601634            protocol.set_cipher_in(protocol.encryption, DEFAULT_IV, password, DEFAULT_SALT, DEFAULT_ITERATIONS, INITIAL_PADDING)
    602635        protocol.start()
    603636        self.timeout_add(SOCKET_TIMEOUT*1000, self.verify_connection_accepted, protocol)
    604         return True
    605637
    606638    def invalid_header(self, proto, data):
    607639        netlog("invalid_header(%s, %s bytes: '%s') input_packetcount=%s, tcp_proxy=%s, html=%s", proto, len(data or ""), repr_ellipsized(data), proto.input_packetcount, self._tcp_proxy, self._html)
     
    617649                netlog("new_websocket_client(%s)", wsh)
    618650                wsc = WebSocketConnection(conn._socket, conn.local, conn.remote, conn.target, conn.info, wsh)
    619651                self.make_protocol("tcp", wsc, frominfo)
    620             WSRequestHandler(conn._socket, frominfo, new_websocket_client, self._www_dir)
    621             return
     652            wsrh = WSRequestHandler(conn._socket, frominfo, new_websocket_client, self._www_dir)
     653            netlog("WSRequestHandler=%s", wsrh)
    622654        except IOError as e:
    623655            netlog.error("Error: http failure responding to %s:", frominfo)
    624656            netlog.error(" %s", e)
     
    626658        except Exception as e:
    627659            netlog.error("Error: http failure responding to %s:", frominfo, exc_info=True)
    628660        try:
     661            try:
     662                conn._socket.shutdown(socket.SHUT_RDWR)
     663            except Exception as ce:
     664                netlog("error closing connection following error: %s", ce)           
    629665            conn.close()
    630666        except Exception as ce:
    631667            netlog("error closing connection following error: %s", ce)