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

[Xen-changelog] [xen-unstable] Implement an "allowed hosts" mechanism for the XML-RPC server layer, using



# HG changeset patch
# User Ewan Mellor <ewan@xxxxxxxxxxxxx>
# Node ID 6206685650f582d79f4b84f2b4d35d886cccdff0
# Parent  b4baf35cff112b60c5f7d077e2c23d97e9480cf8
Implement an "allowed hosts" mechanism for the XML-RPC server layer, using
code from the relocation protocol handling and some plumbing.  Add a new
configuration entry for the Xen-API server, including use of this mechanism.

Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx>
---
 tools/examples/xend-config.sxp               |   26 ++++++++++++++++++++++++++
 tools/python/xen/util/xmlrpclib2.py          |   27 ++++++++++++++++++++++-----
 tools/python/xen/web/connection.py           |   16 +++++++++++++++-
 tools/python/xen/web/tcp.py                  |   14 ++------------
 tools/python/xen/xend/XendRoot.py            |    9 +++++++++
 tools/python/xen/xend/server/SrvServer.py    |   24 ++++++++++++++++++++++++
 tools/python/xen/xend/server/XMLRPCServer.py |   13 +++++++++++--
 7 files changed, 109 insertions(+), 20 deletions(-)

diff -r b4baf35cff11 -r 6206685650f5 tools/examples/xend-config.sxp
--- a/tools/examples/xend-config.sxp    Tue Nov 28 09:51:05 2006 +0000
+++ b/tools/examples/xend-config.sxp    Tue Nov 28 10:23:34 2006 +0000
@@ -13,6 +13,32 @@
 
 #(logfile /var/log/xen/xend.log)
 #(loglevel DEBUG)
+
+# The Xen-API server configuration.  (Please note that this server is available
+# as an UNSUPPORTED PREVIEW in Xen 3.0.4, and should not be relied upon).
+#
+# This value configures the ports, interfaces, and access controls for the
+# Xen-API server.  Each entry in the list starts with either unix, a port
+# number, or an address:port pair.  If this is "unix", then a UDP socket is
+# opened, and this entry applies to that.  If it is a port, then Xend will
+# listen on all interfaces on that TCP port, and if it is an address:port pair,
+# then Xend will listen on the specified port, using the interface with the
+# specified address.
+#
+# The subsequent string gives the access control for the listener in question. 
+# If this is missing or empty, then all connections are accepted.
+# Otherwise, this should be a space-separated sequence of regular expressions;
+# any host with a fully-qualified domain name or an IP address that matches one
+# of these regular expressions will be accepted.
+#
+# Example:
+#
+#  Listen on TCP port 9363 on all interfaces, accepting connections only from
+#  machines in example.com or localhost.
+#  (xen-api-server ((9363 '^localhost$ example\\.com$')))
+#
+# Default:
+#   (xen-api-server ((unix)))
 
 #(xend-http-server no)
 #(xend-unix-server no)
diff -r b4baf35cff11 -r 6206685650f5 tools/python/xen/util/xmlrpclib2.py
--- a/tools/python/xen/util/xmlrpclib2.py       Tue Nov 28 09:51:05 2006 +0000
+++ b/tools/python/xen/util/xmlrpclib2.py       Tue Nov 28 10:23:34 2006 +0000
@@ -30,6 +30,7 @@ import SocketServer
 import SocketServer
 import xmlrpclib, socket, os, stat
 
+from xen.web import connection
 from xen.xend.XendLogging import log
 
 try:
@@ -70,6 +71,11 @@ class XMLRPCRequestHandler(SimpleXMLRPCR
 class XMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
     protocol_version = "HTTP/1.1"
 
+    def __init__(self, hosts_allowed, request, client_address, server):
+        self.hosts_allowed = hosts_allowed
+        SimpleXMLRPCRequestHandler.__init__(self, request, client_address,
+                                            server)
+
     # this is inspired by SimpleXMLRPCRequestHandler's do_POST but differs
     # in a few non-trivial ways
     # 1) we never generate internal server errors.  We let the exception
@@ -77,6 +83,11 @@ class XMLRPCRequestHandler(SimpleXMLRPCR
     # 2) we don't bother checking for a _dispatch function since we don't
     #    use one
     def do_POST(self):
+        addrport = self.client_address
+        if not connection.hostAllowed(addrport, self.hosts_allowed):
+            self.connection.shutdown(1)
+            return
+
         data = self.rfile.read(int(self.headers["content-length"]))
         rsp = self.server._marshaled_dispatch(data)
 
@@ -150,9 +161,14 @@ class TCPXMLRPCServer(SocketServer.Threa
 class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
     allow_reuse_address = True
 
-    def __init__(self, addr, requestHandler=XMLRPCRequestHandler,
+    def __init__(self, addr, allowed, requestHandler=None,
                  logRequests = 1):
-        SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests)
+        if requestHandler is None:
+            requestHandler = XMLRPCRequestHandler
+        SimpleXMLRPCServer.__init__(self, addr,
+                                    (lambda x, y, z:
+                                     requestHandler(allowed, x, y, z)),
+                                    logRequests)
 
         flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
         flags |= fcntl.FD_CLOEXEC
@@ -217,7 +233,7 @@ class UnixXMLRPCServer(TCPXMLRPCServer):
 class UnixXMLRPCServer(TCPXMLRPCServer):
     address_family = socket.AF_UNIX
 
-    def __init__(self, addr, logRequests = 1):
+    def __init__(self, addr, allowed, logRequests = 1):
         parent = os.path.dirname(addr)
         if os.path.exists(parent):
             os.chown(parent, os.geteuid(), os.getegid())
@@ -226,5 +242,6 @@ class UnixXMLRPCServer(TCPXMLRPCServer):
                 os.unlink(addr)
         else:
             os.makedirs(parent, stat.S_IRWXU)
-        TCPXMLRPCServer.__init__(self, addr, UnixXMLRPCRequestHandler,
-                                 logRequests)
+
+        TCPXMLRPCServer.__init__(self, addr, allowed,
+                                 UnixXMLRPCRequestHandler, logRequests)
diff -r b4baf35cff11 -r 6206685650f5 tools/python/xen/web/connection.py
--- a/tools/python/xen/web/connection.py        Tue Nov 28 09:51:05 2006 +0000
+++ b/tools/python/xen/web/connection.py        Tue Nov 28 10:23:34 2006 +0000
@@ -24,6 +24,8 @@ import fcntl
 
 from errno import EAGAIN, EINTR, EWOULDBLOCK
 
+from xen.xend.XendLogging import log
+
 """General classes to support server and client sockets, without
 specifying what kind of socket they are. There are subclasses
 for TCP and unix-domain sockets (see tcp.py and unix.py).
@@ -76,7 +78,7 @@ class SocketListener:
     Accepts connections and runs a thread for each one.
     """
 
-    def __init__(self, protocol_class, hosts_allow = ''):
+    def __init__(self, protocol_class):
         self.protocol_class = protocol_class
         self.sock = self.createSocket()
         threading.Thread(target=self.main).start()
@@ -111,3 +113,15 @@ class SocketListener:
                         break
         finally:
             self.close()
+
+
+def hostAllowed(addrport, hosts_allowed):
+    if hosts_allowed is None:
+        return True
+    else:
+        fqdn = socket.getfqdn(addrport[0])
+        for h in hosts_allowed:
+            if h.match(fqdn) or h.match(addrport[0]):
+                return True
+        log.warn("Rejected connection from %s (%s).", addrport[0], fqdn)
+        return False
diff -r b4baf35cff11 -r 6206685650f5 tools/python/xen/web/tcp.py
--- a/tools/python/xen/web/tcp.py       Tue Nov 28 09:51:05 2006 +0000
+++ b/tools/python/xen/web/tcp.py       Tue Nov 28 10:23:34 2006 +0000
@@ -57,20 +57,10 @@ class TCPListener(connection.SocketListe
 
     def acceptConnection(self, sock, addrport):
         addr = addrport[0]
-        if self.hosts_allow is None:
-                connection.SocketServerConnection(sock, self.protocol_class)
+        if connection.hostAllowed(addrport, self.hosts_allow):
+            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
-
             try:
-                log.warn("Rejected connection from %s:%d (%s) for port %d.",
-                         addr, addrport[1], fqdn, self.port)
                 sock.close()
             except:
                 pass
diff -r b4baf35cff11 -r 6206685650f5 tools/python/xen/xend/XendRoot.py
--- a/tools/python/xen/xend/XendRoot.py Tue Nov 28 09:51:05 2006 +0000
+++ b/tools/python/xen/xend/XendRoot.py Tue Nov 28 10:23:34 2006 +0000
@@ -53,6 +53,9 @@ class XendRoot:
 
     """Default level of information to be logged."""
     loglevel_default = 'DEBUG'
+
+    """Default Xen-API server configuration. """
+    xen_api_server_default = [['unix']]
 
     """Default for the flag indicating whether xend should run an http server
     (deprecated)."""
@@ -189,6 +192,12 @@ class XendRoot:
         except Exception:
             raise XendError("invalid xend config %s: expected int: %s" % 
(name, v))
 
+    def get_xen_api_server(self):
+        """Get the Xen-API server configuration.
+        """
+        return self.get_config_value('xen-api-server',
+                                     self.xen_api_server_default)
+
     def get_xend_http_server(self):
         """Get the flag indicating whether xend should run an http server.
         """
diff -r b4baf35cff11 -r 6206685650f5 tools/python/xen/xend/server/SrvServer.py
--- a/tools/python/xen/xend/server/SrvServer.py Tue Nov 28 09:51:05 2006 +0000
+++ b/tools/python/xen/xend/server/SrvServer.py Tue Nov 28 10:23:34 2006 +0000
@@ -41,6 +41,7 @@
 # todo Support command-line args.
 
 import fcntl
+import re
 import time
 import signal
 from threading import Thread
@@ -148,6 +149,29 @@ def create():
         log.info('unix path=' + path)
         servers.add(UnixHttpServer(root, path))
 
+    api_cfg = xroot.get_xen_api_server()
+    if api_cfg:
+        try:
+            addrs = [(str(x[0]).split(':'),
+                      len(x) > 1 and x[1] and map(re.compile, x[1].split(" "))
+                      or None)
+                     for x in api_cfg]
+            for addrport, allowed in addrs:
+                if len(addrport) == 1:
+                    if addrport[0] == 'unix':
+                        servers.add(XMLRPCServer(allowed = allowed))
+                    else:
+                        servers.add(XMLRPCServer(True, '', int(addrport[0]),
+                                                 allowed = allowed))
+                else:
+                    addr, port = addrport
+                    servers.add(XMLRPCServer(True, addr, int(port),
+                                             allowed = allowed))
+        except ValueError:
+            log.error('Xen-API server configuration %s is invalid' % api_cfg)
+        except TypeError:
+            log.error('Xen-API server configuration %s is invalid' % api_cfg)
+
     if xroot.get_xend_tcp_xmlrpc_server():
         servers.add(XMLRPCServer(True))
 
diff -r b4baf35cff11 -r 6206685650f5 
tools/python/xen/xend/server/XMLRPCServer.py
--- a/tools/python/xen/xend/server/XMLRPCServer.py      Tue Nov 28 09:51:05 
2006 +0000
+++ b/tools/python/xen/xend/server/XMLRPCServer.py      Tue Nov 28 10:23:34 
2006 +0000
@@ -85,11 +85,12 @@ exclude = ['domain_create', 'domain_rest
 
 class XMLRPCServer:
     def __init__(self, use_tcp=False, host = "localhost", port = 8006,
-                 path = XML_RPC_SOCKET):
+                 path = XML_RPC_SOCKET, hosts_allowed = None):
         self.use_tcp = use_tcp
         self.port = port
         self.host = host
         self.path = path
+        self.hosts_allowed = hosts_allowed
         
         self.ready = False        
         self.running = True
@@ -97,10 +98,18 @@ class XMLRPCServer:
         
     def run(self):
         if self.use_tcp:
+            log.info("Opening TCP XML-RPC server on %s%d.",
+                     self.host and '%s:' % self.host or
+                     'all interfaces, port ',
+                     self.port)
             self.server = TCPXMLRPCServer((self.host, self.port),
+                                          self.hosts_allowed,
                                           logRequests = False)
         else:
-            self.server = UnixXMLRPCServer(self.path, logRequests = False)
+            log.info("Opening Unix domain socket XML-RPC server on %s:%d.",
+                     self.path)
+            self.server = UnixXMLRPCServer(self.path, self.hosts_allowed,
+                                           logRequests = False)
 
         # Register Xen API Functions
         # -------------------------------------------------------------------

_______________________________________________
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®.