Commit d242923c authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

utils.text: Function to verify MAC address prefix



The network management code needs to verify a MAC address prefix.
Instead of (ab)using NormalizeAndValidateMac, clean code should be used.
Unit tests for NormalizeAndValidateMac are updated and new ones for
NormalizeAndValidateThreeOctetMacPrefix are added.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarGuido Trotter <ultrotter@google.com>
parent cbcd9144
......@@ -37,15 +37,15 @@ _PARSEUNIT_REGEX = re.compile(r"^([.\d]+)\s*([a-zA-Z]+)?$")
#: Characters which don't need to be quoted for shell commands
_SHELL_UNQUOTED_RE = re.compile("^[-.,=:/_+@A-Za-z0-9]+$")
#: MAC checker regexp
_MAC_CHECK_RE = re.compile("^([0-9a-f]{2}:){5}[0-9a-f]{2}$", re.I)
#: Shell param checker regexp
_SHELLPARAM_REGEX = re.compile(r"^[-a-zA-Z0-9._+/:%@]+$")
#: ASCII equivalent of unicode character 'HORIZONTAL ELLIPSIS' (U+2026)
_ASCII_ELLIPSIS = "..."
#: MAC address octet
_MAC_ADDR_OCTET_RE = r"[0-9a-f]{2}"
def MatchNameComponent(key, name_list, case_sensitive=True):
"""Try to match a name against a list.
......@@ -301,25 +301,75 @@ def GenerateSecret(numbytes=20):
return os.urandom(numbytes).encode("hex")
def NormalizeAndValidateMac(mac):
"""Normalizes and check if a MAC address is valid.
def _MakeMacAddrRegexp(octets):
"""Builds a regular expression for verifying MAC addresses.
Checks whether the supplied MAC address is formally correct, only
accepts colon separated format. Normalize it to all lower.
@type octets: integer
@param octets: How many octets to expect (1-6)
@return: Compiled regular expression
@type mac: str
@param mac: the MAC to be validated
@rtype: str
@return: returns the normalized and validated MAC.
"""
assert octets > 0
assert octets <= 6
return re.compile("^%s$" % ":".join([_MAC_ADDR_OCTET_RE] * octets),
re.I)
#: Regular expression for full MAC address
_MAC_CHECK_RE = _MakeMacAddrRegexp(6)
#: Regular expression for half a MAC address
_MAC_PREFIX_CHECK_RE = _MakeMacAddrRegexp(3)
def _MacAddressCheck(check_re, mac, msg):
"""Checks a MAC address using a regular expression.
@param check_re: Compiled regular expression as returned by C{re.compile}
@type mac: string
@param mac: MAC address to be validated
@type msg: string
@param msg: Error message (%s will be replaced with MAC address)
"""
if check_re.match(mac):
return mac.lower()
raise errors.OpPrereqError(msg % mac, errors.ECODE_INVAL)
@raise errors.OpPrereqError: If the MAC isn't valid
def NormalizeAndValidateMac(mac):
"""Normalizes and check if a MAC address is valid and contains six octets.
Checks whether the supplied MAC address is formally correct. Accepts
colon-separated format only. Normalize it to all lower case.
@type mac: string
@param mac: MAC address to be validated
@rtype: string
@return: Normalized and validated MAC address
@raise errors.OpPrereqError: If the MAC address isn't valid
"""
if not _MAC_CHECK_RE.match(mac):
raise errors.OpPrereqError("Invalid MAC address '%s'" % mac,
errors.ECODE_INVAL)
return _MacAddressCheck(_MAC_CHECK_RE, mac, "Invalid MAC address '%s'")
return mac.lower()
def NormalizeAndValidateThreeOctetMacPrefix(mac):
"""Normalizes a potential MAC address prefix (three octets).
Checks whether the supplied string is a valid MAC address prefix consisting
of three colon-separated octets. The result is normalized to all lower case.
@type mac: string
@param mac: Prefix to be validated
@rtype: string
@return: Normalized and validated prefix
@raise errors.OpPrereqError: If the MAC address prefix isn't valid
"""
return _MacAddressCheck(_MAC_PREFIX_CHECK_RE, mac,
"Invalid MAC address prefix '%s'")
def SafeEncode(text):
......
......@@ -356,14 +356,28 @@ class TestShellWriter(unittest.TestCase):
class TestNormalizeAndValidateMac(unittest.TestCase):
def testInvalid(self):
self.assertRaises(errors.OpPrereqError,
utils.NormalizeAndValidateMac, "xxx")
for i in ["xxx", "00:11:22:33:44:55:66", "zz:zz:zz:zz:zz:zz"]:
self.assertRaises(errors.OpPrereqError, utils.NormalizeAndValidateMac, i)
def testNormalization(self):
for mac in ["aa:bb:cc:dd:ee:ff", "00:AA:11:bB:22:cc"]:
self.assertEqual(utils.NormalizeAndValidateMac(mac), mac.lower())
class TestNormalizeAndValidateThreeOctetMacPrefix(unittest.TestCase):
def testInvalid(self):
for i in ["xxx", "00:11:22:33:44:55:66", "zz:zz:zz:zz:zz:zz",
"aa:bb:cc:dd:ee:ff", "00:AA:11:bB:22:cc",
"00:11:"]:
self.assertRaises(errors.OpPrereqError,
utils.NormalizeAndValidateThreeOctetMacPrefix, i)
def testNormalization(self):
for mac in ["aa:bb:cc", "00:AA:11"]:
self.assertEqual(utils.NormalizeAndValidateThreeOctetMacPrefix(mac),
mac.lower())
class TestSafeEncode(unittest.TestCase):
"""Test case for SafeEncode"""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment