diff options
author | Tom Gundersen <teg@jklm.no> | 2014-01-05 23:01:10 +0100 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2014-01-12 15:37:21 +0100 |
commit | 3bef724f7e7f7eaca69881548b06e221b77d7031 (patch) | |
tree | 0b17e5a43d7e5c5d07dc696d23d4c829f9ab7200 | |
parent | 924fe4304af981ffd849346b4a1d415f11e9dd79 (diff) |
networkd: generate resolv.conf
This adds support to generate a basic resolv.conf in /run/systemd/network.
This file will not take any effect unless a symlink is created from
/etc/resolv.conf.
Nameservers received over DHCP takes precedence over statically configured ones.
Note: /etc/resolv.conf is severely limited, so in the future we will likely
rather provide a much more powerfull nss plugin (or something to that effect),
but this should allow current users to function without any loss of
functionality.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/network/networkd-address.c | 37 | ||||
-rw-r--r-- | src/network/networkd-gperf.gperf | 1 | ||||
-rw-r--r-- | src/network/networkd-link.c | 8 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 75 | ||||
-rw-r--r-- | src/network/networkd-network.c | 8 | ||||
-rw-r--r-- | src/network/networkd.c | 7 | ||||
-rw-r--r-- | src/network/networkd.h | 8 |
8 files changed, 146 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index 65b445ec5..b4bb6e1e3 100644 --- a/Makefile.am +++ b/Makefile.am | |||
@@ -4107,6 +4107,7 @@ systemd_networkd_LDADD = \ | |||
4107 | libsystemd-id128-internal.la \ | 4107 | libsystemd-id128-internal.la \ |
4108 | libsystemd-rtnl.la \ | 4108 | libsystemd-rtnl.la \ |
4109 | libsystemd-dhcp.la \ | 4109 | libsystemd-dhcp.la \ |
4110 | libsystemd-label.la \ | ||
4110 | libsystemd-shared.la | 4111 | libsystemd-shared.la |
4111 | 4112 | ||
4112 | nodist_systemunit_DATA += \ | 4113 | nodist_systemunit_DATA += \ |
@@ -4133,6 +4134,7 @@ test_network_LDADD = \ | |||
4133 | libsystemd-daemon-internal.la \ | 4134 | libsystemd-daemon-internal.la \ |
4134 | libsystemd-rtnl.la \ | 4135 | libsystemd-rtnl.la \ |
4135 | libsystemd-dhcp.la \ | 4136 | libsystemd-dhcp.la \ |
4137 | libsystemd-label.la \ | ||
4136 | libsystemd-shared.la | 4138 | libsystemd-shared.la |
4137 | 4139 | ||
4138 | tests += \ | 4140 | tests += \ |
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 8a7163005..7d06cf887 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c | |||
@@ -190,6 +190,43 @@ int address_configure(Address *address, Link *link, | |||
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | int config_parse_dns(const char *unit, | ||
194 | const char *filename, | ||
195 | unsigned line, | ||
196 | const char *section, | ||
197 | unsigned section_line, | ||
198 | const char *lvalue, | ||
199 | int ltype, | ||
200 | const char *rvalue, | ||
201 | void *data, | ||
202 | void *userdata) { | ||
203 | Address **dns = data; | ||
204 | _cleanup_address_free_ Address *n = NULL; | ||
205 | int r; | ||
206 | |||
207 | assert(filename); | ||
208 | assert(section); | ||
209 | assert(lvalue); | ||
210 | assert(rvalue); | ||
211 | assert(data); | ||
212 | |||
213 | r = address_new_dynamic(&n); | ||
214 | if (r < 0) | ||
215 | return r; | ||
216 | |||
217 | r = net_parse_inaddr(rvalue, &n->family, &n->in_addr); | ||
218 | if (r < 0) { | ||
219 | log_syntax(unit, LOG_ERR, filename, line, EINVAL, | ||
220 | "DNS address is invalid, ignoring assignment: %s", rvalue); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | *dns = n; | ||
225 | n = NULL; | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
193 | int config_parse_address(const char *unit, | 230 | int config_parse_address(const char *unit, |
194 | const char *filename, | 231 | const char *filename, |
195 | unsigned line, | 232 | unsigned line, |
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index f1594d56c..92954a836 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf | |||
@@ -25,6 +25,7 @@ Network.Bridge, config_parse_bridge, 0, offsetof(Networ | |||
25 | Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp) | 25 | Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp) |
26 | Network.Address, config_parse_address, 0, 0 | 26 | Network.Address, config_parse_address, 0, 0 |
27 | Network.Gateway, config_parse_gateway, 0, 0 | 27 | Network.Gateway, config_parse_gateway, 0, 0 |
28 | Network.DNS, config_parse_dns, 0, offsetof(Network, dns) | ||
28 | Address.Address, config_parse_address, 0, 0 | 29 | Address.Address, config_parse_address, 0, 0 |
29 | Address.Label, config_parse_label, 0, 0 | 30 | Address.Label, config_parse_label, 0, 0 |
30 | Route.Gateway, config_parse_gateway, 0, 0 | 31 | Route.Gateway, config_parse_gateway, 0, 0 |
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 25d92c8aa..5dd8e9100 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c | |||
@@ -378,6 +378,7 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { | |||
378 | if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) { | 378 | if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) { |
379 | _cleanup_address_free_ Address *addr = NULL; | 379 | _cleanup_address_free_ Address *addr = NULL; |
380 | _cleanup_route_free_ Route *rt = NULL; | 380 | _cleanup_route_free_ Route *rt = NULL; |
381 | struct in_addr **nameservers; | ||
381 | 382 | ||
382 | log_struct_link(LOG_INFO, link, | 383 | log_struct_link(LOG_INFO, link, |
383 | "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u", | 384 | "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u", |
@@ -420,6 +421,13 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { | |||
420 | addr = NULL; | 421 | addr = NULL; |
421 | rt = NULL; | 422 | rt = NULL; |
422 | 423 | ||
424 | r = sd_dhcp_client_get_dns(client, &nameservers); | ||
425 | if (r >= 0) { | ||
426 | r = manager_update_resolv_conf(link->manager); | ||
427 | if (r < 0) | ||
428 | log_error("Failed to update resolv.conf"); | ||
429 | } | ||
430 | |||
423 | link_enter_set_addresses(link); | 431 | link_enter_set_addresses(link); |
424 | } | 432 | } |
425 | 433 | ||
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index c9ce1d6a1..f02eed1a5 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c | |||
@@ -19,10 +19,13 @@ | |||
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | 19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
20 | ***/ | 20 | ***/ |
21 | 21 | ||
22 | #include <resolv.h> | ||
23 | |||
22 | #include "path-util.h" | 24 | #include "path-util.h" |
23 | #include "networkd.h" | 25 | #include "networkd.h" |
24 | #include "libudev-private.h" | 26 | #include "libudev-private.h" |
25 | #include "udev-util.h" | 27 | #include "udev-util.h" |
28 | #include "mkdir.h" | ||
26 | 29 | ||
27 | const char* const network_dirs[] = { | 30 | const char* const network_dirs[] = { |
28 | "/etc/systemd/network", | 31 | "/etc/systemd/network", |
@@ -276,3 +279,75 @@ int manager_rtnl_listen(Manager *m) { | |||
276 | 279 | ||
277 | return 0; | 280 | return 0; |
278 | } | 281 | } |
282 | |||
283 | static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) { | ||
284 | char buf[INET6_ADDRSTRLEN]; | ||
285 | const char *address; | ||
286 | |||
287 | address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN); | ||
288 | if (!address) { | ||
289 | log_warning("Invalid DNS address. Ignoring."); | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | if (*count == MAXNS) | ||
294 | fputs("# Too many dynamic name servers configured, the " | ||
295 | "following entries will be ignored\n", f); | ||
296 | |||
297 | fprintf(f, "nameserver %s\n", address); | ||
298 | |||
299 | (*count) ++; | ||
300 | } | ||
301 | |||
302 | int manager_update_resolv_conf(Manager *m) { | ||
303 | _cleanup_free_ char *temp_path = NULL; | ||
304 | _cleanup_fclose_ FILE *f = NULL; | ||
305 | Link *link; | ||
306 | Iterator i; | ||
307 | unsigned count = 0; | ||
308 | int r; | ||
309 | |||
310 | assert(m); | ||
311 | |||
312 | r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0); | ||
313 | if (r < 0) | ||
314 | return r; | ||
315 | |||
316 | r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path); | ||
317 | if (r < 0) | ||
318 | return r; | ||
319 | |||
320 | fchmod(fileno(f), 0644); | ||
321 | |||
322 | fputs("# This file is managed by systemd-networkd(8). Do not edit.\n", f); | ||
323 | |||
324 | HASHMAP_FOREACH(link, m->links, i) { | ||
325 | if (link->dhcp) { | ||
326 | struct in_addr **nameservers; | ||
327 | |||
328 | r = sd_dhcp_client_get_dns(link->dhcp, &nameservers); | ||
329 | if (r >= 0) { | ||
330 | unsigned j; | ||
331 | |||
332 | for (j = 0; nameservers[j]; j++) | ||
333 | append_dns(f, nameservers[j], AF_INET, &count); | ||
334 | } | ||
335 | } | ||
336 | } | ||
337 | |||
338 | HASHMAP_FOREACH(link, m->links, i) | ||
339 | if (link->network && link->network->dns) | ||
340 | append_dns(f, &link->network->dns->in_addr.in, | ||
341 | link->network->dns->family, &count); | ||
342 | |||
343 | fflush(f); | ||
344 | |||
345 | if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) { | ||
346 | r = -errno; | ||
347 | unlink("/run/systemd/network/resolv.conf"); | ||
348 | unlink(temp_path); | ||
349 | return r; | ||
350 | } | ||
351 | |||
352 | return 0; | ||
353 | } | ||
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index f2546440c..f98731001 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c | |||
@@ -144,6 +144,8 @@ void network_free(Network *network) { | |||
144 | 144 | ||
145 | free(network->description); | 145 | free(network->description); |
146 | 146 | ||
147 | address_free(network->dns); | ||
148 | |||
147 | while ((route = network->static_routes)) | 149 | while ((route = network->static_routes)) |
148 | route_free(route); | 150 | route_free(route); |
149 | 151 | ||
@@ -197,6 +199,12 @@ int network_apply(Manager *manager, Network *network, Link *link) { | |||
197 | if (r < 0) | 199 | if (r < 0) |
198 | return r; | 200 | return r; |
199 | 201 | ||
202 | if (network->dns) { | ||
203 | r = manager_update_resolv_conf(manager); | ||
204 | if (r < 0) | ||
205 | return r; | ||
206 | } | ||
207 | |||
200 | return 0; | 208 | return 0; |
201 | } | 209 | } |
202 | 210 | ||
diff --git a/src/network/networkd.c b/src/network/networkd.c index 360afba98..055200cb0 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c | |||
@@ -60,6 +60,13 @@ int main(int argc, char *argv[]) { | |||
60 | if (r < 0) | 60 | if (r < 0) |
61 | goto out; | 61 | goto out; |
62 | 62 | ||
63 | |||
64 | /* write out empty resolv.conf to avoid a | ||
65 | * dangling symlink */ | ||
66 | r = manager_update_resolv_conf(m); | ||
67 | if (r < 0) | ||
68 | goto out; | ||
69 | |||
63 | sd_notify(false, | 70 | sd_notify(false, |
64 | "READY=1\n" | 71 | "READY=1\n" |
65 | "STATUS=Processing requests..."); | 72 | "STATUS=Processing requests..."); |
diff --git a/src/network/networkd.h b/src/network/networkd.h index 55181f2bb..607feba0e 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h | |||
@@ -88,6 +88,7 @@ struct Network { | |||
88 | 88 | ||
89 | LIST_HEAD(Address, static_addresses); | 89 | LIST_HEAD(Address, static_addresses); |
90 | LIST_HEAD(Route, static_routes); | 90 | LIST_HEAD(Route, static_routes); |
91 | Address *dns; | ||
91 | 92 | ||
92 | Hashmap *addresses_by_section; | 93 | Hashmap *addresses_by_section; |
93 | Hashmap *routes_by_section; | 94 | Hashmap *routes_by_section; |
@@ -157,6 +158,7 @@ struct Link { | |||
157 | 158 | ||
158 | Route *dhcp_route; | 159 | Route *dhcp_route; |
159 | Address *dhcp_address; | 160 | Address *dhcp_address; |
161 | Address *dns; | ||
160 | 162 | ||
161 | LinkState state; | 163 | LinkState state; |
162 | 164 | ||
@@ -195,6 +197,8 @@ int manager_udev_listen(Manager *m); | |||
195 | 197 | ||
196 | int manager_rtnl_listen(Manager *m); | 198 | int manager_rtnl_listen(Manager *m); |
197 | 199 | ||
200 | int manager_update_resolv_conf(Manager *m); | ||
201 | |||
198 | DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); | 202 | DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); |
199 | #define _cleanup_manager_free_ _cleanup_(manager_freep) | 203 | #define _cleanup_manager_free_ _cleanup_(manager_freep) |
200 | 204 | ||
@@ -258,6 +262,10 @@ int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callbac | |||
258 | DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); | 262 | DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); |
259 | #define _cleanup_address_free_ _cleanup_(address_freep) | 263 | #define _cleanup_address_free_ _cleanup_(address_freep) |
260 | 264 | ||
265 | int config_parse_dns(const char *unit, const char *filename, unsigned line, | ||
266 | const char *section, unsigned section_line, const char *lvalue, | ||
267 | int ltype, const char *rvalue, void *data, void *userdata); | ||
268 | |||
261 | int config_parse_address(const char *unit, const char *filename, unsigned line, | 269 | int config_parse_address(const char *unit, const char *filename, unsigned line, |
262 | const char *section, unsigned section_line, const char *lvalue, | 270 | const char *section, unsigned section_line, const char *lvalue, |
263 | int ltype, const char *rvalue, void *data, void *userdata); | 271 | int ltype, const char *rvalue, void *data, void *userdata); |