stages(kickstart): add ipv4 related regex pattern checks

Check for valid ipv4 addresses via a regex in the schema and
add matching tests. This will ensure that only valid ipv4
addresses can be entereed in "ip", "gateway" or "nameservers".

Note that libc/kernel accept invalid ipv4 addresses and do
"interesting" things with them. So they accept `127.1` and
turn that into `127.0.0.1` or even `127.256` and turn that
into `127.0.1.0` because 256 overflows into the next segment
(thanks to Simon for poiting this out). If this becomes a
problem and customers rely on invalid ipv4 addresses we will
need to relax the rules but let's start strict and help our
users with more guardrails.

Note that no ipv6 validation via regex is done. The regex
on stackoverflow for validating ipv6 is 660 chars long
and that seems a bit too long for our schemas and putting
and error with that in front of our users.
This commit is contained in:
Michael Vogt 2023-11-21 07:51:16 +01:00 committed by Simon de Vlieger
parent 3b346a6a30
commit 60e78f5084
2 changed files with 18 additions and 3 deletions

View file

@ -45,7 +45,8 @@ SCHEMA = r"""
},
"ip": {
"description": "IP address of the device",
"type": "string"
"type": "string",
"pattern": "^(((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}|auto)$"
},
"ipv6": {
"description": "IPv6 address of the device, in the form of address[/prefix length]",
@ -53,7 +54,8 @@ SCHEMA = r"""
},
"gateway": {
"description": "Default gateway as a single IPv4 address",
"type": "string"
"type": "string",
"pattern": "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$"
},
"ipv6gateway": {
"description": "Default gateway as a single IPv6 address",
@ -64,7 +66,8 @@ SCHEMA = r"""
"type": "array",
"minSize": 1,
"items": {
"type": "string"
"type": "string",
"pattern": "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$"
}
},
"netmask": {

View file

@ -267,6 +267,18 @@ def test_kickstart_valid(tmp_path, test_input, expected): # pylint: disable=unu
({"network": [{"device": "foo", "activate": "string"}]}, " is not of type 'boolean'"),
({"network": [{"device": "foo", "random": "option"}]}, "Additional properties are not allowed "),
({"network": [{"device": "foo", "bootproto": "invalid"}]}, " is not one of ["),
({"network": [{"device": "foo", "ip": "invalid"}]}, " does not match "),
({"network": [{"device": "foo", "ip": "256.1.1.1"}]}, " does not match "),
({"network": [{"device": "foo", "ip": "1.256.1.1"}]}, " does not match "),
({"network": [{"device": "foo", "ip": "1.1.256.1"}]}, " does not match "),
({"network": [{"device": "foo", "ip": "1.1.1.256"}]}, " does not match "),
# kernel will accept this (and make it 127.0.0.1) but it's
# technically not valid. if this becomes a problem we may need to
# relax (or remove) the ipv4 validation regex. Also
# 127.256 will be accepted and overflows into "127.0.1.0".
({"network": [{"device": "foo", "ip": "127.1"}]}, " does not match "),
({"network": [{"device": "foo", "gateway": "invalid"}]}, " does not match "),
({"network": [{"device": "foo", "nameservers": ["invalid"]}]}, " does not match "),
],
)
def test_schema_validation_bad_apples(test_data, expected_err):