From 2ba0fe2f92fd9fbc5ddac49a265e57c094e6abf7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 13 May 2014 14:27:58 +0100 Subject: [PATCH] Use the Python ipaddress module to represent IP addresses Use the Python ipaddress module to represent IP addresses internally rather than trying to do it myself. Signed-off-by: David Howells --- suite/exception.py | 4 ++ suite/lib/addrcache.py | 142 +++++++++++++++++------------------------ suite/lib/cell.py | 14 ++-- suite/lib/server.py | 24 +++---- suite/lib/vlserver.py | 4 +- 5 files changed, 78 insertions(+), 110 deletions(-) diff --git a/suite/exception.py b/suite/exception.py index 7d90a8c..815e94c 100644 --- a/suite/exception.py +++ b/suite/exception.py @@ -6,6 +6,10 @@ class AFSArgumentError(AFSException): """An argument parsing error was encountered""" pass +class AFSNetAddressError(AFSException): + """A network address parsing error was encountered""" + pass + class AFSHelpFlag(AFSException): """The -help flag was specified to a command.""" pass diff --git a/suite/lib/addrcache.py b/suite/lib/addrcache.py index 8829263..05e3204 100644 --- a/suite/lib/addrcache.py +++ b/suite/lib/addrcache.py @@ -22,34 +22,32 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ from afs import exception -from socket import gethostbyname_ex, gethostbyaddr, gaierror, herror, inet_pton, inet_ntoa, AF_INET, AF_INET6 +from socket import gethostbyname_ex, gethostbyaddr, gaierror, herror import sys +import ipaddress cache_n2a = dict() cache_a2n = dict() -class NetAddressError(exception.AFSException): - """Error raised by L{address cache}.""" - def add(name, addr): global cache_n2a, cache_a2n name = name.lower().rstrip(".") if name not in cache_n2a: cache_n2a[name] = [] - if addr not in cache_n2a[name]: + if str(addr) not in cache_n2a[name]: cache_n2a[name].append(addr) - cache_a2n[addr] = name + cache_a2n[str(addr)] = name def add_ghb(name, addr, result): hostname, aliaslist, ipaddrlist = result - if addr and addr not in ipaddrlist: - print("Inconsistent lookup of '", addr, "'", file=sys.stderr) + if addr and str(addr) not in ipaddrlist: + print("Inconsistent lookup of '", str(addr), "'", file=sys.stderr) for i in ipaddrlist: if name: - add(name, i) - add(hostname, i) + add(name, ipaddress.IPv4Address(i)) + add(hostname, ipaddress.IPv4Address(i)) for j in aliaslist: - add(j, i) + add(j, ipaddress.IPv4Address(i)) ############################################################################### # @@ -59,18 +57,12 @@ def add_ghb(name, addr, result): def name2addrs(name): global cache_n2a - # Try parsing as a numeric IPv4 address try: - addr = inet_pton(AF_INET, name) - return name - except OSError: - pass - - # Try parsing as a numeric IPv6 address - try: - addr = inet_pton(AF_INET6, name) - raise NetAddressError("IPv6 is not currently supported") - except OSError: + addr = ipaddress.ip_address(name) + if addr.version == 6: + raise exception.AFSNetAddressError("IPv6 is not currently supported") + return str(addr) + except ValueError: pass name = name.lower().rstrip(".") @@ -80,70 +72,45 @@ def name2addrs(name): try: result = gethostbyname_ex(name) except gaierror as e: - raise NetAddressError("Couldn't resolve '" + name + "'") + raise exception.AFSNetAddressError("Couldn't resolve '" + name + "'") add_ghb(name, None, result) return cache_n2a[name] ############################################################################### # -# Convert a string address to an address in integer form +# Convert a string address to an address # ############################################################################### -def addr2addr_int(name): - # Try parsing as a numeric IPv4 address - try: - addr = inet_pton(AF_INET, name) - inaddr = addr[0] << 24 - inaddr |= addr[1] << 16 - inaddr |= addr[2] << 8 - inaddr |= addr[3] << 0 - return inaddr - except OSError: - pass - - # Try parsing as a numeric IPv6 address +def addr2addr(name): try: - addr = inet_pton(AF_INET6, name) - raise NetAddressError("IPv6 is not currently supported") - except OSError: - pass - raise NetAddressError("Can't translate '" + name + "' to integer") + addr = ipaddress.ip_address(name) + if addr.version == 6: + raise exception.AFSNetAddressError("IPv6 is not currently supported") + return addr + except ValueError: + raise exception.AFSNetAddressError("Can't translate '" + name + "' to integer") ############################################################################### # -# Convert a name or string address to an address in integer form +# Convert a name or string address to an address # ############################################################################### -def name2addr_int(name): +def name2addr(name): global cache_n2a # Try parsing as a numeric IPv4 address try: - addr = inet_pton(AF_INET, name) - inaddr = addr[0] << 24 - inaddr |= addr[1] << 16 - inaddr |= addr[2] << 8 - inaddr |= addr[3] << 0 - return inaddr - except OSError: - pass - - # Try parsing as a numeric IPv6 address - try: - addr = inet_pton(AF_INET6, name) - raise NetAddressError("IPv6 is not currently supported") - except OSError: + addr = ipaddress.ip_address(name) + if addr.version == 6: + raise exception.AFSNetAddressError("IPv6 is not currently supported") + return addr + except ValueError: pass if name not in cache_n2a: return None - addr = inet_pton(AF_INET, cache_n2a[name][0]) - inaddr = addr[0] << 24 - inaddr |= addr[1] << 16 - inaddr |= addr[2] << 8 - inaddr |= addr[3] << 0 - return inaddr + return cache_n2a[name][0] ############################################################################### # @@ -153,15 +120,21 @@ def name2addr_int(name): ############################################################################### def addrs2name(addrs): global cache_a2n + cooked_addrs = [] for addr in addrs: - if addr in cache_a2n: - return cache_a2n[addr] + if str(type(addr)) != "": + addr = ipaddress.ip_address(addr) + cooked_addrs.append(addr) + else: + cooked_addrs.append(addr) + if str(addr) in cache_a2n: + return cache_a2n[str(addr)] for addr in addrs: try: - result = gethostbyaddr(addr) + result = gethostbyaddr(str(addr)) add_ghb(None, addr, result) - return cache_a2n[addr] + return cache_a2n[str(addr)] except herror: pass @@ -170,19 +143,6 @@ def addrs2name(addrs): def addr2name(addr): return addrs2name([ addr ]) -############################################################################### -# -# Convert an integer address to a string address. -# -############################################################################### -def int2addr(i): - inaddr = bytearray(4) - inaddr[0] = (i >> 24) & 0xff - inaddr[1] = (i >> 16) & 0xff - inaddr[2] = (i >> 8) & 0xff - inaddr[3] = (i >> 0) & 0xff - return inet_ntoa(bytes(inaddr)) - ############################################################################### # # Resolve an integer or string address to a string address or a name, @@ -190,11 +150,23 @@ def int2addr(i): # ############################################################################### def resolve(params, addr): - if str(type(addr)) == "": - addr = int2addr(addr) + if str(type(addr)) != "" and str(type(addr)) != "": + addr = ipaddress.ip_address(addr) if "noresolve" in params: - return addr + return str(addr) name = addr2name(addr) if name == None: - return addr + return str(addr) return name + +############################################################################### +# +# Convert an integer or a string address to an address. +# +############################################################################### +def addr2addr(addr): + if str(type(addr)) != "" and str(type(addr)) != "": + addr = ipaddress.ip_address(addr) + if addr.version == 6: + raise exception.AFSNetAddressError("IPv6 is not currently supported") + return addr diff --git a/suite/lib/cell.py b/suite/lib/cell.py index fda13c1..9fdfa1e 100644 --- a/suite/lib/cell.py +++ b/suite/lib/cell.py @@ -143,10 +143,10 @@ class cell: key, security = self.determine_security(params) - for vlserver in self.query_vl_addrs(): - verbose("Trying ", vlserver, "\n") + for vladdr in self.query_vl_addrs(): + verbose("Trying vlserver ", vladdr, "\n") - z_conn = kafs.rx_new_connection(vlserver, kafs.VL_PORT, kafs.VL_SERVICE, + z_conn = kafs.rx_new_connection(str(vladdr), kafs.VL_PORT, kafs.VL_SERVICE, key, security) try: ret = kafs.VL_Probe(z_conn) @@ -164,8 +164,8 @@ class cell: def open_volume_server(self, server, params=None): key, security = self.determine_security(params) - verbose("Trying ", server.addr(), "\n") - vol_conn = kafs.rx_new_connection(server.addr(), + verbose("Trying volserver ", server, "\n") + vol_conn = kafs.rx_new_connection(str(server.addr()), kafs.VOLSERVICE_PORT, kafs.VOLSERVICE_ID, key, security) @@ -175,8 +175,8 @@ class cell: def open_bos_server(self, server, params=None): key, security = self.determine_security(params) - verbose("Trying ", server.addr(), "\n") - bos_conn = kafs.rx_new_connection(server.addr(), + verbose("Trying bosserver ", server, "\n") + bos_conn = kafs.rx_new_connection(str(server.addr()), kafs.BOSSERVICE_PORT, kafs.BOSSERVICE_ID, key, security) diff --git a/suite/lib/server.py b/suite/lib/server.py index aed6a66..4b43deb 100644 --- a/suite/lib/server.py +++ b/suite/lib/server.py @@ -24,32 +24,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from afs import exception import afs.lib.addrcache as addrcache from afs.lib.output import * -from socket import inet_pton, inet_ntoa, AF_INET, AF_INET6; class ServerError(exception.AFSException): """Error raised by L{volserver} objects.""" class server: """Represents the name and addresses of a server on the network.""" - def __init__(self, name): + def __init__(self, name, addr=None): self.__name = None self.__addrs4 = None self.__addrs6 = None - self.__inaddr = None - if str(type(name)) == "": - self.__addrs4 = [ addrcache.int2addr(name) ] - else: - # Try parsing as a numeric IPv4 address - try: - self.__addrs4 = [ inet_pton(AF_INET, name) ] - except OSError: - # Try parsing as a numeric IPv6 address - try: - self.__addrs6 = [ inet_pton(AF_INET6, name) ] - raise NetAddressError("IPv6 is not currently supported") - except OSError: - self.__name = name + try: + self.__addrs4 = [ addrcache.addr2addr(name) ] + except ValueError: + self.__name = name + + if addr != None: + self.__addrs4 = [ addrcache.addr2addr(addr) ] def __repr__(self): if self.__name != None: diff --git a/suite/lib/vlserver.py b/suite/lib/vlserver.py index 6e0b57b..d632a2f 100644 --- a/suite/lib/vlserver.py +++ b/suite/lib/vlserver.py @@ -27,9 +27,9 @@ from afs.lib.server import server class vlserver(server): """Represents an AFS Volume Location server. We hold the server address here.""" - def __init__(self, name): + def __init__(self, name, addr=None): verbose("New VolServer ", name, "\n") - server.__init__(self, name) + server.__init__(self, name, addr) def __repr__(self): return "<" + "AFSVL:" + server.__str_(self) + ">" -- 2.49.0