| #!/usr/bin/env python3 |
| # |
| # Copyright 2022 The Fuchsia Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import random |
| from collections import namedtuple |
| from typing import Dict, Union |
| |
| from mobly import asserts, test_runner |
| |
| from antlion.test_utils.dhcp import base_test |
| |
| OPT_NUM_DOMAIN_SEARCH = 119 |
| OPT_NUM_DOMAIN_NAME = 15 |
| |
| Test = namedtuple(typename="Args", field_names=["name", "settings"]) |
| |
| |
| class Dhcpv4InteropCombinatorialOptionsTest(base_test.Dhcpv4InteropFixture): |
| """DhcpV4 tests which validate combinations of DHCP options.""" |
| |
| def setup_generated_tests(self) -> None: |
| self.generate_tests( |
| self.run_test_case_expect_dhcp_success, |
| lambda name, *_: f"test_{name}", |
| [ |
| Test( |
| "domain_name_valid", |
| { |
| "dhcp_options": { |
| "domain-name": '"example.test"', |
| "dhcp-parameter-request-list": OPT_NUM_DOMAIN_NAME, |
| }, |
| "dhcp_parameters": {}, |
| }, |
| ), |
| Test( |
| "domain_name_invalid", |
| { |
| "dhcp_options": { |
| "domain-name": '"example.invalid"', |
| "dhcp-parameter-request-list": OPT_NUM_DOMAIN_NAME, |
| }, |
| "dhcp_parameters": {}, |
| }, |
| ), |
| Test( |
| "domain_search_valid", |
| { |
| "dhcp_options": { |
| "domain-name": '"example.test"', |
| "dhcp-parameter-request-list": OPT_NUM_DOMAIN_SEARCH, |
| }, |
| "dhcp_parameters": {}, |
| }, |
| ), |
| Test( |
| "domain_search_invalid", |
| { |
| "dhcp_options": { |
| "domain-name": '"example.invalid"', |
| "dhcp-parameter-request-list": OPT_NUM_DOMAIN_SEARCH, |
| }, |
| "dhcp_parameters": {}, |
| }, |
| ), |
| Test( |
| "max_sized_message", |
| { |
| "dhcp_options": self._generate_max_sized_message_dhcp_options(), |
| "dhcp_parameters": {}, |
| }, |
| ), |
| ], |
| ) |
| |
| def _generate_max_sized_message_dhcp_options(self) -> Dict[str, Union[int, str]]: |
| """Generates the DHCP options for max sized message test. |
| |
| The RFC limits DHCP payloads to 576 bytes unless the client signals it |
| can handle larger payloads, which it does by sending DHCP option 57, |
| "Maximum DHCP Message Size". Despite being able to accept larger |
| payloads, clients typically don't advertise this. The test verifies that |
| the client accepts a large message split across multiple ethernet |
| frames. The test is created by sending many bytes of options through the |
| domain-name-servers option, which is of unbounded length (though is |
| compressed per RFC1035 section 4.1.4). |
| |
| Returns: |
| A dict of DHCP options. |
| """ |
| typical_ethernet_mtu = 1500 |
| |
| long_dns_setting = ", ".join( |
| f'"ns{num}.example"' |
| for num in random.sample(range(100_000, 1_000_000), 250) |
| ) |
| # RFC1035 compression means any shared suffix ('.example' in this case) |
| # will be deduplicated. Calculate approximate length by removing that |
| # suffix. |
| long_dns_setting_len = len( |
| long_dns_setting.replace(", ", "") |
| .replace('"', "") |
| .replace(".example", "") |
| .encode("utf-8") |
| ) |
| asserts.assert_true( |
| long_dns_setting_len > typical_ethernet_mtu, |
| "Expected to generate message greater than ethernet mtu", |
| ) |
| |
| return { |
| "dhcp-max-message-size": long_dns_setting_len * 2, |
| "domain-search": long_dns_setting, |
| "dhcp-parameter-request-list": OPT_NUM_DOMAIN_SEARCH, |
| } |
| |
| |
| if __name__ == "__main__": |
| test_runner.main() |