Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dhcp: have DHCP library support multiple router entries in Router option (3) #11208

Merged
merged 4 commits into from Feb 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/basic/in-addr-util.c
Expand Up @@ -68,6 +68,14 @@ bool in4_addr_is_localhost(const struct in_addr *a) {
return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
}

bool in4_addr_is_non_local(const struct in_addr *a) {
/* Whether the address is not null and not localhost.
*
* As such, it is suitable to configure as DNS/NTP server from DHCP. */
return !in4_addr_is_null(a) &&
!in4_addr_is_localhost(a);
}

int in_addr_is_localhost(int family, const union in_addr_union *u) {
assert(u);

Expand Down
2 changes: 2 additions & 0 deletions src/basic/in-addr-util.h
Expand Up @@ -30,6 +30,8 @@ int in_addr_is_link_local(int family, const union in_addr_union *u);
bool in4_addr_is_localhost(const struct in_addr *a);
int in_addr_is_localhost(int family, const union in_addr_union *u);

bool in4_addr_is_non_local(const struct in_addr *a);

int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
Expand Down
4 changes: 3 additions & 1 deletion src/libsystemd-network/dhcp-lease-internal.h
Expand Up @@ -41,7 +41,6 @@ struct sd_dhcp_lease {
/* each 0 if unset */
be32_t address;
be32_t server_address;
be32_t router;
be32_t next_server;

bool have_subnet_mask;
Expand All @@ -50,6 +49,9 @@ struct sd_dhcp_lease {
bool have_broadcast;
be32_t broadcast;

struct in_addr *router;
size_t router_size;

struct in_addr *dns;
size_t dns_size;

Expand Down
36 changes: 27 additions & 9 deletions src/libsystemd-network/network-internal.c
Expand Up @@ -414,16 +414,33 @@ int config_parse_bridge_port_priority(
return 0;
}

void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
unsigned i;
size_t serialize_in_addrs(FILE *f,
const struct in_addr *addresses,
size_t size,
bool with_leading_space,
bool (*predicate)(const struct in_addr *addr)) {
size_t count;
size_t i;

assert(f);
assert(addresses);
assert(size);

for (i = 0; i < size; i++)
fprintf(f, "%s%s", inet_ntoa(addresses[i]),
(i < (size - 1)) ? " ": "");
count = 0;

for (i = 0; i < size; i++) {
char sbuf[INET_ADDRSTRLEN];

if (predicate && !predicate(&addresses[i]))
continue;
if (with_leading_space)
fputc(' ', f);
else
with_leading_space = true;
fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
count++;
}

return count;
}

int deserialize_in_addrs(struct in_addr **ret, const char *string) {
Expand Down Expand Up @@ -457,7 +474,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
size++;
}

*ret = TAKE_PTR(addresses);
*ret = size > 0 ? TAKE_PTR(addresses) : NULL;

return size;
}
Expand Down Expand Up @@ -526,15 +543,16 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
fprintf(f, "%s=", key);

for (i = 0; i < size; i++) {
char sbuf[INET_ADDRSTRLEN];
struct in_addr dest, gw;
uint8_t length;

assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);

fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof(sbuf)), length);
fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof(sbuf)), (i < (size - 1)) ? " ": "");
}

fputs("\n", f);
Expand Down
6 changes: 5 additions & 1 deletion src/libsystemd-network/network-internal.h
Expand Up @@ -40,7 +40,11 @@ CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
int net_get_unique_predictable_data(sd_device *device, uint64_t *result);
const char *net_get_name(sd_device *device);

void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size);
size_t serialize_in_addrs(FILE *f,
const struct in_addr *addresses,
size_t size,
bool with_leading_space,
bool (*predicate)(const struct in_addr *addr));
int deserialize_in_addrs(struct in_addr **addresses, const char *string);
void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
size_t size);
Expand Down
75 changes: 30 additions & 45 deletions src/libsystemd-network/sd-dhcp-lease.c
Expand Up @@ -151,15 +151,15 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
return 0;
}

int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);

if (lease->router == 0)
if (lease->router_size <= 0)
return -ENODATA;

addr->s_addr = lease->router;
return 0;
*addr = lease->router;
return (int) lease->router_size;
}

int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
Expand Down Expand Up @@ -261,6 +261,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
}

free(lease->root_path);
free(lease->router);
free(lease->timezone);
free(lease->hostname);
free(lease->domainname);
Expand Down Expand Up @@ -370,23 +371,6 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
return 0;
}

static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) {
size_t i, j;

/* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */

for (i = 0, j = 0; i < *n; i ++) {

if (in4_addr_is_null(addresses+i) ||
in4_addr_is_localhost(addresses+i))
continue;

addresses[j++] = addresses[i];
}

*n = j;
}

static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
assert(option);
assert(ret);
Expand All @@ -408,8 +392,6 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add
if (!addresses)
return -ENOMEM;

filter_bogus_addresses(addresses, &n_addresses);

free(*ret);
*ret = addresses;
*n_ret = n_addresses;
Expand Down Expand Up @@ -554,11 +536,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
break;

case SD_DHCP_OPTION_ROUTER:
if (len >= 4) {
r = lease_parse_be32(option, 4, &lease->router);
if (r < 0)
log_debug_errno(r, "Failed to parse router address, ignoring: %m");
}
r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size);
if (r < 0)
log_debug_errno(r, "Failed to parse router addresses, ignoring: %m");
break;

case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
Expand Down Expand Up @@ -820,7 +800,6 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
if (!lease)
return -ENOMEM;

lease->router = INADDR_ANY;
lease->n_ref = 1;

*ret = lease;
Expand All @@ -835,6 +814,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
const struct in_addr *addresses;
const void *client_id, *data;
size_t client_id_len, data_len;
char sbuf[INET_ADDRSTRLEN];
const char *string;
uint16_t mtu;
_cleanup_free_ sd_dhcp_route **routes = NULL;
Expand All @@ -857,27 +837,30 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {

r = sd_dhcp_lease_get_address(lease, &address);
if (r >= 0)
fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));

r = sd_dhcp_lease_get_netmask(lease, &address);
if (r >= 0)
fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));

r = sd_dhcp_lease_get_router(lease, &address);
if (r >= 0)
fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
r = sd_dhcp_lease_get_router(lease, &addresses);
if (r > 0) {
fputs("ROUTER=", f);
serialize_in_addrs(f, addresses, r, false, NULL);
fputc('\n', f);
}

r = sd_dhcp_lease_get_server_identifier(lease, &address);
if (r >= 0)
fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));

r = sd_dhcp_lease_get_next_server(lease, &address);
if (r >= 0)
fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));

r = sd_dhcp_lease_get_broadcast(lease, &address);
if (r >= 0)
fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));

r = sd_dhcp_lease_get_mtu(lease, &mtu);
if (r >= 0)
Expand All @@ -898,15 +881,15 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_dns(lease, &addresses);
if (r > 0) {
fputs("DNS=", f);
serialize_in_addrs(f, addresses, r);
fputs("\n", f);
serialize_in_addrs(f, addresses, r, false, NULL);
fputc('\n', f);
}

r = sd_dhcp_lease_get_ntp(lease, &addresses);
if (r > 0) {
fputs("NTP=", f);
serialize_in_addrs(f, addresses, r);
fputs("\n", f);
serialize_in_addrs(f, addresses, r, false, NULL);
fputc('\n', f);
}

r = sd_dhcp_lease_get_domainname(lease, &string);
Expand All @@ -917,7 +900,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r > 0) {
fputs("DOMAIN_SEARCH_LIST=", f);
fputstrv(f, search_domains, NULL, NULL);
fputs("\n", f);
fputc('\n', f);
}

r = sd_dhcp_lease_get_hostname(lease, &string);
Expand Down Expand Up @@ -1080,9 +1063,11 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
}

if (router) {
r = inet_pton(AF_INET, router, &lease->router);
if (r <= 0)
log_debug("Failed to parse router %s, ignoring.", router);
r = deserialize_in_addrs(&lease->router, router);
if (r < 0)
log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router);
else
lease->router_size = r;
}

if (netmask) {
Expand Down
7 changes: 4 additions & 3 deletions src/libsystemd-network/test-dhcp-client.c
Expand Up @@ -423,6 +423,7 @@ static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
sd_event *e = userdata;
sd_dhcp_lease *lease;
struct in_addr addr;
const struct in_addr *addrs;

assert_se(client);
assert_se(event == SD_DHCP_CLIENT_EVENT_IP_ACQUIRE);
Expand All @@ -438,9 +439,9 @@ static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
sizeof(addr.s_addr)) == 0);

assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
sizeof(addr.s_addr)) == 0);
assert_se(sd_dhcp_lease_get_router(lease, &addrs) == 1);
assert_se(memcmp(&addrs[0].s_addr, &test_addr_acq_ack[308],
sizeof(addrs[0].s_addr)) == 0);

if (verbose)
printf(" DHCP address acquired\n");
Expand Down