diff --git a/lib/bootstrap.py b/lib/bootstrap.py index 57b29cc1052d735a0296a049b3420a21a7c963b8..94ad63e062394eed2a21d97b62deb2d495e1fe6e 100644 --- a/lib/bootstrap.py +++ b/lib/bootstrap.py @@ -259,7 +259,7 @@ def InitCluster(cluster_name, mac_prefix, errors.ECODE_NOTUNIQUE) if secondary_ip: - if not utils.IsValidIP(secondary_ip): + if not utils.IsValidIP4(secondary_ip): raise errors.OpPrereqError("Invalid secondary ip given", errors.ECODE_INVAL) if (secondary_ip != hostname.ip and diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 60f9aed7683618fcb3e23141839d7af6bc07ff65..a8f9d176ea5a9825428530cc9fb2937f7ef1830f 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -3594,7 +3594,7 @@ class LUAddNode(LogicalUnit): primary_ip = self.op.primary_ip = dns_data.ip if self.op.secondary_ip is None: self.op.secondary_ip = primary_ip - if not utils.IsValidIP(self.op.secondary_ip): + if not utils.IsValidIP4(self.op.secondary_ip): raise errors.OpPrereqError("Invalid secondary IP given", errors.ECODE_INVAL) secondary_ip = self.op.secondary_ip @@ -6839,7 +6839,7 @@ class LUCreateInstance(LogicalUnit): errors.ECODE_INVAL) nic_ip = self.hostname1.ip else: - if not utils.IsValidIP(ip): + if not utils.IsValidIP4(ip): raise errors.OpPrereqError("Given IP address '%s' doesn't look" " like a valid IP" % ip, errors.ECODE_INVAL) @@ -8513,7 +8513,7 @@ class LUSetInstanceParams(LogicalUnit): if nic_ip.lower() == constants.VALUE_NONE: nic_dict['ip'] = None else: - if not utils.IsValidIP(nic_ip): + if not utils.IsValidIP4(nic_ip): raise errors.OpPrereqError("Invalid IP address '%s'" % nic_ip, errors.ECODE_INVAL) diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py index 67d83cca2e6c48de6185df89ac344bf3464123d7..400cd85ce9f5180b38484806b5a062c9d95b623d 100644 --- a/lib/hypervisor/hv_kvm.py +++ b/lib/hypervisor/hv_kvm.py @@ -71,7 +71,7 @@ class KVMHypervisor(hv_base.BaseHypervisor): constants.HV_ACPI: hv_base.NO_CHECK, constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK, constants.HV_VNC_BIND_ADDRESS: - (False, lambda x: (utils.IsValidIP(x) or utils.IsNormAbsPath(x)), + (False, lambda x: (utils.IsValidIP4(x) or utils.IsNormAbsPath(x)), "the VNC bind address must be either a valid IP address or an absolute" " pathname", None, None), constants.HV_VNC_TLS: hv_base.NO_CHECK, @@ -514,7 +514,7 @@ class KVMHypervisor(hv_base.BaseHypervisor): vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS] if vnc_bind_address: - if utils.IsValidIP(vnc_bind_address): + if utils.IsValidIP4(vnc_bind_address): if instance.network_port > constants.VNC_BASE_PORT: display = instance.network_port - constants.VNC_BASE_PORT if vnc_bind_address == constants.IP4_ADDRESS_ANY: diff --git a/lib/hypervisor/hv_xen.py b/lib/hypervisor/hv_xen.py index acf5e0b2d65f1afb5ced4b9687fe386d28ed80ee..876e072b03d43c59f2347d052de07fd8d63fbe1b 100644 --- a/lib/hypervisor/hv_xen.py +++ b/lib/hypervisor/hv_xen.py @@ -549,7 +549,7 @@ class XenHvmHypervisor(XenHypervisor): hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES), constants.HV_PAE: hv_base.NO_CHECK, constants.HV_VNC_BIND_ADDRESS: - (False, utils.IsValidIP, + (False, utils.IsValidIP4, "VNC bind address is not a valid IP address", None, None), constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK, constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK, diff --git a/lib/utils.py b/lib/utils.py index ebbde57709bf5005ee6985f73c2de1f4ef62b1d5..2f6d04ea12eb6815c9910c7ded2bc36a5e35628d 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1292,22 +1292,64 @@ def TryConvert(fn, val): return nv +def _GenericIsValidIP(family, ip): + """Generic internal version of ip validation. + + @type family: int + @param family: socket.AF_INET | socket.AF_INET6 + @type ip: str + @param ip: the address to be checked + @rtype: boolean + @return: True if ip is valid, False otherwise + + """ + try: + socket.inet_pton(family, ip) + return True + except socket.error: + return False + + +def IsValidIP4(ip): + """Verifies an IPv4 address. + + This function checks if the given address is a valid IPv4 address. + + @type ip: str + @param ip: the address to be checked + @rtype: boolean + @return: True if ip is valid, False otherwise + + """ + return _GenericIsValidIP(socket.AF_INET, ip) + + +def IsValidIP6(ip): + """Verifies an IPv6 address. + + This function checks if the given address is a valid IPv6 address. + + @type ip: str + @param ip: the address to be checked + @rtype: boolean + @return: True if ip is valid, False otherwise + + """ + return _GenericIsValidIP(socket.AF_INET6, ip) + + def IsValidIP(ip): - """Verifies the syntax of an IPv4 address. + """Verifies an IP address. - This function checks if the IPv4 address passes is valid or not based - on syntax (not IP range, class calculations, etc.). + This function checks if the given IP address (both IPv4 and IPv6) is valid. @type ip: str @param ip: the address to be checked - @rtype: a regular expression match object - @return: a regular expression match object, or None if the - address is not valid + @rtype: boolean + @return: True if ip is valid, False otherwise """ - unit = "(0|[1-9]\d{0,2})" - #TODO: convert and return only boolean - return re.match("^%s\.%s\.%s\.%s$" % (unit, unit, unit, unit), ip) + return IsValidIP4(ip) or IsValidIP6(ip) def IsValidShellParam(word): diff --git a/scripts/gnt-instance b/scripts/gnt-instance index 521be301e5c2a9b733a264eca2b62751a660fe56..82abc4df184dd9fa27cbe06c813edd84dd93fab7 100755 --- a/scripts/gnt-instance +++ b/scripts/gnt-instance @@ -1191,7 +1191,7 @@ def ShowInstanceConfig(opts, args): vnc_console_port = "%s:%s (display %s)" % (instance["pnode"], port, display) - elif display > 0 and utils.IsValidIP(vnc_bind_address): + elif display > 0 and utils.IsValidIP4(vnc_bind_address): vnc_console_port = ("%s:%s (node %s) (display %s)" % (vnc_bind_address, port, instance["pnode"], display)) diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index 50ed4e96ea5c831a098b1ffb4740044ce1b8837f..e0cdd0dd633e223c292231dcf8e2d6d609ccf7ed 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -2426,5 +2426,43 @@ class RunIgnoreProcessNotFound(unittest.TestCase): self.assertFalse(utils.IgnoreProcessNotFound(os.kill, pid, 0)) +class TestIsValidIP4(unittest.TestCase): + def test(self): + self.assert_(utils.IsValidIP4("127.0.0.1")) + self.assert_(utils.IsValidIP4("0.0.0.0")) + self.assert_(utils.IsValidIP4("255.255.255.255")) + self.assertFalse(utils.IsValidIP4("0")) + self.assertFalse(utils.IsValidIP4("1")) + self.assertFalse(utils.IsValidIP4("1.1.1")) + self.assertFalse(utils.IsValidIP4("255.255.255.256")) + self.assertFalse(utils.IsValidIP4("::1")) + + +class TestIsValidIP6(unittest.TestCase): + def test(self): + self.assert_(utils.IsValidIP6("::")) + self.assert_(utils.IsValidIP6("::1")) + self.assert_(utils.IsValidIP6("1" + (":1" * 7))) + self.assert_(utils.IsValidIP6("ffff" + (":ffff" * 7))) + self.assertFalse(utils.IsValidIP6("0")) + self.assertFalse(utils.IsValidIP6(":1")) + self.assertFalse(utils.IsValidIP6("f" + (":f" * 6))) + self.assertFalse(utils.IsValidIP6("fffg" + (":ffff" * 7))) + self.assertFalse(utils.IsValidIP6("fffff" + (":ffff" * 7))) + self.assertFalse(utils.IsValidIP6("1" + (":1" * 8))) + self.assertFalse(utils.IsValidIP6("127.0.0.1")) + + +class TestIsValidIP(unittest.TestCase): + def test(self): + self.assert_(utils.IsValidIP("0.0.0.0")) + self.assert_(utils.IsValidIP("127.0.0.1")) + self.assert_(utils.IsValidIP("::")) + self.assert_(utils.IsValidIP("::1")) + self.assertFalse(utils.IsValidIP("0")) + self.assertFalse(utils.IsValidIP("1.1.1.256")) + self.assertFalse(utils.IsValidIP("a:g::1")) + + if __name__ == '__main__': testutils.GanetiTestProgram()