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