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