Annotation of embedaddon/trafshow/domain_resolver.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1999-2004 Rinet Corp., Novosibirsk, Russia
3: *
4: * Redistribution and use in source forms, with and without modification,
5: * are permitted provided that this entire comment appears intact.
6: *
7: * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
8: */
9:
10: #ifdef HAVE_CONFIG_H
11: #include <config.h>
12: #endif
13:
14: #include <sys/types.h>
15: #include <sys/param.h>
16: #include <sys/socket.h>
17: #include <netinet/in.h>
18: #include <arpa/inet.h>
19: #include <arpa/nameser.h>
20: #include <stdio.h>
21: #include <stdlib.h>
22: #include <string.h>
23: #include <errno.h>
24: #ifdef HAVE_PATHS_H
25: #include <paths.h>
26: #endif
27: #ifdef HAVE_RESOLV_H
28: #include <resolv.h>
29: #endif
30:
31: #include "domain_resolver.h"
32: #include "session.h"
33: #include "util.h"
34: #include "trafshow.h" /* just for dprintf() */
35:
36:
37: #ifndef _PATH_RESCONF
38: #define _PATH_RESCONF "/etc/resolv.conf"
39: #endif
40: #ifndef NAMESERVER_TOKEN
41: #define NAMESERVER_TOKEN "nameserver"
42: #endif
43: #ifndef NAMESERVER_PORT
44: #define NAMESERVER_PORT 53 /* nameserver port */
45: #endif
46: #ifndef PACKETSZ
47: #define PACKETSZ 512 /* maximum packet size */
48: #endif
49:
50: static struct sockaddr_in *primary = 0, *secondary = 0;
51:
52: /* currently we handle only following types of nameserver requests */
53: typedef enum {
54: IpAddress, /* get A resource records */
55: DomainName, /* get PTR resource records */
56: MailExchanger /* get MX resource records */
57: } DomainType;
58:
59: #define MAX_EXPAND_TRIES 3 /* to resolve MX pointing to CNAME */
60:
61: typedef struct domain_transact_ent {
62: /* caller supplied data */
63: char *name; /* original requested name (or ip address) */
64: SESSION *sd;
65: void (*callback)(SESSION *sd, DOMAIN_DATA *dd);
66:
67: /* request */
68: u_short reqid; /* request id */
69: u_short expand; /* expand MX pointing to CNAME */
70: int retry; /* retry counter */
71: char *domain; /* actual domain name requested */
72: DomainType type; /* type of request */
73:
74: /* response */
75: int rcode; /* nameserver reply code */
76: DOMAIN_DATA *data; /* list of answered data */
77:
78: struct domain_transact_ent *next;
79: } DOMAIN_TRANSACT;
80:
81: #define TRANSACT(sd) ((DOMAIN_TRANSACT *)session_cookie(sd))
82:
83: static DOMAIN_TRANSACT *first_transact = 0;
84: static DOMAIN_TRANSACT *new_transact();
85: static DOMAIN_TRANSACT *find_transact(u_short reqid);
86: static void free_transact(DOMAIN_TRANSACT *dt);
87: static DOMAIN_TRANSACT *parse_packet(const unsigned char *data, int len);
88:
89: static void nameserver_error(SESSION *sd, int error);
90: static void nameserver_close(SESSION *sd);
91: static void nameserver_reply(SESSION *sd, const unsigned char *data, int len);
92: static int nameserver_request(const char *domain, DomainType type,
93: SESSION *org,
94: void (*notify)(SESSION *sd, DOMAIN_DATA *dd));
95: static int nameserver_send(SESSION *sd);
96: static void discard_request(void *arg); /* (DOMAIN_TRANSACT *) */
97: static u_short unique_reqid();
98:
99: #ifdef HAVE_REPORT_FUNC
100: static const char *rcode2text[6] = {
101: "No error", /* 0 - NOERROR */
102: "Format error", /* 1 - FORMERR */
103: "Server failure", /* 2 - SERVFAIL */
104: "Non existend domain", /* 3 - NXDOAMIN */
105: "Not implemented", /* 4 - NOTIMP */
106: "Query refused" /* 5 - REFUSED */
107: };
108: #endif
109:
110: #ifdef DEBUG
111: void
112: dump_reply(dt)
113: DOMAIN_TRANSACT *dt;
114: {
115: DOMAIN_DATA *dd;
116: char ipaddr[50];
117:
118: if (!dt) {
119: printf("REPLY: domain transaction is null\n");
120: return;
121: }
122: printf("REPLY: reqid=%d retry=%d domain=\"%s\" type=%d rcode=\"%s\"\n",
123: dt->reqid, dt->retry, dt->domain, dt->type, rcode2text[dt->rcode]);
124: for (dd = dt->data; dd; dd = dd->next) {
125: printf("REPLY:\tttl=%u\tpref=%u\tname=\"%s\"\taddr=%s\n",
126: dd->ttl, dd->pref, dd->name, intoa(ipaddr, dd->addr));
127:
128: }
129: }
130: #endif
131:
132: int
133: domain_resolver_init()
134: {
135: FILE *fp;
136: int ns_cnt = 0;
137: char *cp, buf[1024];
138:
139: if (!primary) {
140: primary = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
141: if (!primary) return -1;
142: }
143: memset(primary, 0, sizeof(struct sockaddr_in));
144: primary->sin_family = AF_INET;
145: primary->sin_port = htons(NAMESERVER_PORT);
146: primary->sin_addr.s_addr = htonl(0x7f000001);/* 127.0.0.1 by default */
147:
148: if (secondary) {
149: free(secondary);
150: secondary = 0;
151: }
152:
153: if ((fp = fopen(_PATH_RESCONF, "r")) != 0) {
154: while (fgets(buf, sizeof(buf), fp) != 0) {
155: buf[sizeof(buf)-1] = '\0';
156: for (cp = buf; *cp; cp++) {
157: if (*cp == '#' || *cp == '\r' || *cp == '\n') {
158: *cp = '\0';
159: break;
160: }
161: if (*cp < ' ') *cp = ' ';
162: }
163: if (buf[0] == '\0')
164: continue; /* skip empty lines and commentary */
165:
166: if (!strncasecmp(buf, NAMESERVER_TOKEN, sizeof(NAMESERVER_TOKEN)-1)) {
167: cp = strip_blanks(buf + sizeof(NAMESERVER_TOKEN)-1);
168: if (!ns_cnt++) {
169: primary->sin_addr.s_addr = inet_addr(cp);
170: } else if (!secondary) {
171: secondary = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
172: if (secondary) {
173: memset(secondary, 0, sizeof(struct sockaddr_in));
174: secondary->sin_family = AF_INET;
175: secondary->sin_port = htons(NAMESERVER_PORT);
176: secondary->sin_addr.s_addr = inet_addr(cp);
177: }
178: }
179: }
180: }
181: (void)fclose(fp);
182: }
183: return ns_cnt;
184: }
185:
186: int
187: domain_resolve_addr(domain, sd, notify)
188: const char *domain;
189: SESSION *sd;
190: void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
191: {
192: return nameserver_request(domain, IpAddress, sd, notify);
193: }
194:
195: int
196: domain_resolve_mxlist(domain, sd, notify)
197: const char *domain;
198: SESSION *sd;
199: void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
200: {
201: return nameserver_request(domain, MailExchanger, sd, notify);
202: }
203:
204: int
205: domain_resolve_name(ipaddr, sd, notify)
206: in_addr_t ipaddr;
207: SESSION *sd;
208: void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
209: {
210: return nameserver_request((char *)&ipaddr, DomainName, sd, notify);
211: }
212:
213:
214: /*
215: * Callback function: catch all errors during nameserver request.
216: */
217: static void
218: nameserver_error(sd, error)
219: SESSION *sd;
220: int error;
221: {
222: DOMAIN_TRANSACT *dt = TRANSACT(sd);
223: if (sd && dt) {
224: if (error != ETIMEDOUT) {
225: #ifdef HAVE_REPORT_FUNC
226: report(Warn, 0, error, "%lu: domain_resolver: %s (try=%d)",
227: sd->sid, peertoa(0, session_peer(sd)),
228: dt->retry + 1);
229: #endif
230: } else if (++dt->retry < NAMESERVER_RETRIES) {
231: nameserver_send(sd);
232: return;
233: }
234: }
235: nameserver_close(sd);
236: }
237:
238: /*
239: * Normal close nameserver request.
240: */
241: static void
242: nameserver_close(sd)
243: SESSION *sd;
244: {
245: DOMAIN_TRANSACT *dt = TRANSACT(sd);
246:
247: session_free(sd);
248: if (dt) {
249: if (dt->data) { /* purge unresolved names */
250: if (dt->type != DomainName)
251: domain_data_free(&dt->data, "");
252: else if (dt->data->addr == 0 || dt->data->addr == -1)
253: memcpy(&dt->data->addr, dt->name, sizeof(dt->data->addr));
254: }
255: #ifdef DEBUG
256: dump_reply(dt);
257: #endif
258: if (dt->callback) {
259: (*dt->callback)(dt->sd, dt->data);
260: dt->data = 0; /* received data dispatched */
261: }
262: free_transact(dt);
263: }
264: }
265:
266: static void
267: discard_request(arg)
268: void *arg;
269: {
270: DOMAIN_TRANSACT *dt = (DOMAIN_TRANSACT *)arg;
271: if (dt) {
272: dt->sd = 0;
273: dt->callback = 0;
274: }
275: }
276:
277: static u_short
278: unique_reqid()
279: {
280: static u_short reqid = 0;
281: if (++reqid == 0) reqid++; /* prevent 0 reqid */
282: return reqid;
283: }
284:
285: static DOMAIN_TRANSACT *
286: new_transact()
287: {
288: DOMAIN_TRANSACT *curr;
289: if ((curr = (DOMAIN_TRANSACT *)malloc(sizeof(DOMAIN_TRANSACT))) == 0)
290: return 0;
291: memset(curr, 0, sizeof(DOMAIN_TRANSACT));
292:
293: if (first_transact) {
294: DOMAIN_TRANSACT *prev = first_transact;
295: while (prev->next) prev = prev->next;
296: prev->next = curr;
297: } else first_transact = curr;
298:
299: return curr;
300: }
301:
302: static DOMAIN_TRANSACT *
303: find_transact(reqid)
304: u_short reqid;
305: {
306: DOMAIN_TRANSACT *curr;
307: for (curr = first_transact; curr; curr = curr->next) {
308: if (curr->reqid && curr->reqid == reqid)
309: return curr;
310: }
311: return 0;
312: }
313:
314: static void
315: free_transact(dt)
316: DOMAIN_TRANSACT *dt;
317: {
318: DOMAIN_TRANSACT *curr, *prev, *next;
319:
320: curr = first_transact;
321: prev = 0;
322: while (curr) {
323: if (!dt || curr == dt) {
324: next = curr->next;
325: if (prev)
326: prev->next = next;
327: else first_transact = next;
328:
329: if (curr->sd)
330: session_unbind(curr->sd, discard_request, curr);
331: if (curr->name)
332: free(curr->name);
333: if (curr->domain)
334: free(curr->domain);
335: domain_data_free(&curr->data, 0);
336: free(curr);
337:
338: curr = next;
339: } else {
340: prev = curr;
341: curr = curr->next;
342: }
343: }
344: }
345:
346: DOMAIN_DATA *
347: domain_data_add(list, name, pref)
348: DOMAIN_DATA **list;
349: const char *name;
350: int pref;
351: {
352: DOMAIN_DATA *curr, *last, *prev;
353: int insert;
354: char *cp;
355:
356: /* sanity check */
357: if (!list || !name || !*name) {
358: errno = EINVAL;
359: return 0;
360: }
361:
362: /* sort it by pref ascending (bigger pref farther) */
363: last = prev = 0;
364: insert = 0;
365: for (curr = *list; curr; curr = curr->next) {
366: /* prevent duplicates */
367: if (curr->name && !strcasecmp(curr->name, name))
368: return curr;
369:
370: if (!insert && pref < curr->pref) {
371: insert++;
372: prev = last;
373: }
374: last = curr;
375: }
376: if ((curr = (DOMAIN_DATA *)malloc(sizeof(DOMAIN_DATA))) == 0)
377: return 0;
378: memset(curr, 0, sizeof(DOMAIN_DATA));
379:
380: if ((curr->name = strdup(name)) == 0) {
381: int save_errno = errno;
382: free(curr);
383: save_errno = errno;
384: return 0;
385: }
386: /* make all lowercase */
387: for (cp = curr->name; *cp; cp++) {
388: if (*cp >= 'A' && *cp <= 'Z')
389: *cp = *cp + 32;
390: }
391: curr->pref = pref;
392:
393: if (insert) {
394: if (prev) {
395: curr->next = prev->next;
396: prev->next = curr;
397: } else {
398: curr->next = *list;
399: *list = curr;
400: }
401: } else if (last) {
402: last->next = curr;
403: } else {
404: *list = curr;
405: }
406: return curr;
407: }
408:
409: DOMAIN_DATA *
410: domain_data_find(list, name)
411: DOMAIN_DATA **list;
412: const char *name;
413: {
414: DOMAIN_DATA *curr;
415:
416: /* sanity check */
417: if (!list || !name || !*name)
418: return 0;
419:
420: for (curr = *list; curr; curr = curr->next) {
421: if (!strcasecmp(curr->name, name))
422: return curr;
423: }
424: return 0;
425: }
426:
427: void
428: domain_data_free(list, name)
429: DOMAIN_DATA **list;
430: const char *name;
431: {
432: DOMAIN_DATA *curr, *prev, *next;
433:
434: /* sanity check */
435: if (!list) return;
436:
437: curr = *list;
438: prev = 0;
439: while (curr) {
440: if (!name || (*name == '\0' && curr->addr == 0) ||
441: curr->name == name || !strcasecmp(curr->name, name)) {
442: next = curr->next;
443: if (prev)
444: prev->next = next;
445: else *list = next;
446:
447: if (curr->name) free(curr->name);
448: free(curr);
449:
450: curr = next;
451: } else {
452: prev = curr;
453: curr = curr->next;
454: }
455: }
456: }
457:
458: static int
459: nameserver_request(domain, type, org, notify)
460: const char *domain;
461: DomainType type;
462: SESSION *org;
463: void (*notify)(SESSION *sd, DOMAIN_DATA *dd);
464: {
465: SESSION *sd;
466: DOMAIN_TRANSACT *dt;
467: char buf[MAXDNAME];
468: const u_char *cp;
469:
470: /* sanity check */
471: if (!domain || !*domain) {
472: errno = EINVAL;
473: return -1;
474: }
475: if (!primary && domain_resolver_init() < 0)
476: return -1;
477:
478: if ((sd = session_open(-1, (struct sockaddr *)primary, DataSequence)) == 0)
479: return -1;
480:
481: if ((dt = new_transact()) == 0) {
482: int save_errno = errno;
483: session_free(sd);
484: errno = save_errno;
485: return -1;
486: }
487: switch (type) {
488: case IpAddress:
489: case MailExchanger:
490: dt->name = strdup(domain);
491: (void)strncpy(buf, domain, sizeof(buf));
492: buf[sizeof(buf)-1] = '\0';
493: dt->domain = strdup(buf);
494: break;
495: case DomainName:
496: if ((dt->name = (char *)malloc(sizeof(in_addr_t))) == 0)
497: break;
498: memcpy(dt->name, domain, sizeof(in_addr_t));
499: cp = (u_char *)domain;
500: snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
501: cp[3], cp[2], cp[1], cp[0]);
502: dt->domain = strdup(buf);
503: break;
504: }
505: if (!dt->name || !dt->domain) {
506: int save_errno = errno;
507: session_free(sd);
508: free_transact(dt);
509: errno = save_errno;
510: return -1;
511: }
512: dt->reqid = unique_reqid();
513: dt->type = type;
514:
515: session_setcallback(sd, 0, nameserver_error, nameserver_reply);
516: session_setcookie(sd, dt);
517: session_settimeout(sd, NAMESERVER_TIMEOUT);
518:
519: if (nameserver_send(sd) < 0) {
520: int save_errno = errno;
521: #ifdef HAVE_REPORT_FUNC
522: char ipaddr[50];
523: report(Warn, 0, errno, "%lu: nameserver_send: %s",
524: sd->sid, peertoa(ipaddr, session_peer(sd)));
525: #endif
526: session_free(sd);
527: free_transact(dt);
528: errno = save_errno;
529: return -1;
530: }
531: if (org && session_bind(org, discard_request, dt) != -1)
532: dt->sd = org;
533: dt->callback = notify;
534: return 0;
535: }
536:
537: static int
538: nameserver_send(sd)
539: SESSION *sd;
540: {
541: DOMAIN_TRANSACT *dt = TRANSACT(sd);
542: u_char buf[PACKETSZ];
543: HEADER *hp = (HEADER *)buf;
544: int len;
545: u_char *cp, *dnptrs[50], **dpp, **lastdnptr;
546:
547: /* sanity check */
548: if (!dt) {
549: errno = EINVAL;
550: return -1;
551: }
552: memset(hp, 0, HFIXEDSZ);
553: hp->id = htons(dt->reqid);
554: hp->rd = 1; /* recursion desired */
555: hp->qdcount = htons(1); /* we allways utilize one query per packet */
556:
557: cp = buf + HFIXEDSZ;
558: len = PACKETSZ - (HFIXEDSZ + QFIXEDSZ);
559: dpp = dnptrs;
560: *dpp++ = buf;
561: *dpp = 0;
562: lastdnptr = dnptrs + sizeof(dnptrs) / sizeof(dnptrs[0]);
563:
564: if ((len = dn_comp(dt->domain, cp, len, dnptrs, lastdnptr)) < 0)
565: return -1;
566:
567: cp += len;
568: /* translate our type into appropriate NS opcode && type */
569: switch (dt->type) {
570: case IpAddress:
571: PUTSHORT(T_A, cp);
572: break;
573: case DomainName:
574: PUTSHORT(T_PTR, cp);
575: break;
576: case MailExchanger:
577: PUTSHORT(T_MX, cp);
578: break;
579: }
580: PUTSHORT(C_IN, cp);
581: len = cp - buf;
582:
583: dprintf(("nameserver_send: \"%s\"", dt->domain));
584:
585: return session_send(sd, buf, len);
586: }
587:
588: static void
589: nameserver_reply(sd, data, len)
590: SESSION *sd;
591: const unsigned char *data;
592: int len;
593: {
594: DOMAIN_TRANSACT *dt;
595:
596: /* sanity check */
597: if (!sd) return;
598:
599: if ((dt = parse_packet(data, len)) == 0) {
600: #ifdef HAVE_REPORT_FUNC
601: char ipaddr[50];
602: report(Info, 0, 0, "%lu: nameserver_reply: %s: unexpected packet (len=%d)",
603: sd->sid, peertoa(ipaddr, session_peer(sd)), len);
604: #endif
605: return;
606: }
607: if (dt->rcode < 0) {
608: #ifdef HAVE_REPORT_FUNC
609: char ipaddr[50];
610: report(Info, 0, 0, "%lu: nameserver_reply: %s: broken packet (len=%d try=%d err=%d)",
611: sd->sid, peertoa(ipaddr, session_peer(sd)),
612: len, dt->retry + 1, -dt->rcode);
613: #endif
614: return;
615: }
616: #ifdef HAVE_REPORT_FUNC
617: if (dt->rcode != NOERROR &&
618: dt->rcode != SERVFAIL &&
619: dt->rcode != NXDOMAIN) {
620: char ipaddr[50];
621: report(Crit, 0, 0, "%lu: nameserver_reply: %s: %s (try=%d)",
622: sd->sid, peertoa(ipaddr, session_peer(sd)),
623: rcode2text[dt->rcode], dt->retry + 1);
624: }
625: #endif
626: #ifdef DEBUG
627: dump_reply(dt);
628: #endif
629: if (dt->rcode == NOERROR &&
630: (dt->type == MailExchanger ||
631: (dt->type == IpAddress && dt->expand && dt->expand < MAX_EXPAND_TRIES))) {
632: DOMAIN_DATA *dd;
633: for (dd = dt->data; dd; dd = dd->next) {
634: /* it was CNAME -- expand it */
635: if (dd->name && !dd->addr) {
636: if (dt->domain) {
637: if (!strcasecmp(dd->name, dt->domain))
638: break; /* to prevent looping */
639: free(dt->domain);
640: }
641: if ((dt->domain = strdup(dd->name)) == 0)
642: break;
643: dt->reqid = unique_reqid();
644: dt->expand++;
645: dt->retry = 0;
646: dt->type = IpAddress;
647: if (nameserver_send(sd) < 0)
648: break;
649: return;
650: }
651: }
652: }
653: nameserver_close(sd); /* caller notified inside */
654: }
655:
656: static DOMAIN_TRANSACT *
657: parse_packet(data, len)
658: const unsigned char *data;
659: int len;
660: {
661: const u_char *pkt = data;
662: HEADER *hp = (HEADER *)pkt;
663: const u_char *cp = pkt + HFIXEDSZ;
664: int qdcount, ancount, nscount, arcount, nb;
665: DOMAIN_TRANSACT *dt;
666: DOMAIN_DATA *dd;
667: u_short type, class, rdlen, pref;
668: u_int ttl;
669: char name[MAXDNAME+1];
670:
671: /*
672: * first check the response Header.
673: */
674: if (!hp || len < HFIXEDSZ) {
675: dprintf(("parse_packet: undersized packet, len=%d", len));
676: return 0;
677: }
678: if (!hp->qr) {
679: dprintf(("parse_packet: not a response"));
680: return 0;
681: }
682: if (hp->opcode) {
683: dprintf(("parse_packet: response not a QUERY"));
684: return 0;
685: }
686: if (hp->rcode < NOERROR || hp->rcode > REFUSED) {
687: dprintf(("parse_packet: bad reply code %d", (int)hp->rcode));
688: return 0;
689: }
690: if ((dt = find_transact(ntohs(hp->id))) == 0) {
691: dprintf(("parse_packet: invalid reqid"));
692: return 0;
693: }
694: dt->rcode = hp->rcode; /* Header is OK; reply code fixed */
695:
696: qdcount = ntohs(hp->qdcount);
697: ancount = ntohs(hp->ancount);
698: nscount = ntohs(hp->nscount);
699: arcount = ntohs(hp->arcount);
700:
701: dprintf(("parse_packet: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d",
702: hp->rcode, qdcount, ancount, nscount, arcount));
703:
704: /*
705: * check Question section.
706: */
707: while (qdcount-- > 0) {
708: if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
709: dprintf(("parse_packet: dn_expand: unexpected end of question"));
710: dt->rcode = -1;
711: return dt;
712: }
713: if (strcasecmp(name, dt->domain)) {
714: dprintf(("parse_packet: question name mismatch transaction"));
715: dt->rcode = -2;
716: return dt;
717: }
718: cp += nb;
719: if (cp + 2 * INT16SZ > pkt + len) {
720: dprintf(("parse_packet: unexpected end of question"));
721: dt->rcode = -3;
722: return dt;
723: }
724: GETSHORT(type, cp);
725: GETSHORT(class, cp);
726: if (class != C_IN) {
727: dprintf(("parse_packet: question class mismatch transaction"));
728: dt->rcode = -4;
729: return dt;
730: }
731: if ((type == T_A && dt->type == IpAddress) ||
732: (type == T_PTR && dt->type == DomainName) ||
733: (type == T_MX && dt->type == MailExchanger))
734: continue;
735:
736: dprintf(("parse_packet: question type mismatch transaction"));
737: dt->rcode = -5;
738: return dt;
739: }
740:
741: /*
742: * parse Answer section.
743: */
744: while (ancount-- > 0) {
745: if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
746: dprintf(("parse_packet: dn_expand: unexpected end of answer"));
747: dt->rcode = -10;
748: return dt;
749: }
750: dprintf(("parse_packet: answer name \"%s\"", name));
751: cp += nb;
752: if (cp + 3 * INT16SZ + INT32SZ > pkt + len) {
753: dprintf(("parse_packet: unexpected end of answer"));
754: dt->rcode = -11;
755: return dt;
756: }
757: GETSHORT(type, cp);
758: GETSHORT(class, cp);
759: GETLONG(ttl, cp);
760: GETSHORT(rdlen, cp);
761: if (cp + rdlen > pkt + len) {
762: dprintf(("parse_packet: unexpected end of answer"));
763: dt->rcode = -12;
764: return dt;
765: }
766: if (class != C_IN) {
767: dprintf(("parse_packet: answer class mismatch transaction"));
768: dt->rcode = -13;
769: return dt;
770: }
771: dprintf(("parse_packet: answer rdlen=%d", rdlen));
772:
773: if (type == T_A && dt->type == IpAddress) {
774: /* XXX IPv6 incompatible yet */
775: if (rdlen % sizeof(in_addr_t)) {
776: dprintf(("parse_packet: unexpected rdlen in A RR"));
777: dt->rcode = -14;
778: return dt;
779: }
780: while (rdlen > 0) {
781: dprintf(("parse_packet: A %d.%d.%d.%d (ttl=%d)",
782: cp[0], cp[1], cp[2], cp[3], ttl));
783: if ((dd = domain_data_add(&dt->data, name, 0)) != 0) {
784: if (!dd->ttl || !ttl || dd->ttl > ttl)
785: dd->ttl = ttl;
786: if (dd->addr == 0 || dd->addr == -1)
787: dd->addr = *((in_addr_t *)cp);
788: }
789: cp += sizeof(in_addr_t);
790: rdlen -= sizeof(in_addr_t);
791: }
792: continue;
793: }
794: if (type == T_MX && dt->type == MailExchanger) {
795: if (rdlen < INT16SZ) {
796: dprintf(("parse_packet: unexpected rdlen in MX RR"));
797: dt->rcode = -15;
798: return dt;
799: }
800: GETSHORT(pref, cp);
801: rdlen -= INT16SZ;
802: while (rdlen > 0) {
803: if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
804: dprintf(("parse_packet: dn_expand: unexpected end of answer"));
805: dt->rcode = -16;
806: return dt;
807: }
808: dprintf(("parse_packet: MX %d \"%s\" (ttl=%d)",
809: pref, name, ttl));
810: if ((dd = domain_data_add(&dt->data, name, pref)) != 0) {
811: if (!dd->ttl || !ttl || dd->ttl > ttl)
812: dd->ttl = ttl;
813: }
814: cp += nb;
815: rdlen -= nb;
816: }
817: continue;
818: }
819: if (type == T_PTR && dt->type == DomainName) {
820: while (rdlen > 0) {
821: if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
822: dprintf(("parse_packet: dn_expand: unexpected end of answer"));
823: dt->rcode = -17;
824: return dt;
825: }
826: dprintf(("parse_packet: PTR \"%s\" (ttl=%d)",
827: name, ttl));
828: if ((dd = domain_data_add(&dt->data, name, 0)) != 0) {
829: if (!dd->ttl || !ttl || dd->ttl > ttl)
830: dd->ttl = ttl;
831: }
832: cp += nb;
833: rdlen -= nb;
834: }
835: continue;
836: }
837: if (type == T_CNAME) {
838: dprintf(("parse_packet: CNAME \"%s\" removed", name));
839: domain_data_free(&dt->data, name);
840: cp += rdlen;
841: continue;
842: }
843: /* simply skip it */
844: dprintf(("parse_packet: answer name \"%s\" type %d",
845: name, type));
846: cp += rdlen;
847: }
848:
849: if (dt->type != MailExchanger)
850: return dt;
851:
852: /*
853: * skip Authority section.
854: */
855: while (nscount-- > 0) {
856: if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
857: dprintf(("parse_packet: dn_expand: unexpected end of authority"));
858: dt->rcode = -20;
859: return dt;
860: }
861: cp += nb;
862: if (cp + 3 * INT16SZ + INT32SZ > pkt + len) {
863: dprintf(("parse_packet: unexpected end of authority"));
864: dt->rcode = -21;
865: return dt;
866: }
867: GETSHORT(type, cp);
868: GETSHORT(class, cp);
869: GETLONG(ttl, cp);
870: GETSHORT(rdlen, cp);
871: if (cp + rdlen > pkt + len) {
872: dprintf(("parse_packet: unexpected end of authority"));
873: dt->rcode = -22;
874: return dt;
875: }
876: /* simply skip it */
877: dprintf(("parse_packet: authority name \"%s\" type %d",
878: name, type));
879: cp += rdlen;
880: }
881:
882: /*
883: * parse Additional section.
884: */
885: while (arcount-- > 0) {
886: if ((nb = dn_expand(pkt, pkt + len, cp, name, sizeof(name))) < 0) {
887: dprintf(("parse_packet: dn_expand: unexpected end of answer"));
888: dt->rcode = -30;
889: return dt;
890: }
891: dprintf(("parse_packet: additional name \"%s\"", name));
892: cp += nb;
893: if (cp + 3 * INT16SZ + INT32SZ > pkt + len) {
894: dprintf(("parse_packet: unexpected end of additional"));
895: dt->rcode = -31;
896: return dt;
897: }
898: GETSHORT(type, cp);
899: GETSHORT(class, cp);
900: GETLONG(ttl, cp);
901: GETSHORT(rdlen, cp);
902: if (cp + rdlen > pkt + len) {
903: dprintf(("parse_packet: unexpected end of additional"));
904: dt->rcode = -32;
905: return dt;
906: }
907: if (class == C_IN && type == T_A) {
908: /* XXX IPv6 incompatible yet */
909: if (rdlen % sizeof(in_addr_t)) {
910: dprintf(("parse_packet: unexpected rdlen in A RR"));
911: dt->rcode = -33;
912: return dt;
913: }
914: while (rdlen > 0) {
915: dprintf(("parse_packet: A %d.%d.%d.%d (ttl=%d)",
916: cp[0], cp[1], cp[2], cp[3], ttl));
917: if ((dd = domain_data_find(&dt->data, name)) != 0) {
918: if (!dd->ttl || !ttl || dd->ttl > ttl)
919: dd->ttl = ttl;
920: if (dd->addr == 0 || dd->addr == -1)
921: dd->addr = *((in_addr_t *)cp);
922: }
923: cp += sizeof(in_addr_t);
924: rdlen -= sizeof(in_addr_t);
925: }
926: continue;
927: }
928: /* simply skip it */
929: dprintf(("parse_packet: additional name \"%s\" type %d",
930: name, type));
931: cp += rdlen;
932: }
933:
934: return dt;
935: }
936:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>