=== modified file 'mandos' --- mandos 2016-06-03 18:24:51 +0000 +++ mandos 2016-06-03 18:28:39 +0000 @@ -86,13 +86,30 @@ import xml.dom.minidom import inspect +# Try to find the value of SO_BINDTODEVICE: try: + # This is where SO_BINDTODEVICE is in Python 3.3 (or 3.4?) and + # newer, and it is also the most natural place for it: SO_BINDTODEVICE = socket.SO_BINDTODEVICE except AttributeError: try: + # This is where SO_BINDTODEVICE was up to and including Python + # 2.6, and also 3.2: from IN import SO_BINDTODEVICE except ImportError: - SO_BINDTODEVICE = None + # In Python 2.7 it seems to have been removed entirely. + # Try running the C preprocessor: + try: + cc = subprocess.Popen(["cc", "--language=c", "-E", + "/dev/stdin"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + stdout = cc.communicate( + "#include \nSO_BINDTODEVICE\n")[0] + SO_BINDTODEVICE = int(stdout.splitlines()[-1]) + except (OSError, ValueError, IndexError): + # No value found + SO_BINDTODEVICE = None if sys.version_info.major == 2: str = unicode @@ -2438,27 +2455,27 @@ bind to an address or port if they were not specified.""" if self.interface is not None: if SO_BINDTODEVICE is None: - logger.error("SO_BINDTODEVICE does not exist;" - " cannot bind to interface %s", - self.interface) - else: - try: - self.socket.setsockopt( - socket.SOL_SOCKET, SO_BINDTODEVICE, - (self.interface + "\0").encode("utf-8")) - except socket.error as error: - if error.errno == errno.EPERM: - logger.error("No permission to bind to" - " interface %s", self.interface) - elif error.errno == errno.ENOPROTOOPT: - logger.error("SO_BINDTODEVICE not available;" - " cannot bind to interface %s", - self.interface) - elif error.errno == errno.ENODEV: - logger.error("Interface %s does not exist," - " cannot bind", self.interface) - else: - raise + # Fall back to a hard-coded value which seems to be + # common enough. + logger.warning("SO_BINDTODEVICE not found, trying 25") + SO_BINDTODEVICE = 25 + try: + self.socket.setsockopt( + socket.SOL_SOCKET, SO_BINDTODEVICE, + (self.interface + "\0").encode("utf-8")) + except socket.error as error: + if error.errno == errno.EPERM: + logger.error("No permission to bind to" + " interface %s", self.interface) + elif error.errno == errno.ENOPROTOOPT: + logger.error("SO_BINDTODEVICE not available;" + " cannot bind to interface %s", + self.interface) + elif error.errno == errno.ENODEV: + logger.error("Interface %s does not exist," + " cannot bind", self.interface) + else: + raise # Only bind(2) the socket if we really need to. if self.server_address[0] or self.server_address[1]: if not self.server_address[0]: