Codebase list getdns / 0b38887
clarify per-query options vs. per-upstream options Sending DNS cookies was overwriting any existing options (DNS OPT) in the outbound query. Also, DNS cookies may not be the only option that gets set per-upstream (instead of per-query). This changeset establishes a set of per-query options (established at the time of the query), and a buffer of additional space for adding options based on the upstream is in use. The size of this buffer is defined at configure time (defaults to 3000 octets). Just before a query is sent out, we add the per-upstream options to the query. Note: we're also standardizing the query in tls too, even though we're not sending any upstream options in that case at the moment (edns_cookies are much weaker than TLS itself) Daniel Kahn Gillmor 8 years ago
4 changed file(s) with 135 addition(s) and 55 deletion(s). Raw diff Collapse all Expand all
407407 AC_DEFINE_UNQUOTED([EDNS_COOKIE_OPCODE], [10], [The edns cookie option code.])
408408 AC_DEFINE_UNQUOTED([EDNS_COOKIE_ROLLOVER_TIME], [(24 * 60 * 60)], [How often the edns client cookie is refreshed.])
409409
410 AC_DEFINE_UNQUOTED([MAXIMUM_UPSTREAM_OPTION_SPACE], [3000], [limit for dynamically-generated DNS options])
411
410412 my_with_libunbound=1
411413 AC_ARG_ENABLE(stub-only, AC_HELP_STRING([--enable-stub-only], [Restricts resolution modes to STUB (which will be the default mode). Removes the libunbound dependency.]))
412414 case "$enable_stub_only" in
112112 ? edns_maximum_udp_payload_size : 1432;
113113 net_req->write_queue_tail = NULL;
114114 net_req->response_len = 0;
115 net_req->base_query_option_sz = opt_options_size;
115116
116117 net_req->wire_data_sz = wire_data_sz;
117118 if (max_query_sz) {
183184 return r;
184185 }
185186
187 /* req->opt + 9 is the length; req->opt + 11 is the start of the
188 options.
189
190 clear_upstream_options() goes back to the per-query options.
191 */
192
193 void
194 _getdns_network_req_clear_upstream_options(getdns_network_req * req)
195 {
196 size_t pktlen;
197 if (req->opt) {
198 gldns_write_uint16(req->opt + 9, req->base_query_option_sz);
199 req->response = req->opt + 11 + req->base_query_option_sz;
200 pktlen = req->response - req->query;
201 gldns_write_uint16(req->query - 2, pktlen);
202 }
203 }
204
205 /* add_upstream_option appends an option that is derived at send time.
206 (you can send data as NULL and it will fill with all zeros) */
207 getdns_return_t
208 _getdns_network_req_add_upstream_option(getdns_network_req * req, uint16_t code, uint16_t sz, const void* data)
209 {
210 uint16_t oldlen;
211 uint32_t newlen;
212 uint32_t pktlen;
213 size_t cur_upstream_option_sz;
214
215 /* if no options are set, we can't add upstream options */
216 if (!req->opt)
217 return GETDNS_RETURN_GENERIC_ERROR;
218
219 /* if TCP, no overflow allowed for length field
220 https://tools.ietf.org/html/rfc1035#section-4.2.2 */
221 pktlen = req->response - req->query;
222 pktlen += 4 + sz;
223 if (pktlen > UINT16_MAX)
224 return GETDNS_RETURN_GENERIC_ERROR;
225
226 /* no overflow allowed for OPT size either (maybe this is overkill
227 given the above check?) */
228 oldlen = gldns_read_uint16(req->opt + 9);
229 newlen = oldlen + 4 + sz;
230 if (newlen > UINT16_MAX)
231 return GETDNS_RETURN_GENERIC_ERROR;
232
233 /* avoid overflowing MAXIMUM_UPSTREAM_OPTION_SPACE */
234 cur_upstream_option_sz = (size_t)oldlen - req->base_query_option_sz;
235 if (cur_upstream_option_sz + 4 + sz > MAXIMUM_UPSTREAM_OPTION_SPACE)
236 return GETDNS_RETURN_GENERIC_ERROR;
237
238 /* actually add the option: */
239 gldns_write_uint16(req->opt + 11 + oldlen, code);
240 gldns_write_uint16(req->opt + 11 + oldlen + 2, sz);
241 if (data != NULL)
242 memcpy(req->opt + 11 + oldlen + 4, data, sz);
243 else
244 memset(req->opt + 11 + oldlen + 4, 0, sz);
245 gldns_write_uint16(req->opt + 9, newlen);
246
247 /* the response should start right after the options end: */
248 req->response = req->opt + 11 + newlen;
249
250 /* for TCP, adjust the size of the wire format itself: */
251 gldns_write_uint16(req->query - 2, pktlen);
252
253 return GETDNS_RETURN_GOOD;
254 }
255
186256 void
187257 _getdns_dns_req_free(getdns_dns_req * req)
188258 {
322392 max_query_sz = ( GLDNS_HEADER_SIZE
323393 + strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */
324394 + 12 + opt_options_size /* space needed for OPT (if needed) */
325 + ( !edns_cookies ? 0
326 : 2 /* EDNS0 Option Code */
327 + 2 /* Option length = 8 + 16 = 24 */
328 + 8 /* client cookie */
329 + 16 /* server cookie */
330 )
395 + MAXIMUM_UPSTREAM_OPTION_SPACE
331396 /* TODO: TSIG */
332397 + 7) / 8 * 8;
333398 }
4545 #include "util-internal.h"
4646 #include "general.h"
4747
48 #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */
4849 #define STUB_TLS_SETUP_ERROR -4
4950 #define STUB_TCP_AGAIN -3
5051 #define STUB_TCP_ERROR -2
128129 cookie[i % 8] ^= md_value[i];
129130 }
130131
131 static uint8_t *
132 attach_edns_cookie(getdns_upstream *upstream, uint8_t *opt)
133 {
132 static getdns_return_t
133 attach_edns_cookie(getdns_network_req *req)
134 {
135 getdns_upstream *upstream = req->upstream;
136 uint16_t sz;
137 void* val;
138 uint8_t buf[8 + 32]; /* server cookies can be no larger than 32 bytes */
134139 rollover_secret();
135140
136141 if (!upstream->has_client_cookie) {
138143 upstream->secret = secret;
139144 upstream->has_client_cookie = 1;
140145
141 gldns_write_uint16(opt + 9, 12); /* rdata len */
142 gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
143 gldns_write_uint16(opt + 13, 8); /* opt len */
144 memcpy(opt + 15, upstream->client_cookie, 8);
145 return opt + 23;
146
146 sz = 8;
147 val = upstream->client_cookie;
147148 } else if (upstream->secret != secret) {
148149 memcpy( upstream->prev_client_cookie
149150 , upstream->client_cookie, 8);
151152 calc_new_cookie(upstream, upstream->client_cookie);
152153 upstream->secret = secret;
153154
154 gldns_write_uint16(opt + 9, 12); /* rdata len */
155 gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
156 gldns_write_uint16(opt + 13, 8); /* opt len */
157 memcpy(opt + 15, upstream->client_cookie, 8);
158 return opt + 23;
159
155 sz = 8;
156 val = upstream->client_cookie;
160157 } else if (!upstream->has_server_cookie) {
161 gldns_write_uint16(opt + 9, 12); /* rdata len */
162 gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
163 gldns_write_uint16(opt + 13, 8); /* opt len */
164 memcpy(opt + 15, upstream->client_cookie, 8);
165 return opt + 23;
158 sz = 8;
159 val = upstream->client_cookie;
166160 } else {
167 gldns_write_uint16( opt + 9, 12 /* rdata len */
168 + upstream->server_cookie_len);
169 gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE);
170 gldns_write_uint16(opt + 13, 8 /* opt len */
171 + upstream->server_cookie_len);
172 memcpy(opt + 15, upstream->client_cookie, 8);
173 memcpy(opt + 23, upstream->server_cookie
174 , upstream->server_cookie_len);
175 return opt + 23+ upstream->server_cookie_len;
176 }
161 sz = 8 + upstream->server_cookie_len;
162 memcpy(buf, upstream->client_cookie, 8);
163 memcpy(buf+8, upstream->server_cookie, upstream->server_cookie_len);
164 val = buf;
165 }
166 return _getdns_network_req_add_upstream_option(req, EDNS_COOKIE_OPCODE, sz, val);
167
177168 }
178169
179170 static int
680671 stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
681672 {
682673
683 size_t pkt_len = netreq->response - netreq->query;
674 size_t pkt_len;
684675 ssize_t written;
685676 uint16_t query_id;
686677 intptr_t query_id_intptr;
703694
704695 GLDNS_ID_SET(netreq->query, query_id);
705696 if (netreq->opt) {
697 _getdns_network_req_clear_upstream_options(netreq);
706698 /* no limits on the max udp payload size with tcp */
707699 gldns_write_uint16(netreq->opt + 3, 65535);
708700
709 if (netreq->owner->edns_cookies) {
710 netreq->response = attach_edns_cookie(
711 netreq->upstream, netreq->opt);
712 pkt_len = netreq->response - netreq->query;
713 gldns_write_uint16(netreq->query - 2, pkt_len);
714 }
715 }
701 if (netreq->owner->edns_cookies)
702 if (attach_edns_cookie(netreq))
703 return STUB_OUT_OF_OPTIONS;
704 }
705 pkt_len = netreq->response - netreq->query;
716706 /* We have an initialized packet buffer.
717707 * Lets see how much of it we can write
718708 */
11251115 stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
11261116 getdns_network_req *netreq)
11271117 {
1128 size_t pkt_len = netreq->response - netreq->query;
1118 size_t pkt_len;
11291119 ssize_t written;
11301120 uint16_t query_id;
11311121 intptr_t query_id_intptr;
11551145 &netreq->upstream->netreq_by_query_id, &netreq->node));
11561146
11571147 GLDNS_ID_SET(netreq->query, query_id);
1158 if (netreq->opt)
1148 if (netreq->opt) {
1149 _getdns_network_req_clear_upstream_options(netreq);
11591150 /* no limits on the max udp payload size with tcp */
11601151 gldns_write_uint16(netreq->opt + 3, 65535);
1161
1152 /* we do not edns_cookie over TLS, since TLS
1153 * provides stronger guarantees than cookies
1154 * already */
1155 }
1156
1157 pkt_len = netreq->response - netreq->query;
11621158 /* We have an initialized packet buffer.
11631159 * Lets see how much of it we can write */
11641160
12471243 DEBUG_STUB("%s\n", __FUNCTION__);
12481244 getdns_network_req *netreq = (getdns_network_req *)userarg;
12491245 getdns_dns_req *dnsreq = netreq->owner;
1250 size_t pkt_len = netreq->response - netreq->query;
1246 size_t pkt_len;
12511247
12521248 GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
12531249
12541250 netreq->query_id = arc4random();
12551251 GLDNS_ID_SET(netreq->query, netreq->query_id);
12561252 if (netreq->opt) {
1253 _getdns_network_req_clear_upstream_options(netreq);
12571254 if (netreq->edns_maximum_udp_payload_size == -1)
12581255 gldns_write_uint16(netreq->opt + 3,
12591256 ( netreq->max_udp_payload_size =
12601257 netreq->upstream->addr.ss_family == AF_INET6
12611258 ? 1232 : 1432));
1262 if (netreq->owner->edns_cookies) {
1263 netreq->response = attach_edns_cookie(
1264 netreq->upstream, netreq->opt);
1265 pkt_len = netreq->response - netreq->query;
1266 }
1267 }
1268
1259 if (netreq->owner->edns_cookies)
1260 if (attach_edns_cookie(netreq))
1261 return; /* too many upstream options */
1262 }
1263 pkt_len = netreq->response - netreq->query;
12691264 if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0,
12701265 (struct sockaddr *)&netreq->upstream->addr,
12711266 netreq->upstream->addr_len)) {
231231 */
232232 uint8_t *query;
233233 uint8_t *opt; /* offset of OPT RR in query */
234
235 /* each network_req has a set of base options that are
236 * specific to the query, which are static and included when
237 * the network_req is created. When the query is sent out to
238 * a given upstream, some additional options are added that
239 * are specific to the upstream. There can be at most
240 * GETDNS_MAXIMUM_UPSTREAM_OPTION_SPACE bytes of
241 * upstream-specific options.
242
243 * use _getdns_network_req_clear_upstream_options() and
244 * _getdns_network_req_add_upstream_option() to fiddle with the
245 */
246 size_t base_query_option_sz;
234247 size_t response_len;
235248 uint8_t *response;
236249 size_t wire_data_sz;
343356
344357 void _getdns_dns_req_free(getdns_dns_req * req);
345358
359 /* network request utils */
360 getdns_return_t _getdns_network_req_add_upstream_option(getdns_network_req * req,
361 uint16_t code, uint16_t sz, const void* data);
362 void _getdns_network_req_clear_upstream_options(getdns_network_req * req);
363
346364 #endif
347365 /* types-internal.h */