resolved-manager.c revision ec2c5e4398f9d65e5dfe61530f2556224733d1e6
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering This file is part of systemd.
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering Copyright 2014 Tom Gundersen <teg@jklm.no>
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering (at your option) any later version.
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering systemd is distributed in the hope that it will be useful, but
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering Lesser General Public License for more details.
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d7bd3de0654669e65b9642c248c5fa6d1d9a9f61Lennart Poettering#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
7027ff61a34a12487712b382a061c654acc3a679Lennart Poetteringstatic int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
d7bd3de0654669e65b9642c248c5fa6d1d9a9f61Lennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
374ec6abf31ada6ca554cc8ea99b282373fac010Lennart Poettering log_debug("Found new link %i/%s", ifindex, l->name);
d7bd3de0654669e65b9642c248c5fa6d1d9a9f61Lennart Poettering log_debug("Removing link %i/%s", l->ifindex, l->name);
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering log_warning("Failed to process RTNL link message: %s", strerror(-r));
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poetteringstatic int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering l = hashmap_get(m->links, INT_TO_PTR(ifindex));
374ec6abf31ada6ca554cc8ea99b282373fac010Lennart Poettering r = sd_rtnl_message_addr_get_family(mm, &family);
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_LOCAL, &address.in);
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering r = sd_rtnl_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poettering r = sd_rtnl_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poettering a = link_find_address(l, family, &address);
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poettering r = link_address_new(l, &a, family, &address);
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poettering log_warning("Failed to process RTNL address message: %s", strerror(-r));
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poetteringstatic int manager_rtnl_listen(Manager *m) {
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering /* First, subscibe to interfaces coming and going */
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
a0ab566574303be1ca12cdb334f284cfd407caa5Lennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poettering r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poettering /* Then, enumerate all links */
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poettering r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
a016b9228f338cb9b380ce7e00826ef462767d98Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
a016b9228f338cb9b380ce7e00826ef462767d98Lennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
a016b9228f338cb9b380ce7e00826ef462767d98Lennart Poettering for (i = reply; i; i = sd_rtnl_message_next(i)) {
7027ff61a34a12487712b382a061c654acc3a679Lennart Poettering /* Finally, enumerate all addresses, too */
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
9444b1f20e311f073864d81e913bd4f32fe95cfdLennart Poettering r = sd_rtnl_message_request_dump(req, true);
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poettering r = sd_rtnl_call(m->rtnl, req, 0, &reply);
96cde13ace6406582688028f3df5668a172ba628Zbigniew Jędrzejewski-Szmek for (i = reply; i; i = sd_rtnl_message_next(i)) {
Iterator i;
Link *l;
assert(m);
r = link_update_monitor(l);
r = manager_write_resolv_conf(m);
assert(m);
if (fd < 0)
return fd;
if (events < 0)
return events;
assert(m);
int family;
int config_parse_dnsv(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
assert(m);
while (m->dns_servers)
assert(m);
return -ENOMEM;
m->use_llmnr = true;
if (!m->hostname)
return -ENOMEM;
r = manager_network_monitor_listen(m);
r = manager_rtnl_listen(m);
r = manager_connect_bus(m);
r = manager_llmnr_ipv4_udp_fd(m);
r = manager_llmnr_ipv6_udp_fd(m);
r = manager_llmnr_ipv4_tcp_fd(m);
r = manager_llmnr_ipv6_tcp_fd(m);
*ret = m;
m = NULL;
Link *l;
return NULL;
while (m->dns_queries)
link_free(l);
while (m->dns_servers)
free(m);
return NULL;
assert(s);
assert(f);
(*count) ++;
unsigned count = 0;
DnsServer *s;
Iterator i;
Link *l;
assert(m);
"# only through the symlink at /etc/resolv.conf. To manage\n"
"# resolv.conf(5) in a different way, replace the symlink by a\n"
r = fflush_and_check(f);
goto fail;
r = -errno;
goto fail;
fail:
} control;
int ms = 0, r;
ssize_t l;
assert(m);
return -errno;
if (ms < 0)
return -EIO;
return -errno;
return -EIO;
return -EAFNOSUPPORT;
case IPV6_PKTINFO: {
if (p->ifindex <= 0)
case IPV6_HOPLIMIT:
case IP_PKTINFO: {
if (p->ifindex <= 0)
case IP_TTL:
p->ifindex = 0;
if (p->ifindex <= 0)
*ret = p;
p = NULL;
if (dns_packet_validate_reply(p) > 0) {
assert(m);
if (m->dns_ipv4_fd >= 0)
return m->dns_ipv4_fd;
if (m->dns_ipv4_fd < 0)
return -errno;
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);
goto fail;
return m->dns_ipv4_fd;
fail:
assert(m);
if (m->dns_ipv6_fd >= 0)
return m->dns_ipv6_fd;
if (m->dns_ipv6_fd < 0)
return -errno;
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);
goto fail;
return m->dns_ipv6_fd;
fail:
return -errno;
return -ETIMEDOUT;
static int manager_ipv4_send(Manager *m, int fd, int ifindex, const struct in_addr *addr, uint16_t port, DnsPacket *p) {
} control;
assert(m);
assert(p);
if (ifindex > 0) {
static int manager_ipv6_send(Manager *m, int fd, int ifindex, const struct in6_addr *addr, uint16_t port, DnsPacket *p) {
} control;
assert(m);
assert(p);
if (ifindex > 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(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));
return -EAFNOSUPPORT;
DnsServer *s;
assert(m);
return NULL;
assert(m);
if (!m->current_dns_server)
return m->current_dns_server;
assert(m);
if (!m->current_dns_server) {
if (!m->current_dns_server)
Link *l;
Iterator i;
if (l->mtu <= 0)
return mtu;
if (dns_packet_validate_reply(p) > 0) {
} else if (dns_packet_validate_query(p) > 0) {
Link *l;
if (scope)
assert(m);
if (m->llmnr_ipv4_udp_fd >= 0)
return m->llmnr_ipv4_udp_fd;
if (m->llmnr_ipv4_udp_fd < 0)
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m);
goto fail;
return m->llmnr_ipv4_udp_fd;
fail:
assert(m);
if (m->llmnr_ipv6_udp_fd >= 0)
return m->llmnr_ipv6_udp_fd;
if (m->llmnr_ipv6_udp_fd < 0)
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m);
r = -errno;
goto fail;
return m->llmnr_ipv6_udp_fd;
fail:
assert(s);
Link *l;
if (scope) {
if (s->write_packet)
dns_stream_free(s);
int cfd, r;
if (cfd < 0) {
return -errno;
assert(m);
if (m->llmnr_ipv4_tcp_fd >= 0)
return m->llmnr_ipv4_tcp_fd;
if (m->llmnr_ipv4_tcp_fd < 0)
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m);
goto fail;
return m->llmnr_ipv4_tcp_fd;
fail:
assert(m);
if (m->llmnr_ipv6_tcp_fd >= 0)
return m->llmnr_ipv6_tcp_fd;
if (m->llmnr_ipv6_tcp_fd < 0)
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m);
r = -errno;
goto fail;
return m->llmnr_ipv6_tcp_fd;
fail:
Link *l;
assert(m);
if (ifindex <= 0)
return -EINVAL;
LinkAddress *a;
assert(m);
Iterator i;
uint64_t u;
Link *l;
assert(m);
assert(p);
while (p > m->hostname) {
if (*p == 0 || safe_atou64(p, &u) < 0 || u <= 0)
return -ENOMEM;
m->hostname = h;
link_add_rrs(l, true);
link_add_rrs(l, false);
Iterator i;
Link *l;
assert(m);
LinkAddress *a;
return NULL;
assert(m);
assert(p);