diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/resolve/resolve-tool.c | 2 | ||||
-rw-r--r-- | src/resolve/resolved-dns-packet.c | 26 | ||||
-rw-r--r-- | src/resolve/resolved-dns-packet.h | 14 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 4 | ||||
-rw-r--r-- | src/resolve/resolved-dns-stream.c | 2 | ||||
-rw-r--r-- | src/resolve/resolved-dns-stub.c | 48 | ||||
-rw-r--r-- | src/resolve/resolved-manager.c | 2 | ||||
-rw-r--r-- | src/resolve/test-dns-packet.c | 4 | ||||
-rw-r--r-- | src/resolve/test-resolved-packet.c | 4 |
9 files changed, 69 insertions, 37 deletions
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index c62058917f..195555c3c0 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -357,7 +357,7 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) { int r; char ifname[IF_NAMESIZE] = ""; - r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); + r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX); if (r < 0) return log_oom(); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index bf879475d4..e2f227bfc6 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -43,11 +43,20 @@ static void rewind_dns_packet(DnsPacketRewinder *rewinder) { #define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while (0) #define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while (0) -int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize) { +int dns_packet_new( + DnsPacket **ret, + DnsProtocol protocol, + size_t min_alloc_dsize, + size_t max_size) { + DnsPacket *p; size_t a; assert(ret); + assert(max_size >= DNS_PACKET_HEADER_SIZE); + + if (max_size > DNS_PACKET_SIZE_MAX) + max_size = DNS_PACKET_SIZE_MAX; /* The caller may not check what is going to be truly allocated, so do not allow to * allocate a DNS packet bigger than DNS_PACKET_SIZE_MAX. @@ -70,8 +79,8 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket)); /* make sure we never allocate more than useful */ - if (a > DNS_PACKET_SIZE_MAX) - a = DNS_PACKET_SIZE_MAX; + if (a > max_size) + a = max_size; p = malloc0(ALIGN(sizeof(DnsPacket)) + a); if (!p) @@ -79,6 +88,7 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize p->size = p->rindex = DNS_PACKET_HEADER_SIZE; p->allocated = a; + p->max_size = max_size; p->protocol = protocol; p->opt_start = p->opt_size = (size_t) -1; p->n_ref = 1; @@ -144,7 +154,7 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc assert(ret); - r = dns_packet_new(&p, protocol, min_alloc_dsize); + r = dns_packet_new(&p, protocol, min_alloc_dsize, DNS_PACKET_SIZE_MAX); if (r < 0) return r; @@ -313,11 +323,13 @@ static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start assert(p); if (p->size + add > p->allocated) { - size_t a; + size_t a, ms; a = PAGE_ALIGN((p->size + add) * 2); - if (a > DNS_PACKET_SIZE_MAX) - a = DNS_PACKET_SIZE_MAX; + + ms = dns_packet_size_max(p); + if (a > ms) + a = ms; if (p->size + add > a) return -EMSGSIZE; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index d4c6b3c9cb..b873c0f745 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -73,7 +73,7 @@ struct DnsPacketHeader { struct DnsPacket { int n_ref; DnsProtocol protocol; - size_t size, allocated, rindex; + size_t size, allocated, rindex, max_size; void *_data; /* don't access directly, use DNS_PACKET_DATA()! */ Hashmap *names; /* For name compression */ size_t opt_start, opt_size; @@ -187,7 +187,7 @@ static inline unsigned DNS_PACKET_RRCOUNT(DnsPacket *p) { (unsigned) DNS_PACKET_ARCOUNT(p); } -int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize); +int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, size_t max_size); int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, bool dnssec_checking_disabled); void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated); @@ -303,3 +303,13 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family, return f; } } + +static inline size_t dns_packet_size_max(DnsPacket *p) { + assert(p); + + /* Why not insist on a fully initialized max_size during DnsPacket construction? Well, this way it's easy to + * allocate a transient, throw-away DnsPacket on the stack by simple zero initialization, without having to + * deal with explicit field initialization. */ + + return p->max_size != 0 ? p->max_size : DNS_PACKET_SIZE_MAX; +} diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index b01ee6c9cc..ca54158898 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -632,7 +632,7 @@ int dns_scope_make_reply_packet( dns_answer_isempty(soa)) return -EINVAL; - r = dns_packet_new(&p, s->protocol, 0); + r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX); if (r < 0) return r; @@ -818,7 +818,7 @@ static int dns_scope_make_conflict_packet( assert(rr); assert(ret); - r = dns_packet_new(&p, s->protocol, 0); + r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index 4a94fa9916..5892534687 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -260,7 +260,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use ssize_t ss; if (!s->read_packet) { - r = dns_packet_new(&s->read_packet, s->protocol, be16toh(s->read_size)); + r = dns_packet_new(&s->read_packet, s->protocol, be16toh(s->read_size), DNS_PACKET_SIZE_MAX); if (r < 0) return dns_stream_complete(s, -r); diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 292e94daa3..5bc79a313e 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -30,9 +30,12 @@ static int manager_dns_stub_tcp_fd(Manager *m); static int dns_stub_make_reply_packet( DnsPacket **p, + size_t max_size, DnsQuestion *q, - DnsAnswer *answer) { + DnsAnswer *answer, + bool *ret_truncated) { + bool truncated = false; DnsResourceRecord *rr; unsigned c = 0; int r; @@ -43,7 +46,7 @@ static int dns_stub_make_reply_packet( * roundtrips aren't expensive. */ if (!*p) { - r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0); + r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size); if (r < 0) return r; @@ -71,12 +74,21 @@ static int dns_stub_make_reply_packet( continue; add: r = dns_packet_append_rr(*p, rr, 0, NULL, NULL); + if (r == -EMSGSIZE) { + truncated = true; + break; + } if (r < 0) return r; c++; } + if (ret_truncated) + *ret_truncated = truncated; + else if (truncated) + return -EMSGSIZE; + DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c); return 0; @@ -86,6 +98,7 @@ static int dns_stub_finish_reply_packet( DnsPacket *p, uint16_t id, int rcode, + bool tc, /* set the Truncated bit? */ bool add_opt, /* add an OPT RR to this packet? */ bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */ bool ad) { /* set the DNSSEC authenticated data bit? */ @@ -110,14 +123,14 @@ static int dns_stub_finish_reply_packet( DNS_PACKET_HEADER(p)->id = id; DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS( - 1 /* qr */, - 0 /* opcode */, - 0 /* aa */, - 0 /* tc */, - 1 /* rd */, - 1 /* ra */, + 1 /* qr */, + 0 /* opcode */, + 0 /* aa */, + tc /* tc */, + 1 /* rd */, + 1 /* ra */, ad /* ad */, - 0 /* cd */, + 0 /* cd */, rcode)); if (add_opt) { @@ -149,12 +162,6 @@ static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *repl else { int fd; - /* Truncate the message to the right size */ - if (reply->size > DNS_PACKET_PAYLOAD_SIZE_MAX(p)) { - dns_packet_truncate(reply, DNS_PACKET_UNICAST_SIZE_MAX); - DNS_PACKET_HEADER(reply)->flags = htobe16(be16toh(DNS_PACKET_HEADER(reply)->flags) | DNS_PACKET_FLAG_TC); - } - fd = manager_dns_stub_udp_fd(m); if (fd < 0) return log_debug_errno(fd, "Failed to get reply socket: %m"); @@ -178,11 +185,11 @@ static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rco assert(m); assert(p); - r = dns_stub_make_reply_packet(&reply, p->question, NULL); + r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL); if (r < 0) return log_debug_errno(r, "Failed to make failure packet: %m"); - r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, !!p->opt, DNS_PACKET_DO(p), authenticated); + r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, false, !!p->opt, DNS_PACKET_DO(p), authenticated); if (r < 0) return log_debug_errno(r, "Failed to build failure packet: %m"); @@ -197,9 +204,10 @@ static void dns_stub_query_complete(DnsQuery *q) { switch (q->state) { - case DNS_TRANSACTION_SUCCESS: + case DNS_TRANSACTION_SUCCESS: { + bool truncated; - r = dns_stub_make_reply_packet(&q->reply_dns_packet, q->question_idna, q->answer); + r = dns_stub_make_reply_packet(&q->reply_dns_packet, DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_dns_packet), q->question_idna, q->answer, &truncated); if (r < 0) { log_debug_errno(r, "Failed to build reply packet: %m"); break; @@ -221,6 +229,7 @@ static void dns_stub_query_complete(DnsQuery *q) { q->reply_dns_packet, DNS_PACKET_ID(q->request_dns_packet), q->answer_rcode, + truncated, !!q->request_dns_packet->opt, DNS_PACKET_DO(q->request_dns_packet), dns_query_fully_authenticated(q)); @@ -231,6 +240,7 @@ static void dns_stub_query_complete(DnsQuery *q) { (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet); break; + } case DNS_TRANSACTION_RCODE_FAILURE: (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q)); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 1270ca2b25..58fe572d3b 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -723,7 +723,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { if (ms < 0) return ms; - r = dns_packet_new(&p, protocol, ms); + r = dns_packet_new(&p, protocol, ms, DNS_PACKET_SIZE_MAX); if (r < 0) return r; diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index 8cbe492526..00dde9b6bd 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -75,7 +75,7 @@ static void test_packet_from_file(const char* filename, bool canonical) { assert_se(packet_size > 0); assert_se(offset + 8 + packet_size <= data_size); - assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0) >= 0); + assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX) >= 0); assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0); assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0); @@ -90,7 +90,7 @@ static void test_packet_from_file(const char* filename, bool canonical) { assert_se(dns_resource_record_to_wire_format(rr, canonical) >= 0); - assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0) >= 0); + assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX) >= 0); assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0); assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0); diff --git a/src/resolve/test-resolved-packet.c b/src/resolve/test-resolved-packet.c index cf886b1bf2..ab11fbcd32 100644 --- a/src/resolve/test-resolved-packet.c +++ b/src/resolve/test-resolved-packet.c @@ -27,7 +27,7 @@ static void test_dns_packet_new(void) { for (i = 0; i <= DNS_PACKET_SIZE_MAX; i++) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i) == 0); + assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i, DNS_PACKET_SIZE_MAX) == 0); log_debug("dns_packet_new: %zu → %zu", i, p->allocated); assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i)); @@ -36,7 +36,7 @@ static void test_dns_packet_new(void) { i = MIN(i * 2, DNS_PACKET_SIZE_MAX - 10); } - assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1) == -EFBIG); + assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1, DNS_PACKET_SIZE_MAX) == -EFBIG); } int main(int argc, char **argv) { |