diff --git a/tools/python/xen/web/connection.py b/tools/python/xen/web/connection.py index 342e6a6f59..cc3660d538 100644 --- a/tools/python/xen/web/connection.py +++ b/tools/python/xen/web/connection.py @@ -19,7 +19,6 @@ import sys import threading -import select import socket import fcntl @@ -31,21 +30,17 @@ for TCP and unix-domain sockets (see tcp.py and unix.py). """ 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 @@ class SocketServerConnection: pass + def close(self): + self.sock.close() + + def write(self, data): self.sock.send(data) @@ -77,52 +76,38 @@ class SocketListener: 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 --git a/tools/python/xen/web/tcp.py b/tools/python/xen/web/tcp.py index f3d67a7de4..552bf4a5cc 100644 --- a/tools/python/xen/web/tcp.py +++ b/tools/python/xen/web/tcp.py @@ -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 @@ class TCPListener(SocketListener): 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 --git a/tools/python/xen/web/unix.py b/tools/python/xen/web/unix.py index 64ae2fcf1b..174e7284bc 100644 --- a/tools/python/xen/web/unix.py +++ b/tools/python/xen/web/unix.py @@ -21,15 +21,15 @@ import socket import os import os.path -from connection import * +import connection -class UnixListener(SocketListener): - - def __init__(self, path, protocol, backlog=None): - SocketListener.__init__(self, protocol, backlog=backlog) +class UnixListener(connection.SocketListener): + def __init__(self, path, protocol_class): self.path = path - + connection.SocketListener.__init__(self, protocol_class) + + def createSocket(self): pathdir = os.path.dirname(self.path) if not os.path.exists(pathdir): @@ -45,9 +45,6 @@ class UnixListener(SocketListener): 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 --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index b61532737a..c806f75e2f 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -75,6 +75,8 @@ class XendRoot: """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 @@ class XendRoot: """ 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 --git a/tools/python/xen/xend/server/relocate.py b/tools/python/xen/xend/server/relocate.py index c20d577156..1b7ed157e9 100644 --- a/tools/python/xen/xend/server/relocate.py +++ b/tools/python/xen/xend/server/relocate.py @@ -16,6 +16,7 @@ # Copyright (C) 2005 XenSource Ltd #============================================================================ +import re import sys import StringIO @@ -116,8 +117,16 @@ def listenRelocation(): 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)