resolved-manager.c revision 36a03ca2a8952ca1acb29fbe796210c27ff71aff
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/***
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ***/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <arpa/inet.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <resolv.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <net/if.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <sys/ioctl.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <sys/poll.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <netinet/in.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "rtnl-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "event-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "network-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "network-internal.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "conf-parser.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "socket-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "af-list.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "utf8.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "fileio-label.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "resolved-dns-domain.h"
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering#include "resolved-conf.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "resolved-bus.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "resolved-manager.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Manager *m = userdata;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint16_t type;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Link *l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int ifindex, r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(rtnl);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(mm);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_get_type(mm, &type);
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (type) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case RTM_NEWLINK:{
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool is_new = !l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!l) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = link_new(m, &l, ifindex);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = link_update_rtnl(l, mm);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = link_update_monitor(l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (is_new)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Found new link %i/%s", ifindex, l->name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case RTM_DELLINK:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Removing link %i/%s", l->ifindex, l->name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering link_free(l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringfail:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning_errno(r, "Failed to process RTNL link message: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Manager *m = userdata;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering union in_addr_union address;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint16_t type;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r, ifindex, family;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LinkAddress *a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Link *l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(rtnl);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(mm);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_get_type(mm, &type);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!l)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_addr_get_family(mm, &family);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (family) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case AF_INET:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_LOCAL, &address.in);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case AF_INET6:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering default:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a = link_find_address(l, family, &address);
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (type) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case RTM_NEWADDR:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!a) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = link_address_new(l, &a, family, &address);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = link_address_update_rtnl(a, mm);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case RTM_DELADDR:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (a)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering link_address_free(a);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringfail:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning_errno(r, "Failed to process RTNL address message: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_rtnl_listen(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_rtnl_message *i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* First, subscibe to interfaces coming and going */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Then, enumerate all links */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_request_dump(req, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = reply; i; i = sd_rtnl_message_next(i)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_process_link(m->rtnl, i, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering req = sd_rtnl_message_unref(req);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering reply = sd_rtnl_message_unref(reply);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Finally, enumerate all addresses, too */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_message_request_dump(req, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = reply; i; i = sd_rtnl_message_next(i)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_process_address(m->rtnl, i, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna Manager *m = userdata;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Iterator i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Link *l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_network_monitor_flush(m->network_monitor);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering HASHMAP_FOREACH(l, m->links, i) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = link_update_monitor(l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_write_resolv_conf(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning_errno(r, "Could not update resolv.conf: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_network_monitor_listen(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r, fd, events;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_network_monitor_new(&m->network_monitor, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fd = sd_network_monitor_get_fd(m->network_monitor);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (fd < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return fd;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering events = sd_network_monitor_get_events(m->network_monitor);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (events < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return events;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_io(m->event, &m->network_event_source, fd, events, &on_network_event, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnastatic int determine_hostname(char **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ char *h = NULL, *n = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(ret);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering h = gethostname_malloc();
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!h)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return log_oom();
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!utf8_is_valid(h)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("System hostname is not UTF-8 clean.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_name_normalize(h, &n);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("System hostname '%s' cannot be normalized.", h);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *ret = n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ char *h = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Manager *m = userdata;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = determine_hostname(&h);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0; /* ignore invalid hostnames */
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar if (streq(h, m->hostname))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_info("System hostname changed to '%s'.", h);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(m->hostname);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->hostname = h;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering h = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_refresh_rrs(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering return 0;
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering}
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int manager_watch_hostname(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (m->hostname_fd < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning_errno(errno, "Failed to watch hostname: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == -EPERM)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->hostname_fd = safe_close(m->hostname_fd);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna else
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return log_error_errno(r, "Failed to add hostname event source: %m");
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna }
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = determine_hostname(&m->hostname);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r < 0) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna log_info("Defaulting to hostname 'linux'.");
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->hostname = strdup("linux");
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer if (!m->hostname)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return log_oom();
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna } else
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna log_info("Using system hostname '%s'.", m->hostname);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna}
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnastatic void manager_llmnr_stop(Manager *m) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert(m);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek}
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnastatic int manager_llmnr_start(Manager *m) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna int r;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert(m);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (m->llmnr_support == SUPPORT_NO)
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = manager_llmnr_ipv4_udp_fd(m);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r == -EADDRINUSE)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna goto eaddrinuse;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r < 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return r;
8333c77edf8fd1654cd96f3f6ee0f078dd64b58bZbigniew Jędrzejewski-Szmek
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = manager_llmnr_ipv4_tcp_fd(m);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek if (r == -EADDRINUSE)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna goto eaddrinuse;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r < 0)
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek return r;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (socket_ipv6_is_supported()) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = manager_llmnr_ipv6_udp_fd(m);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek if (r == -EADDRINUSE)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna goto eaddrinuse;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r < 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return r;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = manager_llmnr_ipv6_tcp_fd(m);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r == -EADDRINUSE)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna goto eaddrinuse;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r < 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return r;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek }
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmekeaddrinuse:
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->llmnr_support = SUPPORT_NO;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek manager_llmnr_stop(m);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint manager_new(Manager **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_(manager_freep) Manager *m = NULL;
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek assert(ret);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m = new0(Manager, 1);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!m)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->hostname_fd = -1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->llmnr_support = SUPPORT_YES;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->read_resolv_conf = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_default(&m->event);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_set_watchdog(m->event, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_watch_hostname(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_network_monitor_listen(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_rtnl_listen(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_connect_bus(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *ret = m;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint manager_start(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = manager_llmnr_start(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringManager *manager_free(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Link *l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!m)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while ((l = hashmap_first(m->links)))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering link_free(l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while (m->dns_queries)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dns_query_free(m->dns_queries);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dns_scope_free(m->unicast_scope);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_flush_dns_servers(m, DNS_SERVER_SYSTEM);
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer manager_flush_dns_servers(m, DNS_SERVER_FALLBACK);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hashmap_free(m->links);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hashmap_free(m->dns_transactions);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(m->network_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_network_monitor_unref(m->network_monitor);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(m->dns_ipv4_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(m->dns_ipv6_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering safe_close(m->dns_ipv4_fd);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering safe_close(m->dns_ipv6_fd);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_llmnr_stop(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_bus_slot_unref(m->prepare_for_sleep_slot);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(m->bus_retry_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_bus_unref(m->bus);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_unref(m->event);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dns_resource_key_unref(m->host_ipv4_key);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dns_resource_key_unref(m->host_ipv6_key);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering safe_close(m->hostname_fd);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(m->hostname_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(m->hostname);
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint manager_read_resolv_conf(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_fclose_ FILE *f = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct stat st, own;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char line[LINE_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering DnsServer *s, *nx;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t t;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Reads the system /etc/resolv.conf, if it exists and is not
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * symlinked to our own resolv.conf instance */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!m->read_resolv_conf)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = stat("/etc/resolv.conf", &st);
6b2b6f30e38d67b032d6bdc6b47ae05e143e96c5Michal Schmidt if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (errno != ENOENT)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = -errno;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto clear;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Have we already seen the file? */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering t = timespec_load(&st.st_mtim);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t == m->resolv_conf_mtime)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->resolv_conf_mtime = t;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Is it symlinked to our own file? */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering st.st_dev == own.st_dev &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering st.st_ino == own.st_ino) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto clear;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer f = fopen("/etc/resolv.conf", "re");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!f) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (errno != ENOENT)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = -errno;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering goto clear;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (fstat(fileno(f), &st) < 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_error_errno(errno, "Failed to stat open file: %m");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = -errno;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering goto clear;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering LIST_FOREACH(servers, s, m->dns_servers)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering s->marked = true;
c62e11ce3966c55d23520b9f0785c7e839cf7f37Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering FOREACH_LINE(line, f, r = -errno; goto clear) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering union in_addr_union address;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int family;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering char *l;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering const char *a;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering truncate_nl(line);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering l = strstrip(line);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (*l == '#' || *l == ';')
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering continue;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering a = first_word(l, "nameserver");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!a)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering continue;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = in_addr_from_string_auto(a, &family, &address);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_warning("Failed to parse name server %s.", a);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering continue;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering LIST_FOREACH(servers, s, m->dns_servers)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, &address) > 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering break;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (s)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering s->marked = false;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering else {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &address);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering goto clear;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (s->marked)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dns_server_free(s);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Whenever /etc/resolv.conf changes, start using the first
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * DNS server of it. This is useful to deal with broken
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * network managing implementations (like NetworkManager),
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * that when connecting to a VPN place both the VPN DNS
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * servers and the local ones in /etc/resolv.conf. Without
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * resetting the DNS server to use back to the first entry we
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * will continue to use the local one thus being unable to
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * resolve VPN domains. */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering manager_set_dns_server(m, m->dns_servers);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return 0;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringclear:
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering while (m->dns_servers)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dns_server_free(m->dns_servers);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering _cleanup_free_ char *t = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(s);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(f);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(count);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = in_addr_to_string(s->family, &s->address, &t);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_warning_errno(r, "Invalid DNS address. Ignoring: %m");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (*count == MAXNS)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering fprintf(f, "nameserver %s\n", t);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering (*count) ++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic void write_resolv_conf_search(const char *domain, FILE *f,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering unsigned *count, unsigned *length) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(domain);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(f);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(length);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*count >= MAXDNSRCH ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *length + strlen(domain) > 256) {
82c1d8f4eb74ddd9be2c9b9b56d9dc564c599effLennart Poettering if (*count == MAXDNSRCH)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering fputs(" # Too many search domains configured, remaining ones ignored.", f);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (*length <= 256)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering fputs(" # Total length of all search domains is too long, remaining ones ignored.", f);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering fprintf(f, " %s", domain);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering (*length) += strlen(domain);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering (*count) ++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int write_resolv_conf_contents(FILE *f, Set *dns, Set *domains) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering Iterator i;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "# Third party programs must not access this file directly, but\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "# only through the symlink at /etc/resolv.conf. To manage\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "# resolv.conf(5) in a different way, replace the symlink by a\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "# static file or a different symlink.\n\n", f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (set_isempty(dns))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fputs("# No DNS servers known.\n", f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering DnsServer *s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned count = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SET_FOREACH(s, dns, i)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering write_resolv_conf_server(s, f, &count);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!set_isempty(domains)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned length = 0, count = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char *domain;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fputs("search", f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SET_FOREACH(domain, domains, i)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering write_resolv_conf_search(domain, f, &count, &length);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fputs("\n", f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return fflush_and_check(f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint manager_write_resolv_conf(Manager *m) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering static const char path[] = "/run/systemd/resolve/resolv.conf";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ char *temp_path = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_fclose_ FILE *f = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_set_free_ Set *dns = NULL, *domains = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering DnsServer *s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Iterator i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Link *l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Read the system /etc/resolv.conf first */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_read_resolv_conf(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Add the full list to a set, to filter out duplicates */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dns = set_new(&dns_server_hash_ops);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!dns)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering domains = set_new(&dns_name_hash_ops);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!domains)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* First add the system-wide servers */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_FOREACH(servers, s, m->dns_servers) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = set_put(dns, s);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == -EEXIST)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering continue;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Then, add the per-link servers and domains */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering HASHMAP_FOREACH(l, m->links, i) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char **domain;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_FOREACH(servers, s, l->dns_servers) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = set_put(dns, s);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == -EEXIST)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering continue;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!l->unicast_scope)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering continue;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering STRV_FOREACH(domain, l->unicast_scope->domains) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = set_put(domains, *domain);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == -EEXIST)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering continue;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* If we found nothing, add the fallback servers */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (set_isempty(dns)) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering LIST_FOREACH(servers, s, m->fallback_dns_servers) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = set_put(dns, s);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == -EEXIST)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering continue;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = fopen_temporary_label(path, path, &f, &temp_path);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fchmod(fileno(f), 0644);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = write_resolv_conf_contents(f, dns, domains);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (rename(temp_path, path) < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = -errno;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringfail:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unlink(path);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unlink(temp_path);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering union {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct cmsghdr header; /* For alignment */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering + CMSG_SPACE(int) /* ttl/hoplimit */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering + EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } control;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering union sockaddr_union sa;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct msghdr mh = {};
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct cmsghdr *cmsg;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct iovec iov;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int ms = 0, r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ssize_t l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(m);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(fd >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(ret);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = ioctl(fd, FIONREAD, &ms);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -errno;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (ms < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EIO;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_packet_new(&p, protocol, ms);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering iov.iov_base = DNS_PACKET_DATA(p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering iov.iov_len = p->allocated;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mh.msg_name = &sa.sa;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mh.msg_namelen = sizeof(sa);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mh.msg_iov = &iov;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mh.msg_iovlen = 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mh.msg_control = &control;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mh.msg_controllen = sizeof(control);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = recvmsg(fd, &mh, 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (errno == EAGAIN || errno == EINTR)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -errno;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EIO;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!(mh.msg_flags & MSG_CTRUNC));
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner assert(!(mh.msg_flags & MSG_TRUNC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->size = (size_t) l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->family = sa.sa.sa_family;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->ipproto = IPPROTO_UDP;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (p->family == AF_INET) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->sender.in = sa.in.sin_addr;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->sender_port = be16toh(sa.in.sin_port);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (p->family == AF_INET6) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->sender.in6 = sa.in6.sin6_addr;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->sender_port = be16toh(sa.in6.sin6_port);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->ifindex = sa.in6.sin6_scope_id;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EAFNOSUPPORT;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (cmsg->cmsg_level == IPPROTO_IPV6) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(p->family == AF_INET6);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (cmsg->cmsg_type) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case IPV6_PKTINFO: {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (p->ifindex <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->ifindex = i->ipi6_ifindex;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->destination.in6 = i->ipi6_addr;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case IPV6_HOPLIMIT:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p->ttl = *(int *) CMSG_DATA(cmsg);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
} else if (cmsg->cmsg_level == IPPROTO_IP) {
assert(p->family == AF_INET);
switch (cmsg->cmsg_type) {
case IP_PKTINFO: {
struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
if (p->ifindex <= 0)
p->ifindex = i->ipi_ifindex;
p->destination.in = i->ipi_addr;
break;
}
case IP_TTL:
p->ttl = *(int *) CMSG_DATA(cmsg);
break;
}
}
}
/* The Linux kernel sets the interface index to the loopback
* device if the packet came from the local host since it
* avoids the routing table in such a case. Let's unset the
* interface index in such a case. */
if (p->ifindex == LOOPBACK_IFINDEX)
p->ifindex = 0;
/* If we don't know the interface index still, we look for the
* first local interface with a matching address. Yuck! */
if (p->ifindex <= 0)
p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
*ret = p;
p = NULL;
return 1;
}
static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
DnsTransaction *t = NULL;
Manager *m = userdata;
int r;
r = manager_recv(m, fd, DNS_PROTOCOL_DNS, &p);
if (r <= 0)
return r;
if (dns_packet_validate_reply(p) > 0) {
t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
if (!t)
return 0;
dns_transaction_process_reply(t, p);
} else
log_debug("Invalid DNS packet.");
return 0;
}
int manager_dns_ipv4_fd(Manager *m) {
const int one = 1;
int r;
assert(m);
if (m->dns_ipv4_fd >= 0)
return m->dns_ipv4_fd;
m->dns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (m->dns_ipv4_fd < 0)
return -errno;
r = setsockopt(m->dns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = sd_event_add_io(m->event, &m->dns_ipv4_event_source, m->dns_ipv4_fd, EPOLLIN, on_dns_packet, m);
if (r < 0)
goto fail;
return m->dns_ipv4_fd;
fail:
m->dns_ipv4_fd = safe_close(m->dns_ipv4_fd);
return r;
}
int manager_dns_ipv6_fd(Manager *m) {
const int one = 1;
int r;
assert(m);
if (m->dns_ipv6_fd >= 0)
return m->dns_ipv6_fd;
m->dns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (m->dns_ipv6_fd < 0)
return -errno;
r = setsockopt(m->dns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = sd_event_add_io(m->event, &m->dns_ipv6_event_source, m->dns_ipv6_fd, EPOLLIN, on_dns_packet, m);
if (r < 0)
goto fail;
return m->dns_ipv6_fd;
fail:
m->dns_ipv6_fd = safe_close(m->dns_ipv6_fd);
return r;
}
static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
int r;
assert(fd >= 0);
assert(mh);
for (;;) {
if (sendmsg(fd, mh, flags) >= 0)
return 0;
if (errno == EINTR)
continue;
if (errno != EAGAIN)
return -errno;
r = fd_wait_for_event(fd, POLLOUT, SEND_TIMEOUT_USEC);
if (r < 0)
return r;
if (r == 0)
return -ETIMEDOUT;
}
}
static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
};
union {
struct cmsghdr header; /* For alignment */
uint8_t buffer[CMSG_SPACE(sizeof(struct in_pktinfo))];
} control;
struct msghdr mh = {};
struct iovec iov;
assert(m);
assert(fd >= 0);
assert(addr);
assert(port > 0);
assert(p);
iov.iov_base = DNS_PACKET_DATA(p);
iov.iov_len = p->size;
sa.in.sin_addr = *addr;
sa.in.sin_port = htobe16(port),
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
mh.msg_name = &sa.sa;
mh.msg_namelen = sizeof(sa.in);
if (ifindex > 0) {
struct cmsghdr *cmsg;
struct in_pktinfo *pi;
zero(control);
mh.msg_control = &control;
mh.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_len = mh.msg_controllen;
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
pi = (struct in_pktinfo*) CMSG_DATA(cmsg);
pi->ipi_ifindex = ifindex;
}
return sendmsg_loop(fd, &mh, 0);
}
static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
union sockaddr_union sa = {
.in6.sin6_family = AF_INET6,
};
union {
struct cmsghdr header; /* For alignment */
uint8_t buffer[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control;
struct msghdr mh = {};
struct iovec iov;
assert(m);
assert(fd >= 0);
assert(addr);
assert(port > 0);
assert(p);
iov.iov_base = DNS_PACKET_DATA(p);
iov.iov_len = p->size;
sa.in6.sin6_addr = *addr;
sa.in6.sin6_port = htobe16(port),
sa.in6.sin6_scope_id = ifindex;
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
mh.msg_name = &sa.sa;
mh.msg_namelen = sizeof(sa.in6);
if (ifindex > 0) {
struct cmsghdr *cmsg;
struct in6_pktinfo *pi;
zero(control);
mh.msg_control = &control;
mh.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_len = mh.msg_controllen;
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
pi = (struct in6_pktinfo*) CMSG_DATA(cmsg);
pi->ipi6_ifindex = ifindex;
}
return sendmsg_loop(fd, &mh, 0);
}
int manager_send(Manager *m, int fd, int ifindex, int family, const union in_addr_union *addr, uint16_t port, DnsPacket *p) {
assert(m);
assert(fd >= 0);
assert(addr);
assert(port > 0);
assert(p);
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));
if (family == AF_INET)
return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p);
else if (family == AF_INET6)
return manager_ipv6_send(m, fd, ifindex, &addr->in6, port, p);
return -EAFNOSUPPORT;
}
DnsServer* manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr) {
DnsServer *s;
assert(m);
assert(in_addr);
LIST_FOREACH(servers, s, m->dns_servers)
if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
return s;
LIST_FOREACH(servers, s, m->fallback_dns_servers)
if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0)
return s;
return NULL;
}
DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
assert(m);
if (m->current_dns_server == s)
return s;
if (s) {
_cleanup_free_ char *ip = NULL;
in_addr_to_string(s->family, &s->address, &ip);
log_info("Switching to system DNS server %s.", strna(ip));
}
m->current_dns_server = s;
if (m->unicast_scope)
dns_cache_flush(&m->unicast_scope->cache);
return s;
}
DnsServer *manager_get_dns_server(Manager *m) {
Link *l;
assert(m);
/* Try to read updates resolv.conf */
manager_read_resolv_conf(m);
if (!m->current_dns_server)
manager_set_dns_server(m, m->dns_servers);
if (!m->current_dns_server) {
bool found = false;
Iterator i;
/* No DNS servers configured, let's see if there are
* any on any links. If not, we use the fallback
* servers */
HASHMAP_FOREACH(l, m->links, i)
if (l->dns_servers) {
found = true;
break;
}
if (!found)
manager_set_dns_server(m, m->fallback_dns_servers);
}
return m->current_dns_server;
}
void manager_next_dns_server(Manager *m) {
assert(m);
/* If there's currently no DNS server set, then the next
* manager_get_dns_server() will find one */
if (!m->current_dns_server)
return;
/* Change to the next one */
if (m->current_dns_server->servers_next) {
manager_set_dns_server(m, m->current_dns_server->servers_next);
return;
}
/* If there was no next one, then start from the beginning of
* the list */
if (m->current_dns_server->type == DNS_SERVER_FALLBACK)
manager_set_dns_server(m, m->fallback_dns_servers);
else
manager_set_dns_server(m, m->dns_servers);
}
uint32_t manager_find_mtu(Manager *m) {
uint32_t mtu = 0;
Link *l;
Iterator i;
/* If we don't know on which link a DNS packet would be
* delivered, let's find the largest MTU that works on all
* interfaces we know of */
HASHMAP_FOREACH(l, m->links, i) {
if (l->mtu <= 0)
continue;
if (mtu <= 0 || l->mtu < mtu)
mtu = l->mtu;
}
return mtu;
}
static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
DnsTransaction *t = NULL;
Manager *m = userdata;
DnsScope *scope;
int r;
r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p);
if (r <= 0)
return r;
scope = manager_find_scope(m, p);
if (!scope) {
log_warning("Got LLMNR UDP packet on unknown scope. Ignoring.");
return 0;
}
if (dns_packet_validate_reply(p) > 0) {
log_debug("Got reply packet for id %u", DNS_PACKET_ID(p));
dns_scope_check_conflicts(scope, p);
t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p)));
if (t)
dns_transaction_process_reply(t, p);
} else if (dns_packet_validate_query(p) > 0) {
log_debug("Got query packet for id %u", DNS_PACKET_ID(p));
dns_scope_process_query(scope, NULL, p);
} else
log_debug("Invalid LLMNR UDP packet.");
return 0;
}
int manager_llmnr_ipv4_udp_fd(Manager *m) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
.in.sin_port = htobe16(5355),
};
static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255;
int r;
assert(m);
if (m->llmnr_ipv4_udp_fd >= 0)
return m->llmnr_ipv4_udp_fd;
m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (m->llmnr_ipv4_udp_fd < 0)
return -errno;
/* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
/* Disable Don't-Fragment bit in the IP header */
r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
if (r < 0) {
r = -errno;
goto fail;
}
r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in));
if (r < 0) {
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);
if (r < 0)
goto fail;
return m->llmnr_ipv4_udp_fd;
fail:
m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
return r;
}
int manager_llmnr_ipv6_udp_fd(Manager *m) {
union sockaddr_union sa = {
.in6.sin6_family = AF_INET6,
.in6.sin6_port = htobe16(5355),
};
static const int one = 1, ttl = 255;
int r;
assert(m);
if (m->llmnr_ipv6_udp_fd >= 0)
return m->llmnr_ipv6_udp_fd;
m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (m->llmnr_ipv6_udp_fd < 0)
return -errno;
r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
if (r < 0) {
r = -errno;
goto fail;
}
/* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */
r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6));
if (r < 0) {
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);
if (r < 0) {
r = -errno;
goto fail;
}
return m->llmnr_ipv6_udp_fd;
fail:
m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
return r;
}
static int on_llmnr_stream_packet(DnsStream *s) {
DnsScope *scope;
assert(s);
scope = manager_find_scope(s->manager, s->read_packet);
if (!scope) {
log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
return 0;
}
if (dns_packet_validate_query(s->read_packet) > 0) {
log_debug("Got query packet for id %u", DNS_PACKET_ID(s->read_packet));
dns_scope_process_query(scope, s, s->read_packet);
/* If no reply packet was set, we free the stream */
if (s->write_packet)
return 0;
} else
log_debug("Invalid LLMNR TCP packet.");
dns_stream_free(s);
return 0;
}
static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
DnsStream *stream;
Manager *m = userdata;
int cfd, r;
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
return -errno;
}
r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd);
if (r < 0) {
safe_close(cfd);
return r;
}
stream->on_packet = on_llmnr_stream_packet;
return 0;
}
int manager_llmnr_ipv4_tcp_fd(Manager *m) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
.in.sin_port = htobe16(5355),
};
static const int one = 1, pmtu = IP_PMTUDISC_DONT;
int r;
assert(m);
if (m->llmnr_ipv4_tcp_fd >= 0)
return m->llmnr_ipv4_tcp_fd;
m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (m->llmnr_ipv4_tcp_fd < 0)
return -errno;
/* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
/* Disable Don't-Fragment bit in the IP header */
r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
if (r < 0) {
r = -errno;
goto fail;
}
r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in));
if (r < 0) {
r = -errno;
goto fail;
}
r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN);
if (r < 0) {
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);
if (r < 0)
goto fail;
return m->llmnr_ipv4_tcp_fd;
fail:
m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
return r;
}
int manager_llmnr_ipv6_tcp_fd(Manager *m) {
union sockaddr_union sa = {
.in6.sin6_family = AF_INET6,
.in6.sin6_port = htobe16(5355),
};
static const int one = 1;
int r;
assert(m);
if (m->llmnr_ipv6_tcp_fd >= 0)
return m->llmnr_ipv6_tcp_fd;
m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (m->llmnr_ipv6_tcp_fd < 0)
return -errno;
/* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */
r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one));
if (r < 0) {
r = -errno;
goto fail;
}
r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6));
if (r < 0) {
r = -errno;
goto fail;
}
r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN);
if (r < 0) {
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);
if (r < 0) {
r = -errno;
goto fail;
}
return m->llmnr_ipv6_tcp_fd;
fail:
m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
return r;
}
int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) {
LinkAddress *a;
assert(m);
a = manager_find_link_address(m, family, in_addr);
if (a)
return a->link->ifindex;
return 0;
}
void manager_refresh_rrs(Manager *m) {
Iterator i;
Link *l;
assert(m);
m->host_ipv4_key = dns_resource_key_unref(m->host_ipv4_key);
m->host_ipv6_key = dns_resource_key_unref(m->host_ipv6_key);
HASHMAP_FOREACH(l, m->links, i) {
link_add_rrs(l, true);
link_add_rrs(l, false);
}
}
int manager_next_hostname(Manager *m) {
const char *p;
uint64_t u, a;
char *h;
assert(m);
p = strchr(m->hostname, 0);
assert(p);
while (p > m->hostname) {
if (!strchr("0123456789", p[-1]))
break;
p--;
}
if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
u = 1;
/* Add a random number to the old value. This way we can avoid
* that two hosts pick the same hostname, win on IPv4 and lose
* on IPv6 (or vice versa), and pick the same hostname
* replacement hostname, ad infinitum. We still want the
* numbers to go up monotonically, hence we just add a random
* value 1..10 */
random_bytes(&a, sizeof(a));
u += 1 + a % 10;
if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->hostname), m->hostname, u) < 0)
return -ENOMEM;
log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->hostname, h);
free(m->hostname);
m->hostname = h;
manager_refresh_rrs(m);
return 0;
}
LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr) {
Iterator i;
Link *l;
assert(m);
HASHMAP_FOREACH(l, m->links, i) {
LinkAddress *a;
a = link_find_address(l, family, in_addr);
if (a)
return a;
}
return NULL;
}
bool manager_our_packet(Manager *m, DnsPacket *p) {
assert(m);
assert(p);
return !!manager_find_link_address(m, p->family, &p->sender);
}
DnsScope* manager_find_scope(Manager *m, DnsPacket *p) {
Link *l;
assert(m);
assert(p);
l = hashmap_get(m->links, INT_TO_PTR(p->ifindex));
if (!l)
return NULL;
if (p->protocol == DNS_PROTOCOL_LLMNR) {
if (p->family == AF_INET)
return l->llmnr_ipv4_scope;
else if (p->family == AF_INET6)
return l->llmnr_ipv6_scope;
}
return NULL;
}
void manager_verify_all(Manager *m) {
DnsScope *s;
assert(m);
LIST_FOREACH(scopes, s, m->dns_scopes)
dns_zone_verify_all(&s->zone);
}
void manager_flush_dns_servers(Manager *m, DnsServerType t) {
assert(m);
if (t == DNS_SERVER_SYSTEM)
while (m->dns_servers)
dns_server_free(m->dns_servers);
if (t == DNS_SERVER_FALLBACK)
while (m->fallback_dns_servers)
dns_server_free(m->fallback_dns_servers);
}
static const char* const support_table[_SUPPORT_MAX] = {
[SUPPORT_NO] = "no",
[SUPPORT_YES] = "yes",
[SUPPORT_RESOLVE] = "resolve",
};
DEFINE_STRING_TABLE_LOOKUP(support, Support);