1 #include "dnscrypt.h"
2
3 static int
_skip_name(const uint8_t * const dns_packet,const size_t dns_packet_len,size_t * const offset_p)4 _skip_name(const uint8_t *const dns_packet, const size_t dns_packet_len,
5 size_t * const offset_p)
6 {
7 size_t offset = *offset_p;
8 uint8_t name_component_len;
9
10 if (dns_packet_len < (size_t) 1U || offset >= dns_packet_len - (size_t) 1U) {
11 return -1;
12 }
13 do {
14 name_component_len = dns_packet[offset];
15 if ((name_component_len & 0xC0) == 0xC0) {
16 name_component_len = 1U;
17 }
18 if (name_component_len >= dns_packet_len - offset - 1U) {
19 return -1;
20 }
21 offset += name_component_len + 1U;
22 } while (name_component_len != 0U);
23 if (offset >= dns_packet_len) {
24 return -1;
25 }
26 *offset_p = offset;
27
28 return 0;
29 }
30
31 #define DNS_QTYPE_PLUS_QCLASS_LEN 4U
32
33 static ssize_t
edns_get_payload_size(const uint8_t * const dns_packet,const size_t dns_packet_len)34 edns_get_payload_size(const uint8_t *const dns_packet,
35 const size_t dns_packet_len)
36 {
37 size_t offset;
38 size_t payload_size;
39 unsigned int arcount;
40
41 assert(dns_packet_len >= DNS_HEADER_SIZE);
42 arcount = (dns_packet[DNS_OFFSET_ARCOUNT] << 8) |
43 dns_packet[DNS_OFFSET_ARCOUNT + 1U];
44 assert(arcount > 0U);
45 assert(DNS_OFFSET_QUESTION <= DNS_HEADER_SIZE);
46 if (dns_packet[DNS_OFFSET_QDCOUNT] != 0U ||
47 dns_packet[DNS_OFFSET_QDCOUNT + 1U] != 1U ||
48 (dns_packet[DNS_OFFSET_ANCOUNT] |
49 dns_packet[DNS_OFFSET_ANCOUNT + 1U]) != 0U ||
50 (dns_packet[DNS_OFFSET_NSCOUNT] |
51 dns_packet[DNS_OFFSET_NSCOUNT + 1U]) != 0U) {
52 return (ssize_t) - 1;
53 }
54 offset = DNS_OFFSET_QUESTION;
55 if (_skip_name(dns_packet, dns_packet_len, &offset) != 0) {
56 return (ssize_t) - 1;
57 }
58 assert(dns_packet_len > (size_t) DNS_QTYPE_PLUS_QCLASS_LEN);
59 if (offset >= dns_packet_len - (size_t) DNS_QTYPE_PLUS_QCLASS_LEN) {
60 return (ssize_t) - 1;
61 }
62 offset += DNS_QTYPE_PLUS_QCLASS_LEN;
63 assert(dns_packet_len >= DNS_OFFSET_EDNS_PAYLOAD_SIZE + 2U);
64 if (_skip_name(dns_packet, dns_packet_len, &offset) != 0 ||
65 offset >= dns_packet_len - DNS_OFFSET_EDNS_PAYLOAD_SIZE - 2U) {
66 return (ssize_t) - 1;
67 }
68 assert(DNS_OFFSET_EDNS_PAYLOAD_SIZE > DNS_OFFSET_EDNS_TYPE);
69 if (dns_packet[offset + DNS_OFFSET_EDNS_TYPE] != 0U ||
70 dns_packet[offset + DNS_OFFSET_EDNS_TYPE + 1U] != DNS_TYPE_OPT) {
71 return (ssize_t) - 1;
72 }
73 payload_size = (dns_packet[offset + DNS_OFFSET_EDNS_PAYLOAD_SIZE] << 8) |
74 dns_packet[offset + DNS_OFFSET_EDNS_PAYLOAD_SIZE + 1U];
75 if (payload_size < DNS_MAX_PACKET_SIZE_UDP_SEND) {
76 payload_size = DNS_MAX_PACKET_SIZE_UDP_SEND;
77 }
78 return (ssize_t) payload_size;
79 }
80
81 int
edns_add_section(struct context * const c,uint8_t * const dns_packet,size_t * const dns_packet_len_p,size_t dns_packet_max_size,size_t * const request_edns_payload_size)82 edns_add_section(struct context *const c,
83 uint8_t *const dns_packet,
84 size_t * const dns_packet_len_p,
85 size_t dns_packet_max_size,
86 size_t * const request_edns_payload_size)
87 {
88 const size_t edns_payload_size = c->edns_payload_size;
89
90 assert(edns_payload_size <= (size_t) 0xFFFF);
91 assert(DNS_OFFSET_ARCOUNT + 2U <= DNS_HEADER_SIZE);
92 if (edns_payload_size <= DNS_MAX_PACKET_SIZE_UDP_SEND ||
93 *dns_packet_len_p <= DNS_HEADER_SIZE) {
94 *request_edns_payload_size = (size_t) 0U;
95 return -1;
96 }
97 if ((dns_packet[DNS_OFFSET_ARCOUNT] |
98 dns_packet[DNS_OFFSET_ARCOUNT + 1U]) != 0U) {
99 const ssize_t edns_payload_ssize =
100 edns_get_payload_size(dns_packet, *dns_packet_len_p);
101 if (edns_payload_ssize <= (ssize_t) 0U) {
102 *request_edns_payload_size = (size_t) 0U;
103 return -1;
104 }
105 *request_edns_payload_size = (size_t) edns_payload_ssize;
106 return 1;
107 }
108 assert(dns_packet_max_size >= *dns_packet_len_p);
109
110 assert(DNS_OFFSET_EDNS_TYPE == 0U);
111 assert(DNS_OFFSET_EDNS_PAYLOAD_SIZE == 2U);
112 uint8_t opt_rr[] = {
113 0U, /* name */
114 0U, DNS_TYPE_OPT, /* type */
115 (edns_payload_size >> 8) & 0xFF, edns_payload_size & 0xFF,
116 0U, 0U, 0U, 0U, /* rcode */
117 0U, 0U /* rdlen */
118 };
119 if (dns_packet_max_size - *dns_packet_len_p < sizeof opt_rr) {
120 *request_edns_payload_size = (size_t) 0U;
121 return -1;
122 }
123
124 assert(dns_packet[DNS_OFFSET_ARCOUNT + 1U] == 0U);
125 dns_packet[DNS_OFFSET_ARCOUNT + 1U] = 1U;
126 memcpy(dns_packet + *dns_packet_len_p, opt_rr, sizeof opt_rr);
127 *dns_packet_len_p += sizeof opt_rr;
128 *request_edns_payload_size = edns_payload_size;
129 assert(*dns_packet_len_p <= dns_packet_max_size);
130 assert(*dns_packet_len_p <= 0xFFFF);
131
132 return 0;
133 }
134