Changes to update Tomato RAF.
[tomato.git] / release / src / router / dnscrypt / src / proxy / edns.c
blob6f111ac3e79779916e74e37098d7117f20005433
2 #include <config.h>
3 #include <sys/types.h>
5 #include <assert.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
10 #include "dnscrypt_proxy.h"
11 #include "edns.h"
13 static int
14 _skip_name(const uint8_t * const dns_packet, const size_t dns_packet_len,
15 size_t * const offset_p)
17 size_t offset = *offset_p;
18 uint8_t name_component_len;
20 if (dns_packet_len < (size_t) 1U ||
21 offset >= dns_packet_len - (size_t) 1U) {
22 return -1;
24 do {
25 name_component_len = dns_packet[offset];
26 if ((name_component_len & 0xC0) == 0xC0) {
27 name_component_len = 1U;
29 if (name_component_len >= dns_packet_len - offset - 1U) {
30 return -1;
32 offset += name_component_len + 1U;
33 } while (name_component_len != 0U);
34 if (offset >= dns_packet_len) {
35 return -1;
37 *offset_p = offset;
39 return 0;
42 #define DNS_QTYPE_PLUS_QCLASS_LEN 4U
44 static ssize_t
45 edns_get_payload_size(const uint8_t * const dns_packet,
46 const size_t dns_packet_len)
48 size_t offset;
49 size_t payload_size;
50 unsigned int arcount;
52 assert(dns_packet_len >= DNS_HEADER_SIZE);
53 arcount = (dns_packet[DNS_OFFSET_ARCOUNT] << 8) |
54 dns_packet[DNS_OFFSET_ARCOUNT + 1U];
55 assert(arcount > 0U);
56 assert(DNS_OFFSET_QUESTION <= DNS_HEADER_SIZE);
57 if (dns_packet[DNS_OFFSET_QDCOUNT] != 0U ||
58 dns_packet[DNS_OFFSET_QDCOUNT + 1U] != 1U ||
59 (dns_packet[DNS_OFFSET_ANCOUNT] |
60 dns_packet[DNS_OFFSET_ANCOUNT + 1U]) != 0U ||
61 (dns_packet[DNS_OFFSET_NSCOUNT] |
62 dns_packet[DNS_OFFSET_NSCOUNT + 1U]) != 0U) {
63 return (ssize_t) -1;
65 offset = DNS_OFFSET_QUESTION;
66 if (_skip_name(dns_packet, dns_packet_len, &offset) != 0) {
67 return (ssize_t) -1;
69 assert(dns_packet_len > (size_t) DNS_QTYPE_PLUS_QCLASS_LEN);
70 if (offset >= dns_packet_len - (size_t) DNS_QTYPE_PLUS_QCLASS_LEN) {
71 return (ssize_t) -1;
73 offset += DNS_QTYPE_PLUS_QCLASS_LEN;
74 assert(dns_packet_len >= DNS_OFFSET_EDNS_PAYLOAD_SIZE + 2U);
75 if (_skip_name(dns_packet, dns_packet_len, &offset) != 0 ||
76 offset >= dns_packet_len - DNS_OFFSET_EDNS_PAYLOAD_SIZE - 2U) {
77 return (ssize_t) -1;
79 assert(DNS_OFFSET_EDNS_PAYLOAD_SIZE > DNS_OFFSET_EDNS_TYPE);
80 if (dns_packet[offset + DNS_OFFSET_EDNS_TYPE] != 0U ||
81 dns_packet[offset + DNS_OFFSET_EDNS_TYPE + 1U] != DNS_TYPE_OPT) {
82 return (ssize_t) -1;
84 payload_size = (dns_packet[offset + DNS_OFFSET_EDNS_PAYLOAD_SIZE] << 8) |
85 dns_packet[offset + DNS_OFFSET_EDNS_PAYLOAD_SIZE + 1U];
86 if (payload_size < DNS_MAX_PACKET_SIZE_UDP_SEND) {
87 payload_size = DNS_MAX_PACKET_SIZE_UDP_SEND;
89 return (ssize_t) payload_size;
92 int
93 edns_add_section(ProxyContext * const proxy_context,
94 uint8_t * const dns_packet, size_t * const dns_packet_len_p,
95 size_t dns_packet_max_size,
96 size_t * const request_edns_payload_size)
98 const size_t edns_payload_size = proxy_context->edns_payload_size;
100 assert(edns_payload_size <= (size_t) 0xFFFF);
101 assert(DNS_OFFSET_ARCOUNT + 2U <= DNS_HEADER_SIZE);
102 if (edns_payload_size <= DNS_MAX_PACKET_SIZE_UDP_SEND ||
103 *dns_packet_len_p <= DNS_HEADER_SIZE) {
104 *request_edns_payload_size = (size_t) 0U;
105 return -1;
107 if ((dns_packet[DNS_OFFSET_ARCOUNT] |
108 dns_packet[DNS_OFFSET_ARCOUNT + 1U]) != 0U) {
109 const ssize_t edns_payload_ssize =
110 edns_get_payload_size(dns_packet, *dns_packet_len_p);
111 if (edns_payload_ssize <= (ssize_t) 0U) {
112 *request_edns_payload_size = (size_t) 0U;
113 return -1;
115 *request_edns_payload_size = (size_t) edns_payload_ssize;
116 return 1;
118 assert(dns_packet_max_size >= *dns_packet_len_p);
120 assert(DNS_OFFSET_EDNS_TYPE == 0U);
121 assert(DNS_OFFSET_EDNS_PAYLOAD_SIZE == 2U);
122 uint8_t opt_rr[] = {
123 0U, /* name */
124 0U, DNS_TYPE_OPT, /* type */
125 (edns_payload_size >> 8) & 0xFF, edns_payload_size & 0xFF,
126 0U, 0U, 0U, 0U, /* rcode */
127 0U, 0U /* rdlen */
129 if (dns_packet_max_size - *dns_packet_len_p < sizeof opt_rr) {
130 *request_edns_payload_size = (size_t) 0U;
131 return -1;
133 assert(dns_packet[DNS_OFFSET_ARCOUNT + 1U] == 0U);
134 dns_packet[DNS_OFFSET_ARCOUNT + 1U] = 1U;
135 memcpy(dns_packet + *dns_packet_len_p, opt_rr, sizeof opt_rr);
136 *dns_packet_len_p += sizeof opt_rr;
137 *request_edns_payload_size = edns_payload_size;
138 assert(*dns_packet_len_p <= dns_packet_max_size);
139 assert(*dns_packet_len_p <= 0xFFFF);
141 return 0;