Skip to content

Commit d540205

Browse files
committed
Merge branch 'master' of https://github.com/shiomax/websockify
2 parents ac74ade + 63eb24d commit d540205

File tree

2 files changed

+78
-34
lines changed

2 files changed

+78
-34
lines changed

websockify/websocketproxy.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
1212
'''
1313

14-
import signal, socket, optparse, time, os, sys, subprocess, logging, errno, ssl
14+
import signal, socket, optparse, time, os, sys, subprocess, logging, errno, ssl, stat
1515
from socketserver import ThreadingMixIn
1616
from http.server import HTTPServer
1717

@@ -112,7 +112,9 @@ def new_websocket_client(self):
112112
self.server.target_host, self.server.target_port, e)
113113
raise self.CClose(1011, "Failed to connect to downstream server")
114114

115-
self.request.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
115+
# Option unavailable when listening to unix socket
116+
if not self.server.unix_listen:
117+
self.request.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
116118
if not self.server.wrap_cmd and not self.server.unix_target:
117119
tsock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
118120

@@ -495,6 +497,10 @@ def websockify_init():
495497
parser.add_option("--ssl-ciphers", action="store",
496498
help="list of ciphers allowed for connection. For a list of "
497499
"supported ciphers run `openssl ciphers`")
500+
parser.add_option("--unix-listen",
501+
help="listen to unix socket", metavar="FILE", default=None)
502+
parser.add_option("--unix-listen-mode", default=None,
503+
help="specify mode for unix socket (defaults to 0600)")
498504
parser.add_option("--unix-target",
499505
help="connect to unix socket target", metavar="FILE")
500506
parser.add_option("--inetd",
@@ -650,6 +656,16 @@ def websockify_init():
650656

651657
if opts.inetd:
652658
opts.listen_fd = sys.stdin.fileno()
659+
elif opts.unix_listen:
660+
if opts.unix_listen_mode:
661+
try:
662+
# Parse octal notation (like 750)
663+
opts.unix_listen_mode = int(opts.unix_listen_mode, 8)
664+
except ValueError:
665+
parser.error("Error parsing listen unix socket mode")
666+
else:
667+
# Default to 0600 (Owner Read/Write)
668+
opts.unix_listen_mode = stat.S_IREAD | stat.S_IWRITE
653669
else:
654670
if len(args) < 1:
655671
parser.error("Too few arguments")

websockify/websockifyserver.py

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -325,37 +325,40 @@ def __init__(self, RequestHandlerClass, listen_fd=None,
325325
file_only=False,
326326
run_once=False, timeout=0, idle_timeout=0, traffic=False,
327327
tcp_keepalive=True, tcp_keepcnt=None, tcp_keepidle=None,
328-
tcp_keepintvl=None, ssl_ciphers=None, ssl_options=0):
328+
tcp_keepintvl=None, ssl_ciphers=None, ssl_options=0,
329+
unix_listen=None, unix_listen_mode=None):
329330

330331
# settings
331332
self.RequestHandlerClass = RequestHandlerClass
332-
self.verbose = verbose
333-
self.listen_fd = listen_fd
334-
self.listen_host = listen_host
335-
self.listen_port = listen_port
336-
self.prefer_ipv6 = source_is_ipv6
337-
self.ssl_only = ssl_only
338-
self.ssl_ciphers = ssl_ciphers
339-
self.ssl_options = ssl_options
340-
self.verify_client = verify_client
341-
self.daemon = daemon
342-
self.run_once = run_once
343-
self.timeout = timeout
344-
self.idle_timeout = idle_timeout
345-
self.traffic = traffic
346-
self.file_only = file_only
347-
self.web_auth = web_auth
348-
349-
self.launch_time = time.time()
350-
self.ws_connection = False
351-
self.handler_id = 1
352-
self.terminating = False
353-
354-
self.logger = self.get_logger()
355-
self.tcp_keepalive = tcp_keepalive
356-
self.tcp_keepcnt = tcp_keepcnt
357-
self.tcp_keepidle = tcp_keepidle
358-
self.tcp_keepintvl = tcp_keepintvl
333+
self.verbose = verbose
334+
self.listen_fd = listen_fd
335+
self.unix_listen = unix_listen
336+
self.unix_listen_mode = unix_listen_mode
337+
self.listen_host = listen_host
338+
self.listen_port = listen_port
339+
self.prefer_ipv6 = source_is_ipv6
340+
self.ssl_only = ssl_only
341+
self.ssl_ciphers = ssl_ciphers
342+
self.ssl_options = ssl_options
343+
self.verify_client = verify_client
344+
self.daemon = daemon
345+
self.run_once = run_once
346+
self.timeout = timeout
347+
self.idle_timeout = idle_timeout
348+
self.traffic = traffic
349+
self.file_only = file_only
350+
self.web_auth = web_auth
351+
352+
self.launch_time = time.time()
353+
self.ws_connection = False
354+
self.handler_id = 1
355+
self.terminating = False
356+
357+
self.logger = self.get_logger()
358+
self.tcp_keepalive = tcp_keepalive
359+
self.tcp_keepcnt = tcp_keepcnt
360+
self.tcp_keepidle = tcp_keepidle
361+
self.tcp_keepintvl = tcp_keepintvl
359362

360363
# keyfile path must be None if not specified
361364
self.key = None
@@ -387,6 +390,8 @@ def __init__(self, RequestHandlerClass, listen_fd=None,
387390
self.msg("WebSocket server settings:")
388391
if self.listen_fd != None:
389392
self.msg(" - Listen for inetd connections")
393+
elif self.unix_listen != None:
394+
self.msg(" - Listen on unix socket %s", self.unix_listen)
390395
else:
391396
self.msg(" - Listen on %s:%s",
392397
self.listen_host, self.listen_port)
@@ -421,8 +426,9 @@ def get_logger():
421426

422427
@staticmethod
423428
def socket(host, port=None, connect=False, prefer_ipv6=False,
424-
unix_socket=None, use_ssl=False, tcp_keepalive=True,
425-
tcp_keepcnt=None, tcp_keepidle=None, tcp_keepintvl=None):
429+
unix_socket=None, unix_socket_mode=None, unix_socket_listen=False,
430+
use_ssl=False, tcp_keepalive=True, tcp_keepcnt=None,
431+
tcp_keepidle=None, tcp_keepintvl=None):
426432
""" Resolve a host (and optional port) to an IPv4 or IPv6
427433
address. Create a socket. Bind to it if listen is set,
428434
otherwise connect to it. Return the socket.
@@ -470,8 +476,22 @@ def socket(host, port=None, connect=False, prefer_ipv6=False,
470476
sock.bind(addrs[0][4])
471477
sock.listen(100)
472478
else:
473-
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
474-
sock.connect(unix_socket)
479+
if unix_socket_listen:
480+
# Make sure the socket does not already exist
481+
try:
482+
os.unlink(unix_socket)
483+
except FileNotFoundError:
484+
pass
485+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
486+
oldmask = os.umask(0o777 ^ unix_socket_mode)
487+
try:
488+
sock.bind(unix_socket)
489+
finally:
490+
os.umask(oldmask)
491+
sock.listen(100)
492+
else:
493+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
494+
sock.connect(unix_socket)
475495

476496
return sock
477497

@@ -700,6 +720,11 @@ def start_server(self):
700720

701721
if self.listen_fd != None:
702722
lsock = socket.fromfd(self.listen_fd, socket.AF_INET, socket.SOCK_STREAM)
723+
elif self.unix_listen != None:
724+
lsock = self.socket(host=None,
725+
unix_socket=self.unix_listen,
726+
unix_socket_mode=self.unix_listen_mode,
727+
unix_socket_listen=True)
703728
else:
704729
lsock = self.socket(self.listen_host, self.listen_port, False,
705730
self.prefer_ipv6,
@@ -766,6 +791,9 @@ def start_server(self):
766791
ready = select.select([lsock], [], [], 1)[0]
767792
if lsock in ready:
768793
startsock, address = lsock.accept()
794+
# Unix Socket will not report address (empty string), but address[0] is logged a bunch
795+
if self.unix_listen != None:
796+
address = [ self.unix_listen ]
769797
else:
770798
continue
771799
except self.Terminate:

0 commit comments

Comments
 (0)