resolved-manager.c revision 21d73c87b09ec2b8642424bc714ce9af3da4fc40
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering log_debug("Found new link %i/%s", ifindex, l->name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Removing link %i/%s", l->ifindex, l->name);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering log_warning("Failed to process RTNL link message: %s", strerror(-r));
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poetteringstatic int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
8ba9fd9cee0eef572f7b3ed7a8c3ed31160e93d3Lennart Poettering r = sd_rtnl_message_addr_get_family(mm, &family);
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_LOCAL, &address.in);
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering a = link_find_address(l, family, &address);
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poettering r = link_address_new(l, &a, family, &address);
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering log_warning("Failed to process RTNL address message: %s", strerror(-r));
ad867662936a4c7ab2c7116d804c272338801231Lennart Poetteringstatic int manager_rtnl_listen(Manager *m) {
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* First, subscibe to interfaces coming and going */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
309e9d86f0e7f9c5f0a2a09227bdfdb3174d4436Lennart Poettering r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
51323288fc628a5cac50914df915545d685b793eLennart Poettering /* Then, enumerate all links */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = sd_rtnl_message_request_dump(req, true);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (i = reply; i; i = sd_rtnl_message_next(i)) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Finally, enumerate all addresses, too */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
51323288fc628a5cac50914df915545d685b793eLennart Poettering for (i = reply; i; i = sd_rtnl_message_next(i)) {
51323288fc628a5cac50914df915545d685b793eLennart Poettering r = manager_process_address(m->rtnl, i, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_network_monitor_flush(m->network_monitor);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning("Failed to update monitor information for %i: %s", l->ifindex, strerror(-r));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_warning("Could not update resolv.conf: %s", strerror(-r));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int manager_network_monitor_listen(Manager *m) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_network_monitor_new(&m->network_monitor, NULL);
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering fd = sd_network_monitor_get_fd(m->network_monitor);
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering events = sd_network_monitor_get_events(m->network_monitor);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_event_add_io(m->event, &m->network_event_source, fd, events, &on_network_event, m);
3339cb71d44c5198f9546f113674f06dc7b01a6fLennart Poetteringstatic int determine_hostname(char **ret) {
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering _cleanup_free_ char *h = NULL, *n = NULL;
ad867662936a4c7ab2c7116d804c272338801231Lennart Poettering log_error("System hostname is not UTF-8 clean.");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("System hostname '%s' cannot be normalized.", h);
51323288fc628a5cac50914df915545d685b793eLennart Poetteringstatic int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0; /* ignore invalid hostnames */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_info("System hostname changed to '%s'.", h);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int manager_watch_hostname(Manager *m) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_warning("Failed to watch hostname: %m");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering m->hostname_fd = safe_close(m->hostname_fd);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_error("Failed to add hostname event source: %s", strerror(-r));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_info("Defaulting to hostname 'linux'.");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_info("Using system hostname '%s'.", m->hostname);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void manager_llmnr_stop(Manager *m) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
82bd6dddc4a363a9c3c6f41eb46eb171a80dca27Lennart Poettering m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int manager_llmnr_start(Manager *m) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_warning("There appears to be another LLMNR respondering running. Turning off LLMNR support.");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(manager_freep) Manager *m = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering dns_server_free(m->fallback_dns_servers);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_event_source_unref(m->network_event_source);
7b9f7afcc04e80b77a2567b0750aa2cd03c1a1cdLennart Poettering sd_network_monitor_unref(m->network_monitor);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering sd_event_source_unref(m->dns_ipv4_event_source);
7b9f7afcc04e80b77a2567b0750aa2cd03c1a1cdLennart Poettering sd_event_source_unref(m->dns_ipv6_event_source);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering sd_event_source_unref(m->bus_retry_event_source);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering dns_resource_key_unref(m->host_ipv4_key);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering dns_resource_key_unref(m->host_ipv6_key);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering sd_event_source_unref(m->hostname_event_source);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringint manager_read_resolv_conf(Manager *m) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Reads the system /etc/resolv.conf, if it exists and is not
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * symlinked to our own resolv.conf instance */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_warning("Failed to open /etc/resolv.conf: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Have we already seen the file? */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Is it symlinked to our own file? */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_warning("Failed to open /etc/resolv.conf: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_error("Failed to stat open file: %m");
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering FOREACH_LINE(line, f, r = -errno; goto clear) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering const char *a;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = in_addr_from_string_auto(a, &family, &address);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_warning("Failed to parse name server %s.", a);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (s->family == family && in_addr_equal(family, &s->address, &address) > 0)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &address);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = in_addr_to_string(s->family, &s->address, &t);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering log_warning("Invalid DNS address. Ignoring: %s", strerror(-r));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering fputs("# Too many DNS servers configured, the following entries may be ignored\n", f);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringint manager_write_resolv_conf(Manager *m) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering static const char path[] = "/run/systemd/resolve/resolv.conf";
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* Read the system /etc/resolv.conf first */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = fopen_temporary(path, &f, &temp_path);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering "# Third party programs must not access this file directly, but\n"
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering "# only through the symlink at /etc/resolv.conf. To manage\n"
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering "# resolv.conf(5) in a different way, replace the symlink by a\n"
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering "# static file or a different symlink.\n\n", f);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering LIST_FOREACH(servers, s, m->fallback_dns_servers)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringint manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering struct cmsghdr header; /* For alignment */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint8_t buffer[CMSG_SPACE(MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo)))
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering p->sender_port = be16toh(sa.in.sin_port);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering p->sender_port = be16toh(sa.in6.sin6_port);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering } else if (cmsg->cmsg_level == IPPROTO_IP) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* The Linux kernel sets the interface index to the loopback
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * device if the packet came from the local host since it
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * avoids the routing table in such a case. Let's unset the
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * interface index in such a case. */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering if (p->ifindex > 0 && manager_ifindex_is_loopback(m, p->ifindex) != 0)
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering /* If we don't know the interface index still, we look for the
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering * first local interface with a matching address. Yuck! */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = setsockopt(m->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_event_add_io(m->event, &m->dns_ipv4_event_source, m->dns_ipv4_fd, EPOLLIN, on_dns_packet, m);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->dns_ipv4_fd = safe_close(m->dns_ipv4_fd);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = setsockopt(m->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = sd_event_add_io(m->event, &m->dns_ipv6_event_source, m->dns_ipv6_fd, EPOLLIN, on_dns_packet, m);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering m->dns_ipv6_fd = safe_close(m->dns_ipv6_fd);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringstatic int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
703e4f5e39c019da8c002ba10bd450ce378c0e91Lennart Poettering struct cmsghdr header; /* For alignment */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering struct cmsghdr header; /* For alignment */
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poetteringint manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) {
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering log_debug("Sending %s packet with id %u on interface %i/%s", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family));
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart PoetteringDnsServer* manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering LIST_FOREACH(servers, s, m->fallback_dns_servers)
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
7f220d94a938a99c77400fa0ca30485e269bae7cLennart PoetteringDnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering in_addr_to_string(s->family, &s->address, &ip);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering log_info("Switching to system DNS server %s.", strna(ip));
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering dns_cache_flush(&m->unicast_scope->cache);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart PoetteringDnsServer *manager_get_dns_server(Manager *m) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering /* Try to read updates resolv.conf */
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering manager_set_dns_server(m, m->dns_servers);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering /* No DNS servers configured, let's see if there are
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering * any on any links. If not, we use the fallback
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering manager_set_dns_server(m, m->fallback_dns_servers);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poetteringvoid manager_next_dns_server(Manager *m) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering /* If there's currently no DNS server set, then the next
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering * manager_get_dns_server() will find one */
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering /* Change to the next one */
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering if (m->current_dns_server->servers_next) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering manager_set_dns_server(m, m->current_dns_server->servers_next);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering /* If there was no next one, then start from the beginning of
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering manager_set_dns_server(m, m->fallback_dns_servers);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering manager_set_dns_server(m, m->dns_servers);
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering /* If we don't know on which link a DNS packet would be
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering * delivered, let's find the largest MTU that works on all
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering * interfaces we know of */
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poetteringstatic int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
7f220d94a938a99c77400fa0ca30485e269bae7cLennart Poettering _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
45ec7efb6c2560c80dfa752bc9d3733749dc52cbLennart Poettering r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Got reply packet for id %u", DNS_PACKET_ID(p));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering } else if (dns_packet_validate_query(p) > 0) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering l = hashmap_get(m->links, INT_TO_PTR(p->ifindex));
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poetteringint manager_llmnr_ipv4_udp_fd(Manager *m) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
902bb5d8abb2a7d258741828d212ca549ab16950Lennart Poettering r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
goto fail;
return m->llmnr_ipv4_udp_fd;
fail:
assert(m);
if (m->llmnr_ipv6_udp_fd >= 0)
return m->llmnr_ipv6_udp_fd;
if (m->llmnr_ipv6_udp_fd < 0)
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
r = -errno;
goto fail;
return m->llmnr_ipv6_udp_fd;
fail:
assert(s);
Link *l;
if (scope) {
if (s->write_packet)
dns_stream_free(s);
int cfd, r;
if (cfd < 0) {
return -errno;
assert(m);
if (m->llmnr_ipv4_tcp_fd >= 0)
return m->llmnr_ipv4_tcp_fd;
if (m->llmnr_ipv4_tcp_fd < 0)
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
goto fail;
return m->llmnr_ipv4_tcp_fd;
fail:
assert(m);
if (m->llmnr_ipv6_tcp_fd >= 0)
return m->llmnr_ipv6_tcp_fd;
if (m->llmnr_ipv6_tcp_fd < 0)
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
r = -errno;
goto fail;
return m->llmnr_ipv6_tcp_fd;
fail:
Link *l;
assert(m);
if (ifindex <= 0)
return -EINVAL;
LinkAddress *a;
assert(m);
Iterator i;
Link *l;
assert(m);
link_add_rrs(l, true);
link_add_rrs(l, false);
uint64_t u;
assert(m);
assert(p);
while (p > m->hostname) {
if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
return -ENOMEM;
m->hostname = h;
LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr) {
Iterator i;
Link *l;
assert(m);
LinkAddress *a;
return NULL;
assert(m);
assert(p);