mirror of
https://github.com/linux-system-roles/network.git
synced 2026-01-23 02:15:17 +00:00
argument_validator: fix IPRouteUtils.get_route_tables_mapping() for whitespace sequence
Accept any whitespace sequence, according to Python's `rb"\s"` class. This way, tabs are also accepted. This is also what iproute2 does. Use just one regex for this. Also add a unit test for the default iproute2 file. Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
parent
200cf67507
commit
a74092634a
2 changed files with 65 additions and 41 deletions
|
|
@ -2568,65 +2568,61 @@ class ArgValidator_ListConnections(ArgValidatorList):
|
|||
|
||||
class IPRouteUtils(object):
|
||||
|
||||
# iproute2 does not care much about the valid characters of a
|
||||
# table alias (it doesn't even require UTF-8 encoding, the only
|
||||
# forbidden parts are whitespace).
|
||||
#
|
||||
# We don't allow such flexibility. Aliases must only contain a
|
||||
# certain set of ASCII characters. These aliases are what we accept
|
||||
# as input (in the playbook), and there is no need to accept
|
||||
# user input with unusual characters or non-ASCII names.
|
||||
ROUTE_TABLE_ALIAS_RE = re.compile("^[a-zA-Z0-9_.-]+$")
|
||||
|
||||
@classmethod
|
||||
def _parse_route_tables_mapping(cls, file_content, mapping):
|
||||
|
||||
# This parses the /etc/iproute2/rt_tables file and constructs
|
||||
# the mapping from table aliases the table numeric IDs.
|
||||
#
|
||||
# It is thus similar to rtnl_rttable_a2n(), from here:
|
||||
# https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/lib/rt_names.c?id=11e41a635cfab54e8e02fbff2a03715467e77ae9#n447
|
||||
regex = re.compile(
|
||||
b"^\\s*(0x[0-9a-fA-F]+|[0-9]+)\\s+([a-zA-Z0-9_.-]+)(\\s*|\\s+#.*)$"
|
||||
)
|
||||
for line in file_content.split(b"\n"):
|
||||
|
||||
# iproute2 only skips over leading ' ' and '\t'.
|
||||
line = line.lstrip()
|
||||
|
||||
# skip empty lines or comments
|
||||
if not line:
|
||||
rmatch = regex.match(line)
|
||||
if not rmatch:
|
||||
continue
|
||||
|
||||
# In Python 2.x, there is no new type called `bytes`. And Python 2.x
|
||||
# `bytes` is just an alias to the str type
|
||||
if Util.PY3:
|
||||
if line[0] == ord(b"#"):
|
||||
continue
|
||||
else:
|
||||
if line[0] == "#":
|
||||
continue
|
||||
table = rmatch.group(1)
|
||||
name = rmatch.group(2)
|
||||
|
||||
# iproute2 splits at the first space.
|
||||
ll = line.split(b" ", 1)
|
||||
if len(ll) != 2:
|
||||
continue
|
||||
line1 = ll[0]
|
||||
line2 = ll[1]
|
||||
name = name.decode("utf-8")
|
||||
|
||||
comment_space = line2.find(b" ")
|
||||
if comment_space >= 0:
|
||||
# when commenting the route table entry in the same line,
|
||||
# iproute2 only accepts one ' ', followed by '#'
|
||||
if not re.match(b"^[a-zA-Z0-9_.-]+ #", line2):
|
||||
continue
|
||||
line2 = line2[:comment_space]
|
||||
|
||||
# convert to UTF-8 and only accept benign characters.
|
||||
try:
|
||||
line2 = line2.decode("utf-8")
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not cls.ROUTE_TABLE_ALIAS_RE.match(line2):
|
||||
continue
|
||||
if not cls.ROUTE_TABLE_ALIAS_RE.match(name):
|
||||
raise AssertionError(
|
||||
"bug: table alias contains unexpected characters: %s" % (name,)
|
||||
)
|
||||
|
||||
tableid = None
|
||||
try:
|
||||
tableid = int(line1)
|
||||
tableid = int(table)
|
||||
except Exception:
|
||||
if line.startswith(b"0x"):
|
||||
if table.startswith(b"0x"):
|
||||
try:
|
||||
tableid = int(line1[2:], 16)
|
||||
tableid = int(table[2:], 16)
|
||||
except Exception:
|
||||
pass
|
||||
if tableid is None or tableid < 0 or tableid > 0xFFFFFFFF:
|
||||
continue
|
||||
|
||||
mapping[line2] = tableid
|
||||
# In case of duplicates, the latter wins. That is unlike iproute2's
|
||||
# rtnl_rttable_a2n(), which does a linear search over the
|
||||
# hash table (thus, the first found name depends on the content
|
||||
# of the hash table and the result in face of duplicates is
|
||||
# not well defined).
|
||||
mapping[name] = tableid
|
||||
|
||||
@classmethod
|
||||
def _parse_route_tables_mapping_from_file(cls, filename, mapping):
|
||||
|
|
|
|||
|
|
@ -4551,12 +4551,40 @@ class TestValidatorRouteTable(Python26CompatTestCase):
|
|||
return mapping
|
||||
|
||||
self.assertEqual(parse(b""), {})
|
||||
self.assertEqual(parse(b"5x"), {})
|
||||
self.assertEqual(parse(b"0xF5 x"), {"x": 0xF5})
|
||||
self.assertEqual(parse(b"0x5a x"), {"x": 0x5A})
|
||||
self.assertEqual(parse(b" 0x5a x"), {"x": 0x5A})
|
||||
self.assertEqual(parse(b"0x0 x"), {"x": 0x0})
|
||||
self.assertEqual(parse(b"0x x"), {})
|
||||
self.assertEqual(parse(b"5 x"), {"x": 5})
|
||||
self.assertEqual(parse(b" 7 y "), {})
|
||||
self.assertEqual(parse(b" 7 y "), {"y": 7})
|
||||
self.assertEqual(parse(b"5 x\n0x4 y"), {"x": 5, "y": 4})
|
||||
self.assertEqual(parse(b"5 x #df\n0x4 y"), {"x": 5, "y": 4})
|
||||
self.assertEqual(parse(b"5 x #df\n0x4 y\n7\ty"), {"x": 5, "y": 4})
|
||||
self.assertEqual(parse(b"5 x #df\n0x4 y\n7\ty"), {"x": 5, "y": 7})
|
||||
self.assertEqual(parse(b"-1 x #df\n0x4 y\n5 x"), {"x": 5, "y": 4})
|
||||
self.assertEqual(
|
||||
parse(b"5 x #df\n0x4 y\n7\t \ty\n\t\t44 7\n 66 a%\n 67 ab"),
|
||||
{"x": 5, "y": 7, "7": 44, "ab": 67},
|
||||
)
|
||||
|
||||
# https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/etc/iproute2/rt_tables?id=11e41a635cfab54e8e02fbff2a03715467e77ae9
|
||||
self.assertEqual(
|
||||
parse(
|
||||
b"#\n"
|
||||
b"# reserved values\n"
|
||||
b"#\n"
|
||||
b"255 local\n"
|
||||
b"254 main\n"
|
||||
b"253 default\n"
|
||||
b"0 unspec\n"
|
||||
b"#\n"
|
||||
b"# local\n"
|
||||
b"#\n"
|
||||
b"#1 inr.ruhep\n"
|
||||
),
|
||||
{"local": 255, "main": 254, "default": 253, "unspec": 0},
|
||||
)
|
||||
|
||||
def test_table_found_when_validate_route_tables(self):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue