}
#define CANCEL_REWINDER(rewinder) do { (rewinder).packet = NULL; } while (0)
+uint16_t dns_packet_rcode(DnsPacket *p) {
+ uint16_t rcode;
+
+ assert(p);
+
+ if (p->opt)
+ rcode = (uint16_t) ((p->opt->ttl >> 20) & 0xFF0);
+ else
+ rcode = 0;
+
+ return rcode | (be16toh(DNS_PACKET_HEADER(p)->flags) & 0xF);
+};
+
+uint16_t dns_packet_payload_size_max(DnsPacket *p) {
+ assert(p);
+
+ /* Returns the advertised maximum size for replies, or the DNS default if there's nothing defined. */
+
+ if (p->ipproto == IPPROTO_TCP) /* we ignore EDNS(0) size data on TCP, like everybody else */
+ return DNS_PACKET_SIZE_MAX;
+
+ if (p->opt)
+ return MAX(DNS_PACKET_UNICAST_SIZE_MAX, p->opt->key->class);
+
+ return DNS_PACKET_UNICAST_SIZE_MAX;
+}
+
+bool dns_packet_do(DnsPacket *p) {
+ assert(p);
+
+ if (!p->opt)
+ return false;
+
+ return !!(p->opt->ttl & (1U << 15));
+}
+
+bool dns_packet_version_supported(DnsPacket *p) {
+ assert(p);
+
+ /* Returns true if this packet is in a version we support. Which means either non-EDNS or EDNS(0), but not EDNS
+ * of any newer versions */
+
+ if (!p->opt)
+ return true;
+
+ return DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(p->opt);
+}
+
int dns_packet_new(
DnsPacket **ret,
DnsProtocol protocol,
case DNS_PROTOCOL_MDNS:
/* RFC 6762, Section 18 */
- if (DNS_PACKET_RCODE(p) != 0)
+ if (dns_packet_rcode(p) != 0)
return -EBADMSG;
break;
/* RFC 6762, Section 18 specifies that messages with non-zero RCODE
* must be silently ignored, and that we must ignore the values of
* AA, RD, RA, AD, and CD bits. */
- if (DNS_PACKET_RCODE(p) != 0)
+ if (dns_packet_rcode(p) != 0)
return -EBADMSG;
break;
#define DNS_PACKET_FLAG_AD (UINT16_C(1) << 5)
#define DNS_PACKET_FLAG_TC (UINT16_C(1) << 9)
-static inline uint16_t DNS_PACKET_RCODE(DnsPacket *p) {
- uint16_t rcode;
-
- if (p->opt)
- rcode = (uint16_t) ((p->opt->ttl >> 20) & 0xFF0);
- else
- rcode = 0;
-
- return rcode | (be16toh(DNS_PACKET_HEADER(p)->flags) & 0xF);
-}
-
-static inline uint16_t DNS_PACKET_PAYLOAD_SIZE_MAX(DnsPacket *p) {
-
- /* Returns the advertised maximum size for replies, or the DNS default if there's nothing defined. */
-
- if (p->ipproto == IPPROTO_TCP) /* we ignore EDNS(0) size data on TCP, like everybody else */
- return DNS_PACKET_SIZE_MAX;
-
- if (p->opt)
- return MAX(DNS_PACKET_UNICAST_SIZE_MAX, p->opt->key->class);
-
- return DNS_PACKET_UNICAST_SIZE_MAX;
-}
-
-static inline bool DNS_PACKET_DO(DnsPacket *p) {
- if (!p->opt)
- return false;
-
- return !!(p->opt->ttl & (1U << 15));
-}
-
-static inline bool DNS_PACKET_VERSION_SUPPORTED(DnsPacket *p) {
- /* Returns true if this packet is in a version we support. Which means either non-EDNS or EDNS(0), but not EDNS
- * of any newer versions */
-
- if (!p->opt)
- return true;
-
- return DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(p->opt);
-}
+uint16_t dns_packet_rcode(DnsPacket *p);
+uint16_t dns_packet_payload_size_max(DnsPacket *p);
+bool dns_packet_do(DnsPacket *p);
+bool dns_packet_version_supported(DnsPacket *p);
static inline bool DNS_PACKET_IS_FRAGMENTED(DnsPacket *p) {
assert(p);
* ourselves, or consider the data fully authenticated because we generated it locally, or the client
* set cd */
- return DNS_PACKET_DO(q->request_packet) &&
+ return dns_packet_do(q->request_packet) &&
(q->answer_dnssec_result >= 0 || /* we did proper DNSSEC validation … */
dns_query_fully_authenticated(q) || /* … or we considered it authentic otherwise … */
DNS_PACKET_CD(q->request_packet)); /* … or client set CD */
r = dns_stub_make_reply_packet(
&reply,
- DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_packet),
+ dns_packet_payload_size_max(q->request_packet),
q->request_packet->question,
&truncated);
if (r < 0)
DNS_PACKET_RD(q->request_packet),
!!q->request_packet->opt,
edns0_do,
- (DNS_PACKET_AD(q->request_packet) || DNS_PACKET_DO(q->request_packet)) && dns_query_fully_authenticated(q),
+ (DNS_PACKET_AD(q->request_packet) || dns_packet_do(q->request_packet)) && dns_query_fully_authenticated(q),
FLAGS_SET(q->flags, SD_RESOLVED_NO_VALIDATE),
q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra);
r = dns_stub_make_reply_packet(
&reply,
- DNS_PACKET_PAYLOAD_SIZE_MAX(p),
+ dns_packet_payload_size_max(p),
p->question,
&truncated);
if (r < 0)
false,
DNS_PACKET_RD(p),
!!p->opt,
- DNS_PACKET_DO(p),
- (DNS_PACKET_AD(p) || DNS_PACKET_DO(p)) && authenticated,
+ dns_packet_do(p),
+ (DNS_PACKET_AD(p) || dns_packet_do(p)) && authenticated,
DNS_PACKET_CD(p),
l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX,
dns_packet_has_nsid_request(p) > 0 && !l);
/* Our upstream connection might have supported larger DNS requests than our downstream one, hence
* set the TC bit if our reply is larger than what the client supports, and truncate. */
- if (c->size > DNS_PACKET_PAYLOAD_SIZE_MAX(request)) {
+ if (c->size > dns_packet_payload_size_max(request)) {
log_debug("Artificially truncating stub response, as advertised size of client is smaller than upstream one.");
- dns_packet_truncate(c, DNS_PACKET_PAYLOAD_SIZE_MAX(request));
+ dns_packet_truncate(c, dns_packet_payload_size_max(request));
DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) | DNS_PACKET_FLAG_TC);
}
return;
}
- if (!DNS_PACKET_VERSION_SUPPORTED(p)) {
+ if (!dns_packet_version_supported(p)) {
log_debug("Got EDNS OPT field with unsupported version number.");
dns_stub_send_failure(m, l, s, p, DNS_RCODE_BADVERS, false);
return;
log_debug("Got request to DNS proxy address 127.0.0.54, enabling bypass logic.");
bypass = true;
protocol_flags = SD_RESOLVED_DNS|SD_RESOLVED_NO_ZONE; /* Turn off mDNS/LLMNR for proxy stub. */
- } else if (DNS_PACKET_DO(p)) {
+ } else if (dns_packet_do(p)) {
log_debug("Got request with DNSSEC enabled, enabling bypass logic.");
bypass = true;
}
protocol_flags|
SD_RESOLVED_NO_SEARCH|
(DNS_PACKET_CD(p) ? SD_RESOLVED_NO_VALIDATE | SD_RESOLVED_NO_CACHE : 0)|
- (DNS_PACKET_DO(p) ? SD_RESOLVED_REQUIRE_PRIMARY : 0)|
+ (dns_packet_do(p) ? SD_RESOLVED_REQUIRE_PRIMARY : 0)|
SD_RESOLVED_CLAMP_TTL);
if (r == -ENOANO) /* Refuse query if there is -ENOANO */
return (void) dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false);
t->answer_rcode,
t->answer,
/* If neither DO nor EDE is set, the full packet isn't useful to cache */
- DNS_PACKET_DO(t->received) || t->answer_ede_rcode > 0 || t->answer_ede_msg ? t->received : NULL,
+ dns_packet_do(t->received) || t->answer_ede_rcode > 0 || t->answer_ede_msg ? t->received : NULL,
t->answer_query_flags,
t->answer_dnssec_result,
t->answer_nsec_ttl,
* server returns a failure response code. This ensures a more accurate count of the number of queries
* that received a failure response code, as it doesn't consider retries. */
- if (t->n_attempts == 1 && !IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN))
+ if (t->n_attempts == 1 && !IN_SET(dns_packet_rcode(p), DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN))
t->scope->manager->n_failure_responses_total++;
/* Note that this call might invalidate the query. Callers
log_debug("Processing incoming packet of size %zu on transaction %" PRIu16" (rcode=%s).",
p->size,
- t->id, FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)));
+ t->id, FORMAT_DNS_RCODE(dns_packet_rcode(p)));
switch (t->scope->protocol) {
(void) dns_packet_ede_rcode(p, &t->answer_ede_rcode, &t->answer_ede_msg);
if (!t->bypass &&
- IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) {
+ IN_SET(dns_packet_rcode(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) {
/* If the server has replied with detailed error data, using a degraded feature set
* will likely not help anyone. Examine the detailed error to determine the best
* course of action. */
- if (t->answer_ede_rcode >= 0 && DNS_PACKET_RCODE(p) == DNS_RCODE_SERVFAIL) {
+ if (t->answer_ede_rcode >= 0 && dns_packet_rcode(p) == DNS_RCODE_SERVFAIL) {
/* These codes are related to DNSSEC configuration errors. If accurate,
* this is the domain operator's problem, and retrying won't help. */
if (dns_ede_rcode_is_dnssec(t->answer_ede_rcode)) {
log_debug("Server returned error: %s (%s%s%s). Lookup failed.",
- FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
+ FORMAT_DNS_RCODE(dns_packet_rcode(p)),
FORMAT_DNS_EDE_RCODE(t->answer_ede_rcode),
isempty(t->answer_ede_msg) ? "" : ": ",
strempty(t->answer_ede_msg));
/* These codes probably indicate a transient error. Let's try again. */
if (t->answer_ede_rcode == DNS_EDE_RCODE_NOT_READY) {
log_debug("Server returned error: %s (%s%s%s), retrying transaction.",
- FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
+ FORMAT_DNS_RCODE(dns_packet_rcode(p)),
FORMAT_DNS_EDE_RCODE(t->answer_ede_rcode),
isempty(t->answer_ede_msg) ? "" : ": ",
strempty(t->answer_ede_msg));
/* OK, the query failed, but we still shouldn't degrade the feature set for
* this server. */
log_debug("Server returned error: %s (%s%s%s)",
- FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
+ FORMAT_DNS_RCODE(dns_packet_rcode(p)),
FORMAT_DNS_EDE_RCODE(t->answer_ede_rcode),
isempty(t->answer_ede_msg) ? "" : ": ",
strempty(t->answer_ede_msg));
return;
/* Give up, accept the rcode */
- log_debug("Server returned error: %s", FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)));
+ log_debug("Server returned error: %s", FORMAT_DNS_RCODE(dns_packet_rcode(p)));
break;
}
* first attempt to downgrade. If so, clamp to the current value so that the transaction
* is retried without actually downgrading. If the next try also fails we will downgrade by
* hitting the else branch below. */
- if (DNS_PACKET_RCODE(p) == DNS_RCODE_SERVFAIL &&
+ if (dns_packet_rcode(p) == DNS_RCODE_SERVFAIL &&
t->clamp_feature_level_servfail < 0) {
t->clamp_feature_level_servfail = t->current_feature_level;
log_debug("Server returned error %s, retrying transaction.",
- FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)));
+ FORMAT_DNS_RCODE(dns_packet_rcode(p)));
} else {
/* Reduce this feature level by one and try again. */
switch (t->current_feature_level) {
}
log_debug("Server returned error %s, retrying transaction with reduced feature level %s.",
- FORMAT_DNS_RCODE(DNS_PACKET_RCODE(p)),
+ FORMAT_DNS_RCODE(dns_packet_rcode(p)),
dns_server_feature_level_to_string(t->clamp_feature_level_servfail));
}
return;
}
- if (DNS_PACKET_RCODE(p) == DNS_RCODE_REFUSED) {
+ if (dns_packet_rcode(p) == DNS_RCODE_REFUSED) {
/* This server refused our request? If so, try again, use a different server */
if (t->answer_ede_rcode >= 0)
log_debug("Server returned REFUSED (%s), switching servers, and retrying.",
/* Report that we successfully received a valid packet with a good rcode after we initially got a bad
* rcode and subsequently downgraded the protocol */
- if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN) &&
+ if (IN_SET(dns_packet_rcode(p), DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN) &&
t->clamp_feature_level_servfail != _DNS_SERVER_FEATURE_LEVEL_INVALID)
dns_server_packet_rcode_downgrade(t->server, t->clamp_feature_level_servfail);
dns_server_packet_bad_opt(t->server, t->current_feature_level);
/* Report that the server didn't copy our query DO bit from request to response */
- if (DNS_PACKET_DO(t->sent) && !DNS_PACKET_DO(t->received))
+ if (dns_packet_do(t->sent) && !dns_packet_do(t->received))
dns_server_packet_do_off(t->server, t->current_feature_level);
/* Report that we successfully received a packet. We keep track of the largest packet
* original complete record set, including RRSIG and friends. We use this when passing data to
* clients that ask for DNSSEC metadata. */
DNS_ANSWER_REPLACE(t->answer, dns_answer_ref(p->answer));
- t->answer_rcode = DNS_PACKET_RCODE(p);
+ t->answer_rcode = dns_packet_rcode(p);
t->answer_dnssec_result = _DNSSEC_RESULT_INVALID;
SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false);
SET_FLAG(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, encrypted);
scope->manager->enable_cache,
DNS_PROTOCOL_MDNS,
NULL,
- DNS_PACKET_RCODE(p),
+ dns_packet_rcode(p),
p->answer,
NULL,
false,
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 0);
+ ASSERT_EQ(dns_packet_rcode(packet), 0);
}
TEST(packet_set_flags_dns_checking_disabled) {
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 1);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 0);
+ ASSERT_EQ(dns_packet_rcode(packet), 0);
}
TEST(packet_set_flags_llmnr) {
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 0);
+ ASSERT_EQ(dns_packet_rcode(packet), 0);
}
TEST(packet_set_flags_mdns_not_truncated) {
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 0);
+ ASSERT_EQ(dns_packet_rcode(packet), 0);
}
TEST(packet_set_flags_mdns_truncated) {
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 0);
+ ASSERT_EQ(dns_packet_rcode(packet), 0);
}
/* ================================================================
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 0);
+ ASSERT_EQ(dns_packet_rcode(packet), 0);
ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1);
ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0);
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 0);
+ ASSERT_EQ(dns_packet_rcode(packet), 0);
ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 339);
ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0);
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS);
+ ASSERT_EQ(dns_packet_rcode(packet), DNS_RCODE_SUCCESS);
ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 3);
ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 4);
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_NXDOMAIN);
+ ASSERT_EQ(dns_packet_rcode(packet), DNS_RCODE_NXDOMAIN);
ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1);
ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0);
ASSERT_EQ(DNS_PACKET_RA(packet), 1);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS);
+ ASSERT_EQ(dns_packet_rcode(packet), DNS_RCODE_SUCCESS);
ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1283);
ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 3588);
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 0);
ASSERT_EQ(DNS_PACKET_CD(packet), 0);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS);
+ ASSERT_EQ(dns_packet_rcode(packet), DNS_RCODE_SUCCESS);
ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 1);
ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 0);
ASSERT_EQ(DNS_PACKET_RA(packet), 0);
ASSERT_EQ(DNS_PACKET_AD(packet), 1);
ASSERT_EQ(DNS_PACKET_CD(packet), 1);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), DNS_RCODE_SUCCESS);
+ ASSERT_EQ(dns_packet_rcode(packet), DNS_RCODE_SUCCESS);
ASSERT_EQ(DNS_PACKET_QDCOUNT(packet), 3);
ASSERT_EQ(DNS_PACKET_ANCOUNT(packet), 4);
ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr));
dns_resource_record_unref(rr);
- ASSERT_EQ(DNS_PACKET_PAYLOAD_SIZE_MAX(packet), 513u);
- ASSERT_EQ(DNS_PACKET_RCODE(packet), 2467u);
- ASSERT_EQ(DNS_PACKET_DO(packet), 0u);
+ ASSERT_EQ(dns_packet_payload_size_max(packet), 513u);
+ ASSERT_EQ(dns_packet_rcode(packet), 2467u);
+ ASSERT_EQ(dns_packet_do(packet), 0u);
}
TEST(packet_reply_opt_multiple) {
ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr));
dns_resource_record_unref(rr);
- ASSERT_EQ(DNS_PACKET_PAYLOAD_SIZE_MAX(packet), 513u);
- ASSERT_EQ(DNS_PACKET_DO(packet), 0u);
+ ASSERT_EQ(dns_packet_payload_size_max(packet), 513u);
+ ASSERT_EQ(dns_packet_do(packet), 0u);
}
TEST(packet_reply_opt_version_bad) {
ASSERT_TRUE(dns_resource_record_equal(packet->opt, rr));
dns_resource_record_unref(rr);
- ASSERT_EQ(DNS_PACKET_PAYLOAD_SIZE_MAX(packet), 4097u);
- ASSERT_EQ(DNS_PACKET_DO(packet), 1u);
+ ASSERT_EQ(dns_packet_payload_size_max(packet), 4097u);
+ ASSERT_EQ(dns_packet_do(packet), 1u);
}
TEST(packet_reply_opt_with_data) {
assert(packet);
assert(ret);
- r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_PAYLOAD_SIZE_MAX(packet));
+ r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, dns_packet_payload_size_max(packet));
if (r < 0)
return r;