/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <net/if_arp.h>
+
#include "sd-messages.h"
#include "alloc-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
#include "resolved-bus.h"
#include "resolved-dns-server.h"
#include "resolved-dns-stub.h"
#include "resolved-manager.h"
#include "resolved-resolv-conf.h"
#include "siphash24.h"
+#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
.ifindex = ifindex,
.server_name = TAKE_PTR(name),
.config_source = config_source,
+ .accessible = -1,
};
dns_server_reset_features(s);
SD_JSON_BUILD_PAIR_BOOLEAN("PacketInvalid", server->packet_invalid),
SD_JSON_BUILD_PAIR_BOOLEAN("PacketDoOff", server->packet_do_off));
}
+
+int dns_server_is_accessible(DnsServer *s) {
+ _cleanup_close_ int fd = -EBADF;
+ union sockaddr_union sa;
+ int r;
+
+ assert(s);
+
+ if (s->accessible >= 0)
+ return s->accessible;
+
+ r = sockaddr_set_in_addr(&sa, s->family, &s->address, dns_server_port(s));
+ if (r < 0)
+ return r;
+
+ fd = socket(s->family, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return -errno;
+
+ if (s->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &s->address)) {
+ /* Connecting to ipv6 link-local requires binding to an interface. */
+ r = socket_bind_to_ifindex(fd, dns_server_ifindex(s));
+ if (r < 0)
+ return r;
+ }
+
+ r = RET_NERRNO(connect(fd, &sa.sa, SOCKADDR_LEN(sa)));
+ if (!IN_SET(r,
+ 0,
+ -ENETUNREACH,
+ -EHOSTDOWN,
+ -EHOSTUNREACH,
+ -ENETDOWN,
+ -ENETRESET,
+ -ENONET))
+ /* If we did not receive one of the expected return values,
+ * then leave the accessible flag untouched. */
+ return r;
+
+ return (s->accessible = r >= 0);
+}
+
+void dns_server_reset_accessible_all(DnsServer *first) {
+ LIST_FOREACH(servers, s, first)
+ dns_server_reset_accessible(s);
+}
/* Servers registered via D-Bus are not removed on reload */
ResolveConfigSource config_source;
+
+ /* Tri-state to indicate if the DNS server is accessible. */
+ int accessible;
};
int dns_server_new(
}
int dns_server_dump_state_to_json(DnsServer *server, sd_json_variant **ret);
+
+int dns_server_is_accessible(DnsServer *s);
+static inline void dns_server_reset_accessible(DnsServer *s) {
+ s->accessible = -1;
+}
+void dns_server_reset_accessible_all(DnsServer *first);