diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-02-01 22:35:43 +0100 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-02-02 02:02:44 +0100 |
commit | 32f8a613c542a30eb48317db3f446360afa89a73 (patch) | |
tree | 35c34c3087e858064614f1961948c0b7aab8e3bf /src | |
parent | Merge pull request #22351 from mrc0mmand/TEST-56-cgroupsv1 (diff) | |
download | systemd-32f8a613c542a30eb48317db3f446360afa89a73.tar.xz systemd-32f8a613c542a30eb48317db3f446360afa89a73.zip |
sd-dhcp-lease: store static routes and classless static routes in different arrays
When classless static routes option is provided, then static routes
option should not be used. Hence, let's not mix and store them in one
storage.
This introduce sd_dhcp_lease_get_static_routes() and
sd_dhcp_lease_get_classless_routes().
Diffstat (limited to 'src')
-rw-r--r-- | src/libsystemd-network/dhcp-lease-internal.h | 8 | ||||
-rw-r--r-- | src/libsystemd-network/network-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-lease.c | 158 | ||||
-rw-r--r-- | src/network/networkd-dhcp4.c | 80 | ||||
-rw-r--r-- | src/systemd/sd-dhcp-lease.h | 4 |
5 files changed, 132 insertions, 120 deletions
diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index 992ac9f325..c67e9511a1 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -16,8 +16,6 @@ struct sd_dhcp_route { struct in_addr dst_addr; struct in_addr gw_addr; unsigned char dst_prefixlen; - - uint8_t option; }; struct sd_dhcp_raw_option { @@ -52,8 +50,10 @@ struct sd_dhcp_lease { DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX]; - struct sd_dhcp_route *static_route; - size_t static_route_size; + struct sd_dhcp_route *static_routes; + size_t n_static_routes; + struct sd_dhcp_route *classless_routes; + size_t n_classless_routes; uint16_t mtu; /* 0 if unset */ diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 895a00d01b..5aa225e977 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -21,7 +21,7 @@ int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); struct sd_dhcp_route; struct sd_dhcp_lease; -void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size); +void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route **routes, size_t size); int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string); /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index b87af04736..1f7978eb03 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -215,25 +215,38 @@ int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { * The returned routes array must be freed by the caller. * Route objects have the same lifetime of the lease and must not be freed. */ -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) { - sd_dhcp_route **ret; - unsigned i; +static int dhcp_lease_get_routes(sd_dhcp_route *routes, size_t n_routes, sd_dhcp_route ***ret) { + assert(routes || n_routes == 0); - assert_return(lease, -EINVAL); - assert_return(routes, -EINVAL); - - if (lease->static_route_size <= 0) + if (n_routes <= 0) return -ENODATA; - ret = new(sd_dhcp_route *, lease->static_route_size); - if (!ret) - return -ENOMEM; + if (ret) { + sd_dhcp_route **buf; - for (i = 0; i < lease->static_route_size; i++) - ret[i] = &lease->static_route[i]; + buf = new(sd_dhcp_route*, n_routes); + if (!buf) + return -ENOMEM; + + for (size_t i = 0; i < n_routes; i++) + buf[i] = &routes[i]; + + *ret = buf; + } - *routes = ret; - return (int) lease->static_route_size; + return (int) n_routes; +} + +int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) { + assert_return(lease, -EINVAL); + + return dhcp_lease_get_routes(lease->static_routes, lease->n_static_routes, ret); +} + +int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) { + assert_return(lease, -EINVAL); + + return dhcp_lease_get_routes(lease->classless_routes, lease->n_classless_routes, ret); } int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) { @@ -312,7 +325,8 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) free(lease->servers[i].addr); - free(lease->static_route); + free(lease->static_routes); + free(lease->classless_routes); free(lease->client_id); free(lease->vendor_specific); strv_free(lease->search_domains); @@ -467,17 +481,11 @@ static int lease_parse_sip_server(const uint8_t *option, size_t len, struct in_a return lease_parse_in_addrs(option + 1, len - 1, ret, n_ret); } -static int lease_parse_routes( - const uint8_t *option, - size_t len, - struct sd_dhcp_route **routes, - size_t *routes_size) { - +static int lease_parse_static_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { int r; + assert(lease); assert(option || len <= 0); - assert(routes); - assert(routes_size); if (len % 8 != 0) return -EINVAL; @@ -495,73 +503,66 @@ static int lease_parse_routes( len -= 8; r = in4_addr_default_prefixlen(&dst, &prefixlen); - if (r < 0) - return -EINVAL; + if (r < 0) { + log_debug("sd-dhcp-lease: cannot determine class of received static route, ignoring."); + continue; + } (void) in4_addr_mask(&dst, prefixlen); - if (!GREEDY_REALLOC(*routes, *routes_size + 1)) + if (!GREEDY_REALLOC(lease->static_routes, lease->n_static_routes + 1)) return -ENOMEM; - (*routes)[*routes_size] = (struct sd_dhcp_route) { + lease->static_routes[lease->n_static_routes++] = (struct sd_dhcp_route) { .dst_addr = dst, .gw_addr = gw, .dst_prefixlen = prefixlen, - .option = SD_DHCP_OPTION_STATIC_ROUTE, }; - - (*routes_size)++; } return 0; } /* parses RFC3442 Classless Static Route Option */ -static int lease_parse_classless_routes( - const uint8_t *option, size_t len, - struct sd_dhcp_route **routes, size_t *routes_size) { - +static int lease_parse_classless_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { + assert(lease); assert(option || len <= 0); - assert(routes); - assert(routes_size); - if (len <= 0) - return 0; - - /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */ + /* option format: (subnet-mask-width significant-subnet-octets gateway-ip) */ while (len > 0) { - uint8_t dst_octets; - struct sd_dhcp_route *route; - - if (!GREEDY_REALLOC(*routes, *routes_size + 1)) - return -ENOMEM; - - route = *routes + *routes_size; - route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE; + uint8_t prefixlen, dst_octets; + struct in_addr dst = {}, gw; - dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1); - route->dst_prefixlen = *option; + prefixlen = *option; option++; len--; + dst_octets = DIV_ROUND_UP(prefixlen, 8); + /* can't have more than 4 octets in IPv4 */ if (dst_octets > 4 || len < dst_octets) return -EINVAL; - route->dst_addr.s_addr = 0; - memcpy(&route->dst_addr.s_addr, option, dst_octets); + memcpy(&dst, option, dst_octets); option += dst_octets; len -= dst_octets; if (len < 4) return -EINVAL; - assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0); + assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0); option += 4; len -= 4; - (*routes_size)++; + if (!GREEDY_REALLOC(lease->classless_routes, lease->n_classless_routes + 1)) + return -ENOMEM; + + lease->classless_routes[lease->n_classless_routes++] = (struct sd_dhcp_route) { + .dst_addr = dst, + .gw_addr = gw, + .dst_prefixlen = prefixlen, + }; } return 0; @@ -703,7 +704,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void break; case SD_DHCP_OPTION_STATIC_ROUTE: - r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size); + r = lease_parse_static_routes(lease, option, len); if (r < 0) log_debug_errno(r, "Failed to parse static routes, ignoring: %m"); break; @@ -762,10 +763,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void break; case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE: - r = lease_parse_classless_routes( - option, len, - &lease->static_route, - &lease->static_route_size); + r = lease_parse_classless_routes(lease, option, len); if (r < 0) log_debug_errno(r, "Failed to parse classless routes, ignoring: %m"); break; @@ -972,7 +970,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { const char *string; uint16_t mtu; _cleanup_free_ sd_dhcp_route **routes = NULL; - char **search_domains = NULL; + char **search_domains; uint32_t t1, t2, lifetime; int r; @@ -1071,9 +1069,14 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { if (r >= 0) fprintf(f, "ROOT_PATH=%s\n", string); - r = sd_dhcp_lease_get_routes(lease, &routes); + r = sd_dhcp_lease_get_static_routes(lease, &routes); + if (r > 0) + serialize_dhcp_routes(f, "STATIC_ROUTES", routes, r); + + routes = mfree(routes); + r = sd_dhcp_lease_get_classless_routes(lease, &routes); if (r > 0) - serialize_dhcp_routes(f, "ROUTES", routes, r); + serialize_dhcp_routes(f, "CLASSLESS_ROUTES", routes, r); r = sd_dhcp_lease_get_timezone(lease, &string); if (r >= 0) @@ -1149,7 +1152,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { *smtp = NULL, *lpr = NULL, *mtu = NULL, - *routes = NULL, + *static_routes = NULL, + *classless_routes = NULL, *domains = NULL, *client_id_hex = NULL, *vendor_specific_hex = NULL, @@ -1189,7 +1193,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "HOSTNAME", &lease->hostname, "DOMAIN_SEARCH_LIST", &domains, "ROOT_PATH", &lease->root_path, - "ROUTES", &routes, + "STATIC_ROUTES", &static_routes, + "CLASSLESS_ROUTES", &classless_routes, "CLIENTID", &client_id_hex, "TIMEZONE", &lease->timezone, "VENDOR_SPECIFIC", &vendor_specific_hex, @@ -1336,13 +1341,22 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { lease->search_domains = TAKE_PTR(a); } - if (routes) { + if (static_routes) { + r = deserialize_dhcp_routes( + &lease->static_routes, + &lease->n_static_routes, + static_routes); + if (r < 0) + log_debug_errno(r, "Failed to parse DHCP static routes %s, ignoring: %m", static_routes); + } + + if (classless_routes) { r = deserialize_dhcp_routes( - &lease->static_route, - &lease->static_route_size, - routes); + &lease->classless_routes, + &lease->n_classless_routes, + classless_routes); if (r < 0) - log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes); + log_debug_errno(r, "Failed to parse DHCP classless routes %s, ignoring: %m", classless_routes); } if (lifetime) { @@ -1489,9 +1503,3 @@ int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) { *gateway = route->gw_addr; return 0; } - -int sd_dhcp_route_get_option(sd_dhcp_route *route) { - assert_return(route, -EINVAL); - - return route->option; -} diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 718ac62f8e..4f37491e96 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -404,67 +404,66 @@ static int dhcp4_request_route_auto( } static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_gw) { - _cleanup_free_ sd_dhcp_route **static_routes = NULL; - bool classless_route = false, static_route = false; + _cleanup_free_ sd_dhcp_route **static_routes = NULL, **classless_routes = NULL; + size_t n_static_routes, n_classless_routes, n; struct in_addr default_gw = {}; - int n, r; + sd_dhcp_route **routes; + int r; assert(link); assert(link->dhcp_lease); assert(ret_default_gw); - n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes); - if (IN_SET(n, 0, -ENODATA)) { + r = sd_dhcp_lease_get_static_routes(link->dhcp_lease, &static_routes); + if (r == -ENODATA) + n_static_routes = 0; + else if (r < 0) + return r; + else + n_static_routes = r; + + r = sd_dhcp_lease_get_classless_routes(link->dhcp_lease, &classless_routes); + if (r == -ENODATA) + n_classless_routes = 0; + else if (r < 0) + return r; + else + n_classless_routes = r; + + if (n_classless_routes == 0 && n_static_routes == 0) { log_link_debug(link, "DHCP: No static routes received from DHCP server."); return 0; } - if (n < 0) - return n; - - for (int i = 0; i < n; i++) { - switch (sd_dhcp_route_get_option(static_routes[i])) { - case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE: - classless_route = true; - break; - case SD_DHCP_OPTION_STATIC_ROUTE: - static_route = true; - break; - } - } /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option, * the DHCP client MUST ignore the Static Routes option. */ - if (classless_route && static_route) + if (n_classless_routes > 0 && n_static_routes > 0) log_link_debug(link, "Classless static routes received from DHCP server: ignoring static-route option"); if (!link->network->dhcp_use_routes) { - if (!classless_route) - return 0; /* Even if UseRoutes=no, try to find default gateway to make semi-static routes and * routes to DNS or NTP servers can be configured in later steps. */ - for (int i = 0; i < n; i++) { + + for (size_t i = 0; i < n_classless_routes; i++) { struct in_addr dst; uint8_t prefixlen; - if (sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE) - continue; - - r = sd_dhcp_route_get_destination(static_routes[i], &dst); + r = sd_dhcp_route_get_destination(classless_routes[i], &dst); if (r < 0) return r; if (in4_addr_is_set(&dst)) continue; - r = sd_dhcp_route_get_destination_prefix_length(static_routes[i], &prefixlen); + r = sd_dhcp_route_get_destination_prefix_length(classless_routes[i], &prefixlen); if (r < 0) return r; if (prefixlen != 0) continue; - r = sd_dhcp_route_get_gateway(static_routes[i], ret_default_gw); + r = sd_dhcp_route_get_gateway(classless_routes[i], ret_default_gw); if (r < 0) return r; @@ -476,36 +475,41 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g return 0; } - for (int i = 0; i < n; i++) { + if (n_classless_routes > 0) { + n = n_classless_routes; + routes = classless_routes; + } else if (n_static_routes > 0){ + n = n_static_routes; + routes = static_routes; + } else + assert_not_reached(); + + for (size_t i = 0; i < n; i++) { _cleanup_(route_freep) Route *route = NULL; struct in_addr gw; - if (sd_dhcp_route_get_option(static_routes[i]) != - (classless_route ? SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE : SD_DHCP_OPTION_STATIC_ROUTE)) - continue; - r = route_new(&route); if (r < 0) return r; route->gw_family = AF_INET; - r = sd_dhcp_route_get_gateway(static_routes[i], &gw); + r = sd_dhcp_route_get_gateway(routes[i], &gw); if (r < 0) return r; - r = sd_dhcp_route_get_destination(static_routes[i], &route->dst.in); + r = sd_dhcp_route_get_destination(routes[i], &route->dst.in); if (r < 0) return r; - r = sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen); + r = sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen); if (r < 0) return r; /* When classless static routes are provided, then router option will be ignored. To * use the default gateway later in other routes, e.g., routes to dns servers, here we * need to find the default gateway in the classless static routes. */ - if (classless_route && + if (n_classless_routes > 0 && in4_addr_is_null(&route->dst.in) && route->dst_prefixlen == 0 && in4_addr_is_null(&default_gw)) default_gw = gw; @@ -516,7 +520,7 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g } *ret_default_gw = default_gw; - return classless_route; + return n_classless_routes > 0; } static int dhcp4_request_gateway(Link *link, struct in_addr *gw) { diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h index 478bbfd7a6..578ac6d4db 100644 --- a/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/sd-dhcp-lease.h @@ -67,7 +67,8 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains); int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes); +int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret); +int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret); int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len); int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); @@ -82,7 +83,6 @@ int sd_dhcp_lease_get_6rd( int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination); int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length); int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway); -int sd_dhcp_route_get_option(sd_dhcp_route *route); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref); |