diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-08-27 14:48:37 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-08-27 14:48:37 +0200 |
commit | 1a04db0fc9d08fffe80d6d7b5b60459295922b11 (patch) | |
tree | facfacd2ca4ed5f1498db730b5dd32a82678631b | |
parent | fc2f9534d07db2b185c02b1961428b53daf1986e (diff) |
dhcp,network: support emitting DNS/NTP server information from DHCP server
For now, this is very simple and IP addresses have to be configured
manually.
-rw-r--r-- | src/libsystemd-network/dhcp-server-internal.h | 3 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-server.c | 72 | ||||
-rw-r--r-- | src/network/networkd-link.c | 21 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 4 | ||||
-rw-r--r-- | src/network/networkd-network.c | 96 | ||||
-rw-r--r-- | src/network/networkd-network.h | 10 | ||||
-rw-r--r-- | src/systemd/sd-dhcp-server.h | 7 |
7 files changed, 210 insertions, 3 deletions
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 4f562c73ef..6cc794c937 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -63,6 +63,9 @@ struct sd_dhcp_server { char *timezone; + struct in_addr *ntp, *dns; + unsigned n_ntp, n_dns; + Hashmap *leases_by_client_id; DHCPLease **bound_leases; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 35564d8317..a46858258b 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -145,6 +145,8 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { sd_event_unref(server->event); free(server->timezone); + free(server->dns); + free(server->ntp); while ((lease = hashmap_steal_first(server->leases_by_client_id))) dhcp_lease_free(lease); @@ -481,6 +483,24 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, if (r < 0) return r; + if (server->n_dns > 0) { + r = dhcp_option_append( + &packet->dhcp, req->max_optlen, &offset, 0, + DHCP_OPTION_DOMAIN_NAME_SERVER, + sizeof(struct in_addr) * server->n_dns, server->dns); + if (r < 0) + return r; + } + + if (server->n_ntp > 0) { + r = dhcp_option_append( + &packet->dhcp, req->max_optlen, &offset, 0, + DHCP_OPTION_NTP_SERVER, + sizeof(struct in_addr) * server->n_ntp, server->ntp); + if (r < 0) + return r; + } + if (server->timezone) { r = dhcp_option_append( &packet->dhcp, req->max_optlen, &offset, 0, @@ -1042,3 +1062,55 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) { server->default_lease_time = t; return 1; } + +int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) { + assert_return(server, -EINVAL); + assert_return(dns || n <= 0, -EINVAL); + + if (server->n_dns == n && + memcmp(server->dns, dns, sizeof(struct in_addr) * n) == 0) + return 0; + + if (n <= 0) { + server->dns = mfree(server->dns); + server->n_dns = 0; + } else { + struct in_addr *c; + + c = newdup(struct in_addr, dns, n); + if (!c) + return -ENOMEM; + + free(server->dns); + server->dns = c; + server->n_dns = n; + } + + return 1; +} + +int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) { + assert_return(server, -EINVAL); + assert_return(ntp || n <= 0, -EINVAL); + + if (server->n_ntp == n && + memcmp(server->ntp, ntp, sizeof(struct in_addr) * n) == 0) + return 0; + + if (n <= 0) { + server->ntp = mfree(server->ntp); + server->n_ntp = 0; + } else { + struct in_addr *c; + + c = newdup(struct in_addr, ntp, n); + if (!c) + return -ENOMEM; + + free(server->ntp); + server->ntp = c; + server->n_ntp = n; + } + + return 1; +} diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 0a72c14469..0d85005c8c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -691,6 +691,27 @@ static int link_enter_set_addresses(Link *link) { return r; } + if (link->network->dhcp_server_emit_dns) { + + if (link->network->n_dhcp_server_dns > 0) { + r = sd_dhcp_server_set_dns(link->dhcp_server, link->network->dhcp_server_dns, link->network->n_dhcp_server_dns); + if (r < 0) + log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m"); + } else + log_link_warning_errno(link, r, "DNS server emitting enabled, but no DNS servers set, ignoring: %m"); + } + + + if (link->network->dhcp_server_emit_ntp) { + + if (link->network->n_dhcp_server_ntp > 0) { + r = sd_dhcp_server_set_ntp(link->dhcp_server, link->network->dhcp_server_ntp, link->network->n_dhcp_server_ntp); + if (r < 0) + log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m"); + } else + log_link_warning_errno(link, r, "NTP server emitting enabled, but no NTP servers set, ignoring: %m"); + } + if (link->network->dhcp_server_emit_timezone) { _cleanup_free_ char *buffer = NULL; const char *tz; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 21e33efb42..108e892fb8 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -76,6 +76,10 @@ DHCP.RouteMetric, config_parse_unsigned, 0 DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec,config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) +DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) +DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0 +DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp) +DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0 DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone) DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 11671b500d..848ec66151 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -260,6 +260,8 @@ void network_free(Network *network) { condition_free_list(network->match_arch); free(network->dhcp_server_timezone); + free(network->dhcp_server_dns); + free(network->dhcp_server_ntp); free(network); } @@ -802,3 +804,97 @@ int config_parse_timezone( return 0; } + +int config_parse_dhcp_server_dns( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *n = data; + const char *p = rvalue; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *w = NULL; + struct in_addr a, *m; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue); + return 0; + } + + if (r == 0) + return 0; + + if (inet_pton(AF_INET, w, &a) <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server address, ignoring: %s", w); + continue; + } + + m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr)); + if (!m) + return log_oom(); + + m[n->n_dhcp_server_dns++] = a; + n->dhcp_server_dns = m; + } +} + +int config_parse_dhcp_server_ntp( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *n = data; + const char *p = rvalue; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *w = NULL; + struct in_addr a, *m; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, r, line, "Failed to extract word, ignoring: %s", rvalue); + return 0; + } + + if (r == 0) + return 0; + + if (inet_pton(AF_INET, w, &a) <= 0) { + log_syntax(unit, LOG_ERR, filename, r, line, "Failed to parse NTP server address, ignoring: %s", w); + continue; + } + + m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr)); + if (!m) + return log_oom(); + + m[n->n_dhcp_server_ntp++] = a; + n->dhcp_server_ntp = m; + } +} diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 7d2add300f..d691cc3a45 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -93,8 +93,14 @@ struct Network { /* DHCP Server Support */ bool dhcp_server; - char *dhcp_server_timezone; + bool dhcp_server_emit_dns; + struct in_addr *dhcp_server_dns; + unsigned n_dhcp_server_dns; + bool dhcp_server_emit_ntp; + struct in_addr *dhcp_server_ntp; + unsigned n_dhcp_server_ntp; bool dhcp_server_emit_timezone; + char *dhcp_server_timezone; usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec; /* IPV4LL Support */ @@ -156,6 +162,8 @@ int config_parse_ipv6token(const char *unit, const char *filename, unsigned line int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_timezone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* Legacy IPv4LL support */ int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index e070174a88..7e4f2ffb30 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -30,11 +30,11 @@ typedef struct sd_dhcp_server sd_dhcp_server; +int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex); + sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server); sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server); -int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex); - int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority); int sd_dhcp_server_detach_event(sd_dhcp_server *client); sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client); @@ -48,9 +48,12 @@ int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address, int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *start, size_t size); int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone); +int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n); +int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr dns[], unsigned n); int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t); int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t); int sd_dhcp_server_forcerenew(sd_dhcp_server *server); + #endif |