[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Added a hosts-allow facility to TCP connections, which allows us to restrict



# HG changeset patch
# User emellor@xxxxxxxxxxxxxxxxxxxxxx
# Node ID 58397be18c524eeb3af0352472e808f2987d810e
# Parent  566395e5a14fd914b3f38c3ed7b6b019a1bcdae3
Added a hosts-allow facility to TCP connections, which allows us to restrict
the acceptable connections based upon a regular expression comparison with the
FQDN or the IP address.

Use the hosts-allow facility to restrict access to the relocation socket.  This
adds the configuration option xend-relocation-hosts-allow, which takes a
space-separated sequence of regular expressions.

Pass the protocol class instance through to SocketServerConnection, rather than
a new instance of that class.  This means that the new instance need not be
passed through SocketListener.acceptConnection.

Make the SocketServerConnection and SocketListener classes start their
corresponding threads and open their sockets (in the case of SocketListener)
automatically.  This means that callers do not need to save an instance locally,
just to call run() or listen() on it.  This also means that listenTCP and
listenUnix can go -- simply creating a TCPListener or UnixListener instance is
sufficient.

Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx>

diff -r 566395e5a14f -r 58397be18c52 tools/python/xen/web/connection.py
--- a/tools/python/xen/web/connection.py        Mon Dec 12 16:32:50 2005
+++ b/tools/python/xen/web/connection.py        Mon Dec 12 16:43:48 2005
@@ -19,7 +19,6 @@
 
 import sys
 import threading
-import select
 import socket
 import fcntl
 
@@ -31,21 +30,17 @@
 """
 
 BUFFER_SIZE = 1024
+BACKLOG = 5
 
 
 class SocketServerConnection:
     """An accepted connection to a server.
     """
 
-    def __init__(self, sock, protocol, addr, server):
+    def __init__(self, sock, protocol_class):
         self.sock = sock
-        self.protocol = protocol
-        self.addr = addr
-        self.server = server
+        self.protocol = protocol_class()
         self.protocol.setTransport(self)
-
-
-    def run(self):
         threading.Thread(target=self.main).start()
 
 
@@ -68,6 +63,10 @@
                 pass
 
 
+    def close(self):
+        self.sock.close()
+
+
     def write(self, data):
         self.sock.send(data)
 
@@ -77,52 +76,38 @@
     Accepts connections and runs a thread for each one.
     """
 
-    def __init__(self, protocol_class, backlog=None):
-        if backlog is None:
-            backlog = 5
+    def __init__(self, protocol_class, hosts_allow = ''):
         self.protocol_class = protocol_class
-        self.sock = None
-        self.backlog = backlog
-        self.thread = None
+        self.sock = self.createSocket()
+        threading.Thread(target=self.main).start()
+
+
+    def close(self):
+        try:
+            self.sock.close()
+        except:
+            pass
 
 
     def createSocket(self):
         raise NotImplementedError()
 
 
-    def setCloExec(self):
-        fcntl.fcntl(self.sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
-
-
     def acceptConnection(self, sock, protocol, addr):
-        return SocketServerConnection(sock, protocol, addr, self)
-
-
-    def listen(self):
-        if self.sock or self.thread:
-            raise IOError("already listening")
-        self.sock = self.createSocket()
-        self.sock.listen(self.backlog)
-        self.run()
-
-
-    def run(self):
-        self.thread = threading.Thread(target=self.main)
-        self.thread.start()
+        raise NotImplementedError()
 
 
     def main(self):
         try:
+            fcntl.fcntl(self.sock.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
+            self.sock.listen(BACKLOG)
+
             while True:
                 try:
                     (sock, addr) = self.sock.accept()
-                    self.acceptConnection(sock, self.protocol_class(),
-                                          addr).run()
+                    self.acceptConnection(sock, addr)
                 except socket.error, ex:
                     if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
                         break
         finally:
-            try:
-                self.sock.close()
-            except:
-                pass
+            self.close()
diff -r 566395e5a14f -r 58397be18c52 tools/python/xen/web/tcp.py
--- a/tools/python/xen/web/tcp.py       Mon Dec 12 16:32:50 2005
+++ b/tools/python/xen/web/tcp.py       Mon Dec 12 16:43:48 2005
@@ -17,20 +17,25 @@
 #============================================================================
 
 
+import errno
+import re
 import socket
 import time
-import errno
 
-from connection import *
+import connection
+
+from xen.xend.XendLogging import log
 
 
-class TCPListener(SocketListener):
+class TCPListener(connection.SocketListener):
 
-    def __init__(self, port, protocol, backlog=None, interface=''):
-        SocketListener.__init__(self, protocol, backlog=backlog)
+    def __init__(self, protocol_class, port, interface, hosts_allow):
         self.port = port
         self.interface = interface
-        
+        self.hosts_allow = hosts_allow
+        connection.SocketListener.__init__(self, protocol_class)
+
+
     def createSocket(self):
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -49,11 +54,23 @@
                 else:
                     raise
 
-    def acceptConnection(self, sock, protocol, addr):
-        return SocketServerConnection(sock, protocol, addr, self)
 
+    def acceptConnection(self, sock, addrport):
+        addr = addrport[0]
+        if self.hosts_allow is None:
+                connection.SocketServerConnection(sock, self.protocol_class)
+        else:
+            fqdn = socket.getfqdn(addr)
+            for h in self.hosts_allow:
+                if h.match(fqdn) or h.match(addr):
+                    log.debug("Match %s %s", fqdn, h.pattern)
+                    connection.SocketServerConnection(sock,
+                                                      self.protocol_class)
+                    return
 
-def listenTCP(port, protocol, interface='', backlog=None):
-    l = TCPListener(port, protocol, interface=interface, backlog=backlog)
-    l.listen()
-    l.setCloExec()
+            try:
+                log.warn("Rejected connection from %s:%d (%s) for port %d.",
+                         addr, addrport[1], fqdn, self.port)
+                sock.close()
+            except:
+                pass
diff -r 566395e5a14f -r 58397be18c52 tools/python/xen/web/unix.py
--- a/tools/python/xen/web/unix.py      Mon Dec 12 16:32:50 2005
+++ b/tools/python/xen/web/unix.py      Mon Dec 12 16:43:48 2005
@@ -21,15 +21,15 @@
 import os
 import os.path
 
-from connection import *
+import connection
 
 
-class UnixListener(SocketListener):
+class UnixListener(connection.SocketListener):
+    def __init__(self, path, protocol_class):
+        self.path = path
+        connection.SocketListener.__init__(self, protocol_class)
 
-    def __init__(self, path, protocol, backlog=None):
-        SocketListener.__init__(self, protocol, backlog=backlog)
-        self.path = path
-        
+
     def createSocket(self):
         pathdir = os.path.dirname(self.path)
         if not os.path.exists(pathdir):
@@ -45,9 +45,6 @@
         sock.bind(self.path)
         return sock
 
-    def acceptConnection(self, sock, protocol, addr):
-        return SocketServerConnection(sock, protocol, self.path, self)
 
-
-def listenUNIX(path, protocol, backlog=None):
-    UnixListener(path, protocol, backlog=backlog).listen()
+    def acceptConnection(self, sock, _):
+        connection.SocketServerConnection(sock, self.protocol_class)
diff -r 566395e5a14f -r 58397be18c52 tools/python/xen/xend/XendRoot.py
--- a/tools/python/xen/xend/XendRoot.py Mon Dec 12 16:32:50 2005
+++ b/tools/python/xen/xend/XendRoot.py Mon Dec 12 16:43:48 2005
@@ -74,6 +74,8 @@
 
     """Default port xend serves relocation at. """
     xend_relocation_port_default = '8002'
+
+    xend_relocation_hosts_allow_default = ''
 
     """Default for the flag indicating whether xend should run a unix-domain 
server."""
     xend_unix_server_default = 'yes'
@@ -194,6 +196,10 @@
         """
         return self.get_config_int('xend-relocation-port', 
self.xend_relocation_port_default)
 
+    def get_xend_relocation_hosts_allow(self):
+        return self.get_config_value("xend-relocation-hosts-allow",
+                                     self.xend_relocation_hosts_allow_default)
+
     def get_xend_address(self):
         """Get the address xend listens at for its HTTP port.
         This defaults to the empty string which allows all hosts to connect.
diff -r 566395e5a14f -r 58397be18c52 tools/python/xen/xend/server/relocate.py
--- a/tools/python/xen/xend/server/relocate.py  Mon Dec 12 16:32:50 2005
+++ b/tools/python/xen/xend/server/relocate.py  Mon Dec 12 16:43:48 2005
@@ -16,6 +16,7 @@
 # Copyright (C) 2005 XenSource Ltd
 #============================================================================
 
+import re
 import sys
 import StringIO
 
@@ -116,8 +117,16 @@
     xroot = XendRoot.instance()
     if xroot.get_xend_unix_server():
         path = '/var/lib/xend/relocation-socket'
-        unix.listenUNIX(path, RelocationProtocol)
+        unix.UnixListener(path, RelocationProtocol)
     if xroot.get_xend_relocation_server():
         port = xroot.get_xend_relocation_port()
         interface = xroot.get_xend_relocation_address()
-        tcp.listenTCP(port, RelocationProtocol, interface=interface)
+
+        hosts_allow = xroot.get_xend_relocation_hosts_allow()
+        if hosts_allow == '':
+            hosts_allow = None
+        else:
+            hosts_allow = map(re.compile, hosts_allow.split(" "))
+
+        tcp.TCPListener(RelocationProtocol, port, interface = interface,
+                        hosts_allow = hosts_allow)

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.