Hello, I'm using a monitoring software called shinken which rely on Pyro 3 for the communication between the many servers it contains. But, in my case, some parts of the network between these servers are IPv6 only.
So, I created a patch against Pyro 3 to add the IPv6 support. I'm not a python developper and I tested it only whith shinken, but I hope a python developer could improve it so it can be included in Pyro 3 repository. Is some intereted in this patch ? I can help to explain what I intended to do with it. Once the patch OK, is it possible to add IPv6 support to Pyro 3 ? Best regards, Vincent Leloup vincent.lel...@ker-is.net
Index: Pyro/core.py =================================================================== --- Pyro/core.py (révision 507) +++ Pyro/core.py (copie de travail) @@ -282,7 +282,7 @@ else: self.address=Pyro.protocol.getIPAddress(host) if not self.address: - raise URIError('unknown host') + raise URIError('unknown host or more than one IPv4 and IPv6 address') if port: if type(port)==type(1): self.port=port @@ -320,12 +320,14 @@ # def processStringURI(URI): # PYRONAME(SSL)://[hostname[:port]/]objectname - x=re.match(r'(?P<protocol>PYRONAME|PYRONAMESSL)://(((?P<hostname>[^\s:]+):(?P<port>\d+)/)|((?P<onlyhostname>[^\s:]+)/))?(?P<name>\S*)',URI) + x=re.match(r'(?P<protocol>PYRONAME|PYRONAMESSL)://(((?P<hostname>\[[0-9a-fA-F:]+]|[^\s:[]+):(?P<port>\d+)/)|((?P<onlyhostname>\[[0-9a-fA-F:]+]|[^\s:[]+)/))?(?P<name>\S*)',URI) if x: protocol=x.group('protocol') if protocol=="PYRONAMESSL": raise ProtocolError("NOT SUPPORTED YET: "+protocol) # XXX obviously, this should be implemented hostname=x.group('hostname') or x.group('onlyhostname') + if hostname.startswith( "[" ): + hostname = hostname.lstrip("[").rstrip("]") port=x.group('port') name=x.group('name') import Pyro.naming @@ -335,10 +337,12 @@ NS=loc.getNS(host=hostname,port=port) return NS.resolve(name) # PYROLOC(SSL)://hostname[:port]/objectname - x=re.match(r'(?P<protocol>PYROLOC|PYROLOCSSL)://(?P<hostname>[^\s:]+):?(?P<port>\d+)?/(?P<name>\S*)',URI) + x=re.match(r'(?P<protocol>PYROLOC|PYROLOCSSL)://(?P<hostname>\[[0-9a-fA-F:]+]|[^\s:[]+):?(?P<port>\d+)?/(?P<name>\S*)',URI) if x: protocol=x.group('protocol') hostname=x.group('hostname') + if hostname.startswith( "[" ): + hostname = hostname.lstrip("[").rstrip("]") port=x.group('port') if port: port=int(port) @@ -622,12 +626,12 @@ if self.hostname!="localhost": ip = Pyro.protocol.getIPAddress(self.hostname) if ip is None: - Log.error("Daemon","no IP address known") - raise socket.error("no IP address known for daemon") - if not ip.startswith("127.0."): + Log.error("Daemon","no or more than one IPv4 and IPv6 address known") + raise socket.error("no or more than one IPv4 and IPv6 address known for daemon") + if not ( ip.startswith("127.0.") or ip == "::1" ): return None # this is good! # 127.0.x.x or 'localhost' is a warning situation! - msg="daemon bound on hostname that resolves to loopback address 127.0.x.x" + msg="daemon bound on hostname that resolves to loopback address 127.0.x.x or ::1" Log.warn("Daemon",msg) Log.warn("Daemon","hostname="+self.hostname) return msg Index: Pyro/protocol.py =================================================================== --- Pyro/protocol.py (révision 507) +++ Pyro/protocol.py (copie de travail) @@ -56,14 +56,30 @@ except socket.error: return None -#------ Get IP address (return None on error) +#------ Get IP address (return None when no or many IPv4 and IPv6 addresses found) def getIPAddress(host=None): try: - return socket.gethostbyname(host or getHostname()) + addresses = socket.getaddrinfo(host or getHostname(), None, 0, socket.SOCK_STREAM) + if len( addresses ) == 1: + return addresses[0][4][0] + else: + return None except socket.error: return None - +#------ Get version of an IP address from its format +def getIPVersion(host=None): + IPaddress = getIPAddress(host) + if IPaddress == None: + return None + elif "." in IPaddress: + return 4 + elif ":" in IPaddress: + return 6 + else: + return None + + #------ Socket helper functions for sending and receiving data correctly. @@ -260,8 +276,14 @@ with self.lock: # only 1 thread at a time can bind the URI try: self.URI=URI - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((URI.address, URI.port)) + if getIPVersion(URI.address) == 4: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect((URI.address, URI.port)) + elif getIPVersion(URI.address) == 6: + sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + sock.connect((URI.address, URI.port,0,0)) + else: + raise ProtocolError("unkown IP address format: " + URI.address) conn=TCPConnection(sock,sock.getpeername()) # receive the authentication challenge string, and use that to build the actual identification string. try: @@ -859,10 +881,20 @@ with self.lock: # only 1 thread at a time can bind the URI try: self.URI=URI - sock = SSL.Connection(self.ctx,socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + if getIPVersion(URI.address) == 4: + sock = SSL.Connection(self.ctx,socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + elif getIPVersion(URI.address) == 6: + sock = SSL.Connection(self.ctx,socket.socket(socket.AF_INET6, socket.SOCK_STREAM)) + else: + raise ProtocolError("unkown IP address format: " + URI.address) if not Pyro.config.PYROSSL_POSTCONNCHECK: sock.postConnectionCheck=None - sock.connect((URI.address, URI.port)) + if getIPVersion(URI.address) == 4: + sock.connect((URI.address, URI.port)) + elif getIPVersion(URI.address) == 6: + sock.connect((URI.address, URI.port,0,0)) + else: + raise ProtocolError("unkown IP address format: " + URI.address) conn=TCPConnection(sock, sock.getpeername()) # receive the authentication challenge string, and use that to build the actual identification string. authChallenge=self.recvAuthChallenge(conn) @@ -1001,7 +1033,7 @@ self.connections = [] # connection threads self.initTLS=lambda tls: None # default do-nothing func if host: - socket.gethostbyname(host) # validate hostname + socket.getaddrinfo(host, None) # validate hostname try: if prtcol=='PYROSSL': try: @@ -1029,10 +1061,18 @@ self.setNewConnectionValidator(DefaultConnValidator()) # create server socket for new connections - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - set_reuse_addr(self.sock) - set_sock_no_inherit(self.sock) - self.sock.bind((host,port)) + if getIPVersion( host ) == 4: + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + set_reuse_addr(self.sock) + set_sock_no_inherit(self.sock) + self.sock.bind((host,port)) + elif getIPVersion( host ) == 6: + self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + set_reuse_addr(self.sock) + set_sock_no_inherit(self.sock) + self.sock.bind((host,port,0,0)) + else: + raise ProtocolError("Unkown IP address format: " + host) self.sock.listen(Pyro.config.PYRO_TCP_LISTEN_BACKLOG) if self._ssl_server: self.sock = SSL.Connection(self.ctx,self.sock) # wrap server socket as SSL socket Index: Pyro/ext/NS_NtService.py =================================================================== --- Pyro/ext/NS_NtService.py (révision 507) +++ Pyro/ext/NS_NtService.py (copie de travail) @@ -51,7 +51,7 @@ PyroDaemon.useNameServer(ns) NS_URI=PyroDaemon.connect(ns,Pyro.constants.NAMESERVER_NAME) - BcServerObject = BroadcastServer((hstn or '',bcport),bcRequestHandler) + BcServerObject = BroadcastServer(hstn or '',bcport,bcRequestHandler) if Guards[1]: BcServerObject.setRequestValidator(Guards[1]) BcServerObject.keepRunning(keep) Index: Pyro/naming.py =================================================================== --- Pyro/naming.py (révision 507) +++ Pyro/naming.py (copie de travail) @@ -119,18 +119,35 @@ raise Pyro.errors.PyroError(msg) if bcaddr: try: - socket.gethostbyname(bcaddr) + socket.getaddrinfo(bcaddr, None) except socket.error: msg="invalid broadcast address '%s'" % bcaddr if trace: print msg raise ValueError(msg) - destination1 = (bcaddr, port1) - destination2 = (bcaddr, port2) + if protocol.getIPAddress( bcaddr ) == 4: + destination1 = (bcaddr, port1) + destination2 = (bcaddr, port2) + elif protocol.getIPAddress( bcaddr ) == 6: + destination1 = (bcaddr, port1, 0, 0) + destination2 = (bcaddr, port2, 0, 0) + else: + raise ValueError("unkown IP address format: " + bcaddr) else: - destination1 = (Pyro.config.PYRO_NS_BC_ADDR or '<broadcast>', port1) - destination2 = (Pyro.config.PYRO_NS2_BC_ADDR or '<broadcast>', port2) - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + if protocol.getIPAddress( bcaddr ) == 4: + destination1 = (Pyro.config.PYRO_NS_BC_ADDR or '<broadcast>', port1) + destination2 = (Pyro.config.PYRO_NS2_BC_ADDR or '<broadcast>', port2) + elif protocol.getIPAddress( bcaddr ) == 6: + destination1 = (Pyro.config.PYRO_NS_BC_ADDR or '<broadcast>', port1, 0, 0) + destination2 = (Pyro.config.PYRO_NS2_BC_ADDR or '<broadcast>', port2, 0, 0) + else: + raise ValueError("unkown IP address format: " + bcaddr) + if protocol.getIPAddress( bcaddr ) == 4: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + elif protocol.getIPAddress( bcaddr ) == 6: + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + else: + raise ValueError("unkown IP address format: " + bcaddr) if hasattr(socket,'SO_BROADCAST'): s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) @@ -1023,15 +1040,19 @@ nameServerURI = '' # the Pyro URI of the Name Server - def __init__(self, addr, bcRequestHandler,norange=0): + def __init__(self, location, port, bcRequestHandler,norange=0): if norange: portrange=1 else: portrange=Pyro.config.PYRO_PORT_RANGE - (location,port)=addr for port in range(port, port+portrange): try: - SocketServer.UDPServer.__init__(self, (location,port), bcRequestHandler) + if protocol.getIPAddress( location ) == 4: + SocketServer.UDPServer.__init__(self, (location,port), bcRequestHandler) + elif protocol.getIPAddress( location ) == 6: + SocketServer.UDPServer.__init__(self, (location,port,0,0), bcRequestHandler) + else: + raise ValueError("unknown IP address format: " + location) return # got it! except socket.error: continue # try the next port in the list @@ -1225,7 +1246,7 @@ broadcastAddresses=["<broadcast>", "", "255.255.255.255"] for bc_bind in broadcastAddresses: try: - self.bcserver = BroadcastServer((bc_bind,bcport),bcRequestHandler,norange=1) + self.bcserver = BroadcastServer(bc_bind,bcport,bcRequestHandler,norange=1) break except socket.error,x: notStartedError += str(x)+" " Index: Pyro/util.py =================================================================== --- Pyro/util.py (révision 507) +++ Pyro/util.py (copie de travail) @@ -9,8 +9,8 @@ from __future__ import with_statement import os, sys, traceback -import time, random, linecache -import socket, binascii +import time, linecache +import uuid import Pyro.constants from Pyro.util2 import * # bring in 'missing' util functions @@ -292,70 +292,9 @@ print -_getGUID_counter=0 # extra safeguard against double numbers -_getGUID_lock=getLockObject() +def getGUID(): + return uuid.uuid1().hex -if os.name=='java': - # define jython specific stuff - # first, the guid stuff. try java5 uuid first. - try: - from java.util import UUID - def getGUID(): - return str(UUID.randomUUID()) - except ImportError: - # older java, use rmi's vmid instead - from java.rmi.dgc import VMID - def getGUID(): - return str(VMID().toString().replace(':','-').replace('--','-')) - import imp - if not hasattr(imp,"acquire_lock"): - # simulate missing imp.acquire_lock() from jython 2.2 (fixed in jython 2.5) - imp_lock=getLockObject() - def imp_acquire_lock(): - return imp_lock.acquire() - def imp_release_lock(): - return imp_lock.release() - imp.acquire_lock=imp_acquire_lock - imp.release_lock=imp_release_lock - -elif sys.platform=='cli': - import System - def getGUID(): - # IronPython uses .NET guid call - return System.Guid.NewGuid().ToString() -else: - def getGUID(): - # Generate readable GUID string. - # The GUID is constructed as follows: hexlified string of - # AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC (a 128-bit number in hex) - # where A=network address, B=timestamp, C=random. - # The 128 bit number is returned as a string of 16 8-bits characters. - # For A: should use the machine's MAC ethernet address, but there is no - # portable way to get it... use the IP address + 2 bytes process id. - try: - ip=socket.gethostbyname(socket.gethostname()) - networkAddrStr=binascii.hexlify(socket.inet_aton(ip))+"%04x" % os.getpid() - except socket.error: - # can't get IP address... use another value, like our Python id() and PID - Log.warn('getGUID','Can\'t get IP address') - try: - ip=os.getpid() - except: - ip=0 - ip += id(getGUID) - networkAddrStr = "%08lx%04x" % (ip, os.getpid()) - - with _getGUID_lock: # cannot generate multiple GUIDs at once - global _getGUID_counter - t1=time.time()*100 +_getGUID_counter - _getGUID_counter+=1 - t2=int((t1*time.clock())%sys.maxint) & 0xffffff - t1=int(t1%sys.maxint) - timestamp = (long(t1) << 24) | t2 - r2=(random.randint(0,sys.maxint//2)>>4) & 0xffff - r3=(random.randint(0,sys.maxint//2)>>5) & 0xff - return networkAddrStr+'%014x%06x' % (timestamp, (r2<<8)|r3 ) - def genguid_scripthelper(argv): p=ArgParser() p.parse(argv,'')
signature.asc
Description: This is a digitally signed message part
------------------------------------------------------------------------------ All of the data generated in your IT infrastructure is seriously valuable. Why? It contains a definitive record of application performance, security threats, fraudulent activity, and more. Splunk takes this data and makes sense of it. IT sense. And common sense. http://p.sf.net/sfu/splunk-d2d-c2
_______________________________________________ Shinken-devel mailing list Shinken-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/shinken-devel