|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 | # |
3 | | -# Copyright (C) 2021-2023 VyOS maintainers and contributors |
| 3 | +# Copyright (C) 2021-2025 VyOS maintainers and contributors |
4 | 4 | # |
5 | 5 | # This program is free software; you can redistribute it and/or modify |
6 | 6 | # it under the terms of the GNU General Public License version 2 or later as |
|
17 | 17 | import re |
18 | 18 | import sys |
19 | 19 |
|
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', '.', '+', '*', '?', '^', '$', '(', ')', '[', ']', '{', '}', '|', '\\', ':', '-', '_', ' ' } |
22 | 33 |
|
23 | 34 | if __name__ == '__main__': |
24 | 35 | if len(sys.argv) != 2: |
25 | 36 | sys.exit(1) |
26 | 37 |
|
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: |
29 | 43 | sys.exit(1) |
30 | 44 |
|
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): |
32 | 47 | sys.exit(1) |
33 | 48 |
|
| 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 | + |
34 | 63 | sys.exit(0) |
0 commit comments