]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors | |
3 | * | |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
9 | /* | |
10 | * Low level DNS protocol routines | |
11 | * | |
12 | * KNOWN BUGS: | |
13 | * | |
14 | * UDP replies with TC set should be retried via TCP | |
15 | */ | |
16 | ||
17 | #include "squid.h" | |
18 | #include "dns/rfc1035.h" | |
19 | #include "dns/rfc2671.h" | |
20 | #include "util.h" | |
21 | ||
22 | #include <cassert> | |
23 | #include <cstring> | |
24 | #if HAVE_UNISTD_H | |
25 | #include <unistd.h> | |
26 | #endif | |
27 | #if HAVE_MEMORY_H | |
28 | #include <memory.h> | |
29 | #endif | |
30 | #if HAVE_NETINET_IN_H | |
31 | #include <netinet/in.h> | |
32 | #endif | |
33 | #if HAVE_ARPA_INET_H | |
34 | #include <arpa/inet.h> | |
35 | #endif | |
36 | #if HAVE_STRINGS_H | |
37 | #include <strings.h> | |
38 | #endif | |
39 | ||
40 | #define RFC1035_MAXLABELSZ 63 | |
41 | #define rfc1035_unpack_error 15 | |
42 | ||
43 | #if 0 | |
44 | #define RFC1035_UNPACK_DEBUG fprintf(stderr, "unpack error at %s:%d\n", __FILE__,__LINE__) | |
45 | #else | |
46 | #define RFC1035_UNPACK_DEBUG (void)0 | |
47 | #endif | |
48 | ||
49 | /* | |
50 | * rfc1035HeaderPack() | |
51 | * | |
52 | * Packs a rfc1035_header structure into a buffer. | |
53 | * Returns number of octets packed (should always be 12) | |
54 | */ | |
55 | int | |
56 | rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr) | |
57 | { | |
58 | int off = 0; | |
59 | unsigned short s; | |
60 | unsigned short t; | |
61 | assert(sz >= 12); | |
62 | s = htons(hdr->id); | |
63 | memcpy(buf + off, &s, sizeof(s)); | |
64 | off += sizeof(s); | |
65 | t = 0; | |
66 | t |= hdr->qr << 15; | |
67 | t |= (hdr->opcode << 11); | |
68 | t |= (hdr->aa << 10); | |
69 | t |= (hdr->tc << 9); | |
70 | t |= (hdr->rd << 8); | |
71 | t |= (hdr->ra << 7); | |
72 | t |= hdr->rcode; | |
73 | s = htons(t); | |
74 | memcpy(buf + off, &s, sizeof(s)); | |
75 | off += sizeof(s); | |
76 | s = htons(hdr->qdcount); | |
77 | memcpy(buf + off, &s, sizeof(s)); | |
78 | off += sizeof(s); | |
79 | s = htons(hdr->ancount); | |
80 | memcpy(buf + off, &s, sizeof(s)); | |
81 | off += sizeof(s); | |
82 | s = htons(hdr->nscount); | |
83 | memcpy(buf + off, &s, sizeof(s)); | |
84 | off += sizeof(s); | |
85 | s = htons(hdr->arcount); | |
86 | memcpy(buf + off, &s, sizeof(s)); | |
87 | off += sizeof(s); | |
88 | assert(off == 12); | |
89 | return off; | |
90 | } | |
91 | ||
92 | /* | |
93 | * rfc1035LabelPack() | |
94 | * | |
95 | * Packs a label into a buffer. The format of | |
96 | * a label is one octet specifying the number of character | |
97 | * bytes to follow. Labels must be smaller than 64 octets. | |
98 | * Returns number of octets packed. | |
99 | */ | |
100 | static int | |
101 | rfc1035LabelPack(char *buf, size_t sz, const char *label) | |
102 | { | |
103 | int off = 0; | |
104 | size_t len = label ? strlen(label) : 0; | |
105 | if (label) | |
106 | assert(!strchr(label, '.')); | |
107 | if (len > RFC1035_MAXLABELSZ) | |
108 | len = RFC1035_MAXLABELSZ; | |
109 | assert(sz >= len + 1); | |
110 | *(buf + off) = (char) len; | |
111 | off++; | |
112 | memcpy(buf + off, label, len); | |
113 | off += len; | |
114 | return off; | |
115 | } | |
116 | ||
117 | /* | |
118 | * rfc1035NamePack() | |
119 | * | |
120 | * Packs a name into a buffer. Names are packed as a | |
121 | * sequence of labels, terminated with NULL label. | |
122 | * Note message compression is not supported here. | |
123 | * Returns number of octets packed. | |
124 | */ | |
125 | static int | |
126 | rfc1035NamePack(char *buf, size_t sz, const char *name) | |
127 | { | |
128 | unsigned int off = 0; | |
129 | char *copy = xstrdup(name); | |
130 | char *t; | |
131 | /* | |
132 | * NOTE: use of strtok here makes names like foo....com valid. | |
133 | */ | |
134 | for (t = strtok(copy, "."); t; t = strtok(nullptr, ".")) | |
135 | off += rfc1035LabelPack(buf + off, sz - off, t); | |
136 | xfree(copy); | |
137 | off += rfc1035LabelPack(buf + off, sz - off, nullptr); | |
138 | assert(off <= sz); | |
139 | return off; | |
140 | } | |
141 | ||
142 | /* | |
143 | * rfc1035QuestionPack() | |
144 | * | |
145 | * Packs a QUESTION section of a message. | |
146 | * Returns number of octets packed. | |
147 | */ | |
148 | int | |
149 | rfc1035QuestionPack(char *buf, | |
150 | const size_t sz, | |
151 | const char *name, | |
152 | const unsigned short type, | |
153 | const unsigned short _class) | |
154 | { | |
155 | unsigned int off = 0; | |
156 | unsigned short s; | |
157 | off += rfc1035NamePack(buf + off, sz - off, name); | |
158 | s = htons(type); | |
159 | memcpy(buf + off, &s, sizeof(s)); | |
160 | off += sizeof(s); | |
161 | s = htons(_class); | |
162 | memcpy(buf + off, &s, sizeof(s)); | |
163 | off += sizeof(s); | |
164 | assert(off <= sz); | |
165 | return off; | |
166 | } | |
167 | ||
168 | /* | |
169 | * rfc1035HeaderUnpack() | |
170 | * | |
171 | * Unpacks a RFC1035 message header buffer into the header fields | |
172 | * of the rfc1035_message structure. | |
173 | * | |
174 | * Updates the buffer offset, which is the same as number of | |
175 | * octects unpacked since the header starts at offset 0. | |
176 | * | |
177 | * Returns 0 (success) or 1 (error) | |
178 | */ | |
179 | int | |
180 | rfc1035HeaderUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_message * h) | |
181 | { | |
182 | unsigned short s; | |
183 | unsigned short t; | |
184 | assert(*off == 0); | |
185 | /* | |
186 | * The header is 12 octets. This is a bogus message if the size | |
187 | * is less than that. | |
188 | */ | |
189 | if (sz < 12) | |
190 | return 1; | |
191 | memcpy(&s, buf + (*off), sizeof(s)); | |
192 | (*off) += sizeof(s); | |
193 | h->id = ntohs(s); | |
194 | memcpy(&s, buf + (*off), sizeof(s)); | |
195 | (*off) += sizeof(s); | |
196 | t = ntohs(s); | |
197 | h->qr = (t >> 15) & 0x01; | |
198 | h->opcode = (t >> 11) & 0x0F; | |
199 | h->aa = (t >> 10) & 0x01; | |
200 | h->tc = (t >> 9) & 0x01; | |
201 | h->rd = (t >> 8) & 0x01; | |
202 | h->ra = (t >> 7) & 0x01; | |
203 | /* | |
204 | * We might want to check that the reserved 'Z' bits (6-4) are | |
205 | * all zero as per RFC 1035. If not the message should be | |
206 | * rejected. | |
207 | * NO! RFCs say ignore inbound reserved, they may be used in future. | |
208 | * NEW messages need to be set 0, that's all. | |
209 | */ | |
210 | h->rcode = t & 0x0F; | |
211 | memcpy(&s, buf + (*off), sizeof(s)); | |
212 | (*off) += sizeof(s); | |
213 | h->qdcount = ntohs(s); | |
214 | memcpy(&s, buf + (*off), sizeof(s)); | |
215 | (*off) += sizeof(s); | |
216 | h->ancount = ntohs(s); | |
217 | memcpy(&s, buf + (*off), sizeof(s)); | |
218 | (*off) += sizeof(s); | |
219 | h->nscount = ntohs(s); | |
220 | memcpy(&s, buf + (*off), sizeof(s)); | |
221 | (*off) += sizeof(s); | |
222 | h->arcount = ntohs(s); | |
223 | assert((*off) == 12); | |
224 | return 0; | |
225 | } | |
226 | ||
227 | /* | |
228 | * rfc1035NameUnpack() | |
229 | * | |
230 | * Unpacks a Name in a message buffer into a char*. | |
231 | * Note 'buf' points to the beginning of the whole message, | |
232 | * 'off' points to the spot where the Name begins, and 'sz' | |
233 | * is the size of the whole message. 'name' must be allocated | |
234 | * by the caller. | |
235 | * | |
236 | * Supports the RFC1035 message compression through recursion. | |
237 | * | |
238 | * Updates the new buffer offset. | |
239 | * | |
240 | * Returns 0 (success) or 1 (error) | |
241 | */ | |
242 | static int | |
243 | rfc1035NameUnpack(const char *buf, size_t sz, unsigned int *off, unsigned short *rdlength, char *name, size_t ns, int rdepth) | |
244 | { | |
245 | unsigned int no = 0; | |
246 | unsigned char c; | |
247 | size_t len; | |
248 | assert(ns > 0); | |
249 | do { | |
250 | if ((*off) >= sz) { | |
251 | RFC1035_UNPACK_DEBUG; | |
252 | return 1; | |
253 | } | |
254 | c = *(buf + (*off)); | |
255 | if (c > 191) { | |
256 | /* blasted compression */ | |
257 | unsigned short s; | |
258 | unsigned int ptr; | |
259 | if (rdepth > 64) { /* infinite pointer loop */ | |
260 | RFC1035_UNPACK_DEBUG; | |
261 | return 1; | |
262 | } | |
263 | memcpy(&s, buf + (*off), sizeof(s)); | |
264 | s = ntohs(s); | |
265 | (*off) += sizeof(s); | |
266 | /* Sanity check */ | |
267 | if ((*off) > sz) { | |
268 | RFC1035_UNPACK_DEBUG; | |
269 | return 1; | |
270 | } | |
271 | ptr = s & 0x3FFF; | |
272 | /* Make sure the pointer is inside this message */ | |
273 | if (ptr >= sz) { | |
274 | RFC1035_UNPACK_DEBUG; | |
275 | return 1; | |
276 | } | |
277 | return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, ns - no, rdepth + 1); | |
278 | } else if (c > RFC1035_MAXLABELSZ) { | |
279 | /* | |
280 | * "(The 10 and 01 combinations are reserved for future use.)" | |
281 | */ | |
282 | RFC1035_UNPACK_DEBUG; | |
283 | return 1; | |
284 | } else { | |
285 | (*off)++; | |
286 | len = (size_t) c; | |
287 | if (len == 0) | |
288 | break; | |
289 | if (len > (ns - no - 1)) { /* label won't fit */ | |
290 | RFC1035_UNPACK_DEBUG; | |
291 | return 1; | |
292 | } | |
293 | if ((*off) + len >= sz) { /* message is too short */ | |
294 | RFC1035_UNPACK_DEBUG; | |
295 | return 1; | |
296 | } | |
297 | memcpy(name + no, buf + (*off), len); | |
298 | (*off) += len; | |
299 | no += len; | |
300 | *(name + (no++)) = '.'; | |
301 | if (rdlength) | |
302 | *rdlength += len + 1; | |
303 | } | |
304 | } while (c > 0 && no < ns); | |
305 | if (no) | |
306 | *(name + no - 1) = '\0'; | |
307 | else | |
308 | *name = '\0'; | |
309 | /* make sure we didn't allow someone to overflow the name buffer */ | |
310 | assert(no <= ns); | |
311 | return 0; | |
312 | } | |
313 | ||
314 | /* | |
315 | * rfc1035RRPack() | |
316 | * | |
317 | * Packs a RFC1035 Resource Record into a message buffer from 'RR'. | |
318 | * The caller must allocate and free RR->rdata and RR->name! | |
319 | * | |
320 | * Updates the new message buffer. | |
321 | * | |
322 | * Returns the number of bytes added to the buffer or 0 for error. | |
323 | */ | |
324 | int | |
325 | rfc1035RRPack(char *buf, const size_t sz, const rfc1035_rr * RR) | |
326 | { | |
327 | unsigned int off; | |
328 | uint16_t s; | |
329 | uint32_t i; | |
330 | ||
331 | off = rfc1035NamePack(buf, sz, RR->name); | |
332 | ||
333 | /* | |
334 | * Make sure the remaining message has enough octets for the | |
335 | * rest of the RR fields. | |
336 | */ | |
337 | if ((off + sizeof(s)*3 + sizeof(i) + RR->rdlength) > sz) { | |
338 | return 0; | |
339 | } | |
340 | s = htons(RR->type); | |
341 | memcpy(buf + off, &s, sizeof(s)); | |
342 | off += sizeof(s); | |
343 | s = htons(RR->_class); | |
344 | memcpy(buf + off, &s, sizeof(s)); | |
345 | off += sizeof(s); | |
346 | i = htonl(RR->ttl); | |
347 | memcpy(buf + off, &i, sizeof(i)); | |
348 | off += sizeof(i); | |
349 | s = htons(RR->rdlength); | |
350 | memcpy(buf + off, &s, sizeof(s)); | |
351 | off += sizeof(s); | |
352 | memcpy(buf + off, &(RR->rdata), RR->rdlength); | |
353 | off += RR->rdlength; | |
354 | assert(off <= sz); | |
355 | return off; | |
356 | } | |
357 | ||
358 | /* | |
359 | * rfc1035RRUnpack() | |
360 | * | |
361 | * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer. | |
362 | * The caller must free RR->rdata! | |
363 | * | |
364 | * Updates the new message buffer offset. | |
365 | * | |
366 | * Returns 0 (success) or 1 (error) | |
367 | */ | |
368 | static int | |
369 | rfc1035RRUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_rr * RR) | |
370 | { | |
371 | unsigned short s; | |
372 | unsigned int i; | |
373 | unsigned short rdlength; | |
374 | unsigned int rdata_off; | |
375 | if (rfc1035NameUnpack(buf, sz, off, nullptr, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) { | |
376 | RFC1035_UNPACK_DEBUG; | |
377 | memset(RR, '\0', sizeof(*RR)); | |
378 | return 1; | |
379 | } | |
380 | /* | |
381 | * Make sure the remaining message has enough octets for the | |
382 | * rest of the RR fields. | |
383 | */ | |
384 | if ((*off) + 10 > sz) { | |
385 | RFC1035_UNPACK_DEBUG; | |
386 | memset(RR, '\0', sizeof(*RR)); | |
387 | return 1; | |
388 | } | |
389 | memcpy(&s, buf + (*off), sizeof(s)); | |
390 | (*off) += sizeof(s); | |
391 | RR->type = ntohs(s); | |
392 | memcpy(&s, buf + (*off), sizeof(s)); | |
393 | (*off) += sizeof(s); | |
394 | RR->_class = ntohs(s); | |
395 | memcpy(&i, buf + (*off), sizeof(i)); | |
396 | (*off) += sizeof(i); | |
397 | RR->ttl = ntohl(i); | |
398 | memcpy(&s, buf + (*off), sizeof(s)); | |
399 | (*off) += sizeof(s); | |
400 | rdlength = ntohs(s); | |
401 | if ((*off) + rdlength > sz) { | |
402 | /* | |
403 | * We got a truncated packet. 'dnscache' truncates UDP | |
404 | * replies at 512 octets, as per RFC 1035. | |
405 | */ | |
406 | RFC1035_UNPACK_DEBUG; | |
407 | memset(RR, '\0', sizeof(*RR)); | |
408 | return 1; | |
409 | } | |
410 | RR->rdlength = rdlength; | |
411 | switch (RR->type) { | |
412 | case RFC1035_TYPE_PTR: | |
413 | RR->rdata = (char*)xmalloc(RFC1035_MAXHOSTNAMESZ); | |
414 | rdata_off = *off; | |
415 | RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */ | |
416 | if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0)) { | |
417 | RFC1035_UNPACK_DEBUG; | |
418 | return 1; | |
419 | } | |
420 | if (rdata_off > ((*off) + rdlength)) { | |
421 | /* | |
422 | * This probably doesn't happen for valid packets, but | |
423 | * I want to make sure that NameUnpack doesn't go beyond | |
424 | * the RDATA area. | |
425 | */ | |
426 | RFC1035_UNPACK_DEBUG; | |
427 | xfree(RR->rdata); | |
428 | memset(RR, '\0', sizeof(*RR)); | |
429 | return 1; | |
430 | } | |
431 | break; | |
432 | case RFC1035_TYPE_A: | |
433 | default: | |
434 | RR->rdata = (char*)xmalloc(rdlength); | |
435 | memcpy(RR->rdata, buf + (*off), rdlength); | |
436 | break; | |
437 | } | |
438 | (*off) += rdlength; | |
439 | assert((*off) <= sz); | |
440 | return 0; | |
441 | } | |
442 | ||
443 | const char * | |
444 | rfc1035ErrorMessage(int n) | |
445 | { | |
446 | if (n < 0) | |
447 | n = -n; | |
448 | switch (n) { | |
449 | case 0: | |
450 | return "No error condition"; | |
451 | break; | |
452 | case 1: | |
453 | return "Format Error: The name server was " | |
454 | "unable to interpret the query."; | |
455 | break; | |
456 | case 2: | |
457 | return "Server Failure: The name server was " | |
458 | "unable to process this query."; | |
459 | break; | |
460 | case 3: | |
461 | return "Name Error: The domain name does " | |
462 | "not exist."; | |
463 | break; | |
464 | case 4: | |
465 | return "Not Implemented: The name server does " | |
466 | "not support the requested kind of query."; | |
467 | break; | |
468 | case 5: | |
469 | return "Refused: The name server refuses to " | |
470 | "perform the specified operation."; | |
471 | break; | |
472 | case rfc1035_unpack_error: | |
473 | return "The DNS reply message is corrupt or could " | |
474 | "not be safely parsed."; | |
475 | break; | |
476 | default: | |
477 | return "Unknown Error"; | |
478 | break; | |
479 | } | |
480 | } | |
481 | ||
482 | void | |
483 | rfc1035RRDestroy(rfc1035_rr ** rr, int n) | |
484 | { | |
485 | if (*rr == nullptr) { | |
486 | return; | |
487 | } | |
488 | ||
489 | while (n-- > 0) { | |
490 | if ((*rr)[n].rdata) | |
491 | xfree((*rr)[n].rdata); | |
492 | } | |
493 | xfree(*rr); | |
494 | *rr = nullptr; | |
495 | } | |
496 | ||
497 | /* | |
498 | * rfc1035QueryUnpack() | |
499 | * | |
500 | * Unpacks a RFC1035 Query Record into 'query' from a message buffer. | |
501 | * | |
502 | * Updates the new message buffer offset. | |
503 | * | |
504 | * Returns 0 (success) or 1 (error) | |
505 | */ | |
506 | static int | |
507 | rfc1035QueryUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_query * query) | |
508 | { | |
509 | unsigned short s; | |
510 | if (rfc1035NameUnpack(buf, sz, off, nullptr, query->name, RFC1035_MAXHOSTNAMESZ, 0)) { | |
511 | RFC1035_UNPACK_DEBUG; | |
512 | memset(query, '\0', sizeof(*query)); | |
513 | return 1; | |
514 | } | |
515 | if (*off + 4 > sz) { | |
516 | RFC1035_UNPACK_DEBUG; | |
517 | memset(query, '\0', sizeof(*query)); | |
518 | return 1; | |
519 | } | |
520 | memcpy(&s, buf + *off, 2); | |
521 | *off += 2; | |
522 | query->qtype = ntohs(s); | |
523 | memcpy(&s, buf + *off, 2); | |
524 | *off += 2; | |
525 | query->qclass = ntohs(s); | |
526 | return 0; | |
527 | } | |
528 | ||
529 | void | |
530 | rfc1035MessageDestroy(rfc1035_message ** msg) | |
531 | { | |
532 | if (!*msg) | |
533 | return; | |
534 | if ((*msg)->query) | |
535 | xfree((*msg)->query); | |
536 | if ((*msg)->answer) | |
537 | rfc1035RRDestroy(&(*msg)->answer, (*msg)->ancount); | |
538 | xfree(*msg); | |
539 | *msg = nullptr; | |
540 | } | |
541 | ||
542 | /* | |
543 | * rfc1035QueryCompare() | |
544 | * | |
545 | * Compares two rfc1035_query entries | |
546 | * | |
547 | * Returns 0 (equal) or !=0 (different) | |
548 | */ | |
549 | int | |
550 | rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b) | |
551 | { | |
552 | size_t la, lb; | |
553 | if (a->qtype != b->qtype) | |
554 | return 1; | |
555 | if (a->qclass != b->qclass) | |
556 | return 1; | |
557 | la = strlen(a->name); | |
558 | lb = strlen(b->name); | |
559 | if (la != lb) { | |
560 | /* Trim root label(s) */ | |
561 | while (la > 0 && a->name[la - 1] == '.') | |
562 | la--; | |
563 | while (lb > 0 && b->name[lb - 1] == '.') | |
564 | lb--; | |
565 | } | |
566 | if (la != lb) | |
567 | return 1; | |
568 | ||
569 | return strncasecmp(a->name, b->name, la); | |
570 | } | |
571 | ||
572 | /* | |
573 | * rfc1035MessageUnpack() | |
574 | * | |
575 | * Takes the contents of a DNS reply and fills in an array | |
576 | * of resource record structures. The records array is allocated | |
577 | * here, and should be freed by calling rfc1035RRDestroy(). | |
578 | * | |
579 | * Returns number of records unpacked, zero if DNS reply indicates | |
580 | * zero answers, or an error number < 0. | |
581 | */ | |
582 | ||
583 | int | |
584 | rfc1035MessageUnpack(const char *buf, | |
585 | size_t sz, | |
586 | rfc1035_message ** answer) | |
587 | { | |
588 | unsigned int off = 0; | |
589 | unsigned int i, j; | |
590 | unsigned int nr = 0; | |
591 | rfc1035_message *msg = nullptr; | |
592 | rfc1035_rr *recs = nullptr; | |
593 | rfc1035_query *querys = nullptr; | |
594 | msg = (rfc1035_message*)xcalloc(1, sizeof(*msg)); | |
595 | if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) { | |
596 | RFC1035_UNPACK_DEBUG; | |
597 | xfree(msg); | |
598 | return -rfc1035_unpack_error; | |
599 | } | |
600 | i = (unsigned int) msg->qdcount; | |
601 | if (i != 1) { | |
602 | /* This can not be an answer to our queries.. */ | |
603 | RFC1035_UNPACK_DEBUG; | |
604 | xfree(msg); | |
605 | return -rfc1035_unpack_error; | |
606 | } | |
607 | querys = msg->query = (rfc1035_query*)xcalloc(i, sizeof(*querys)); | |
608 | for (j = 0; j < i; j++) { | |
609 | if (rfc1035QueryUnpack(buf, sz, &off, &querys[j])) { | |
610 | RFC1035_UNPACK_DEBUG; | |
611 | rfc1035MessageDestroy(&msg); | |
612 | return -rfc1035_unpack_error; | |
613 | } | |
614 | } | |
615 | *answer = msg; | |
616 | if (msg->rcode) { | |
617 | RFC1035_UNPACK_DEBUG; | |
618 | return -msg->rcode; | |
619 | } | |
620 | if (msg->ancount == 0) | |
621 | return 0; | |
622 | i = (unsigned int) msg->ancount; | |
623 | recs = msg->answer = (rfc1035_rr*)xcalloc(i, sizeof(*recs)); | |
624 | for (j = 0; j < i; j++) { | |
625 | if (off >= sz) { /* corrupt packet */ | |
626 | RFC1035_UNPACK_DEBUG; | |
627 | break; | |
628 | } | |
629 | if (rfc1035RRUnpack(buf, sz, &off, &recs[j])) { /* corrupt RR */ | |
630 | RFC1035_UNPACK_DEBUG; | |
631 | break; | |
632 | } | |
633 | nr++; | |
634 | } | |
635 | if (nr == 0) { | |
636 | /* | |
637 | * we expected to unpack some answers (ancount != 0), but | |
638 | * didn't actually get any. | |
639 | */ | |
640 | rfc1035MessageDestroy(&msg); | |
641 | *answer = nullptr; | |
642 | return -rfc1035_unpack_error; | |
643 | } | |
644 | return nr; | |
645 | } | |
646 | ||
647 | /* | |
648 | * rfc1035BuildAQuery() | |
649 | * | |
650 | * Builds a message buffer with a QUESTION to lookup A records | |
651 | * for a hostname. Caller must allocate 'buf' which should | |
652 | * probably be at least 512 octets. The 'szp' initially | |
653 | * specifies the size of the buffer, on return it contains | |
654 | * the size of the message (i.e. how much to write). | |
655 | * Returns the size of the query | |
656 | */ | |
657 | ssize_t | |
658 | rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz) | |
659 | { | |
660 | static rfc1035_message h; | |
661 | size_t offset = 0; | |
662 | memset(&h, '\0', sizeof(h)); | |
663 | h.id = qid; | |
664 | h.qr = 0; | |
665 | h.rd = 1; | |
666 | h.opcode = 0; /* QUERY */ | |
667 | h.qdcount = (unsigned int) 1; | |
668 | h.arcount = (edns_sz > 0 ? 1 : 0); | |
669 | offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); | |
670 | offset += rfc1035QuestionPack(buf + offset, | |
671 | sz - offset, | |
672 | hostname, | |
673 | RFC1035_TYPE_A, | |
674 | RFC1035_CLASS_IN); | |
675 | if (edns_sz > 0) | |
676 | offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz); | |
677 | if (query) { | |
678 | query->qtype = RFC1035_TYPE_A; | |
679 | query->qclass = RFC1035_CLASS_IN; | |
680 | xstrncpy(query->name, hostname, sizeof(query->name)); | |
681 | } | |
682 | assert(offset <= sz); | |
683 | return offset; | |
684 | } | |
685 | ||
686 | /* | |
687 | * rfc1035BuildPTRQuery() | |
688 | * | |
689 | * Builds a message buffer with a QUESTION to lookup PTR records | |
690 | * for an address. Caller must allocate 'buf' which should | |
691 | * probably be at least 512 octets. The 'szp' initially | |
692 | * specifies the size of the buffer, on return it contains | |
693 | * the size of the message (i.e. how much to write). | |
694 | * Returns the size of the query | |
695 | */ | |
696 | ssize_t | |
697 | rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz) | |
698 | { | |
699 | static rfc1035_message h; | |
700 | size_t offset = 0; | |
701 | static char rev[32]; | |
702 | unsigned int i; | |
703 | memset(&h, '\0', sizeof(h)); | |
704 | i = (unsigned int) ntohl(addr.s_addr); | |
705 | snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.", | |
706 | i & 255, | |
707 | (i >> 8) & 255, | |
708 | (i >> 16) & 255, | |
709 | (i >> 24) & 255); | |
710 | h.id = qid; | |
711 | h.qr = 0; | |
712 | h.rd = 1; | |
713 | h.opcode = 0; /* QUERY */ | |
714 | h.qdcount = (unsigned int) 1; | |
715 | h.arcount = (edns_sz > 0 ? 1 : 0); | |
716 | offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); | |
717 | offset += rfc1035QuestionPack(buf + offset, | |
718 | sz - offset, | |
719 | rev, | |
720 | RFC1035_TYPE_PTR, | |
721 | RFC1035_CLASS_IN); | |
722 | if (edns_sz > 0) | |
723 | offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz); | |
724 | if (query) { | |
725 | query->qtype = RFC1035_TYPE_PTR; | |
726 | query->qclass = RFC1035_CLASS_IN; | |
727 | xstrncpy(query->name, rev, sizeof(query->name)); | |
728 | } | |
729 | assert(offset <= sz); | |
730 | return offset; | |
731 | } | |
732 | ||
733 | /* | |
734 | * We're going to retry a former query, but we | |
735 | * just need a new ID for it. Lucky for us ID | |
736 | * is the first field in the message buffer. | |
737 | */ | |
738 | void | |
739 | rfc1035SetQueryID(char *buf, unsigned short qid) | |
740 | { | |
741 | unsigned short s = htons(qid); | |
742 | memcpy(buf, &s, sizeof(s)); | |
743 | } | |
744 |