#include <net/if_arp.h>
#include <netinet/tcp.h>
+#include "capability-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "missing_network.h"
if (s)
r = dns_stream_write_packet(s, reply);
else {
- int fd;
+ int fd, ifindex;
- fd = find_socket_fd(m, l, p->family, &p->sender, SOCK_DGRAM);
+ fd = find_socket_fd(m, l, p->family, &p->destination, SOCK_DGRAM);
if (fd < 0)
return fd;
+ if (address_is_proxy(p->family, &p->destination))
+ /* Force loopback iface if this is the loopback proxy stub
+ * and ifindex was normalized to 0 by manager_recv(). */
+ ifindex = p->ifindex ?: LOOPBACK_IFINDEX;
+ else
+ /* Force loopback iface if this is the main listener stub. */
+ ifindex = l ? p->ifindex : LOOPBACK_IFINDEX;
+
/* Note that it is essential here that we explicitly choose the source IP address for this
* packet. This is because otherwise the kernel will choose it automatically based on the
- * routing table and will thus pick 127.0.0.1 rather than 127.0.0.53. */
+ * routing table and will thus pick 127.0.0.1 rather than 127.0.0.53/54. */
r = manager_send(m,
fd,
- l || address_is_proxy(p->family, &p->destination) ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */
+ ifindex,
p->family, &p->sender, p->sender_port, &p->destination,
reply);
}
return 0;
}
-static void dns_stub_query_complete(DnsQuery *q) {
+static void dns_stub_query_complete(DnsQuery *query) {
+ _cleanup_(dns_query_freep) DnsQuery *q = query;
int r;
assert(q);
else
(void) dns_stub_send(q->manager, q->stub_listener_extra, q->request_stream, q->request_packet, reply);
- dns_query_free(q);
return;
}
}
q,
dns_query_question_for_protocol(q, DNS_PROTOCOL_DNS),
dns_stub_reply_with_edns0_do(q));
- if (r < 0) {
- log_debug_errno(r, "Failed to assign sections: %m");
- dns_query_free(q);
- return;
- }
+ if (r < 0)
+ return (void) log_debug_errno(r, "Failed to assign sections: %m");
switch (q->state) {
cname_result = dns_query_process_cname_one(q);
if (cname_result == -ELOOP) { /* CNAME loop, let's send what we already have */
- log_debug_errno(r, "Detected CNAME loop, returning what we already have.");
+ log_debug("Detected CNAME loop, returning what we already have.");
(void) dns_stub_send_reply(q, q->answer_rcode);
break;
}
* now with the redirected question. We'll */
r = dns_query_go(q);
if (r < 0)
- log_debug_errno(r, "Failed to restart query: %m");
+ return (void) log_debug_errno(r, "Failed to restart query: %m");
+ TAKE_PTR(q);
return;
}
q,
dns_query_question_for_protocol(q, DNS_PROTOCOL_DNS),
dns_stub_reply_with_edns0_do(q));
- if (r < 0) {
- log_debug_errno(r, "Failed to assign sections: %m");
- dns_query_free(q);
- return;
- }
+ if (r < 0)
+ return (void) log_debug_errno(r, "Failed to assign sections: %m");
if (cname_result == DNS_QUERY_MATCH) /* A match? Then we are done, let's return what we got */
break;
default:
assert_not_reached();
}
-
- dns_query_free(q);
}
static int dns_stub_stream_complete(DnsStream *s, int error) {
return;
}
- if (dns_type_is_zone_transer(dns_question_first_key(p->question)->type)) {
+ if (dns_type_is_zone_transfer(dns_question_first_key(p->question)->type)) {
log_debug("Got request for zone transfer, refusing.");
dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false);
return;
}
static int on_dns_stub_packet_extra(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- DnsStubListenerExtra *l = userdata;
-
- assert(l);
+ DnsStubListenerExtra *l = ASSERT_PTR(userdata);
return on_dns_stub_packet_internal(s, fd, revents, l->manager, l);
}
-static int on_dns_stub_stream_packet(DnsStream *s) {
- _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
-
+static int on_dns_stub_stream_packet(DnsStream *s, DnsPacket *p) {
assert(s);
-
- p = dns_stream_take_read_packet(s);
+ assert(s->manager);
assert(p);
if (dns_packet_validate_query(p) > 0) {
return -errno;
}
- r = dns_stream_new(m, &stream, DNS_STREAM_STUB, DNS_PROTOCOL_DNS, cfd, NULL, DNS_STREAM_STUB_TIMEOUT_USEC);
+ r = dns_stream_new(m, &stream, DNS_STREAM_STUB, DNS_PROTOCOL_DNS, cfd, NULL,
+ on_dns_stub_stream_packet, dns_stub_stream_complete, DNS_STREAM_STUB_TIMEOUT_USEC);
if (r < 0) {
safe_close(cfd);
return r;
}
stream->stub_listener_extra = l;
- stream->on_packet = on_dns_stub_stream_packet;
- stream->complete = dns_stub_stream_complete;
/* We let the reference to the stream dangle here, it will be dropped later by the complete callback. */
}
static int on_dns_stub_stream_extra(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- DnsStubListenerExtra *l = userdata;
+ DnsStubListenerExtra *l = ASSERT_PTR(userdata);
- assert(l);
return on_dns_stub_stream_internal(s, fd, revents, l->manager, l);
}
int type) {
sd_event_source **event_source;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
union sockaddr_union sa;
int r;
return -errno;
if (type == SOCK_STREAM &&
- listen(fd, SOMAXCONN) < 0)
+ listen(fd, SOMAXCONN_DELUXE) < 0)
return -errno;
r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int type) {
_cleanup_free_ char *pretty = NULL;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
union sockaddr_union sa;
int r;
if (*event_source)
return sd_event_source_get_io_fd(*event_source);
+ if (!have_effective_cap(CAP_NET_BIND_SERVICE) && dns_stub_listener_extra_port(l) < 1024) {
+ log_warning("Missing CAP_NET_BIND_SERVICE capability, not creating extra stub listener on port %hu.",
+ dns_stub_listener_extra_port(l));
+ return 0;
+ }
+
if (l->family == AF_INET)
sa = (union sockaddr_union) {
.in.sin_family = l->family,
goto fail;
if (type == SOCK_STREAM &&
- listen(fd, SOMAXCONN) < 0) {
+ listen(fd, SOMAXCONN_DELUXE) < 0) {
r = -errno;
goto fail;
}
if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_NO)
log_debug("Not creating stub listener.");
+ else if (!have_effective_cap(CAP_NET_BIND_SERVICE))
+ log_warning("Missing CAP_NET_BIND_SERVICE capability, not creating stub listener on port 53.");
else {
static const struct {
uint32_t addr;