Skip to content

Commit 098ae39

Browse files
author
Andrew Topp
committed
policy: T5069: large-community-list regex validator disallows whitespace
* Re-introduce the symbol/whitespace matches ' ' and '_' as allowed * Perform a general Python regex validity check (not 100% 1003.2, but in combination with allowedChars, pretty close) * Introduce a warning against potentially malformed or over-complex patterns, but leave it up to the user to resolve - there are plenty of useful expressions we cannot validate easily.
1 parent 5490006 commit 098ae39

File tree

1 file changed

+35
-6
lines changed

1 file changed

+35
-6
lines changed

src/validators/bgp-large-community-list

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22
#
3-
# Copyright (C) 2021-2023 VyOS maintainers and contributors
3+
# Copyright (C) 2021-2025 VyOS maintainers and contributors
44
#
55
# This program is free software; you can redistribute it and/or modify
66
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,18 +17,47 @@
1717
import re
1818
import sys
1919

20-
pattern = '(.*):(.*):(.*)'
21-
allowedChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '+', '*', '?', '^', '$', '(', ')', '[', ']', '{', '}', '|', '\\', ':', '-' }
20+
def console_warning(txt: str):
21+
with open('/dev/tty', 'w') as tty:
22+
print(f'WARNING: {txt}', file=tty)
23+
24+
# Regex should:
25+
# * Require complete 3-tuples, no blank members. Catch missed & doubled colons.
26+
# * Permit appropriate community separators (whitespace, underscore)
27+
# * Permit common regex between tuples while requiring at least one separator
28+
# (eg, "1:1:1_.*_4:4:4", matching "1:1:1 4:4:4" and "1:1:1 2:2:2 4:4:4",
29+
# but not "1:1:13 24:4:4")
30+
# * Reject run-on beyond the end of the match - full string match & comply
31+
pattern = r'([^: _]+):([^: _]+):([^: _]+)([ _]([^:]+):([^: _]+):([^: _]+))*'
32+
allowedChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '+', '*', '?', '^', '$', '(', ')', '[', ']', '{', '}', '|', '\\', ':', '-', '_', ' ' }
2233

2334
if __name__ == '__main__':
2435
if len(sys.argv) != 2:
2536
sys.exit(1)
2637

27-
value = sys.argv[1].split(':')
28-
if not len(value) == 3:
38+
value = sys.argv[1]
39+
40+
# Require at least one well-formed large-community tuple in the pattern.
41+
tmp = value.split(':')
42+
if len(tmp) < 3:
2943
sys.exit(1)
3044

31-
if not (re.match(pattern, sys.argv[1]) and set(sys.argv[1]).issubset(allowedChars)):
45+
# Simple guard against invalid community & 1003.2 pattern chars
46+
if not set(value).issubset(allowedChars):
3247
sys.exit(1)
3348

49+
# Don't feed FRR badly formed regex
50+
try:
51+
re.compile(value)
52+
except re.error:
53+
sys.exit(1)
54+
55+
if not re.fullmatch(pattern, value):
56+
# If you know what you're doing, you should be able to do it.
57+
# It is, however, very easy to over- or under-restrict compound regex
58+
# logic against communities and ASNs, especially if they change.
59+
# Best practice: stick with basic patterns, mind your wildcards and whitespace.
60+
console_warning('Regex does not follow expected form and may not match as expected.')
61+
sys.exit(0)
62+
3463
sys.exit(0)

0 commit comments

Comments
 (0)