Ticket #240: bcfg2-ClientBindToAdress.patch

File bcfg2-ClientBindToAdress.patch, 10.6 KB (added by mjung@…, 15 years ago)

The Patch

  • Proxy.py

    old new  
    33 
    44import logging, socket, sys, time, xmlrpclib, ConfigParser, httplib 
    55 
    6 class CobaltComponentError(Exception): 
    7     '''This error signals component connection errors''' 
    8     pass 
    9  
    10 def verify_cb(conn, cert, errnum, depth, ok): 
    11     print 'Got certificate: %s' % cert.get_subject() 
    12     return ok 
    13  
    14 class poSSLFile: 
    15     def __init__(self, sock, master): 
    16         self.sock = sock 
    17         self.master = master 
    18         #self.read = self.sock.read 
    19         self.master.count += 1 
    20  
    21     def close(self): 
    22         self.master.count -= 1 
    23         if not self.master.count: 
    24             self.sock.close() 
    25  
    26     def readline(self): 
    27         print "in readline" 
    28         data = '' 
    29         char = self.read(1) 
    30         while char != '\n': 
    31             data += char 
    32             char = self.read(1) 
    33         print data 
    34         return data 
    35  
    36     def read(self, size=None): 
    37         print "in read", size 
    38         if size: 
    39             data = '' 
    40             while not data: 
    41                 try: 
    42                     data = self.sock.read(size) 
    43                 except OpenSSL.SSL.ZeroReturnError: 
    44                     break 
    45             return data 
    46         else: 
    47             print "no size" 
    48             data = self.sock.read() 
    49             return data 
    50  
    51 class pSockMaster: 
    52     def __init__(self, connection): 
    53         self._connection = connection 
    54         self.sendall = self._connection.send 
    55         self.count = 1 
    56  
    57     def makefile(self, mode, bufsize=None): 
    58         return poSSLFile(self._connection, self) 
    59  
    60     def close(self): 
    61         self.count -= 1 
    62         if not self.count: 
    63             self._connection.close() 
    64  
    65 class PHTTPSConnection(httplib.HTTPSConnection): 
    66     "This class allows communication via SSL." 
    67  
    68     def __init__(self, host, port=None, key_file=None, cert_file=None, 
    69                  strict=None): 
    70         httplib.HTTPSConnection.__init__(self, host, port, strict) 
    71         self.ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) 
    72         self.ctx.set_verify(OpenSSL.SSL.VERIFY_PEER, verify_cb) 
    73         self.ctx.use_privatekey_file ('/tmp/keys/client.pkey') 
    74         self.ctx.use_certificate_file('/tmp/keys/client.cert') 
    75         self.ctx.load_verify_locations('/tmp/keys/CA.cert') 
     6# class CobaltComponentError(Exception): 
     7#     '''This error signals component connection errors''' 
     8#     pass 
     9 
     10# def verify_cb(conn, cert, errnum, depth, ok): 
     11#     print 'Got certificate: %s' % cert.get_subject() 
     12#     return ok 
     13 
     14# class poSSLFile: 
     15#     def __init__(self, sock, master): 
     16#         self.sock = sock 
     17#         self.master = master 
     18#         #self.read = self.sock.read 
     19#         self.master.count += 1 
     20 
     21#     def close(self): 
     22#         self.master.count -= 1 
     23#         if not self.master.count: 
     24#             self.sock.close() 
     25 
     26#     def readline(self): 
     27#         print "in readline" 
     28#         data = '' 
     29#         char = self.read(1) 
     30#         while char != '\n': 
     31#             data += char 
     32#             char = self.read(1) 
     33#         print data 
     34#         return data 
     35 
     36#     def read(self, size=None): 
     37#         print "in read", size 
     38#         if size: 
     39#             data = '' 
     40#             while not data: 
     41#                 try: 
     42#                     data = self.sock.read(size) 
     43#                 except OpenSSL.SSL.ZeroReturnError: 
     44#                     break 
     45#             return data 
     46#         else: 
     47#             print "no size" 
     48#             data = self.sock.read() 
     49#             return data 
     50 
     51# class pSockMaster: 
     52#     def __init__(self, connection): 
     53#         self._connection = connection 
     54#         self.sendall = self._connection.send 
     55#         self.count = 1 
     56 
     57#     def makefile(self, mode, bufsize=None): 
     58#         return poSSLFile(self._connection, self) 
     59 
     60#     def close(self): 
     61#         self.count -= 1 
     62#         if not self.count: 
     63#             self._connection.close() 
     64 
     65# class PHTTPSConnection(httplib.HTTPSConnection): 
     66#     "This class allows communication via SSL." 
     67 
     68#     def __init__(self, host, port=None, key_file=None, cert_file=None, 
     69#                  strict=None): 
     70#         httplib.HTTPSConnection.__init__(self, host, port, strict) 
     71#         self.ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) 
     72#         self.ctx.set_verify(OpenSSL.SSL.VERIFY_PEER, verify_cb) 
     73#         self.ctx.use_privatekey_file ('/tmp/keys/client.pkey') 
     74#         self.ctx.use_certificate_file('/tmp/keys/client.cert') 
     75#         self.ctx.load_verify_locations('/tmp/keys/CA.cert') 
     76 
     77#     def connect(self): 
     78#         "Connect to a host on a given (SSL) port." 
     79#         self._sock = OpenSSL.SSL.Connection(self.ctx, 
     80#                                            socket.socket(socket.AF_INET, socket.SOCK_STREAM)) 
     81#         self._sock.connect((self.host, self.port)) 
     82#         self.sock = pSockMaster(self._sock) 
     83 
     84#     def send(self, msg): 
     85#         print "sending message %s" % (msg) 
     86#         self._sock.sendall(msg) 
     87 
     88# class PHTTPS(httplib.HTTPS): 
     89#     _connection_class = PHTTPSConnection 
     90 
     91# class OSSafeTransport(xmlrpclib.Transport): 
     92#     """Handles an HTTPS transaction to an XML-RPC server.""" 
     93#     def make_connection(self, host): 
     94#         # create a HTTPS connection object from a host descriptor 
     95#         # host may be a string, or a (host, x509-dict) tuple 
     96#         host, extra_headers, x509 = self.get_host_info(host) 
     97#         return PHTTPS(host, None, '/tmp/keys/client.pkey', '/tmp/keys/client.cert') 
     98 
     99#     def _parse_response(self, file, sock): 
     100#         # read response from input file/socket, and parse it 
     101 
     102#         p, u = self.getparser() 
     103 
     104#         while 1: 
     105#             if sock: 
     106#                 response = sock.recv(1024) 
     107#             else: 
     108#                 try: 
     109#                     response = file.read(1024) 
     110#                 except OpenSSL.SSL.ZeroReturnError: 
     111#                     break 
     112#             if not response: 
     113#                 break 
     114#             if self.verbose: 
     115#                 print "body:", repr(response) 
     116#             p.feed(response) 
     117 
     118#         file.close() 
     119#         p.close() 
     120 
     121#         return u.close() 
     122 
     123class Bcfg2HTTPSConnection(httplib.HTTPSConnection): 
    76124 
    77125    def connect(self): 
    78         "Connect to a host on a given (SSL) port." 
    79         self._sock = OpenSSL.SSL.Connection(self.ctx, 
    80                                            socket.socket(socket.AF_INET, socket.SOCK_STREAM)) 
    81         self._sock.connect((self.host, self.port)) 
    82         self.sock = pSockMaster(self._sock) 
    83  
    84     def send(self, msg): 
    85         print "sending message %s" % (msg) 
    86         self._sock.sendall(msg) 
     126        "Connect to a host on a given (SSL) port binding the socket to a specific local address" 
     127 
     128        _cfile = ConfigParser.ConfigParser() 
     129        if '-C' in sys.argv: 
     130            _cfpath = sys.argv[sys.argv.index('-C') + 1] 
     131        else: 
     132            _cfpath = '/etc/bcfg2.conf' 
     133            _cfile.read([_cfpath])       
     134        _bindaddress = "" 
     135        try: 
     136            _bindaddress = _cfile.get('communication', 'bindaddress') 
     137        except: 
     138            self.log.error("%s doesn't contain a valid bindadress value" % (_cfpath)) 
     139            raise SystemExit, 1 
    87140 
    88 class PHTTPS(httplib.HTTPS): 
    89     _connection_class = PHTTPSConnection 
     141        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    90142 
    91 class OSSafeTransport(xmlrpclib.Transport): 
    92     """Handles an HTTPS transaction to an XML-RPC server.""" 
    93     def make_connection(self, host): 
    94         # create a HTTPS connection object from a host descriptor 
    95         # host may be a string, or a (host, x509-dict) tuple 
    96         host, extra_headers, x509 = self.get_host_info(host) 
    97         return PHTTPS(host, None, '/tmp/keys/client.pkey', '/tmp/keys/client.cert') 
     143        # the following line is the sole modification in comparison to the 
     144        # connect() in httplib.HTTPSConnection  
     145        sock.bind((_bindaddress,0)) 
    98146 
    99     def _parse_response(self, file, sock): 
    100         # read response from input file/socket, and parse it 
     147        sock.connect((self.host, self.port)) 
     148        ssl = socket.ssl(sock, self.key_file, self.cert_file)  
     149        self.sock = httplib.FakeSocket(sock, ssl) 
    101150 
    102         p, u = self.getparser() 
    103151 
    104         while 1: 
    105             if sock: 
    106                 response = sock.recv(1024) 
    107             else: 
    108                 try: 
    109                     response = file.read(1024) 
    110                 except OpenSSL.SSL.ZeroReturnError: 
    111                     break 
    112             if not response: 
    113                 break 
    114             if self.verbose: 
    115                 print "body:", repr(response) 
    116             p.feed(response) 
     152class Bcfg2HTTPS(httplib.HTTPS): 
     153    """Own HTTPS class for overriding the _connection_class value""" 
     154     
     155    _connection_class = Bcfg2HTTPSConnection # instead of HTTPSConnection from httplib 
    117156 
    118         file.close() 
    119         p.close() 
    120157 
    121         return u.close() 
     158class Bcfg2SafeTransport(xmlrpclib.Transport): 
     159    """Own SafeTransport class for overriding the HTTPS object""" 
     160 
     161    def make_connection(self, host): 
     162 
     163        # create a HTTPS connection object from a host descriptor 
     164        # host may be a string, or a (host, x509-dict) tuple 
     165        import httplib 
     166        host, extra_headers, x509 = self.get_host_info(host) 
     167        try: 
     168            HTTPS = Bcfg2HTTPS  # instead of HTTPS from httplib 
     169        except AttributeError: 
     170            raise NotImplementedError( 
     171                "your version of httplib doesn't support HTTPS" 
     172                ) 
     173        else: 
     174            return HTTPS(host, None, **(x509 or {})) 
     175 
    122176 
    123177class SafeProxy: 
    124178    '''Wrapper for proxy''' 
     
    138192    except KeyError: 
    139193        print "%s doesn't contain a valid communication setup" % (_cfpath) 
    140194        raise SystemExit, 1 
     195 
     196    _bindaddress = "" 
     197    try: 
     198        _bindaddress = _cfile.get('communication', 'bindaddress') 
     199    except: 
     200        pass 
     201         
    141202    _retries = 4 
    142203 
    143204    def __init__(self, component, url=None): 
     
    148209        else: 
    149210            address = self.__get_location(component) 
    150211        try: 
    151             self.proxy = xmlrpclib.ServerProxy(address, transport=xmlrpclib.SafeTransport()) 
     212            if self._bindaddress != "": 
     213                self.log.info("Binding client to address %s" % self._bindaddress) 
     214                self.proxy = xmlrpclib.ServerProxy(address, transport=Bcfg2SafeTransport()) 
     215            else: 
     216                self.proxy = xmlrpclib.ServerProxy(address, transport=xmlrpclib.SafeTransport()) 
    152217        except IOError, io_error: 
    153218            self.log.error("Invalid server URL %s: %s" % (address, io_error)) 
    154219            raise CobaltComponentError