1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <arpa/inet.h>
27 #include "event-util.h"
28 #include "network-util.h"
29 #include "sd-dhcp-lease.h"
30 #include "dhcp-lease-internal.h"
31 #include "network-internal.h"
32 #include "conf-parser.h"
34 static int set_fallback_dns(Manager
*m
, const char *string
) {
42 FOREACH_WORD_QUOTED(word
, length
, string
, state
) {
43 _cleanup_free_ Address
*address
= NULL
;
45 _cleanup_free_
char *addrstr
= NULL
;
47 address
= new0(Address
, 1);
51 addrstr
= strndup(word
, length
);
55 r
= net_parse_inaddr(addrstr
, &address
->family
, &address
->in_addr
);
57 log_debug("Ignoring invalid DNS address '%s'", addrstr
);
61 LIST_FIND_TAIL(addresses
, m
->fallback_dns
, tail
);
62 LIST_INSERT_AFTER(addresses
, m
->fallback_dns
, tail
, address
);
69 int config_parse_dnsv(
74 unsigned section_line
,
81 Manager
*m
= userdata
;
89 while ((address
= m
->fallback_dns
)) {
90 LIST_REMOVE(addresses
, m
->fallback_dns
, address
);
94 set_fallback_dns(m
, rvalue
);
99 static int manager_parse_config_file(Manager
*m
) {
100 static const char fn
[] = "/etc/systemd/resolved.conf";
101 _cleanup_fclose_
FILE *f
= NULL
;
111 log_warning("Failed to open configuration file %s: %m", fn
);
115 r
= config_parse(NULL
, fn
, f
, "Resolve\0", config_item_perf_lookup
,
116 (void*) resolved_gperf_lookup
, false, false, m
);
118 log_warning("Failed to parse configuration file: %s", strerror(-r
));
123 int manager_new(Manager
**ret
) {
124 _cleanup_manager_free_ Manager
*m
= NULL
;
127 m
= new0(Manager
, 1);
131 r
= set_fallback_dns(m
, DNS_SERVERS
);
135 r
= manager_parse_config_file(m
);
139 r
= sd_event_default(&m
->event
);
143 sd_event_add_signal(m
->event
, NULL
, SIGTERM
, NULL
, NULL
);
144 sd_event_add_signal(m
->event
, NULL
, SIGINT
, NULL
, NULL
);
146 sd_event_set_watchdog(m
->event
, true);
154 void manager_free(Manager
*m
) {
160 sd_event_unref(m
->event
);
162 while ((address
= m
->fallback_dns
)) {
163 LIST_REMOVE(addresses
, m
->fallback_dns
, address
);
170 static void append_dns(FILE *f
, void *dns
, unsigned char family
, unsigned *count
) {
171 char buf
[INET6_ADDRSTRLEN
];
178 address
= inet_ntop(family
, dns
, buf
, INET6_ADDRSTRLEN
);
180 log_warning("Invalid DNS address. Ignoring.");
185 fputs("# Too many DNS servers configured, the following entries "
186 "may be ignored\n", f
);
188 fprintf(f
, "nameserver %s\n", address
);
193 int manager_update_resolv_conf(Manager
*m
) {
194 const char *path
= "/run/systemd/resolve/resolv.conf";
195 _cleanup_free_
char *temp_path
= NULL
;
196 _cleanup_fclose_
FILE *f
= NULL
;
197 _cleanup_free_
unsigned *indices
= NULL
;
204 r
= fopen_temporary(path
, &f
, &temp_path
);
208 fchmod(fileno(f
), 0644);
210 fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
211 "# Third party programs must not access this file directly, but\n"
212 "# only through the symlink at /etc/resolv.conf. To manage\n"
213 "# resolv.conf(5) in a different way, replace the symlink by a\n"
214 "# static file or a different symlink.\n\n", f
);
216 n
= sd_network_get_ifindices(&indices
);
220 for (i
= 0; i
< n
; i
++) {
221 _cleanup_dhcp_lease_unref_ sd_dhcp_lease
*lease
= NULL
;
222 struct in_addr
*nameservers
;
223 struct in6_addr
*nameservers6
;
224 size_t nameservers_size
;
226 r
= sd_network_dhcp_use_dns(indices
[i
]);
228 r
= sd_network_get_dhcp_lease(indices
[i
], &lease
);
230 r
= sd_dhcp_lease_get_dns(lease
, &nameservers
, &nameservers_size
);
234 for (j
= 0; j
< nameservers_size
; j
++)
235 append_dns(f
, &nameservers
[j
], AF_INET
, &count
);
240 r
= sd_network_get_dns(indices
[i
], &nameservers
, &nameservers_size
);
244 for (j
= 0; j
< nameservers_size
; j
++)
245 append_dns(f
, &nameservers
[j
], AF_INET
, &count
);
250 r
= sd_network_get_dns6(indices
[i
], &nameservers6
, &nameservers_size
);
254 for (j
= 0; j
< nameservers_size
; j
++)
255 append_dns(f
, &nameservers6
[j
], AF_INET6
, &count
);
261 LIST_FOREACH(addresses
, address
, m
->fallback_dns
)
262 append_dns(f
, &address
->in_addr
, address
->family
, &count
);
266 if (ferror(f
) || rename(temp_path
, path
) < 0) {
276 static int manager_network_event_handler(sd_event_source
*s
, int fd
, uint32_t revents
,
278 Manager
*m
= userdata
;
283 r
= manager_update_resolv_conf(m
);
285 log_warning("Could not update resolv.conf: %s", strerror(-r
));
287 sd_network_monitor_flush(m
->network_monitor
);
292 int manager_network_monitor_listen(Manager
*m
) {
293 _cleanup_event_source_unref_ sd_event_source
*event_source
= NULL
;
294 _cleanup_network_monitor_unref_ sd_network_monitor
*monitor
= NULL
;
297 r
= sd_network_monitor_new(NULL
, &monitor
);
301 fd
= sd_network_monitor_get_fd(monitor
);
305 events
= sd_network_monitor_get_events(monitor
);
309 r
= sd_event_add_io(m
->event
, &event_source
, fd
, events
,
310 &manager_network_event_handler
, m
);
314 m
->network_monitor
= monitor
;
315 m
->network_event_source
= event_source
;