/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2008 - 2014 Red Hat, Inc. */ #include "src/core/nm-default-daemon.h" #include #include #include #include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-utils.h" #include "dhcp/nm-dhcp-utils.h" #include "dhcp/nm-dhcp-options.h" #include "libnm-platform/nm-platform.h" #include "nm-test-utils-core.h" /*****************************************************************************/ static const NML3ConfigData * _ip4_config_from_options(int ifindex, const char *iface, GHashTable *options) { nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new(); NML3ConfigData * l3cd; l3cd = nm_dhcp_utils_ip4_config_from_options(multi_idx, ifindex, iface, options); g_assert(NM_IS_L3_CONFIG_DATA(l3cd)); g_assert(!nm_l3_config_data_is_sealed(l3cd)); if (nmtst_get_rand_bool()) nm_l3_config_data_seal(l3cd); return l3cd; } typedef struct { const char *name; const char *value; } Option; static GHashTable * fill_table(const Option *test_options, GHashTable *table) { const Option *opt; if (!table) table = g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, NULL); for (opt = test_options; opt->name; opt++) g_hash_table_insert(table, (gpointer) opt->name, (gpointer) opt->value); return table; } static const Option generic_options[] = { {"subnet_mask", "255.255.255.0"}, {"ip_address", "192.168.1.106"}, {"network_number", "192.168.1.0"}, {"expiry", "1232324877"}, {"dhcp_lease_time", "3600"}, {"dhcp_server_identifier", "192.168.1.1"}, {"routers", "192.168.1.1"}, {"domain_name_servers", "216.254.95.2 216.231.41.2"}, {"dhcp_message_type", "5"}, {"broadcast_address", "192.168.1.255"}, {"domain_search", "foobar.com blah.foobar.com"}, {"host_name", "nmreallywhipsthe"}, {"domain_name", "lamasass.com"}, {"interface_mtu", "987"}, {"static_routes", "10.1.1.5 10.1.1.1 100.99.88.56 10.1.1.1"}, {NULL, NULL}}; static void test_generic_options(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const NMPlatformIP4Address * address; const NMPlatformIP4Route * route; guint32 tmp; const char * expected_addr = "192.168.1.106"; const char * expected_gw = "192.168.1.1"; const char * expected_dns1 = "216.254.95.2"; const char * expected_dns2 = "216.231.41.2"; const char * expected_search1 = "foobar.com"; const char * expected_search2 = "blah.foobar.com"; const char * expected_route1_dest = "10.1.1.5"; const char * expected_route1_gw = "10.1.1.1"; const char * expected_route2_dest = "100.99.88.56"; const char * expected_route2_gw = "10.1.1.1"; const char *const * strarr; const in_addr_t * ia_arr; guint u; options = fill_table(generic_options, NULL); l3cd = _ip4_config_from_options(1, "eth0", options); g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(inet_pton(AF_INET, expected_addr, &tmp) > 0); g_assert(address->address == tmp); g_assert(address->peer_address == tmp); g_assert_cmpint(address->plen, ==, 24); nmtst_assert_ip_address(AF_INET, nmtst_l3_config_data_get_best_gateway(l3cd, AF_INET), expected_gw); g_assert(!nm_l3_config_data_get_wins(l3cd, &u)); g_assert_cmpint(u, ==, 0); g_assert_cmpint(nm_l3_config_data_get_mtu(l3cd), ==, 987); strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); g_assert_cmpint(u, ==, 2); g_assert_cmpstr(strarr[0], ==, expected_search1); g_assert_cmpstr(strarr[1], ==, expected_search2); ia_arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &u); g_assert_cmpint(u, ==, 2); nmtst_assert_ip4_address(ia_arr[0], expected_dns1); nmtst_assert_ip4_address(ia_arr[1], expected_dns2); g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); route = nmtst_l3_config_data_get_route_at_4(l3cd, 0); g_assert(inet_pton(AF_INET, expected_route1_dest, &tmp) > 0); g_assert(route->network == tmp); g_assert(inet_pton(AF_INET, expected_route1_gw, &tmp) > 0); g_assert(route->gateway == tmp); g_assert_cmpint(route->plen, ==, 32); g_assert_cmpint(route->metric, ==, 0); route = nmtst_l3_config_data_get_route_at_4(l3cd, 1); g_assert(route->network == nmtst_inet4_from_string(expected_route2_dest)); g_assert(route->gateway == nmtst_inet4_from_string(expected_route2_gw)); g_assert_cmpint(route->plen, ==, 32); g_assert_cmpint(route->metric, ==, 0); route = nmtst_l3_config_data_get_route_at_4(l3cd, 2); g_assert(route->network == nmtst_inet4_from_string("0.0.0.0")); g_assert(route->gateway == nmtst_inet4_from_string("192.168.1.1")); g_assert_cmpint(route->plen, ==, 0); g_assert_cmpint(route->metric, ==, 0); } static void test_wins_options(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const NMPlatformIP4Address * address; const char * expected_wins1 = "63.12.199.5"; const char * expected_wins2 = "150.4.88.120"; static const Option data[] = {{"netbios_name_servers", "63.12.199.5 150.4.88.120"}, {NULL, NULL}}; const in_addr_t * ia_arr; guint u; options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); ia_arr = nm_l3_config_data_get_wins(l3cd, &u); g_assert_cmpint(u, ==, 2); nmtst_assert_ip4_address(ia_arr[0], expected_wins1); nmtst_assert_ip4_address(ia_arr[1], expected_wins2); } static void test_vendor_option_metered(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; static const Option data[] = {{"vendor_encapsulated_options", "ANDROID_METERED"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); l3cd = _ip4_config_from_options(1, "eth0", options); g_assert(nm_l3_config_data_get_metered(l3cd) == NM_TERNARY_DEFAULT); nm_clear_pointer(&options, g_hash_table_destroy); nm_clear_l3cd(&l3cd); options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); g_assert(nm_l3_config_data_get_metered(l3cd) == TRUE); } static void test_parse_search_list(void) { guint8 *data; char ** domains; data = (guint8[]){0x05, 'l', 'o', 'c', 'a', 'l', 0x00}; domains = nm_dhcp_lease_data_parse_search_list(data, 7); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 1); g_assert_cmpstr(domains[0], ==, "local"); g_strfreev(domains); data = (guint8[]){0x04, 't', 'e', 's', 't', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm', 0x00, 0xc0, 0x05, 0x03, 'a', 'b', 'c', 0xc0, 0x0d, 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x00}; domains = nm_dhcp_lease_data_parse_search_list(data, 34); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 4); g_assert_cmpstr(domains[0], ==, "test.example.com"); g_assert_cmpstr(domains[1], ==, "example.com"); g_assert_cmpstr(domains[2], ==, "abc.com"); g_assert_cmpstr(domains[3], ==, "foobar"); g_strfreev(domains); data = (guint8[]){ 0x40, 'b', 'a', 'd', }; domains = nm_dhcp_lease_data_parse_search_list(data, 4); g_assert(!domains); data = (guint8[]){ 0x04, 'o', 'k', 'a', 'y', 0x00, 0x40, 'b', 'a', 'd', }; domains = nm_dhcp_lease_data_parse_search_list(data, 10); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 1); g_assert_cmpstr(domains[0], ==, "okay"); g_strfreev(domains); } static void ip4_test_route(const NML3ConfigData *l3cd, guint route_num, const char * expected_dest, const char * expected_gw, guint expected_prefix) { const NMPlatformIP4Route *route; guint32 tmp; g_assert(expected_prefix <= 32); route = nmtst_l3_config_data_get_route_at_4(l3cd, route_num); g_assert(inet_pton(AF_INET, expected_dest, &tmp) > 0); g_assert(route->network == tmp); g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); g_assert(route->gateway == tmp); g_assert_cmpint(route->plen, ==, expected_prefix); g_assert_cmpint(route->metric, ==, 0); } #define ip4_test_gateway(l3cd, expected_gw) \ G_STMT_START \ { \ const NML3ConfigData *_l3cd = (l3cd); \ \ g_assert_cmpint(nm_l3_config_data_get_num_addresses(_l3cd, AF_INET), ==, 1); \ nmtst_assert_ip_address(AF_INET, \ nmtst_l3_config_data_get_best_gateway(_l3cd, AF_INET), \ expected_gw); \ } \ G_STMT_END static void test_classless_static_routes_1(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "192.168.10.0"; const char * expected_route1_gw = "192.168.1.1"; const char * expected_route2_dest = "10.0.0.0"; const char * expected_route2_gw = "10.17.66.41"; static const Option data[] = { /* dhclient custom format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 8); ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_classless_static_routes_2(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "192.168.10.0"; const char * expected_route1_gw = "192.168.1.1"; const char * expected_route2_dest = "10.0.0.0"; const char * expected_route2_gw = "10.17.66.41"; static const Option data[] = { /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 8); ip4_test_route(l3cd, 2, "0.0.0.0", expected_route1_gw, 0); } static void test_fedora_dhclient_classless_static_routes(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "129.210.177.128"; const char * expected_route1_gw = "192.168.0.113"; const char * expected_route2_dest = "2.0.0.0"; const char * expected_route2_gw = "10.34.255.6"; const char * expected_gateway = "192.168.0.113"; static const Option data[] = { /* Fedora dhclient format */ {"classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 25); ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 7); ip4_test_route(l3cd, 2, "0.0.0.0", expected_route1_gw, 0); ip4_test_gateway(l3cd, expected_gateway); } static void test_dhclient_invalid_classless_routes_1(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "192.168.10.0"; const char * expected_route1_gw = "192.168.1.1"; static const Option data[] = { /* dhclient format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhcpcd_invalid_classless_routes_1(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "10.1.1.5"; const char * expected_route1_gw = "10.1.1.1"; const char * expected_route2_dest = "100.99.88.56"; const char * expected_route2_gw = "10.1.1.1"; static const Option data[] = { /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhclient_invalid_classless_routes_2(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "10.1.1.5"; const char * expected_route1_gw = "10.1.1.1"; const char * expected_route2_dest = "100.99.88.56"; const char * expected_route2_gw = "10.1.1.1"; static const Option data[] = { {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhcpcd_invalid_classless_routes_2(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "10.1.1.5"; const char * expected_route1_gw = "10.1.1.1"; const char * expected_route2_dest = "100.99.88.56"; const char * expected_route2_gw = "10.1.1.1"; static const Option data[] = { {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ /* Routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhclient_invalid_classless_routes_3(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "192.168.10.0"; const char * expected_route1_gw = "192.168.1.1"; static const Option data[] = { {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhcpcd_invalid_classless_routes_3(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "192.168.10.0"; const char * expected_route1_gw = "192.168.1.1"; static Option data[] = { {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*DHCP provided invalid classless static route*"); l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhclient_gw_in_classless_routes(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "192.168.10.0"; const char * expected_route1_gw = "192.168.1.1"; const char * expected_gateway = "192.2.3.4"; static Option data[] = { {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route(l3cd, 1, "0.0.0.0", "192.2.3.4", 0); ip4_test_gateway(l3cd, expected_gateway); } static void test_dhcpcd_gw_in_classless_routes(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_route1_dest = "192.168.10.0"; const char * expected_route1_gw = "192.168.1.1"; const char * expected_gateway = "192.2.3.4"; static Option data[] = { {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route(l3cd, 1, "0.0.0.0", "192.2.3.4", 0); ip4_test_gateway(l3cd, expected_gateway); } static void test_escaped_domain_searches(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const char * expected_search0 = "host1"; const char * expected_search1 = "host2"; const char * expected_search2 = "host3"; static const Option data[] = {{"domain_search", "host1\\032host2\\032host3"}, {NULL, NULL}}; const char *const * strarr; guint u; options = fill_table(generic_options, NULL); options = fill_table(data, options); l3cd = _ip4_config_from_options(1, "eth0", options); strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); g_assert_cmpint(u, ==, 3); g_assert_cmpstr(strarr[0], ==, expected_search0); g_assert_cmpstr(strarr[1], ==, expected_search1); g_assert_cmpstr(strarr[2], ==, expected_search2); } static void test_invalid_escaped_domain_searches(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; static const Option data[] = {{"domain_search", "host1\\aahost2\\032host3"}, {NULL, NULL}}; const char *const * strarr; guint u; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*invalid domain search*"); l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); g_assert_cmpint(u, ==, 0); g_assert(!strarr); } static void test_ip4_missing_prefix(const char *ip, guint32 expected_prefix) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const NMPlatformIP4Address * address; options = fill_table(generic_options, NULL); g_hash_table_insert(options, "ip_address", (gpointer) ip); g_hash_table_remove(options, "subnet_mask"); l3cd = _ip4_config_from_options(1, "eth0", options); g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); g_assert_cmpint(address->plen, ==, expected_prefix); } static void test_ip4_missing_prefix_24(void) { test_ip4_missing_prefix("192.168.1.10", 24); } static void test_ip4_missing_prefix_16(void) { test_ip4_missing_prefix("172.16.54.50", 16); } static void test_ip4_missing_prefix_8(void) { test_ip4_missing_prefix("10.1.2.3", 8); } static void test_ip4_prefix_classless(void) { gs_unref_hashtable GHashTable *options = NULL; nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; const NMPlatformIP4Address * address; /* Ensure that the missing-subnet-mask handler doesn't mangle classless * subnet masks at all. The handler should trigger only if the server * doesn't send the subnet mask. */ options = fill_table(generic_options, NULL); g_hash_table_insert(options, "ip_address", "172.16.54.22"); g_hash_table_insert(options, "subnet_mask", "255.255.252.0"); l3cd = _ip4_config_from_options(1, "eth0", options); g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); g_assert_cmpint(address->plen, ==, 22); } #define COMPARE_ID(src, is_str, expected, expected_len) \ G_STMT_START \ { \ gs_unref_bytes GBytes *b = NULL; \ const char * p; \ gsize l; \ \ b = nm_dhcp_utils_client_id_string_to_bytes(src); \ g_assert(b); \ p = g_bytes_get_data(b, &l); \ if (is_str) { \ g_assert_cmpint(l, ==, expected_len + 1); \ g_assert_cmpint(((const char *) p)[0], ==, 0); \ g_assert(memcmp(p + 1, expected, expected_len) == 0); \ } else { \ g_assert_cmpint(l, ==, expected_len); \ g_assert(memcmp(p, expected, expected_len) == 0); \ } \ } \ G_STMT_END static void test_client_id_from_string(void) { const char * nothex = "asdfasdfasdfasdfasdfasdfasdf"; const char * allhex = "00:11:22:33:4:55:66:77:88"; const guint8 allhex_bin[] = {0x00, 0x11, 0x22, 0x33, 0x04, 0x55, 0x66, 0x77, 0x88}; const char * somehex = "00:11:22:33:44:55:asdfasdfasdf:99:10"; const char * nocolons = "0011223344559910"; const char * endcolon = "00:11:22:33:44:55:"; COMPARE_ID(nothex, TRUE, nothex, strlen(nothex)); COMPARE_ID(allhex, FALSE, allhex_bin, sizeof(allhex_bin)); COMPARE_ID(somehex, TRUE, somehex, strlen(somehex)); COMPARE_ID(nocolons, TRUE, nocolons, strlen(nocolons)); COMPARE_ID(endcolon, TRUE, endcolon, strlen(endcolon)); } /*****************************************************************************/ static void test_dhcp_opt_list(gconstpointer test_data) { const gboolean IS_IPv4 = (GPOINTER_TO_INT(test_data) == 0); const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; const NMDhcpOption *const options = IS_IPv4 ? _nm_dhcp_option_dhcp4_options : _nm_dhcp_option_dhcp6_options; const guint n = (IS_IPv4 ? G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options) : G_N_ELEMENTS(_nm_dhcp_option_dhcp6_options)); guint i; guint j; g_assert(options); g_assert(n > 0); for (i = 0; i < n; i++) { const NMDhcpOption *const opt = &options[i]; g_assert_cmpstr(opt->name, !=, NULL); g_assert(NM_STR_HAS_PREFIX(opt->name, NM_DHCP_OPTION_REQPREFIX)); for (j = 0; j < i; j++) { const NMDhcpOption *const opt2 = &options[j]; g_assert_cmpstr(opt->name, !=, opt2->name); g_assert_cmpint(opt->option_num, !=, opt2->option_num); } } for (i = 0; i < n; i++) { const NMDhcpOption *const opt = &options[i]; g_assert(opt == nm_dhcp_option_find(addr_family, opt->option_num)); } } /*****************************************************************************/ NMTST_DEFINE(); int main(int argc, char **argv) { nmtst_init_assert_logging(&argc, &argv, "WARN", "DEFAULT"); g_test_add_func("/dhcp/generic-options", test_generic_options); g_test_add_func("/dhcp/wins-options", test_wins_options); g_test_add_func("/dhcp/classless-static-routes-1", test_classless_static_routes_1); g_test_add_func("/dhcp/classless-static-routes-2", test_classless_static_routes_2); g_test_add_func("/dhcp/fedora-dhclient-classless-static-routes", test_fedora_dhclient_classless_static_routes); g_test_add_func("/dhcp/dhclient-invalid-classless-routes-1", test_dhclient_invalid_classless_routes_1); g_test_add_func("/dhcp/dhcpcd-invalid-classless-routes-1", test_dhcpcd_invalid_classless_routes_1); g_test_add_func("/dhcp/dhclient-invalid-classless-routes-2", test_dhclient_invalid_classless_routes_2); g_test_add_func("/dhcp/dhcpcd-invalid-classless-routes-2", test_dhcpcd_invalid_classless_routes_2); g_test_add_func("/dhcp/dhclient-invalid-classless-routes-3", test_dhclient_invalid_classless_routes_3); g_test_add_func("/dhcp/dhcpcd-invalid-classless-routes-3", test_dhcpcd_invalid_classless_routes_3); g_test_add_func("/dhcp/dhclient-gw-in-classless-routes", test_dhclient_gw_in_classless_routes); g_test_add_func("/dhcp/dhcpcd-gw-in-classless-routes", test_dhcpcd_gw_in_classless_routes); g_test_add_func("/dhcp/escaped-domain-searches", test_escaped_domain_searches); g_test_add_func("/dhcp/invalid-escaped-domain-searches", test_invalid_escaped_domain_searches); g_test_add_func("/dhcp/ip4-missing-prefix-24", test_ip4_missing_prefix_24); g_test_add_func("/dhcp/ip4-missing-prefix-16", test_ip4_missing_prefix_16); g_test_add_func("/dhcp/ip4-missing-prefix-8", test_ip4_missing_prefix_8); g_test_add_func("/dhcp/ip4-prefix-classless", test_ip4_prefix_classless); g_test_add_func("/dhcp/client-id-from-string", test_client_id_from_string); g_test_add_func("/dhcp/vendor-option-metered", test_vendor_option_metered); g_test_add_func("/dhcp/parse-search-list", test_parse_search_list); g_test_add_data_func("/dhcp/test_dhcp_opt_list/IPv4", GINT_TO_POINTER(0), test_dhcp_opt_list); g_test_add_data_func("/dhcp/test_dhcp_opt_list/IPv6", GINT_TO_POINTER(1), test_dhcp_opt_list); return g_test_run(); }