def websockify_init(): # Setup basic logging to stderr. logger = logging.getLogger(WebSocketProxy.log_prefix) logger.propagate = False logger.setLevel(logging.INFO) stderr_handler = logging.StreamHandler() stderr_handler.setLevel(logging.DEBUG) log_formatter = logging.Formatter("%(message)s") stderr_handler.setFormatter(log_formatter) logger.addHandler(stderr_handler) # Setup optparse. usage = "\n %prog [options]" usage += " [source_addr:]source_port [target_addr:target_port]" usage += "\n %prog [options]" usage += " [source_addr:]source_port -- WRAP_COMMAND_LINE" parser = optparse.OptionParser(usage=usage) parser.add_option("--verbose", "-v", action="store_true", help="verbose messages") parser.add_option("--traffic", action="store_true", help="per frame traffic") parser.add_option("--record", help="record sessions to FILE.[session_number]", metavar="FILE") parser.add_option("--daemon", "-D", dest="daemon", action="store_true", help="become a daemon (background process)") parser.add_option("--run-once", action="store_true", help="handle a single WebSocket connection and exit") parser.add_option("--timeout", type=int, default=0, help="after TIMEOUT seconds exit when not connected") parser.add_option( "--idle-timeout", type=int, default=0, help="server exits after TIMEOUT seconds if there are no " "active connections") parser.add_option("--cert", default="self.pem", help="SSL certificate file") parser.add_option("--key", default=None, help="SSL key file (if separate from cert)") parser.add_option("--key-password", default=None, help="SSL key password") parser.add_option("--ssl-only", action="store_true", help="disallow non-encrypted client connections") parser.add_option("--ssl-target", action="store_true", help="connect to SSL target as SSL client") parser.add_option( "--verify-client", action="store_true", help="require encrypted client to present a valid certificate " "(needs Python 2.7.9 or newer or Python 3.4 or newer)") parser.add_option( "--cafile", metavar="FILE", help="file of concatenated certificates of authorities trusted " "for validating clients (only effective with --verify-client). " "If omitted, system default list of CAs is used.") parser.add_option( "--ssl-version", type="choice", default="default", choices=["default", "tlsv1_1", "tlsv1_2", "tlsv1_3"], action="store", help="minimum TLS version to use (default, tlsv1_1, tlsv1_2, tlsv1_3)") parser.add_option( "--ssl-ciphers", action="store", help="list of ciphers allowed for connection. For a list of " "supported ciphers run `openssl ciphers`") parser.add_option("--unix-target", help="connect to unix socket target", metavar="FILE") parser.add_option("--inetd", help="inetd mode, receive listening socket from stdin", action="store_true") parser.add_option("--web", default=None, metavar="DIR", help="run webserver on same port. Serve files from DIR.") parser.add_option("--web-auth", action="store_true", help="require authentication to access webserver.") parser.add_option("--wrap-mode", default="exit", metavar="MODE", choices=["exit", "ignore", "respawn"], help="action to take when the wrapped program exits " "or daemonizes: exit (default), ignore, respawn") parser.add_option("--prefer-ipv6", "-6", action="store_true", dest="source_is_ipv6", help="prefer IPv6 when resolving source_addr") parser.add_option("--libserver", action="store_true", help="use Python library SocketServer engine") parser.add_option( "--target-config", metavar="FILE", dest="target_cfg", help="Configuration file containing valid targets " "in the form 'token: host:port' or, alternatively, a " "directory containing configuration files of this form " "(DEPRECATED: use `--token-plugin TokenFile --token-source " " path/to/token/file` instead)") parser.add_option( "--token-plugin", default=None, metavar="CLASS", help="use a Python class, usually one from websockify.token_plugins, " "such as TokenFile, to process tokens into host:port pairs") parser.add_option("--token-source", default=None, metavar="ARG", help="an argument to be passed to the token plugin " "on instantiation") parser.add_option("--host-token", action="store_true", help="use the host HTTP header as token instead of the " "token URL query parameter") parser.add_option( "--auth-plugin", default=None, metavar="CLASS", help="use a Python class, usually one from websockify.auth_plugins, " "such as BasicHTTPAuth, to determine if a connection is allowed") parser.add_option("--auth-source", default=None, metavar="ARG", help="an argument to be passed to the auth plugin " "on instantiation") parser.add_option("--heartbeat", type=int, default=0, metavar="INTERVAL", help="send a ping to the client every INTERVAL seconds") parser.add_option("--log-file", metavar="FILE", dest="log_file", help="File where logs will be saved") parser.add_option("--syslog", default=None, metavar="SERVER", help="Log to syslog server. SERVER can be local socket, " "such as /dev/log, or a UDP host:port pair.") parser.add_option( "--legacy-syslog", action="store_true", help="Use the old syslog protocol instead of RFC 5424. " "Use this if the messages produced by websockify seem abnormal.") (opts, args) = parser.parse_args() # Validate options. if opts.token_source and not opts.token_plugin: parser.error("You must use --token-plugin to use --token-source") if opts.host_token and not opts.token_plugin: parser.error("You must use --token-plugin to use --host-token") if opts.auth_source and not opts.auth_plugin: parser.error("You must use --auth-plugin to use --auth-source") if opts.web_auth and not opts.auth_plugin: parser.error("You must use --auth-plugin to use --web-auth") if opts.web_auth and not opts.web: parser.error("You must use --web to use --web-auth") if opts.legacy_syslog and not opts.syslog: parser.error("You must use --syslog to use --legacy-syslog") opts.ssl_options = select_ssl_version(opts.ssl_version) del opts.ssl_version if opts.log_file: # Setup logging to user-specified file. opts.log_file = os.path.abspath(opts.log_file) log_file_handler = logging.FileHandler(opts.log_file) log_file_handler.setLevel(logging.DEBUG) log_file_handler.setFormatter(log_formatter) logger.addHandler(log_file_handler) del opts.log_file if opts.syslog: # Determine how to connect to syslog... if opts.syslog.count(':'): # User supplied a host:port pair. syslog_host, syslog_port = opts.syslog.rsplit(':', 1) try: syslog_port = int(syslog_port) except ValueError: parser.error("Error parsing syslog port") syslog_dest = (syslog_host, syslog_port) else: # User supplied a local socket file. syslog_dest = os.path.abspath(opts.syslog) from websockify.sysloghandler import WebsockifySysLogHandler # Determine syslog facility. if opts.daemon: syslog_facility = WebsockifySysLogHandler.LOG_DAEMON else: syslog_facility = WebsockifySysLogHandler.LOG_USER # Start logging to syslog. syslog_handler = WebsockifySysLogHandler(address=syslog_dest, facility=syslog_facility, ident='websockify', legacy=opts.legacy_syslog) syslog_handler.setLevel(logging.DEBUG) syslog_handler.setFormatter(log_formatter) logger.addHandler(syslog_handler) del opts.syslog del opts.legacy_syslog if opts.verbose: logger.setLevel(logging.DEBUG) # Transform to absolute path as daemon may chdir if opts.target_cfg: opts.target_cfg = os.path.abspath(opts.target_cfg) if opts.target_cfg: opts.token_plugin = 'TokenFile' opts.token_source = opts.target_cfg del opts.target_cfg if sys.argv.count('--'): opts.wrap_cmd = args[1:] else: opts.wrap_cmd = None if not websockifyserver.ssl and opts.ssl_target: parser.error("SSL target requested and Python SSL module not loaded.") if opts.ssl_only and not os.path.exists(opts.cert): parser.error("SSL only and %s not found" % opts.cert) if opts.inetd: opts.listen_fd = sys.stdin.fileno() else: if len(args) < 1: parser.error("Too few arguments") arg = args.pop(0) # Parse host:port and convert ports to numbers if arg.count(':') > 0: opts.listen_host, opts.listen_port = arg.rsplit(':', 1) opts.listen_host = opts.listen_host.strip('[]') else: opts.listen_host, opts.listen_port = '', arg try: opts.listen_port = int(opts.listen_port) except ValueError: parser.error("Error parsing listen port") del opts.inetd if opts.wrap_cmd or opts.unix_target or opts.token_plugin: opts.target_host = None opts.target_port = None else: if len(args) < 1: parser.error("Too few arguments") arg = args.pop(0) if arg.count(':') > 0: opts.target_host, opts.target_port = arg.rsplit(':', 1) opts.target_host = opts.target_host.strip('[]') else: parser.error("Error parsing target") try: opts.target_port = int(opts.target_port) except ValueError: parser.error("Error parsing target port") if len(args) > 0 and opts.wrap_cmd == None: parser.error("Too many arguments") if opts.token_plugin is not None: if '.' not in opts.token_plugin: opts.token_plugin = ('websockify.token_plugins.%s' % opts.token_plugin) token_plugin_module, token_plugin_cls = opts.token_plugin.rsplit( '.', 1) __import__(token_plugin_module) token_plugin_cls = getattr(sys.modules[token_plugin_module], token_plugin_cls) opts.token_plugin = token_plugin_cls(opts.token_source) del opts.token_source if opts.auth_plugin is not None: if '.' not in opts.auth_plugin: opts.auth_plugin = 'websockify.auth_plugins.%s' % opts.auth_plugin auth_plugin_module, auth_plugin_cls = opts.auth_plugin.rsplit('.', 1) __import__(auth_plugin_module) auth_plugin_cls = getattr(sys.modules[auth_plugin_module], auth_plugin_cls) opts.auth_plugin = auth_plugin_cls(opts.auth_source) del opts.auth_source # Create and start the WebSockets proxy libserver = opts.libserver del opts.libserver if libserver: # Use standard Python SocketServer framework server = LibProxyServer(**opts.__dict__) server.serve_forever() else: # Use internal service framework server = WebSocketProxy(**opts.__dict__) server.start_server()
def websockify_init(): # Setup basic logging to stderr. logger = logging.getLogger(WebSocketProxy.log_prefix) logger.propagate = False logger.setLevel(logging.INFO) stderr_handler = logging.StreamHandler() stderr_handler.setLevel(logging.DEBUG) log_formatter = logging.Formatter("%(message)s") stderr_handler.setFormatter(log_formatter) logger.addHandler(stderr_handler) # Setup optparse. usage = "\n %prog [options]" usage += " [source_addr:]source_port [target_addr:target_port]" usage += "\n %prog [options]" usage += " [source_addr:]source_port -- WRAP_COMMAND_LINE" parser = optparse.OptionParser(usage=usage) parser.add_option("--verbose", "-v", action="store_true", help="verbose messages") parser.add_option("--traffic", action="store_true", help="per frame traffic") parser.add_option("--record", help="record sessions to FILE.[session_number]", metavar="FILE") parser.add_option("--daemon", "-D", dest="daemon", action="store_true", help="become a daemon (background process)") parser.add_option("--run-once", action="store_true", help="handle a single WebSocket connection and exit") parser.add_option("--timeout", type=int, default=0, help="after TIMEOUT seconds exit when not connected") parser.add_option("--idle-timeout", type=int, default=0, help="server exits after TIMEOUT seconds if there are no " "active connections") parser.add_option("--cert", default="self.pem", help="SSL certificate file") parser.add_option("--key", default=None, help="SSL key file (if separate from cert)") parser.add_option("--key-password", default=None, help="SSL key password") parser.add_option("--ssl-only", action="store_true", help="disallow non-encrypted client connections") parser.add_option("--ssl-target", action="store_true", help="connect to SSL target as SSL client") parser.add_option("--verify-client", action="store_true", help="require encrypted client to present a valid certificate " "(needs Python 2.7.9 or newer or Python 3.4 or newer)") parser.add_option("--cafile", metavar="FILE", help="file of concatenated certificates of authorities trusted " "for validating clients (only effective with --verify-client). " "If omitted, system default list of CAs is used.") parser.add_option("--ssl-version", type="choice", default="default", choices=["default", "tlsv1_1", "tlsv1_2", "tlsv1_3"], action="store", help="minimum TLS version to use (default, tlsv1_1, tlsv1_2, tlsv1_3)") parser.add_option("--ssl-ciphers", action="store", help="list of ciphers allowed for connection. For a list of " "supported ciphers run `openssl ciphers`") parser.add_option("--unix-target", help="connect to unix socket target", metavar="FILE") parser.add_option("--inetd", help="inetd mode, receive listening socket from stdin", action="store_true") parser.add_option("--web", default=None, metavar="DIR", help="run webserver on same port. Serve files from DIR.") parser.add_option("--web-auth", action="store_true", help="require authentication to access webserver.") parser.add_option("--wrap-mode", default="exit", metavar="MODE", choices=["exit", "ignore", "respawn"], help="action to take when the wrapped program exits " "or daemonizes: exit (default), ignore, respawn") parser.add_option("--prefer-ipv6", "-6", action="store_true", dest="source_is_ipv6", help="prefer IPv6 when resolving source_addr") parser.add_option("--libserver", action="store_true", help="use Python library SocketServer engine") parser.add_option("--target-config", metavar="FILE", dest="target_cfg", help="Configuration file containing valid targets " "in the form 'token: host:port' or, alternatively, a " "directory containing configuration files of this form " "(DEPRECATED: use `--token-plugin TokenFile --token-source " " path/to/token/file` instead)") parser.add_option("--token-plugin", default=None, metavar="CLASS", help="use a Python class, usually one from websockify.token_plugins, " "such as TokenFile, to process tokens into host:port pairs") parser.add_option("--token-source", default=None, metavar="ARG", help="an argument to be passed to the token plugin " "on instantiation") parser.add_option("--host-token", action="store_true", help="use the host HTTP header as token instead of the " "token URL query parameter") parser.add_option("--auth-plugin", default=None, metavar="CLASS", help="use a Python class, usually one from websockify.auth_plugins, " "such as BasicHTTPAuth, to determine if a connection is allowed") parser.add_option("--auth-source", default=None, metavar="ARG", help="an argument to be passed to the auth plugin " "on instantiation") parser.add_option("--heartbeat", type=int, default=0, metavar="INTERVAL", help="send a ping to the client every INTERVAL seconds") parser.add_option("--log-file", metavar="FILE", dest="log_file", help="File where logs will be saved") parser.add_option("--syslog", default=None, metavar="SERVER", help="Log to syslog server. SERVER can be local socket, " "such as /dev/log, or a UDP host:port pair.") parser.add_option("--legacy-syslog", action="store_true", help="Use the old syslog protocol instead of RFC 5424. " "Use this if the messages produced by websockify seem abnormal.") (opts, args) = parser.parse_args() # Validate options. if opts.token_source and not opts.token_plugin: parser.error("You must use --token-plugin to use --token-source") if opts.host_token and not opts.token_plugin: parser.error("You must use --token-plugin to use --host-token") if opts.auth_source and not opts.auth_plugin: parser.error("You must use --auth-plugin to use --auth-source") if opts.web_auth and not opts.auth_plugin: parser.error("You must use --auth-plugin to use --web-auth") if opts.web_auth and not opts.web: parser.error("You must use --web to use --web-auth") if opts.legacy_syslog and not opts.syslog: parser.error("You must use --syslog to use --legacy-syslog") opts.ssl_options = select_ssl_version(opts.ssl_version) del opts.ssl_version if opts.log_file: # Setup logging to user-specified file. opts.log_file = os.path.abspath(opts.log_file) log_file_handler = logging.FileHandler(opts.log_file) log_file_handler.setLevel(logging.DEBUG) log_file_handler.setFormatter(log_formatter) logger.addHandler(log_file_handler) del opts.log_file if opts.syslog: # Determine how to connect to syslog... if opts.syslog.count(':'): # User supplied a host:port pair. syslog_host, syslog_port = opts.syslog.rsplit(':', 1) try: syslog_port = int(syslog_port) except ValueError: parser.error("Error parsing syslog port") syslog_dest = (syslog_host, syslog_port) else: # User supplied a local socket file. syslog_dest = os.path.abspath(opts.syslog) from websockify.sysloghandler import WebsockifySysLogHandler # Determine syslog facility. if opts.daemon: syslog_facility = WebsockifySysLogHandler.LOG_DAEMON else: syslog_facility = WebsockifySysLogHandler.LOG_USER # Start logging to syslog. syslog_handler = WebsockifySysLogHandler(address=syslog_dest, facility=syslog_facility, ident='websockify', legacy=opts.legacy_syslog) syslog_handler.setLevel(logging.DEBUG) syslog_handler.setFormatter(log_formatter) logger.addHandler(syslog_handler) del opts.syslog del opts.legacy_syslog if opts.verbose: logger.setLevel(logging.DEBUG) # Transform to absolute path as daemon may chdir if opts.target_cfg: opts.target_cfg = os.path.abspath(opts.target_cfg) if opts.target_cfg: opts.token_plugin = 'TokenFile' opts.token_source = opts.target_cfg del opts.target_cfg if sys.argv.count('--'): opts.wrap_cmd = args[1:] else: opts.wrap_cmd = None if not websockifyserver.ssl and opts.ssl_target: parser.error("SSL target requested and Python SSL module not loaded."); if opts.ssl_only and not os.path.exists(opts.cert): parser.error("SSL only and %s not found" % opts.cert) if opts.inetd: opts.listen_fd = sys.stdin.fileno() else: if len(args) < 1: parser.error("Too few arguments") arg = args.pop(0) # Parse host:port and convert ports to numbers if arg.count(':') > 0: opts.listen_host, opts.listen_port = arg.rsplit(':', 1) opts.listen_host = opts.listen_host.strip('[]') else: opts.listen_host, opts.listen_port = '', arg try: opts.listen_port = int(opts.listen_port) except ValueError: parser.error("Error parsing listen port") del opts.inetd if opts.wrap_cmd or opts.unix_target or opts.token_plugin: opts.target_host = None opts.target_port = None else: if len(args) < 1: parser.error("Too few arguments") arg = args.pop(0) if arg.count(':') > 0: opts.target_host, opts.target_port = arg.rsplit(':', 1) opts.target_host = opts.target_host.strip('[]') else: parser.error("Error parsing target") try: opts.target_port = int(opts.target_port) except ValueError: parser.error("Error parsing target port") if len(args) > 0 and opts.wrap_cmd == None: parser.error("Too many arguments") if opts.token_plugin is not None: if '.' not in opts.token_plugin: opts.token_plugin = ( 'websockify.token_plugins.%s' % opts.token_plugin) token_plugin_module, token_plugin_cls = opts.token_plugin.rsplit('.', 1) __import__(token_plugin_module) token_plugin_cls = getattr(sys.modules[token_plugin_module], token_plugin_cls) opts.token_plugin = token_plugin_cls(opts.token_source) del opts.token_source if opts.auth_plugin is not None: if '.' not in opts.auth_plugin: opts.auth_plugin = 'websockify.auth_plugins.%s' % opts.auth_plugin auth_plugin_module, auth_plugin_cls = opts.auth_plugin.rsplit('.', 1) __import__(auth_plugin_module) auth_plugin_cls = getattr(sys.modules[auth_plugin_module], auth_plugin_cls) opts.auth_plugin = auth_plugin_cls(opts.auth_source) del opts.auth_source # Create and start the WebSockets proxy libserver = opts.libserver del opts.libserver if libserver: # Use standard Python SocketServer framework server = LibProxyServer(**opts.__dict__) server.serve_forever() else: # Use internal service framework server = WebSocketProxy(**opts.__dict__) server.start_server()