resolved-manager.c revision 90ab504273a7f186ebb76e6acfb778b4e0d7c91b
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering ***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <arpa/inet.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <resolv.h>
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering#include <net/if.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <sys/ioctl.h>
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include <sys/poll.h>
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering#include <netinet/in.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "rtnl-util.h"
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "event-util.h"
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "network-util.h"
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen#include "network-internal.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "conf-parser.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "socket-util.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "af-list.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "utf8.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "resolved-dns-domain.h"
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen#include "resolved-conf.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "resolved-bus.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "resolved-manager.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poetteringstatic int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
3c0cf502796be355431d4a64d738e75f543aa51dLennart Poettering Manager *m = userdata;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint16_t type;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering Link *l;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int ifindex, r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering assert(rtnl);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(mm);
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering r = sd_rtnl_message_get_type(mm, &type);
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering if (r < 0)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering goto fail;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering if (r < 0)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering goto fail;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering switch (type) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering case RTM_NEWLINK:{
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering bool is_new = !l;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (!l) {
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering r = link_new(m, &l, ifindex);
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering if (r < 0)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen goto fail;
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen }
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = link_update_rtnl(l, mm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen goto fail;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = link_update_monitor(l);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering goto fail;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering if (is_new)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering log_debug("Found new link %i/%s", ifindex, l->name);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering break;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering }
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering case RTM_DELLINK:
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (l) {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering log_debug("Removing link %i/%s", l->ifindex, l->name);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering link_free(l);
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering }
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering break;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering }
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return 0;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringfail:
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering log_warning("Failed to process RTNL link message: %s", strerror(-r));
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering}
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poetteringstatic int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering Manager *m = userdata;
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering union in_addr_union address;
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering uint16_t type;
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering int r, ifindex, family;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering LinkAddress *a;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Link *l;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(rtnl);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(mm);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(m);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen r = sd_rtnl_message_get_type(mm, &type);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto fail;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen if (r < 0)
cab5b05903096e1c9cf5575ccc73f89d15c8db69Lennart Poettering goto fail;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen l = hashmap_get(m->links, INT_TO_PTR(ifindex));
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen if (!l)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return 0;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen r = sd_rtnl_message_addr_get_family(mm, &family);
3e684349c2cead2e6fd2f816c34eb17daba23a49Lennart Poettering if (r < 0)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering goto fail;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen switch (family) {
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering case AF_INET:
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_LOCAL, &address.in);
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering if (r < 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto fail;
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering }
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering break;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen case AF_INET6:
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (r < 0) {
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen if (r < 0)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering goto fail;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering }
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering break;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering default:
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return 0;
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering }
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering a = link_find_address(l, family, &address);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering switch (type) {
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering case RTM_NEWADDR:
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (!a) {
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering r = link_address_new(l, &a, family, &address);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (r < 0)
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering return r;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering }
eed857b71702f8551b46b66b31fa0d08583cf23cLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering r = link_address_update_rtnl(a, mm);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (r < 0)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return r;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering break;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering case RTM_DELADDR:
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (a)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering link_address_free(a);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering break;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering }
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen return 0;
91b14d6ff362b938a72db17b095ee9903d07381bTom Gundersen
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poetteringfail:
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering log_warning("Failed to process RTNL address message: %s", strerror(-r));
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return 0;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering}
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poetteringstatic int manager_rtnl_listen(Manager *m) {
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering sd_rtnl_message *i;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering int r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering assert(m);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* First, subscibe to interfaces coming and going */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering /* Then, enumerate all links */
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering if (r < 0)
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering return r;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen if (r < 0)
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen return r;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering if (r < 0)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering for (i = reply; i; i = sd_rtnl_message_next(i)) {
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering r = manager_process_link(m->rtnl, i, m);
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering if (r < 0)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen return r;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen }
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering req = sd_rtnl_message_unref(req);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering reply = sd_rtnl_message_unref(reply);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering /* Finally, enumerate all addresses, too */
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (r < 0)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return r;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering if (r < 0)
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering return r;
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering if (r < 0)
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering return r;
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering for (i = reply; i; i = sd_rtnl_message_next(i)) {
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering r = manager_process_address(m->rtnl, i, m);
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering if (r < 0)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return r;
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering }
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return r;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering}
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering Manager *m = userdata;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering Iterator i;
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering Link *l;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering int r;
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering assert(m);
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen sd_network_monitor_flush(m->network_monitor);
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen HASHMAP_FOREACH(l, m->links, i) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = link_update_monitor(l);
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen if (r < 0)
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen log_warning("Failed to update monitor information for %i: %s", l->ifindex, strerror(-r));
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen }
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
efd46a696d31097c38f653b36921e00c4df62319Lennart Poettering r = manager_write_resolv_conf(m);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (r < 0)
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen log_warning("Could not update resolv.conf: %s", strerror(-r));
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 0;
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen}
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersenstatic int manager_network_monitor_listen(Manager *m) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering int r, fd, events;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert(m);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = sd_network_monitor_new(&m->network_monitor, NULL);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (r < 0)
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen return r;
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering fd = sd_network_monitor_get_fd(m->network_monitor);
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering if (fd < 0)
84129d46cd6e95e142973da93aede4c7433c9600Lennart Poettering return fd;
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen
9df3ba6c6cb65eecec06f39dfe85a3596cedac4eTom Gundersen events = sd_network_monitor_get_events(m->network_monitor);
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering if (events < 0)
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen return events;
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering r = sd_event_add_io(m->event, &m->network_event_source, fd, events, &on_network_event, m);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (r < 0)
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering return r;
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen return 0;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering}
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic int determine_hostname(char **ret) {
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering _cleanup_free_ char *h = NULL, *n = NULL;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering int r;
571370c1555d2aa697733479a50957aff024bbcbLennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering assert(ret);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering h = gethostname_malloc();
571370c1555d2aa697733479a50957aff024bbcbLennart Poettering if (!h)
571370c1555d2aa697733479a50957aff024bbcbLennart Poettering return log_oom();
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen if (!utf8_is_valid(h)) {
4e0b8b17a7465653f4e7b819dad5f8e30d64c0c4Tom Gundersen log_error("System hostname is not UTF-8 clean.");
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return -EINVAL;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering }
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering r = dns_name_normalize(h, &n);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r < 0) {
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering log_error("System hostname '%s' cannot be normalized.", h);
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering return r;
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering }
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering *ret = n;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering n = NULL;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return 0;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering}
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poetteringstatic int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering _cleanup_free_ char *h = NULL;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering Manager *m = userdata;
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering int r;
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering assert(m);
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering
b64513580ce627578351b76a502455e7bc62cae4Lennart Poettering r = determine_hostname(&h);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r < 0)
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering return 0; /* ignore invalid hostnames */
b652d4a2099d1c167584dcc1d179d47c58dc38a2Lennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (streq(h, m->hostname))
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen return 0;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen log_info("System hostname changed to '%s'.", h);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen free(m->hostname);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen m->hostname = h;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen h = NULL;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen manager_refresh_rrs(m);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen return 0;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen}
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersenstatic int manager_watch_hostname(Manager *m) {
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen int r;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen assert(m);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
011842775f750711833526d5bba1b818713947f5Lennart Poettering if (m->hostname_fd < 0) {
011842775f750711833526d5bba1b818713947f5Lennart Poettering log_warning("Failed to watch hostname: %m");
011842775f750711833526d5bba1b818713947f5Lennart Poettering return 0;
011842775f750711833526d5bba1b818713947f5Lennart Poettering }
011842775f750711833526d5bba1b818713947f5Lennart Poettering
011842775f750711833526d5bba1b818713947f5Lennart Poettering r = sd_event_add_io(m->event, &m->hostname_event_source, m->hostname_fd, 0, on_hostname_change, m);
011842775f750711833526d5bba1b818713947f5Lennart Poettering if (r < 0) {
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r == -EPERM)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering /* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
011842775f750711833526d5bba1b818713947f5Lennart Poettering m->hostname_fd = safe_close(m->hostname_fd);
011842775f750711833526d5bba1b818713947f5Lennart Poettering else {
011842775f750711833526d5bba1b818713947f5Lennart Poettering log_error("Failed to add hostname event source: %s", strerror(-r));
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering return r;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen }
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen }
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen r = determine_hostname(&m->hostname);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (r < 0) {
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering log_info("Defaulting to hostname 'linux'.");
011842775f750711833526d5bba1b818713947f5Lennart Poettering m->hostname = strdup("linux");
011842775f750711833526d5bba1b818713947f5Lennart Poettering if (!m->hostname)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return log_oom();
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering } else
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering log_info("Using system hostname '%s'.", m->hostname);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering return 0;
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering}
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poetteringstatic void manager_llmnr_stop(Manager *m) {
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen assert(m);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source);
6a1a5eec43892dee3ff6e208bceb1931c25c782eLennart Poettering m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering}
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poetteringstatic int manager_llmnr_start(Manager *m) {
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering int r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
6a1a5eec43892dee3ff6e208bceb1931c25c782eLennart Poettering assert(m);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (m->llmnr_support == SUPPORT_NO)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return 0;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering r = manager_llmnr_ipv4_udp_fd(m);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r == -EADDRINUSE)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering goto eaddrinuse;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r < 0)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering r = manager_llmnr_ipv4_tcp_fd(m);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r == -EADDRINUSE)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering goto eaddrinuse;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r < 0)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (socket_ipv6_is_supported()) {
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering r = manager_llmnr_ipv6_udp_fd(m);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r == -EADDRINUSE)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering goto eaddrinuse;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r < 0)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering r = manager_llmnr_ipv6_tcp_fd(m);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r == -EADDRINUSE)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering goto eaddrinuse;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering if (r < 0)
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering }
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return 0;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poetteringeaddrinuse:
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering log_warning("There appears to be another LLMNR respondering running. Turning off LLMNR support.");
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_support = SUPPORT_NO;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering manager_llmnr_stop(m);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return 0;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering}
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poetteringint manager_new(Manager **ret) {
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering _cleanup_(manager_freep) Manager *m = NULL;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering int r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering assert(ret);
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering m = new0(Manager, 1);
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering if (!m)
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering return -ENOMEM;
011842775f750711833526d5bba1b818713947f5Lennart Poettering
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering m->dns_ipv4_fd = m->dns_ipv6_fd = -1;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering m->hostname_fd = -1;
6bb2c08597c999c429e889cd2403b2fef5f3e1a0Lennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen m->llmnr_support = SUPPORT_YES;
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen m->read_resolv_conf = true;
f4461e5641d53f27d6e76e0607bdaa9c0c58c1f6Lennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (r < 0)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return r;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = sd_event_default(&m->event);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering if (r < 0)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return r;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering sd_event_set_watchdog(m->event, true);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = manager_watch_hostname(m);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering if (r < 0)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return r;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering if (r < 0)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return r;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = manager_network_monitor_listen(m);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering if (r < 0)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return r;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = manager_rtnl_listen(m);
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering if (r < 0)
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering return r;
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering
519ef04651b07a547f010d6462603669d7fde4e5Lennart Poettering r = manager_connect_bus(m);
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering if (r < 0)
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering return r;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering *ret = m;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering m = NULL;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering return 0;
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering}
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poetteringint manager_start(Manager *m) {
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering int r;
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering assert(m);
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering r = manager_llmnr_start(m);
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering if (r < 0)
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering return r;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering return 0;
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering}
de54e62b4bd7856fb897c9a2ee93cc228adb2135Lennart Poettering
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart PoetteringManager *manager_free(Manager *m) {
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering Link *l;
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering if (!m)
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering return NULL;
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering while ((l = hashmap_first(m->links)))
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering link_free(l);
92ec902aad1ade7acbe50efd7b8ef87fbdc63af3Lennart Poettering
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen while (m->dns_queries)
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering dns_query_free(m->dns_queries);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen dns_scope_free(m->unicast_scope);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen manager_flush_dns_servers(m, DNS_SERVER_SYSTEM);
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen manager_flush_dns_servers(m, DNS_SERVER_FALLBACK);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering hashmap_free(m->links);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt hashmap_free(m->dns_transactions);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering sd_event_source_unref(m->network_event_source);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering sd_network_monitor_unref(m->network_monitor);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering sd_event_source_unref(m->dns_ipv4_event_source);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering sd_event_source_unref(m->dns_ipv6_event_source);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering safe_close(m->dns_ipv4_fd);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering safe_close(m->dns_ipv6_fd);
87f5a19343acf8ba697acc5a62bdb1a2b8c9eda3Lennart Poettering
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt manager_llmnr_stop(m);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt sd_bus_slot_unref(m->prepare_for_sleep_slot);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt sd_event_source_unref(m->bus_retry_event_source);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt sd_bus_unref(m->bus);
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering sd_event_unref(m->event);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering dns_resource_key_unref(m->host_ipv4_key);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering dns_resource_key_unref(m->host_ipv6_key);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering safe_close(m->hostname_fd);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering sd_event_source_unref(m->hostname_event_source);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering free(m->hostname);
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering free(m);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return NULL;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering}
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poetteringint manager_read_resolv_conf(Manager *m) {
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering _cleanup_fclose_ FILE *f = NULL;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering struct stat st, own;
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering char line[LINE_MAX];
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering DnsServer *s, *nx;
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering usec_t t;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering int r;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering assert(m);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering /* Reads the system /etc/resolv.conf, if it exists and is not
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering * symlinked to our own resolv.conf instance */
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (!m->read_resolv_conf)
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering return 0;
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering r = stat("/etc/resolv.conf", &st);
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (r < 0) {
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering if (errno != ENOENT)
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering log_warning("Failed to open /etc/resolv.conf: %m");
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering r = -errno;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering goto clear;
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering }
636e813dc98ea40c58c6c85bc5e7e3c9f0904ea2Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering /* Have we already seen the file? */
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering t = timespec_load(&st.st_mtim);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (t == m->resolv_conf_mtime)
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering return 0;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering m->resolv_conf_mtime = t;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering /* Is it symlinked to our own file? */
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 &&
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering st.st_dev == own.st_dev &&
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering st.st_ino == own.st_ino) {
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering r = 0;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering goto clear;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering f = fopen("/etc/resolv.conf", "re");
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (!f) {
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering if (errno != ENOENT)
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering log_warning("Failed to open /etc/resolv.conf: %m");
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering r = -errno;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering goto clear;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (fstat(fileno(f), &st) < 0) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering log_error("Failed to stat open file: %m");
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering r = -errno;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering goto clear;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering
6cb08a8930bdaca950b152b1e8b82466ed59511cLennart Poettering LIST_FOREACH(servers, s, m->dns_servers)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->marked = true;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering FOREACH_LINE(line, f, r = -errno; goto clear) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering union in_addr_union address;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering int family;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering char *l;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering const char *a;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering truncate_nl(line);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering l = strstrip(line);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (*l == '#' || *l == ';')
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering continue;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering a = first_word(l, "nameserver");
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (!a)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering continue;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering r = in_addr_from_string_auto(a, &family, &address);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (r < 0) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering log_warning("Failed to parse name server %s.", a);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering continue;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering LIST_FOREACH(servers, s, m->dns_servers)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (s->family == family && in_addr_equal(family, &s->address, &address) > 0)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering break;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (s)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering s->marked = false;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering else {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &address);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (r < 0)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering goto clear;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (s->marked)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering dns_server_free(s);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return 0;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poetteringclear:
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering while (m->dns_servers)
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering dns_server_free(m->dns_servers);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return r;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering}
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poetteringstatic void write_resolve_conf_server(DnsServer *s, FILE *f, unsigned *count) {
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering _cleanup_free_ char *t = NULL;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering int r;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert(s);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert(f);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering assert(count);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering r = in_addr_to_string(s->family, &s->address, &t);
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering if (r < 0) {
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering log_warning("Invalid DNS address. Ignoring: %s", strerror(-r));
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering return;
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering }
f2f1dbe50fea13abadc9c1e845a29031b90b40f3Lennart Poettering
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen if (*count == MAXNS)
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen fprintf(f, "nameserver %s\n", t);
9c5e12a4314e7192e834e1b855e5e80111e636a6Tom Gundersen (*count) ++;
7586f4d172dd9c3ccc3126fc47dca9e49adec132Tom Gundersen}
d74fb368b18f0fbd9a4fe6f15691bbea7f3c4a01Tom Gundersen
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersenint manager_write_resolv_conf(Manager *m) {
be808ea083fa07271116b4519c3c27fd20c5f077Tom Gundersen static const char path[] = "/run/systemd/resolve/resolv.conf";
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_set_free_ Set *dns = NULL;
unsigned count = 0;
DnsServer *s;
Iterator i;
Link *l;
int r;
assert(m);
/* Read the system /etc/resolv.conf first */
manager_read_resolv_conf(m);
/* Add the full list to a set, to filter out duplicates */
dns = set_new(dns_server_hash_func, dns_server_compare_func);
if (!dns)
return -ENOMEM;
/* First add the system-wide servers */
LIST_FOREACH(servers, s, m->dns_servers) {
r = set_put(dns, s);
if (r == -EEXIST)
continue;
if (r < 0)
return r;
}
/* Then, add the per-link servers */
HASHMAP_FOREACH(l, m->links, i)
LIST_FOREACH(servers, s, l->dns_servers) {
r = set_put(dns, s);
if (r == -EEXIST)
continue;
if (r < 0)
return r;
}
/* If we found nothing, add the fallback servers */
if (set_isempty(dns)) {
LIST_FOREACH(servers, s, m->fallback_dns_servers) {
r = set_put(dns, s);
if (r == -EEXIST)
continue;
if (r < 0)
return r;
}
}
r = fopen_temporary(path, &f, &temp_path);
if (r < 0)
return r;
fchmod(fileno(f), 0644);
fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
"# Third party programs must not access this file directly, but\n"
"# only through the symlink at /etc/resolv.conf. To manage\n"
"# resolv.conf(5) in a different way, replace the symlink by a\n"
"# static file or a different symlink.\n\n", f);
if (set_isempty(dns))
fputs("# No DNS servers known.\n", f);
else {
SET_FOREACH(s, dns, i)
write_resolve_conf_server(s, f, &count);
}
r = fflush_and_check(f);
if (r < 0)
goto fail;
if (rename(temp_path, path) < 0) {
r = -errno;
goto fail;
}
return 0;
fail:
unlink(path);
unlink(temp_path);
return r;
}
int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
union {
struct cmsghdr header; /* For alignment */
uint8_t buffer[CMSG_SPACE(MAX(sizeof(struct in_pktinfo), sizeof(struct in6_pktinfo)))
+ CMSG_SPACE(int) /* ttl/hoplimit */
+ EXTRA_CMSG_SPACE /* kernel appears to require extra buffer space */];
} control;
union sockaddr_union sa;
struct msghdr mh = {};
struct cmsghdr *cmsg;
struct iovec iov;
int ms = 0, r;
ssize_t l;
assert(m);
assert(fd >= 0);
assert(ret);
r = ioctl(fd, FIONREAD, &ms);
if (r < 0)
return -errno;
if (ms < 0)
return -EIO;
r = dns_packet_new(&p, protocol, ms);
if (r < 0)
return r;
iov.iov_base = DNS_PACKET_DATA(p);
iov.iov_len = p->allocated;
mh.msg_name = &sa.sa;
mh.msg_namelen = sizeof(sa);
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
mh.msg_control = &control;
mh.msg_controllen = sizeof(control);
l = recvmsg(fd, &mh, 0);
if (l < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
return -errno;
}
if (l <= 0)
return -EIO;
assert(!(mh.msg_flags & MSG_CTRUNC));
assert(!(mh.msg_flags & MSG_TRUNC));
p->size = (size_t) l;
p->family = sa.sa.sa_family;
p->ipproto = IPPROTO_UDP;
if (p->family == AF_INET) {
p->sender.in = sa.in.sin_addr;
p->sender_port = be16toh(sa.in.sin_port);
} else if (p->family == AF_INET6) {
p->sender.in6 = sa.in6.sin6_addr;
p->sender_port = be16toh(sa.in6.sin6_port);
p->ifindex = sa.in6.sin6_scope_id;
} else
return -EAFNOSUPPORT;
for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IPV6) {
assert(p->family == AF_INET6);
switch (cmsg->cmsg_type) {
case IPV6_PKTINFO: {
struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
if (p->ifindex <= 0)
p->ifindex = i->ipi6_ifindex;
p->destination.in6 = i->ipi6_addr;
break;
}
case IPV6_HOPLIMIT:
p->ttl = *(int *) CMSG_DATA(cmsg);
break;
}
} 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 > 0 && manager_ifindex_is_loopback(m, p->ifindex) != 0)
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_ifindex_is_loopback(Manager *m, int ifindex) {
Link *l;
assert(m);
if (ifindex <= 0)
return -EINVAL;
l = hashmap_get(m->links, INT_TO_PTR(ifindex));
if (l->flags & IFF_LOOPBACK)
return 1;
return 0;
}
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);