]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/resolve/resolved-manager.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / resolve / resolved-manager.c
index 6b32ee4cf07b6faada3d56ae60bb018e37064752..6c6c98566f1b28ad07b925e5d14faaea772eae32 100644 (file)
@@ -13,6 +13,7 @@
 #include "bus-polkit.h"
 #include "dirent-util.h"
 #include "dns-domain.h"
+#include "event-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
 #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
 
 static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         uint16_t type;
         Link *l;
         int ifindex, r;
 
         assert(rtnl);
-        assert(m);
         assert(mm);
 
         r = sd_netlink_message_get_type(mm, &type);
@@ -105,7 +105,7 @@ fail:
 }
 
 static int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         union in_addr_union address;
         uint16_t type;
         int r, ifindex, family;
@@ -114,7 +114,6 @@ static int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, voi
 
         assert(rtnl);
         assert(mm);
-        assert(m);
 
         r = sd_netlink_message_get_type(mm, &type);
         if (r < 0)
@@ -190,7 +189,6 @@ fail:
 
 static int manager_rtnl_listen(Manager *m) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-        sd_netlink_message *i;
         int r;
 
         assert(m);
@@ -225,7 +223,7 @@ static int manager_rtnl_listen(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_request_dump(req, true);
+        r = sd_netlink_message_set_request_dump(req, true);
         if (r < 0)
                 return r;
 
@@ -233,7 +231,7 @@ static int manager_rtnl_listen(Manager *m) {
         if (r < 0)
                 return r;
 
-        for (i = reply; i; i = sd_netlink_message_next(i)) {
+        for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
                 r = manager_process_link(m->rtnl, i, m);
                 if (r < 0)
                         return r;
@@ -247,7 +245,7 @@ static int manager_rtnl_listen(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_message_request_dump(req, true);
+        r = sd_netlink_message_set_request_dump(req, true);
         if (r < 0)
                 return r;
 
@@ -255,7 +253,7 @@ static int manager_rtnl_listen(Manager *m) {
         if (r < 0)
                 return r;
 
-        for (i = reply; i; i = sd_netlink_message_next(i)) {
+        for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
                 r = manager_process_address(m->rtnl, i, m);
                 if (r < 0)
                         return r;
@@ -265,12 +263,10 @@ static int manager_rtnl_listen(Manager *m) {
 }
 
 static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         Link *l;
         int r;
 
-        assert(m);
-
         sd_network_monitor_flush(m->network_monitor);
 
         HASHMAP_FOREACH(l, m->links) {
@@ -318,9 +314,7 @@ static int manager_network_monitor_listen(Manager *m) {
 static int manager_clock_change_listen(Manager *m);
 
 static int on_clock_change(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
-        Manager *m = userdata;
-
-        assert(m);
+        Manager *m = ASSERT_PTR(userdata);
 
         /* The clock has changed, let's flush all caches. Why that? That's because DNSSEC validation takes
          * the system clock into consideration, and if the clock changes the old validations might have been
@@ -338,28 +332,16 @@ static int on_clock_change(sd_event_source *source, int fd, uint32_t revents, vo
 }
 
 static int manager_clock_change_listen(Manager *m) {
-        _cleanup_close_ int fd = -1;
         int r;
 
         assert(m);
 
         m->clock_change_event_source = sd_event_source_disable_unref(m->clock_change_event_source);
 
-        fd = time_change_fd();
-        if (fd < 0)
-                return log_error_errno(fd, "Failed to allocate clock change timer fd: %m");
-
-        r = sd_event_add_io(m->event, &m->clock_change_event_source, fd, EPOLLIN, on_clock_change, m);
+        r = event_add_time_change(m->event, &m->clock_change_event_source, on_clock_change, m);
         if (r < 0)
                 return log_error_errno(r, "Failed to create clock change event source: %m");
 
-        r = sd_event_source_set_io_fd_own(m->clock_change_event_source, true);
-        if (r < 0)
-                return log_error_errno(r, "Failed to pass ownership of clock fd to event source: %m");
-        TAKE_FD(fd);
-
-        (void) sd_event_source_set_description(m->clock_change_event_source, "clock-change");
-
         return 0;
 }
 
@@ -438,12 +420,10 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
 
 static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
         _cleanup_free_ char *full_hostname = NULL, *llmnr_hostname = NULL, *mdns_hostname = NULL;
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         bool llmnr_hostname_changed;
         int r;
 
-        assert(m);
-
         r = determine_hostnames(&full_hostname, &llmnr_hostname, &mdns_hostname);
         if (r < 0) {
                 log_warning_errno(r, "Failed to determine the local hostname and LLMNR/mDNS names, ignoring: %m");
@@ -513,15 +493,12 @@ static int manager_watch_hostname(Manager *m) {
 static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
         _cleanup_free_ char *buffer = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        Manager *m = userdata;
-        DnsServer *server;
+        Manager *m = ASSERT_PTR(userdata);
         size_t size = 0;
-        DnsScope *scope;
         Link *l;
 
         assert(s);
         assert(si);
-        assert(m);
 
         f = open_memstream_unlocked(&buffer, &size);
         if (!f)
@@ -546,11 +523,10 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
 }
 
 static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
 
         assert(s);
         assert(si);
-        assert(m);
 
         manager_flush_caches(m, LOG_INFO);
 
@@ -558,11 +534,10 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si
 }
 
 static int manager_sigrtmin1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
 
         assert(s);
         assert(si);
-        assert(m);
 
         manager_reset_server_features(m);
         return 0;
@@ -579,13 +554,13 @@ int manager_new(Manager **ret) {
                 return -ENOMEM;
 
         *m = (Manager) {
-                .llmnr_ipv4_udp_fd = -1,
-                .llmnr_ipv6_udp_fd = -1,
-                .llmnr_ipv4_tcp_fd = -1,
-                .llmnr_ipv6_tcp_fd = -1,
-                .mdns_ipv4_fd = -1,
-                .mdns_ipv6_fd = -1,
-                .hostname_fd = -1,
+                .llmnr_ipv4_udp_fd = -EBADF,
+                .llmnr_ipv6_udp_fd = -EBADF,
+                .llmnr_ipv4_tcp_fd = -EBADF,
+                .llmnr_ipv6_tcp_fd = -EBADF,
+                .mdns_ipv4_fd = -EBADF,
+                .mdns_ipv6_fd = -EBADF,
+                .hostname_fd = -EBADF,
 
                 .llmnr_support = DEFAULT_LLMNR_MODE,
                 .mdns_support = DEFAULT_MDNS_MODE,
@@ -816,7 +791,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
         } else
                 return -EAFNOSUPPORT;
 
-        p->timestamp = now(clock_boottime_or_monotonic());
+        p->timestamp = now(CLOCK_BOOTTIME);
 
         CMSG_FOREACH(cmsg, &mh) {
 
@@ -883,64 +858,66 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
                         p->ifindex = manager_find_ifindex(m, p->family, &p->destination);
         }
 
-        if (DEBUG_LOGGING) {
-                _cleanup_free_ char *sender_address = NULL, *destination_address = NULL;
-
-                (void) in_addr_to_string(p->family, &p->sender, &sender_address);
-                (void) in_addr_to_string(p->family, &p->destination, &destination_address);
-
-                log_debug("Received %s UDP packet of size %zu, ifindex=%i, ttl=%i, fragsize=%zu, sender=%s, destination=%s",
-                          dns_protocol_to_string(protocol), p->size, p->ifindex, p->ttl, p->fragsize,
-                          strna(sender_address), strna(destination_address));
-        }
+        log_debug("Received %s UDP packet of size %zu, ifindex=%i, ttl=%u, fragsize=%zu, sender=%s, destination=%s",
+                  dns_protocol_to_string(protocol), p->size, p->ifindex, p->ttl, p->fragsize,
+                  IN_ADDR_TO_STRING(p->family, &p->sender),
+                  IN_ADDR_TO_STRING(p->family, &p->destination));
 
         *ret = TAKE_PTR(p);
         return 1;
 }
 
 static int sendmsg_loop(int fd, struct msghdr *mh, int flags) {
+        usec_t end;
         int r;
 
         assert(fd >= 0);
         assert(mh);
 
+        end = usec_add(now(CLOCK_MONOTONIC), SEND_TIMEOUT_USEC);
+
         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)
+                r = fd_wait_for_event(fd, POLLOUT, LESS_BY(end, now(CLOCK_MONOTONIC)));
+                if (r < 0) {
+                        if (ERRNO_IS_TRANSIENT(r))
+                                continue;
                         return r;
+                }
                 if (r == 0)
                         return -ETIMEDOUT;
         }
 }
 
 static int write_loop(int fd, void *message, size_t length) {
+        usec_t end;
         int r;
 
         assert(fd >= 0);
         assert(message);
 
+        end = usec_add(now(CLOCK_MONOTONIC), SEND_TIMEOUT_USEC);
+
         for (;;) {
                 if (write(fd, message, length) >= 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)
+                r = fd_wait_for_event(fd, POLLOUT, LESS_BY(end, now(CLOCK_MONOTONIC)));
+                if (r < 0) {
+                        if (ERRNO_IS_TRANSIENT(r))
+                                continue;
                         return r;
+                }
                 if (r == 0)
                         return -ETIMEDOUT;
         }
@@ -1073,6 +1050,103 @@ static int manager_ipv6_send(
         return sendmsg_loop(fd, &mh, 0);
 }
 
+static int dns_question_to_json(DnsQuestion *q, JsonVariant **ret) {
+        _cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
+        DnsResourceKey *key;
+        int r;
+
+        assert(ret);
+
+        DNS_QUESTION_FOREACH(key, q) {
+                _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+                r = dns_resource_key_to_json(key, &v);
+                if (r < 0)
+                        return r;
+
+                r = json_variant_append_array(&l, v);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(l);
+        return 0;
+}
+
+int manager_monitor_send(
+                Manager *m,
+                int state,
+                int rcode,
+                int error,
+                DnsQuestion *question_idna,
+                DnsQuestion *question_utf8,
+                DnsQuestion *collected_questions,
+                DnsAnswer *answer) {
+
+        _cleanup_(json_variant_unrefp) JsonVariant *jquestion = NULL, *jcollected_questions = NULL, *janswer = NULL;
+        _cleanup_(dns_question_unrefp) DnsQuestion *merged = NULL;
+        Varlink *connection;
+        DnsAnswerItem *rri;
+        int r;
+
+        assert(m);
+
+        if (set_isempty(m->varlink_subscription))
+                return 0;
+
+        /* Merge both questions format into one */
+        r = dns_question_merge(question_idna, question_utf8, &merged);
+        if (r < 0)
+                return log_error_errno(r, "Failed to merge UTF8/IDNA questions: %m");
+
+        /* Convert the current primary question to JSON */
+        r = dns_question_to_json(merged, &jquestion);
+        if (r < 0)
+                return log_error_errno(r, "Failed to convert question to JSON: %m");
+
+        /* Generate a JSON array of the questions preceding the current one in the CNAME chain */
+        r = dns_question_to_json(collected_questions, &jcollected_questions);
+        if (r < 0)
+                return log_error_errno(r, "Failed to convert question to JSON: %m");
+
+        DNS_ANSWER_FOREACH_ITEM(rri, answer) {
+                _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
+
+                r = dns_resource_record_to_json(rri->rr, &v);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to convert answer resource record to JSON: %m");
+
+                r = dns_resource_record_to_wire_format(rri->rr, /* canonical= */ false); /* don't use DNSSEC canonical format, since it removes casing, but we want that for DNS_SD compat */
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate RR wire format: %m");
+
+                r = json_build(&w, JSON_BUILD_OBJECT(
+                                               JSON_BUILD_PAIR_CONDITION(v, "rr", JSON_BUILD_VARIANT(v)),
+                                               JSON_BUILD_PAIR("raw", JSON_BUILD_BASE64(rri->rr->wire_format, rri->rr->wire_format_size)),
+                                               JSON_BUILD_PAIR_CONDITION(rri->ifindex > 0, "ifindex", JSON_BUILD_INTEGER(rri->ifindex))));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to make answer RR object: %m");
+
+                r = json_variant_append_array(&janswer, w);
+                if (r < 0)
+                        return log_debug_errno(r, "Failed to append notification entry to array: %m");
+        }
+
+        SET_FOREACH(connection, m->varlink_subscription) {
+                r = varlink_notifyb(connection,
+                                    JSON_BUILD_OBJECT(JSON_BUILD_PAIR("state", JSON_BUILD_STRING(dns_transaction_state_to_string(state))),
+                                                      JSON_BUILD_PAIR_CONDITION(state == DNS_TRANSACTION_RCODE_FAILURE, "rcode", JSON_BUILD_INTEGER(rcode)),
+                                                      JSON_BUILD_PAIR_CONDITION(state == DNS_TRANSACTION_ERRNO, "errno", JSON_BUILD_INTEGER(error)),
+                                                      JSON_BUILD_PAIR("question", JSON_BUILD_VARIANT(jquestion)),
+                                                      JSON_BUILD_PAIR_CONDITION(jcollected_questions, "collectedQuestions", JSON_BUILD_VARIANT(jcollected_questions)),
+                                                      JSON_BUILD_PAIR_CONDITION(janswer, "answer", JSON_BUILD_VARIANT(janswer))));
+                if (r < 0)
+                        log_debug_errno(r, "Failed to send monitor event, ignoring: %m");
+        }
+
+        return 0;
+}
+
 int manager_send(
                 Manager *m,
                 int fd,
@@ -1182,7 +1256,7 @@ static int manager_next_random_name(const char *old, char **ret_new) {
         assert(p);
 
         while (p > old) {
-                if (!strchr(DIGITS, p[-1]))
+                if (!ascii_isdigit(p[-1]))
                         break;
 
                 p--;
@@ -1316,8 +1390,6 @@ DnsScope* manager_find_scope(Manager *m, DnsPacket *p) {
 }
 
 void manager_verify_all(Manager *m) {
-        DnsScope *s;
-
         assert(m);
 
         LIST_FOREACH(scopes, s, m->dns_scopes)
@@ -1349,7 +1421,6 @@ int manager_is_own_hostname(Manager *m, const char *name) {
 }
 
 int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
-        DnsServer *s;
         Link *l;
         int r;
 
@@ -1400,7 +1471,6 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
  *   > 0 or true: return only domains which are for routing only
  */
 int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_route) {
-        DnsSearchDomain *d;
         Link *l;
         int r;
 
@@ -1512,8 +1582,6 @@ bool manager_routable(Manager *m) {
 }
 
 void manager_flush_caches(Manager *m, int log_level) {
-        DnsScope *scope;
-
         assert(m);
 
         LIST_FOREACH(scopes, scope, m->dns_scopes)
@@ -1536,7 +1604,6 @@ void manager_reset_server_features(Manager *m) {
 
 void manager_cleanup_saved_user(Manager *m) {
         _cleanup_closedir_ DIR *d = NULL;
-        struct dirent *de;
 
         assert(m);