]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/rfc1035.c
comm_incoming crap for internal DNS
[thirdparty/squid.git] / lib / rfc1035.c
CommitLineData
7f3647d6 1/*
706d89bc 2 * $Id: rfc1035.c,v 1.4 1999/04/14 06:38:03 wessels Exp $
7f3647d6 3 *
4 * Low level DNS protocol routines
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from the
11 * Internet community. Development is led by Duane Wessels of the
12 * National Laboratory for Applied Network Research and funded by the
13 * National Science Foundation. Squid is Copyrighted (C) 1998 by
14 * Duane Wessels and the University of California San Diego. Please
15 * see the COPYRIGHT file for full details. Squid incorporates
16 * software developed and/or copyrighted by other sources. Please see
17 * the CREDITS file for full details.
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.
23 *
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.
28 *
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
fb29421b 35#include "config.h"
36
37#if HAVE_STDIO_H
38#include <stdio.h>
39#endif
40#if HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43#if HAVE_STDLIB_H
44#include <stdlib.h>
45#endif
46#if HAVE_MEMORY_H
47#include <memory.h>
48#endif
49#if HAVE_SYS_TYPES_H
50#include <sys/types.h>
51#endif
52#if HAVE_ASSERT_H
53#include <assert.h>
54#endif
55#if HAVE_NETINET_IN_H
56#include <netinet/in.h>
57#endif
58#if HAVE_ARPA_INET_H
59#include <arpa/inet.h>
60#endif
61#if HAVE_STRINGS_H
62#include <strings.h>
63#endif
64
7b724b86 65#include "rfc1035.h"
fb29421b 66
67#define RFC1035_MAXLABELSZ 63
fb29421b 68
7b724b86 69typedef struct _rfc1035_header rfc1035_header;
fb29421b 70
71int rfc1035_errno;
7b724b86 72const char *rfc1035_error_message;
73struct _rfc1035_header {
fb29421b 74 unsigned short id;
75 unsigned int qr:1;
76 unsigned int opcode:4;
77 unsigned int aa:1;
78 unsigned int tc:1;
79 unsigned int rd:1;
80 unsigned int ra:1;
81 unsigned int rcode:4;
82 unsigned short qdcount;
83 unsigned short ancount;
84 unsigned short nscount;
85 unsigned short arcount;
86};
87
fb29421b 88/*
89 * rfc1035HeaderPack()
90 *
7b724b86 91 * Packs a rfc1035_header structure into a buffer.
fb29421b 92 * Returns number of octets packed (should always be 12)
93 */
94static off_t
7b724b86 95rfc1035HeaderPack(char *buf, size_t sz, rfc1035_header * hdr)
fb29421b 96{
97 off_t off = 0;
98 unsigned short s;
99 unsigned short t;
100 assert(sz >= 12);
101 s = htons(hdr->id);
102 memcpy(buf + off, &s, sizeof(s));
103 off += sizeof(s);
104 t = 0;
105 t |= hdr->qr << 15;
106 t |= (hdr->opcode << 11);
107 t |= (hdr->aa << 10);
108 t |= (hdr->tc << 9);
109 t |= (hdr->rd << 8);
110 t |= (hdr->ra << 7);
111 t |= hdr->rcode;
112 s = htons(t);
113 memcpy(buf + off, &s, sizeof(s));
114 off += sizeof(s);
115 s = htons(hdr->qdcount);
116 memcpy(buf + off, &s, sizeof(s));
117 off += sizeof(s);
118 s = htons(hdr->ancount);
119 memcpy(buf + off, &s, sizeof(s));
120 off += sizeof(s);
121 s = htons(hdr->nscount);
122 memcpy(buf + off, &s, sizeof(s));
123 off += sizeof(s);
124 s = htons(hdr->arcount);
125 memcpy(buf + off, &s, sizeof(s));
126 off += sizeof(s);
127 assert(off == 12);
128 return off;
129}
130
131/*
132 * rfc1035LabelPack()
133 *
134 * Packs a label into a buffer. The format of
135 * a label is one octet specifying the number of character
136 * bytes to follow. Labels must be smaller than 64 octets.
137 * Returns number of octets packed.
138 */
139static off_t
140rfc1035LabelPack(char *buf, size_t sz, const char *label)
141{
142 off_t off = 0;
143 size_t len = label ? strlen(label) : 0;
144 if (label)
145 assert(!strchr(label, '.'));
146 if (len > RFC1035_MAXLABELSZ)
147 len = RFC1035_MAXLABELSZ;
148 assert(sz >= len + 1);
149 *(buf + off) = (char) len;
150 off++;
151 memcpy(buf + off, label, len);
152 off += len;
153 return off;
154}
155
156/*
157 * rfc1035NamePack()
158 *
159 * Packs a name into a buffer. Names are packed as a
160 * sequence of labels, terminated with NULL label.
161 * Note message compression is not supported here.
162 * Returns number of octets packed.
163 */
164off_t
165rfc1035NamePack(char *buf, size_t sz, const char *name)
166{
167 off_t off = 0;
168 char *copy = strdup(name);
169 char *t;
170 for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
171 off += rfc1035LabelPack(buf + off, sz - off, t);
172 free(copy);
173 off += rfc1035LabelPack(buf + off, sz - off, NULL);
174 assert(off <= sz);
175 return off;
176}
177
178/*
179 * rfc1035QuestionPack()
180 *
181 * Packs a QUESTION section of a message.
182 * Returns number of octets packed.
183 */
184static off_t
185rfc1035QuestionPack(char *buf,
186 size_t sz,
187 const char *name,
188 unsigned short type,
189 unsigned short class)
190{
191 off_t off = 0;
192 unsigned short s;
193 off += rfc1035NamePack(buf + off, sz - off, name);
194 s = htons(type);
195 memcpy(buf + off, &s, sizeof(s));
196 off += sizeof(s);
197 s = htons(class);
198 memcpy(buf + off, &s, sizeof(s));
199 off += sizeof(s);
200 assert(off <= sz);
201 return off;
202}
203
204/*
205 * rfc1035HeaderUnpack()
206 *
7b724b86 207 * Unpacks a RFC1035 message header buffer into a rfc1035_header
fb29421b 208 * structure.
209 * Returns the new buffer offset, which is the same as number of
210 * octects unpacked since the header starts at offset 0.
211 */
212static off_t
7b724b86 213rfc1035HeaderUnpack(const char *buf, size_t sz, rfc1035_header * h)
fb29421b 214{
215 unsigned short s;
216 unsigned short t;
217 off_t off = 0;
218 assert(sz >= 12);
219 memcpy(&s, buf + off, sizeof(s));
220 off += sizeof(s);
221 h->id = ntohs(s);
222 memcpy(&s, buf + off, sizeof(s));
223 off += sizeof(s);
224 t = ntohs(s);
225 h->qr = (t >> 15) & 0x01;
226 h->opcode = (t >> 11) & 0x0F;
227 h->aa = (t >> 10) & 0x01;
228 h->tc = (t >> 8) & 0x01;
229 h->rd = (t >> 8) & 0x01;
230 h->ra = (t >> 7) & 0x01;
231 h->rcode = t & 0x0F;
232 memcpy(&s, buf + off, sizeof(s));
233 off += sizeof(s);
234 h->qdcount = ntohs(s);
235 memcpy(&s, buf + off, sizeof(s));
236 off += sizeof(s);
237 h->ancount = ntohs(s);
238 memcpy(&s, buf + off, sizeof(s));
239 off += sizeof(s);
240 h->nscount = ntohs(s);
241 memcpy(&s, buf + off, sizeof(s));
242 off += sizeof(s);
243 h->arcount = ntohs(s);
244 assert(off == 12);
245 return off;
246}
247
248/*
249 * rfc1035NameUnpack()
250 *
251 * Unpacks a Name in a message buffer into a char*.
252 * Note 'buf' points to the beginning of the whole message,
253 * 'off' points to the spot where the Name begins, and 'sz'
254 * is the size of the whole message. 'name' must be allocated
255 * by the caller.
256 *
257 * Supports the RFC1035 message compression through recursion.
258 *
259 * Returns the new buffer offset.
260 */
261static off_t
262rfc1035NameUnpack(const char *buf, size_t sz, off_t off, char *name, size_t ns)
263{
264 off_t no = 0;
265 unsigned char c;
266 size_t len;
267 assert(ns > 0);
268 do {
269 c = *(buf + off);
270 if (c > RFC1035_MAXLABELSZ) {
271 /* fucking compression */
272 unsigned short s;
273 off_t ptr;
274 memcpy(&s, buf + off, sizeof(s));
275 s = ntohs(s);
276 off += sizeof(s);
277 ptr = s & 0x3FFF;
278 (void) rfc1035NameUnpack(buf, sz, ptr, name + no, ns - no);
279 return off;
280 } else {
281 off++;
282 len = (size_t) c;
283 if (len == 0)
284 break;
7b724b86 285 if (len > (ns - 1))
286 len = ns - 1;
fb29421b 287 memcpy(name + no, buf + off, len);
288 off += len;
289 no += len;
290 *(name + (no++)) = '.';
291 }
292 } while (c > 0);
293 *(name + no - 1) = '\0';
294 assert(no <= ns);
295 return off;
296}
297
298/*
299 * rfc1035RRUnpack()
300 *
301 * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
302 * The caller must free RR->rdata!
303 * Returns the new message buffer offset.
304 */
305static off_t
7b724b86 306rfc1035RRUnpack(const char *buf, size_t sz, off_t off, rfc1035_rr * RR)
fb29421b 307{
308 unsigned short s;
309 unsigned int i;
310 off = rfc1035NameUnpack(buf, sz, off, RR->name, RFC1035_MAXHOSTNAMESZ);
311 memcpy(&s, buf + off, sizeof(s));
312 off += sizeof(s);
313 RR->type = ntohs(s);
314 memcpy(&s, buf + off, sizeof(s));
315 off += sizeof(s);
316 RR->class = ntohs(s);
317 memcpy(&i, buf + off, sizeof(i));
318 off += sizeof(i);
319 RR->ttl = ntohl(i);
320 memcpy(&s, buf + off, sizeof(s));
321 off += sizeof(s);
322 RR->rdlength = ntohs(s);
323 RR->rdata = malloc(RR->rdlength);
324 memcpy(RR->rdata, buf + off, RR->rdlength);
325 off += RR->rdlength;
326 assert(off <= sz);
327 return off;
328}
329
7b724b86 330static unsigned short
331rfc1035Qid(void)
332{
333 static unsigned short qid = 0x0001;
334 if (++qid == 0xFFFF)
335 qid = 0x0001;
336 return qid;
337}
338
339void
340rfc1035RRDestroy(rfc1035_rr * rr, int n)
341{
342 if (rr == NULL)
343 return;
344 assert(n > 0);
345 while (n--) {
346 if (rr[n].rdata)
347 free(rr[n].rdata);
348 }
349 free(rr);
350}
351
fb29421b 352int
7b724b86 353rfc1035AnswersUnpack(const char *buf,
354 size_t sz,
355 rfc1035_rr ** records,
356 unsigned short *id)
fb29421b 357{
358 off_t off = 0;
359 int l;
360 int i;
7b724b86 361 int nr = 0;
362 rfc1035_header hdr;
363 rfc1035_rr *recs;
fb29421b 364 memset(&hdr, '\0', sizeof(hdr));
365 off = rfc1035HeaderUnpack(buf + off, sz - off, &hdr);
366 *id = hdr.id;
7b724b86 367 rfc1035_errno = 0;
368 rfc1035_error_message = NULL;
fb29421b 369 if (hdr.rcode) {
370 rfc1035_errno = (int) hdr.rcode;
7b724b86 371 switch (rfc1035_errno) {
372 case 0:
373 rfc1035_error_message = "No error condition";
374 break;
375 case 1:
376 rfc1035_error_message = "Format Error: The name server was "
377 "unable to interpret the query.";
378 break;
379 case 2:
380 rfc1035_error_message = "Server Failure: The name server was "
381 "unable to process this query.";
382 break;
383 case 3:
384 rfc1035_error_message = "Name Error: The domain name does "
385 "not exist.";
386 break;
387 case 4:
388 rfc1035_error_message = "Not Implemented: The name server does "
389 "not support the requested kind of query.";
390 break;
391 case 5:
392 rfc1035_error_message = "Refused: The name server refuses to "
393 "perform the specified operation.";
394 break;
395 default:
396 rfc1035_error_message = "Unknown Error";
397 break;
398 }
fb29421b 399 return -rfc1035_errno;
400 }
401 i = (int) hdr.qdcount;
402 /* skip question */
403 while (i--) {
404 do {
405 l = (int) *(buf + off);
406 off++;
407 if (l > RFC1035_MAXLABELSZ) { /* compression */
408 off++;
409 break;
410 } else {
411 off += l;
412 }
413 } while (l > 0);
414 off += 4; /* qtype, qclass */
415 assert(off <= sz);
416 }
417 i = (int) hdr.ancount;
706d89bc 418 if (i == 0)
419 return 0;
7b724b86 420 recs = calloc(i, sizeof(*recs));
fb29421b 421 while (i--) {
7b724b86 422 off = rfc1035RRUnpack(buf, sz, off, &recs[i]);
fb29421b 423 assert(off <= sz);
7b724b86 424 nr++;
fb29421b 425 }
7b724b86 426 *records = recs;
427 return nr;
fb29421b 428}
429
430/*
431 * rfc1035BuildQuery()
432 *
433 * Builds a message buffer with a QUESTION to lookup A records
434 * for a hostname. Caller must allocate 'buf' which should
435 * probably be at least 512 octets. The 'szp' initially
436 * specifies the size of the buffer, on return it contains
437 * the size of the message (i.e. how much to write).
438 * Return value is the query ID.
439 */
440unsigned short
7b724b86 441rfc1035BuildAQuery(const char *hostname, char *buf, size_t * szp)
fb29421b 442{
7b724b86 443 static rfc1035_header h;
fb29421b 444 off_t offset = 0;
445 size_t sz = *szp;
446 memset(&h, '\0', sizeof(h));
7b724b86 447 h.id = rfc1035Qid();
fb29421b 448 h.qr = 0;
449 h.rd = 1;
450 h.opcode = 0; /* QUERY */
451 h.qdcount = (unsigned int) 1;
452 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
453 offset += rfc1035QuestionPack(buf + offset,
454 sz - offset,
455 hostname,
456 RFC1035_TYPE_A,
457 RFC1035_CLASS_IN);
458 assert(offset <= sz);
459 *szp = (size_t) offset;
7b724b86 460 return h.id;
fb29421b 461}
462
463#if DRIVER
464int
465main(int argc, char *argv[])
466{
7b724b86 467 rfc1035_header h;
fb29421b 468 char input[512];
469 char buf[512];
470 char rbuf[512];
471 size_t sz = 512;
472 unsigned short sid;
473 off_t offset = 0;
474 int s;
475 int rl;
476 struct sockaddr_in S;
477 setbuf(stdout, NULL);
478 setbuf(stderr, NULL);
479 s = socket(PF_INET, SOCK_DGRAM, 0);
480 if (s < 0) {
481 perror("socket");
482 return 1;
483 }
484 while (fgets(input, 512, stdin)) {
485 strtok(input, "\r\n");
486 memset(buf, '\0', 512);
487 memset(&h, '\0', sizeof(h));
488 offset = 0;
489 h.id = sid = (unsigned short) 0x1234;
490 h.qr = 0;
491 h.rd = 1;
492 h.opcode = 0;
493 h.qdcount = (unsigned int) 1;
494 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
495 offset += rfc1035QuestionPack(buf + offset,
496 sz - offset,
497 input,
498 RFC1035_TYPE_A,
499 RFC1035_CLASS_IN);
500 memset(&S, '\0', sizeof(S));
501 S.sin_family = AF_INET;
502 S.sin_port = htons(53);
503 S.sin_addr.s_addr = inet_addr("128.117.28.219");
504 sendto(s, buf, (size_t) offset, 0, (struct sockaddr *) &S, sizeof(S));
505 do {
7b724b86 506 fd_set R;
507 struct timeval to;
fb29421b 508 FD_ZERO(&R);
509 FD_SET(s, &R);
510 to.tv_sec = 10;
511 to.tv_usec = 0;
7b724b86 512 rl = select(s + 1, &R, NULL, NULL, &to);
513 } while (0);
514 if (rl < 1) {
515 printf("TIMEOUT\n");
516 continue;
517 }
fb29421b 518 memset(rbuf, '\0', 512);
519 rl = recv(s, rbuf, 512, 0);
520 {
521 unsigned short rid;
522 int i;
523 int n;
524 struct in_addr addrs[10];
525 time_t ttl = 0;
526 char rname[RFC1035_MAXHOSTNAMESZ];
527 n = rfc1035ARecordsUnpack(rbuf,
528 rl,
529 addrs, 10,
530 rname, RFC1035_MAXHOSTNAMESZ,
531 &rid,
532 &ttl);
533 if (rid != sid) {
534 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
535 } else if (n < 0) {
536 printf("ERROR %d\n", rfc1035_errno);
537 } else {
538 printf("name\t%s, %d A records\n", rname, n);
539 printf("ttl\t%d\n", (int) ttl);
540 for (i = 0; i < n; i++)
541 printf("addr %d\t%s\n", i, inet_ntoa(addrs[i]));
542 }
543 }
544 }
545 return 0;
546}
547#endif