]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/rfc1035.c
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / lib / rfc1035.c
1
2 /*
3 * $Id$
4 *
5 * Low level DNS protocol routines
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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.
24 *
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.
29 *
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
36 /*
37 * KNOWN BUGS:
38 *
39 * UDP replies with TC set should be retried via TCP
40 */
41
42 #include "config.h"
43 #include "util.h"
44
45 #if HAVE_STDIO_H
46 #include <stdio.h>
47 #endif
48 #if HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #if HAVE_STDLIB_H
52 #include <stdlib.h>
53 #endif
54 #if HAVE_MEMORY_H
55 #include <memory.h>
56 #endif
57 #if HAVE_SYS_TYPES_H
58 #include <sys/types.h>
59 #endif
60 #if HAVE_ASSERT_H
61 #include <assert.h>
62 #endif
63 #if HAVE_NETINET_IN_H
64 #include <netinet/in.h>
65 #endif
66 #if HAVE_ARPA_INET_H
67 #include <arpa/inet.h>
68 #endif
69 #if HAVE_STRINGS_H
70 #include <strings.h>
71 #endif
72
73 #include "rfc1035.h"
74
75 #define RFC1035_MAXLABELSZ 63
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
84
85
86 int rfc1035_errno;
87 const char *rfc1035_error_message;
88
89 /*
90 * rfc1035HeaderPack()
91 *
92 * Packs a rfc1035_header structure into a buffer.
93 * Returns number of octets packed (should always be 12)
94 */
95 int
96 rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr)
97 {
98 int off = 0;
99 unsigned short s;
100 unsigned short t;
101 assert(sz >= 12);
102 s = htons(hdr->id);
103 memcpy(buf + off, &s, sizeof(s));
104 off += sizeof(s);
105 t = 0;
106 t |= hdr->qr << 15;
107 t |= (hdr->opcode << 11);
108 t |= (hdr->aa << 10);
109 t |= (hdr->tc << 9);
110 t |= (hdr->rd << 8);
111 t |= (hdr->ra << 7);
112 t |= hdr->rcode;
113 s = htons(t);
114 memcpy(buf + off, &s, sizeof(s));
115 off += sizeof(s);
116 s = htons(hdr->qdcount);
117 memcpy(buf + off, &s, sizeof(s));
118 off += sizeof(s);
119 s = htons(hdr->ancount);
120 memcpy(buf + off, &s, sizeof(s));
121 off += sizeof(s);
122 s = htons(hdr->nscount);
123 memcpy(buf + off, &s, sizeof(s));
124 off += sizeof(s);
125 s = htons(hdr->arcount);
126 memcpy(buf + off, &s, sizeof(s));
127 off += sizeof(s);
128 assert(off == 12);
129 return off;
130 }
131
132 /*
133 * rfc1035LabelPack()
134 *
135 * Packs a label into a buffer. The format of
136 * a label is one octet specifying the number of character
137 * bytes to follow. Labels must be smaller than 64 octets.
138 * Returns number of octets packed.
139 */
140 static int
141 rfc1035LabelPack(char *buf, size_t sz, const char *label)
142 {
143 int off = 0;
144 size_t len = label ? strlen(label) : 0;
145 if (label)
146 assert(!strchr(label, '.'));
147 if (len > RFC1035_MAXLABELSZ)
148 len = RFC1035_MAXLABELSZ;
149 assert(sz >= len + 1);
150 *(buf + off) = (char) len;
151 off++;
152 memcpy(buf + off, label, len);
153 off += len;
154 return off;
155 }
156
157 /*
158 * rfc1035NamePack()
159 *
160 * Packs a name into a buffer. Names are packed as a
161 * sequence of labels, terminated with NULL label.
162 * Note message compression is not supported here.
163 * Returns number of octets packed.
164 */
165 static int
166 rfc1035NamePack(char *buf, size_t sz, const char *name)
167 {
168 unsigned int off = 0;
169 char *copy = xstrdup(name);
170 char *t;
171 /*
172 * NOTE: use of strtok here makes names like foo....com valid.
173 */
174 for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
175 off += rfc1035LabelPack(buf + off, sz - off, t);
176 xfree(copy);
177 off += rfc1035LabelPack(buf + off, sz - off, NULL);
178 assert(off <= sz);
179 return off;
180 }
181
182 /*
183 * rfc1035QuestionPack()
184 *
185 * Packs a QUESTION section of a message.
186 * Returns number of octets packed.
187 */
188 int
189 rfc1035QuestionPack(char *buf,
190 const size_t sz,
191 const char *name,
192 const unsigned short type,
193 const unsigned short _class)
194 {
195 unsigned int off = 0;
196 unsigned short s;
197 off += rfc1035NamePack(buf + off, sz - off, name);
198 s = htons(type);
199 memcpy(buf + off, &s, sizeof(s));
200 off += sizeof(s);
201 s = htons(_class);
202 memcpy(buf + off, &s, sizeof(s));
203 off += sizeof(s);
204 assert(off <= sz);
205 return off;
206 }
207
208 /*
209 * rfc1035HeaderUnpack()
210 *
211 * Unpacks a RFC1035 message header buffer into the header fields
212 * of the rfc1035_message structure.
213 *
214 * Updates the buffer offset, which is the same as number of
215 * octects unpacked since the header starts at offset 0.
216 *
217 * Returns 0 (success) or 1 (error)
218 */
219 int
220 rfc1035HeaderUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_message * h)
221 {
222 unsigned short s;
223 unsigned short t;
224 assert(*off == 0);
225 /*
226 * The header is 12 octets. This is a bogus message if the size
227 * is less than that.
228 */
229 if (sz < 12)
230 return 1;
231 memcpy(&s, buf + (*off), sizeof(s));
232 (*off) += sizeof(s);
233 h->id = ntohs(s);
234 memcpy(&s, buf + (*off), sizeof(s));
235 (*off) += sizeof(s);
236 t = ntohs(s);
237 h->qr = (t >> 15) & 0x01;
238 h->opcode = (t >> 11) & 0x0F;
239 h->aa = (t >> 10) & 0x01;
240 h->tc = (t >> 9) & 0x01;
241 h->rd = (t >> 8) & 0x01;
242 h->ra = (t >> 7) & 0x01;
243 /*
244 * We might want to check that the reserved 'Z' bits (6-4) are
245 * all zero as per RFC 1035. If not the message should be
246 * rejected.
247 * NO! RFCs say ignore inbound reserved, they may be used in future.
248 * NEW messages need to be set 0, thats all.
249 */
250 h->rcode = t & 0x0F;
251 memcpy(&s, buf + (*off), sizeof(s));
252 (*off) += sizeof(s);
253 h->qdcount = ntohs(s);
254 memcpy(&s, buf + (*off), sizeof(s));
255 (*off) += sizeof(s);
256 h->ancount = ntohs(s);
257 memcpy(&s, buf + (*off), sizeof(s));
258 (*off) += sizeof(s);
259 h->nscount = ntohs(s);
260 memcpy(&s, buf + (*off), sizeof(s));
261 (*off) += sizeof(s);
262 h->arcount = ntohs(s);
263 assert((*off) == 12);
264 return 0;
265 }
266
267 /*
268 * rfc1035NameUnpack()
269 *
270 * Unpacks a Name in a message buffer into a char*.
271 * Note 'buf' points to the beginning of the whole message,
272 * 'off' points to the spot where the Name begins, and 'sz'
273 * is the size of the whole message. 'name' must be allocated
274 * by the caller.
275 *
276 * Supports the RFC1035 message compression through recursion.
277 *
278 * Updates the new buffer offset.
279 *
280 * Returns 0 (success) or 1 (error)
281 */
282 static int
283 rfc1035NameUnpack(const char *buf, size_t sz, unsigned int *off, unsigned short *rdlength, char *name, size_t ns, int rdepth)
284 {
285 unsigned int no = 0;
286 unsigned char c;
287 size_t len;
288 assert(ns > 0);
289 do {
290 assert((*off) < sz);
291 c = *(buf + (*off));
292 if (c > 191) {
293 /* blasted compression */
294 unsigned short s;
295 unsigned int ptr;
296 if (rdepth > 64) { /* infinite pointer loop */
297 RFC1035_UNPACK_DEBUG;
298 return 1;
299 }
300 memcpy(&s, buf + (*off), sizeof(s));
301 s = ntohs(s);
302 (*off) += sizeof(s);
303 /* Sanity check */
304 if ((*off) > sz) {
305 RFC1035_UNPACK_DEBUG;
306 return 1;
307 }
308 ptr = s & 0x3FFF;
309 /* Make sure the pointer is inside this message */
310 if (ptr >= sz) {
311 RFC1035_UNPACK_DEBUG;
312 return 1;
313 }
314 return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, ns - no, rdepth + 1);
315 } else if (c > RFC1035_MAXLABELSZ) {
316 /*
317 * "(The 10 and 01 combinations are reserved for future use.)"
318 */
319 RFC1035_UNPACK_DEBUG;
320 return 1;
321 } else {
322 (*off)++;
323 len = (size_t) c;
324 if (len == 0)
325 break;
326 if (len > (ns - no - 1)) { /* label won't fit */
327 RFC1035_UNPACK_DEBUG;
328 return 1;
329 }
330 if ((*off) + len >= sz) { /* message is too short */
331 RFC1035_UNPACK_DEBUG;
332 return 1;
333 }
334 memcpy(name + no, buf + (*off), len);
335 (*off) += len;
336 no += len;
337 *(name + (no++)) = '.';
338 if (rdlength)
339 *rdlength += len + 1;
340 }
341 } while (c > 0 && no < ns);
342 if (no)
343 *(name + no - 1) = '\0';
344 else
345 *name = '\0';
346 /* make sure we didn't allow someone to overflow the name buffer */
347 assert(no <= ns);
348 return 0;
349 }
350
351 /*
352 * rfc1035RRUnpack()
353 *
354 * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
355 * The caller must free RR->rdata!
356 *
357 * Updates the new message buffer offset.
358 *
359 * Returns 0 (success) or 1 (error)
360 */
361 static int
362 rfc1035RRUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_rr * RR)
363 {
364 unsigned short s;
365 unsigned int i;
366 unsigned short rdlength;
367 unsigned int rdata_off;
368 if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
369 RFC1035_UNPACK_DEBUG;
370 memset(RR, '\0', sizeof(*RR));
371 return 1;
372 }
373 /*
374 * Make sure the remaining message has enough octets for the
375 * rest of the RR fields.
376 */
377 if ((*off) + 10 > sz) {
378 RFC1035_UNPACK_DEBUG;
379 memset(RR, '\0', sizeof(*RR));
380 return 1;
381 }
382 memcpy(&s, buf + (*off), sizeof(s));
383 (*off) += sizeof(s);
384 RR->type = ntohs(s);
385 memcpy(&s, buf + (*off), sizeof(s));
386 (*off) += sizeof(s);
387 RR->_class = ntohs(s);
388 memcpy(&i, buf + (*off), sizeof(i));
389 (*off) += sizeof(i);
390 RR->ttl = ntohl(i);
391 memcpy(&s, buf + (*off), sizeof(s));
392 (*off) += sizeof(s);
393 rdlength = ntohs(s);
394 if ((*off) + rdlength > sz) {
395 /*
396 * We got a truncated packet. 'dnscache' truncates UDP
397 * replies at 512 octets, as per RFC 1035.
398 */
399 RFC1035_UNPACK_DEBUG;
400 memset(RR, '\0', sizeof(*RR));
401 return 1;
402 }
403 RR->rdlength = rdlength;
404 switch (RR->type) {
405 #if DNS_CNAME
406 case RFC1035_TYPE_CNAME:
407 #endif
408 case RFC1035_TYPE_PTR:
409 RR->rdata = (char*)xmalloc(RFC1035_MAXHOSTNAMESZ);
410 rdata_off = *off;
411 RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */
412 if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0)) {
413 RFC1035_UNPACK_DEBUG;
414 return 1;
415 }
416 if (rdata_off > ((*off) + rdlength)) {
417 /*
418 * This probably doesn't happen for valid packets, but
419 * I want to make sure that NameUnpack doesn't go beyond
420 * the RDATA area.
421 */
422 RFC1035_UNPACK_DEBUG;
423 xfree(RR->rdata);
424 memset(RR, '\0', sizeof(*RR));
425 return 1;
426 }
427 break;
428 case RFC1035_TYPE_A:
429 default:
430 RR->rdata = (char*)xmalloc(rdlength);
431 memcpy(RR->rdata, buf + (*off), rdlength);
432 break;
433 }
434 (*off) += rdlength;
435 assert((*off) <= sz);
436 return 0;
437 }
438
439 static void
440 rfc1035SetErrno(int n)
441 {
442 switch (rfc1035_errno = n) {
443 case 0:
444 rfc1035_error_message = "No error condition";
445 break;
446 case 1:
447 rfc1035_error_message = "Format Error: The name server was "
448 "unable to interpret the query.";
449 break;
450 case 2:
451 rfc1035_error_message = "Server Failure: The name server was "
452 "unable to process this query.";
453 break;
454 case 3:
455 rfc1035_error_message = "Name Error: The domain name does "
456 "not exist.";
457 break;
458 case 4:
459 rfc1035_error_message = "Not Implemented: The name server does "
460 "not support the requested kind of query.";
461 break;
462 case 5:
463 rfc1035_error_message = "Refused: The name server refuses to "
464 "perform the specified operation.";
465 break;
466 case rfc1035_unpack_error:
467 rfc1035_error_message = "The DNS reply message is corrupt or could "
468 "not be safely parsed.";
469 break;
470 default:
471 rfc1035_error_message = "Unknown Error";
472 break;
473 }
474 }
475
476 void
477 rfc1035RRDestroy(rfc1035_rr ** rr, int n)
478 {
479 if (*rr == NULL || n < 1) {
480 return;
481 }
482
483 while (n--) {
484 if ((*rr)[n].rdata)
485 xfree((*rr)[n].rdata);
486 }
487 xfree(*rr);
488 *rr = NULL;
489 }
490
491 /*
492 * rfc1035QueryUnpack()
493 *
494 * Unpacks a RFC1035 Query Record into 'query' from a message buffer.
495 *
496 * Updates the new message buffer offset.
497 *
498 * Returns 0 (success) or 1 (error)
499 */
500 static int
501 rfc1035QueryUnpack(const char *buf, size_t sz, unsigned int *off, rfc1035_query * query)
502 {
503 unsigned short s;
504 if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) {
505 RFC1035_UNPACK_DEBUG;
506 memset(query, '\0', sizeof(*query));
507 return 1;
508 }
509 if (*off + 4 > sz) {
510 RFC1035_UNPACK_DEBUG;
511 memset(query, '\0', sizeof(*query));
512 return 1;
513 }
514 memcpy(&s, buf + *off, 2);
515 *off += 2;
516 query->qtype = ntohs(s);
517 memcpy(&s, buf + *off, 2);
518 *off += 2;
519 query->qclass = ntohs(s);
520 return 0;
521 }
522
523 void
524 rfc1035MessageDestroy(rfc1035_message ** msg)
525 {
526 if (!*msg)
527 return;
528 if ((*msg)->query)
529 xfree((*msg)->query);
530 if ((*msg)->answer)
531 rfc1035RRDestroy(&(*msg)->answer, (*msg)->ancount);
532 xfree(*msg);
533 *msg = NULL;
534 }
535
536 /*
537 * rfc1035QueryCompare()
538 *
539 * Compares two rfc1035_query entries
540 *
541 * Returns 0 (equal) or !=0 (different)
542 */
543 int
544 rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b)
545 {
546 size_t la, lb;
547 if (a->qtype != b->qtype)
548 return 1;
549 if (a->qclass != b->qclass)
550 return 1;
551 la = strlen(a->name);
552 lb = strlen(b->name);
553 if (la != lb) {
554 /* Trim root label(s) */
555 while (la > 0 && a->name[la - 1] == '.')
556 la--;
557 while (lb > 0 && b->name[lb - 1] == '.')
558 lb--;
559 }
560 if (la != lb)
561 return 1;
562
563 return strncasecmp(a->name, b->name, la);
564 }
565
566 /*
567 * rfc1035MessageUnpack()
568 *
569 * Takes the contents of a DNS reply and fills in an array
570 * of resource record structures. The records array is allocated
571 * here, and should be freed by calling rfc1035RRDestroy().
572 *
573 * Returns number of records unpacked, zero if DNS reply indicates
574 * zero answers, or an error number < 0.
575 */
576
577 int
578 rfc1035MessageUnpack(const char *buf,
579 size_t sz,
580 rfc1035_message ** answer)
581 {
582 unsigned int off = 0;
583 unsigned int i, j;
584 unsigned int nr = 0;
585 rfc1035_message *msg = NULL;
586 rfc1035_rr *recs = NULL;
587 rfc1035_query *querys = NULL;
588 msg = (rfc1035_message*)xcalloc(1, sizeof(*msg));
589 if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) {
590 RFC1035_UNPACK_DEBUG;
591 rfc1035SetErrno(rfc1035_unpack_error);
592 xfree(msg);
593 return -rfc1035_unpack_error;
594 }
595 rfc1035_errno = 0;
596 rfc1035_error_message = NULL;
597 i = (unsigned int) msg->qdcount;
598 if (i != 1) {
599 /* This can not be an answer to our queries.. */
600 RFC1035_UNPACK_DEBUG;
601 rfc1035SetErrno(rfc1035_unpack_error);
602 xfree(msg);
603 return -rfc1035_unpack_error;
604 }
605 querys = msg->query = (rfc1035_query*)xcalloc(i, sizeof(*querys));
606 for (j = 0; j < i; j++) {
607 if (rfc1035QueryUnpack(buf, sz, &off, &querys[j])) {
608 RFC1035_UNPACK_DEBUG;
609 rfc1035SetErrno(rfc1035_unpack_error);
610 rfc1035MessageDestroy(&msg);
611 return -rfc1035_unpack_error;
612 }
613 }
614 *answer = msg;
615 if (msg->rcode) {
616 RFC1035_UNPACK_DEBUG;
617 rfc1035SetErrno((int) msg->rcode);
618 return -rfc1035_errno;
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 = NULL;
642 rfc1035SetErrno(rfc1035_unpack_error);
643 return -rfc1035_unpack_error;
644 }
645 return nr;
646 }
647
648 /*
649 * rfc1035BuildAQuery()
650 *
651 * Builds a message buffer with a QUESTION to lookup A records
652 * for a hostname. Caller must allocate 'buf' which should
653 * probably be at least 512 octets. The 'szp' initially
654 * specifies the size of the buffer, on return it contains
655 * the size of the message (i.e. how much to write).
656 * Returns the size of the query
657 */
658 ssize_t
659 rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
660 {
661 static rfc1035_message h;
662 size_t offset = 0;
663 memset(&h, '\0', sizeof(h));
664 h.id = qid;
665 h.qr = 0;
666 h.rd = 1;
667 h.opcode = 0; /* QUERY */
668 h.qdcount = (unsigned int) 1;
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 (query) {
676 query->qtype = RFC1035_TYPE_A;
677 query->qclass = RFC1035_CLASS_IN;
678 xstrncpy(query->name, hostname, sizeof(query->name));
679 }
680 assert(offset <= sz);
681 return offset;
682 }
683
684 /*
685 * rfc1035BuildPTRQuery()
686 *
687 * Builds a message buffer with a QUESTION to lookup PTR records
688 * for an address. Caller must allocate 'buf' which should
689 * probably be at least 512 octets. The 'szp' initially
690 * specifies the size of the buffer, on return it contains
691 * the size of the message (i.e. how much to write).
692 * Returns the size of the query
693 */
694 ssize_t
695 rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query)
696 {
697 static rfc1035_message h;
698 size_t offset = 0;
699 static char rev[32];
700 unsigned int i;
701 memset(&h, '\0', sizeof(h));
702 i = (unsigned int) ntohl(addr.s_addr);
703 snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.",
704 i & 255,
705 (i >> 8) & 255,
706 (i >> 16) & 255,
707 (i >> 24) & 255);
708 h.id = qid;
709 h.qr = 0;
710 h.rd = 1;
711 h.opcode = 0; /* QUERY */
712 h.qdcount = (unsigned int) 1;
713 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
714 offset += rfc1035QuestionPack(buf + offset,
715 sz - offset,
716 rev,
717 RFC1035_TYPE_PTR,
718 RFC1035_CLASS_IN);
719 if (query) {
720 query->qtype = RFC1035_TYPE_PTR;
721 query->qclass = RFC1035_CLASS_IN;
722 xstrncpy(query->name, rev, sizeof(query->name));
723 }
724 assert(offset <= sz);
725 return offset;
726 }
727
728 /*
729 * We're going to retry a former query, but we
730 * just need a new ID for it. Lucky for us ID
731 * is the first field in the message buffer.
732 */
733 void
734 rfc1035SetQueryID(char *buf, unsigned short qid)
735 {
736 unsigned short s = htons(qid);
737 memcpy(buf, &s, sizeof(s));
738 }
739
740 #if DRIVER
741 #include <sys/socket.h>
742 #include <sys/time.h>
743 int
744 main(int argc, char *argv[])
745 {
746 char input[512];
747 char buf[512];
748 char rbuf[512];
749 size_t sz = 512;
750 unsigned short sid;
751 int s;
752 int rl;
753 struct sockaddr_in S;
754 if (3 != argc) {
755 fprintf(stderr, "usage: %s ip port\n", argv[0]);
756 return 1;
757 }
758 setbuf(stdout, NULL);
759 setbuf(stderr, NULL);
760 s = socket(PF_INET, SOCK_DGRAM, 0);
761 if (s < 0) {
762 perror("socket");
763 return 1;
764 }
765 memset(&S, '\0', sizeof(S));
766 S.sin_family = AF_INET;
767 S.sin_port = htons(atoi(argv[2]));
768 S.sin_addr.s_addr = inet_addr(argv[1]);
769 while (fgets(input, 512, stdin)) {
770 struct in_addr junk;
771 strtok(input, "\r\n");
772 memset(buf, '\0', 512);
773 sz = 512;
774 if (inet_pton(AF_INET, input, &junk)) {
775 sid = rfc1035BuildPTRQuery(junk, buf, &sz);
776 } else {
777 sid = rfc1035BuildAQuery(input, buf, &sz);
778 }
779 sendto(s, buf, sz, 0, (struct sockaddr *) &S, sizeof(S));
780 do {
781 fd_set R;
782 struct timeval to;
783 FD_ZERO(&R);
784 FD_SET(s, &R);
785 to.tv_sec = 10;
786 to.tv_usec = 0;
787 rl = select(s + 1, &R, NULL, NULL, &to);
788 } while (0);
789 if (rl < 1) {
790 printf("TIMEOUT\n");
791 continue;
792 }
793 memset(rbuf, '\0', 512);
794 rl = recv(s, rbuf, 512, 0);
795 {
796 unsigned short rid = 0;
797 int i;
798 int n;
799 rfc1035_rr *answers = NULL;
800 n = rfc1035AnswersUnpack(rbuf,
801 rl,
802 &answers,
803 &rid);
804 if (n < 0) {
805 printf("ERROR %d\n", rfc1035_errno);
806 } else if (rid != sid) {
807 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
808 } else {
809 printf("%d answers\n", n);
810 for (i = 0; i < n; i++) {
811 if (answers[i].type == RFC1035_TYPE_A) {
812 struct in_addr a;
813 memcpy(&a, answers[i].rdata, 4);
814 printf("A\t%d\t%s\n", answers[i].ttl, inet_ntoa(a));
815 } else if (answers[i].type == RFC1035_TYPE_PTR) {
816 char ptr[128];
817 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
818 printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
819 } else {
820 fprintf(stderr, "can't print answer type %d\n",
821 (int) answers[i].type);
822 }
823 }
824 }
825 }
826 }
827 return 0;
828 }
829 #endif