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