Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Listening to unix socket [+ git patch for v0.10.0] #539

Open
shiomax opened this issue Nov 8, 2022 · 1 comment
Open

Support for Listening to unix socket [+ git patch for v0.10.0] #539

shiomax opened this issue Nov 8, 2022 · 1 comment
Labels
feature New feature or request

Comments

@shiomax
Copy link
Contributor

shiomax commented Nov 8, 2022

I´m using websockify and two other services behind NGINX in a docker container. Listening to an IP in this setup is not ideal. Allocates an extra port and a Unix socket should also be slightly faster.

I´ve already implemented a patch for websockify v0.10.0.

This would add two more options

  --unix-listen=FILE    listen to unix socket
  --unix-listen-mode=LISTEN_SOCK_MODE
                        specify mode for unix socket (defaults to 0600)

I used 0600 as the default access modifier as that's what tigervnc seems to default to.

Can work on a merge request if this seems fine to you.

You can apply the patch against either the git tag v0.10.0 or the tar releases (but I have not tested if this works with the latest commit)
Either with

  • Git git apply <patchfile> (I hope... I never used this command)
  • Linux patch command patch --directory /path/to/websockify -p1 </path/to/patch
diff --git a/websockify/websocketproxy.py b/websockify/websocketproxy.py
index 09d7882..16199f0 100644
--- a/websockify/websocketproxy.py
+++ b/websockify/websocketproxy.py
@@ -11,7 +11,7 @@ as taken from http://docs.python.org/dev/library/ssl.html#certificates
 
 '''
 
-import signal, socket, optparse, time, os, sys, subprocess, logging, errno, ssl
+import signal, socket, optparse, time, os, sys, subprocess, logging, errno, ssl, stat
 from socketserver import ThreadingMixIn
 from http.server import HTTPServer
 
@@ -112,7 +112,9 @@ Traffic Legend:
                              self.server.target_host, self.server.target_port, e)
             raise self.CClose(1011, "Failed to connect to downstream server")
 
-        self.request.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
+        # Option unavailable when listening to unix socket
+        if not self.server.listen_sock:
+            self.request.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
         if not self.server.wrap_cmd and not self.server.unix_target:
             tsock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
 
@@ -467,6 +469,12 @@ def websockify_init():
     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-listen",
+            dest="listen_sock",
+            help="listen to unix socket", metavar="FILE")
+    parser.add_option("--unix-listen-mode",
+            dest="listen_sock_mode", default=None,
+            help="specify mode for unix socket (defaults to 0600)")
     parser.add_option("--unix-target",
             help="connect to unix socket target", metavar="FILE")
     parser.add_option("--inetd",
@@ -617,6 +625,16 @@ def websockify_init():
 
     if opts.inetd:
         opts.listen_fd = sys.stdin.fileno()
+    elif opts.listen_sock:
+        if opts.listen_sock_mode:
+            try:
+                # Parse octal notation (like 750)
+                opts.listen_sock_mode = int(opts.listen_sock_mode, 8)
+            except ValueError:
+                parser.error("Error parsing listen unix socket mode")
+        else:
+            # Default to 0600 (Owner Read/Write)
+            opts.listen_sock_mode = stat.S_IREAD | stat.S_IWRITE
     else:
         if len(args) < 1:
             parser.error("Too few arguments")
diff --git a/websockify/websockifyserver.py b/websockify/websockifyserver.py
index 0199e42..948c34b 100644
--- a/websockify/websockifyserver.py
+++ b/websockify/websockifyserver.py
@@ -325,12 +325,15 @@ class WebSockifyServer():
             file_only=False,
             run_once=False, timeout=0, idle_timeout=0, traffic=False,
             tcp_keepalive=True, tcp_keepcnt=None, tcp_keepidle=None,
-            tcp_keepintvl=None, ssl_ciphers=None, ssl_options=0):
+            tcp_keepintvl=None, ssl_ciphers=None, ssl_options=0,
+            listen_sock=None, listen_sock_mode=None):
 
         # settings
         self.RequestHandlerClass = RequestHandlerClass
         self.verbose        = verbose
         self.listen_fd      = listen_fd
+        self.listen_sock         = listen_sock
+        self.listen_sock_mode    = listen_sock_mode
         self.listen_host    = listen_host
         self.listen_port    = listen_port
         self.prefer_ipv6    = source_is_ipv6
@@ -387,6 +390,8 @@ class WebSockifyServer():
         self.msg("WebSocket server settings:")
         if self.listen_fd != None:
             self.msg("  - Listen for inetd connections")
+        elif self.listen_sock != None:
+            self.msg("  - Listen on unix socket %s", self.listen_sock)
         else:
             self.msg("  - Listen on %s:%s",
                     self.listen_host, self.listen_port)
@@ -700,6 +705,17 @@ class WebSockifyServer():
 
         if self.listen_fd != None:
             lsock = socket.fromfd(self.listen_fd, socket.AF_INET, socket.SOCK_STREAM)
+        elif self.listen_sock != None:
+            # Make sure the socket does not already exist
+            try:
+                os.unlink(self.listen_sock)
+            except OSError:
+                if os.path.exists(self.listen_sock):
+                    raise
+            lsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            lsock.bind(self.listen_sock)
+            os.chmod(self.listen_sock, self.listen_sock_mode)
+            lsock.listen(100)
         else:
             lsock = self.socket(self.listen_host, self.listen_port, False,
                                 self.prefer_ipv6,
@@ -766,6 +782,9 @@ class WebSockifyServer():
                             ready = select.select([lsock], [], [], 1)[0]
                             if lsock in ready:
                                 startsock, address = lsock.accept()
+                                # Unix Socket will not report address (empty string), but address[0] is logged a bunch
+                                if self.listen_sock != None:
+                                    address = [ self.listen_sock ]
                             else:
                                 continue
                         except self.Terminate:

@CendioOssman
Copy link
Member

Seems reasonable. Please send this as a pull request and we can look at the details.

@CendioOssman CendioOssman added the feature New feature or request label Nov 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants