|
|
1.1 root 1: /*
2: * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)ns_req.c 4.44 (Berkeley) 6/27/90";
22: #endif /* not lint */
23:
24: #include <stdio.h>
25: #include <sys/param.h>
26: #include <sys/uio.h>
27: #include <sys/time.h>
28: #include <sys/socket.h>
29: #include <netinet/in.h>
30: #include <syslog.h>
31: #include <sys/file.h>
32: #include <arpa/nameser.h>
33: #include "ns.h"
34: #include "db.h"
35:
36: #define NADDRECS 20
37:
38: extern int debug;
39: extern FILE *ddt;
40:
41: struct addinfo {
42: char *a_dname; /* domain name */
43: u_short a_class; /* class for address */
44: };
45:
46: struct addinfo addinfo[NADDRECS]; /* additional info records */
47: int addcount; /* number of names in addinfo */
48: int xfr_disabled = 0; /* set to disable zone xfrs */
49: int needs_prime_cache = 0; /* set if we need a priming */
50:
51: u_char *dnptrs[20]; /* ptrs to dnames in message for dn_comp */
52:
53: extern time_t retrytime();
54: extern struct qinfo *sysquery();
55: extern char *localdomain; /* XXX */
56: extern int errno;
57: /*
58: * Process request using database; assemble and send response.
59: */
60: ns_req(msg, msglen, buflen, qsp, from, dfd)
61: u_char *msg;
62: int msglen, buflen;
63: struct qstream *qsp;
64: struct sockaddr_in *from;
65: int dfd;
66: {
67: register HEADER *hp;
68: register u_char *cp;
69: struct namebuf *np;
70: register struct databuf *dp;
71: struct hashbuf *htp;
72: struct netinfo *lp;
73: char *fname, *answers;
74: u_char *eom, *omsg;
75: char dnbuf[MAXDNAME], *dname;
76: u_char **dpp;
77: int n, class, type, count, foundname, founddata, omsglen, cname = 0;
78: u_short id;
79: struct databuf *nsp[NSMAX];
80: struct qinfo *qp;
81: extern struct qinfo *qhead;
82: extern struct netinfo *local();
83: extern int nsid;
84:
85: #ifdef DEBUG
86: if (debug > 3) {
87: fprintf(ddt,"ns_req()\n");
88: fp_query(msg, ddt);
89: }
90: #endif
91:
92: hp = (HEADER *) msg;
93: if (hp->qr) {
94: ns_resp(msg, msglen);
95:
96: /* Now is a safe time for housekeeping */
97: if (needs_prime_cache)
98: prime_cache();
99: return;
100: }
101:
102: hp->rcode = NOERROR;
103: cp = msg + sizeof(HEADER);
104: eom = msg + msglen;
105: dpp = dnptrs;
106: *dpp++ = msg;
107: addcount = 0;
108:
109: switch (hp->opcode) {
110: case QUERY:
111: #ifdef STATS
112: stats[S_QUERIES].cnt++;
113: #endif
114: if (ntohs(hp->qdcount) != 1 ||
115: hp->ancount || hp->nscount || hp->arcount) {
116: #ifdef DEBUG
117: if (debug)
118: fprintf(ddt,"FORMERR Query header counts wrong\n");
119: #endif
120: hp->qdcount = 0;
121: hp->ancount = 0;
122: hp->nscount = 0;
123: hp->arcount = 0;
124: hp->rcode = FORMERR;
125: goto finish;
126: }
127: /*
128: * Get domain name, class, and type.
129: */
130: if ((*cp & INDIR_MASK) == 0)
131: *dpp++ = cp; /* remember name for compression */
132: *dpp = NULL;
133: if ((n = dn_expand(msg, eom, cp, dnbuf,
134: sizeof(dnbuf))) < 0) {
135: #ifdef DEBUG
136: if (debug)
137: fprintf(ddt,"FORMERR Query expand name failed\n");
138: #endif
139: hp->rcode = FORMERR;
140: goto finish;
141: }
142: cp += n;
143: GETSHORT(type, cp);
144: GETSHORT(class, cp);
145: if (cp > eom) {
146: #ifdef DEBUG
147: if (debug)
148: fprintf(ddt,"FORMERR Query message length short\n");
149: #endif
150: hp->rcode = FORMERR;
151: goto finish;
152: }
153: #ifdef DEBUG
154: if (cp < eom)
155: if (debug > 5)
156: fprintf(ddt,"message length > received message\n");
157: #endif
158:
159: #ifdef STATS
160: if ((type > T_ANY) || (type < 0))
161: typestats[0]++; /* Bad type */
162: else
163: typestats[type]++;
164: #endif
165: /*
166: * Process query.
167: */
168: if (type == T_AXFR) {
169: /* refuse request if not a TCP connection */
170: if (qsp == QSTREAM_NULL || xfr_disabled) {
171: #ifdef DEBUG
172: if (debug)
173: fprintf(ddt,"T_AXFR via UDP refused\n");
174: #endif
175: hp->rcode = REFUSED;
176: goto finish;
177: }
178: dnptrs[0] = NULL; /* don't compress names */
179: hp->rd = 0; /* recursion not possible */
180: }
181: buflen -= msglen;
182: count = 0;
183: foundname = 0;
184: founddata = 0;
185: dname = dnbuf;
186: try_again:
187: #ifdef DEBUG
188: if (debug)
189: fprintf(ddt,"req: nlookup(%s) id %d type=%d\n",
190: dname, hp->id, type);
191: #endif
192: htp = hashtab; /* lookup relative to root */
193: if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)
194: fname = "";
195: #ifdef DEBUG
196: if (debug)
197: fprintf(ddt,"req: %s '%s' as '%s' (cname=%d)\n",
198: np == NULL ? "missed" : "found",
199: dname, fname, cname);
200: #endif
201: /* START XXX */
202: /*
203: * if nlookup failed to find address then
204: * see if there are any '.''s in the name
205: * if not then add local domain name to the
206: * name and try again.
207: */
208: if (np == NULL && localdomain && index(dname, '.') == NULL) {
209: (void) strcat(dname,".");
210: (void) strcat(dname, localdomain);
211: #ifdef DEBUG
212: if (debug)
213: fprintf(ddt,"req: nlookup(%s) type=%d\n",
214: dname, type);
215: #endif
216: htp = hashtab;
217: np = nlookup(dname, &htp, &fname, 0);
218: }
219: /* END XXX */
220: if (np == NULL || fname != dname)
221: goto fetchns;
222:
223: foundname++;
224: answers = (char *)cp;
225: count = cp - msg;
226: n = finddata(np, class, type, hp, &dname, &buflen, &count);
227: if (n == 0)
228: goto fetchns; /* NO data available */
229: cp += n;
230: buflen -= n;
231: msglen += n;
232: hp->ancount += count;
233: if (fname != dname && type != T_CNAME && type != T_ANY) {
234: if (cname++ >= MAXCNAMES) {
235: #ifdef DEBUG
236: if (debug >= 3)
237: fprintf(ddt,
238: "resp: leaving, MAXCNAMES exceeded\n");
239: #endif
240: hp->rcode = SERVFAIL;
241: goto finish;
242: }
243: goto try_again;
244: }
245: founddata = 1;
246: #ifdef DEBUG
247: if (debug >= 3) {
248: fprintf(ddt,"req: foundname = %d count = %d ", foundname, count);
249: fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname);
250: }
251: #endif
252: if ((lp = local(from)) != NULL)
253: sort_response(answers, count, lp, cp);
254: if (type == T_AXFR) {
255: if (founddata) {
256: hp->ancount = htons(hp->ancount);
257: startxfr(qsp, np, msg, cp - msg);
258: return;
259: }
260: hp->rcode = REFUSED; /* No go if unauthoritative */
261: goto finish;
262: }
263: #ifdef notdef
264: /*
265: * If we found an authoritative answer,
266: * we're done.
267: */
268: if (hp->aa)
269: goto finish;
270: #endif
271:
272: fetchns:
273: /*
274: * Look for name servers to refer to and fill in the authority
275: * section or record the address for forwarding the query
276: * (recursion desired).
277: */
278: nsp[0] = NULL;
279: switch (findns(&np, class, nsp, &count)) {
280: case NXDOMAIN:
281: if (!foundname)
282: hp->rcode = NXDOMAIN;
283: #ifdef DEBUG
284: if (debug >= 3)
285: fprintf(ddt,"req: leaving (%s, rcode %d)\n",
286: dname, hp->rcode);
287: #endif
288: if (class != C_ANY) {
289: hp->aa = 1;
290: /* XXX
291: * should return SOA if founddata == 0,
292: * but old named's are confused by an SOA
293: * in the auth. section if there's no error.
294: */
295: if (foundname == 0 && np) {
296: n = doaddauth(hp, cp, buflen, np, nsp[0]);
297: cp += n;
298: buflen -= n;
299: }
300: }
301: goto finish;
302:
303: case SERVFAIL:
304: if (!founddata) {
305: hp->rcode = SERVFAIL;
306: goto finish;
307: }
308: }
309:
310: /*
311: * If we successfully found the answer in the cache
312: * or this is not a recursive query, then add the
313: * nameserver references here and return.
314: */
315: if (founddata || (!hp->rd)) {
316: n = add_data(np, nsp, cp, buflen);
317: if (n < 0) {
318: hp->tc = 1;
319: n = (-n);
320: }
321: cp += n;
322: buflen -= n;
323: hp->nscount = htons((u_short)count);
324: goto finish;
325: }
326:
327: /*
328: * At this point, we don't have the answer, but we do
329: * have some NS's to try. If the user would like us
330: * to recurse, create the initial query. If a cname
331: * is involved, we need to build a new query and save
332: * the old one in cmsg/cmsglen.
333: */
334: if (cname) {
335: omsg = (u_char *)malloc((unsigned)msglen);
336: if (omsg == (u_char *)NULL) {
337: #ifdef DEBUG
338: if (debug)
339: fprintf(ddt,"ns_req: malloc fail\n");
340: #endif
341: syslog(LOG_ERR, "ns_req: Out Of Memory");
342: hp->rcode = SERVFAIL;
343: break;
344: }
345: id = hp->id;
346: hp->ancount = htons(hp->ancount);
347: bcopy(msg, omsg, omsglen = msglen);
348: msglen = res_mkquery(QUERY, dname, class, type,
349: (char *)NULL, 0, NULL, msg, msglen+buflen);
350: }
351: n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp);
352: if (n != FW_OK && cname)
353: free(omsg);
354: switch (n) {
355: case FW_OK:
356: if (cname) {
357: qp->q_cname = cname;
358: qp->q_cmsg = (char *)omsg;
359: qp->q_cmsglen = omsglen;
360: qp->q_id = id;
361: }
362: break;
363: case FW_DUP:
364: break; /* Duplicate request dropped */
365: case FW_NOSERVER:
366: if(np)
367: np = np->n_parent;
368: goto fetchns; /* Try again. */
369: case FW_SERVFAIL:
370: hp->rcode = SERVFAIL;
371: goto finish;
372: }
373: /* Now is a safe time for housekeeping */
374: if (needs_prime_cache)
375: prime_cache();
376: return;
377:
378: case IQUERY: {
379: register struct invbuf *ip;
380: register int i;
381: int dlen, alen;
382: char anbuf[PACKETSZ], *data;
383:
384: #ifdef STATS
385: stats[S_IQUERIES].cnt++;
386: #endif
387: hp->ancount = htons(hp->ancount);
388: if (hp->ancount != 1 ||
389: hp->qdcount || hp->nscount || hp->arcount) {
390: #ifdef DEBUG
391: if (debug)
392: fprintf(ddt,"FORMERR IQuery header counts wrong\n");
393: #endif
394: hp->qdcount = 0;
395: hp->ancount = 0;
396: hp->nscount = 0;
397: hp->arcount = 0;
398: hp->rcode = FORMERR;
399: goto finish;
400: }
401: /*
402: * Skip domain name, get class, and type.
403: */
404: if ((n = dn_skipname(cp, eom)) < 0) {
405: #ifdef DEBUG
406: if (debug)
407: fprintf(ddt,"FORMERR IQuery packet name problem\n");
408: #endif
409: hp->rcode = FORMERR;
410: goto finish;
411: }
412: cp += n;
413: GETSHORT(type, cp);
414: GETSHORT(class, cp);
415: cp += sizeof(u_long);
416: GETSHORT(dlen, cp);
417: cp += dlen;
418: if (cp != eom) {
419: #ifdef DEBUG
420: if (debug)
421: fprintf(ddt,"FORMERR IQuery message length off\n");
422: #endif
423: hp->rcode = FORMERR;
424: goto finish;
425: }
426: /* not all inverse queries are handled. */
427: switch (type) {
428: case T_A:
429: case T_UID:
430: case T_GID:
431: break;
432:
433: default:
434: hp->rcode = REFUSED;
435: goto finish;
436: }
437: #ifdef DEBUG
438: if (debug)
439: fprintf(ddt,"req: IQuery class %d type %d\n",
440: class, type);
441: #endif
442: fname = (char *)msg + sizeof(HEADER);
443: bcopy(fname, anbuf, alen = (char *)cp - fname);
444: data = anbuf + alen - dlen;
445: cp = (u_char *)fname;
446: buflen -= sizeof(HEADER);
447: count = 0;
448: for (ip = invtab[dhash(data, dlen)]; ip != NULL;
449: ip = ip->i_next) {
450: for (i = 0; i < INVBLKSZ; i++) {
451: if ((np = ip->i_dname[i]) == NULL)
452: break;
453: #ifdef DEBUG
454: if (debug >= 5)
455: fprintf(ddt,"dname = %d\n", np->n_dname);
456: #endif
457: for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
458: if (!match(dp, class, type))
459: continue;
460: if (dp->d_size != dlen ||
461: bcmp(dp->d_data, data, dlen))
462: continue;
463: getname(np, dnbuf, sizeof(dnbuf));
464: #ifdef DEBUG
465: if (debug > 2)
466: fprintf(ddt,"req: IQuery found %s\n",
467: dnbuf);
468: #endif
469: buflen -= QFIXEDSZ;
470: if ((n =
471: dn_comp(dnbuf, cp, buflen, (char **)NULL,
472: (char **)NULL)) < 0)
473: {
474: hp->tc = 1;
475: goto finish;
476: }
477: cp += n;
478: PUTSHORT((u_short)dp->d_type, cp);
479: PUTSHORT((u_short)dp->d_class, cp);
480: buflen -= n;
481: count++;
482: }
483: }
484: }
485: #ifdef DEBUG
486: if (debug)
487: fprintf(ddt,"req: IQuery %d records\n", count);
488: #endif
489: hp->qdcount = htons((u_short)count);
490: if (alen > buflen) {
491: hp->tc = 1;
492: break;
493: }
494: bcopy(anbuf, cp, alen);
495: cp += alen;
496: break;
497: }
498:
499: #ifdef ALLOW_UPDATES
500: /*
501: * In a sense the following constant should be defined in <arpa/nameser.h>,
502: * since it is returned here in place of a response code if the update was
503: * forwarded, and the response codes are defined in nameser.h. On the other
504: * hand, though, this constant is only seen in this file. The assumption
505: * here is that none of the other return codes equals this one (a good
506: * assumption, since they only occupy 4 bits over-the-wire)
507: */
508: #define FORWARDED 1000
509: /* Call InitDynUpdate for all dynamic update requests */
510: case UPDATEM:
511: case UPDATEMA:
512: case UPDATED:
513: case UPDATEDA:
514: case UPDATEA:
515: n = InitDynUpdate(hp, nsp, msg, msglen, cp, from, qsp, dfd);
516: if (n == FORWARDED)
517: return; /* Return directly because InitDynUpdate
518: * forwarded the query to the primary, so we
519: * will send response later
520: */
521: else
522: break; /* Either sucessful primary update or failure;
523: * return response code to client
524: */
525: #endif ALLOW_UPDATES
526:
527: case ZONEREF:
528: #ifdef DEBUG
529: if (debug)
530: fprintf(ddt,"Refresh Zone\n");
531: #endif
532:
533: default:
534: #ifdef DEBUG
535: if (debug >= 2)
536: fprintf(ddt,"Opcode %d not implemented\n", hp->opcode);
537: #endif
538: hp->qdcount = 0;
539: hp->ancount = 0;
540: hp->nscount = 0;
541: hp->arcount = 0;
542: hp->rcode = NOTIMP;
543: }
544: finish:
545: #ifdef STATS
546: switch(hp->rcode) {
547: case NOERROR:
548: stats[S_RESPOK].cnt++;
549: break;
550: case FORMERR:
551: stats[S_RESPFORMERR].cnt++;
552: break;
553: default:
554: stats[S_RESPFAIL].cnt++;
555: break;
556: }
557: #endif
558: hp->qr = 1; /* set Response flag */
559: hp->ra = 1; /* Recursion is Available */
560: hp->ancount = htons(hp->ancount);
561: if (addcount) {
562: n = doaddinfo(hp, cp, buflen);
563: cp += n;
564: buflen -= n;
565: }
566:
567: #ifdef DEBUG
568: if (debug) {
569: fprintf(ddt,"req: answer -> %s %d (%d) id=%d %s\n",
570: inet_ntoa(from->sin_addr),
571: qsp == QSTREAM_NULL ? dfd : qsp->s_rfd,
572: ntohs(from->sin_port),
573: ntohs(hp->id), local(from) == NULL ? "Remote" : "Local");
574: }
575: if (debug >= 10)
576: fp_query(msg, ddt);
577: #endif DEBUG
578: if (qsp == QSTREAM_NULL) {
579: if (sendto(dfd, msg, cp-msg, 0, (struct sockaddr *)from,
580: sizeof(*from))< 0){
581: #ifdef DEBUG
582: if (debug)
583: fprintf(ddt,"error returning msg errno=%d\n",errno);
584: #endif DEBUG
585: }
586: #ifdef STATS
587: stats[S_OUTPKTS].cnt++;
588: #endif
589: } else {
590: (void) writemsg(qsp->s_rfd, msg, cp - msg);
591: sq_done(qsp);
592: }
593: if (needs_prime_cache)
594: prime_cache(); /* Now is a safe time */
595: }
596:
597: fwritemsg(rfp, msg, msglen)
598: FILE *rfp;
599: char *msg;
600: int msglen;
601: {
602: u_short len = htons((u_short)msglen);
603:
604: if (fwrite((char *)&len, sizeof(len), 1, rfp) != 1 ||
605: fwrite(msg, msglen, 1, rfp) != 1) {
606: #ifdef DEBUG
607: if (debug)
608: fprintf(ddt,"fwrite failed %d\n", errno);
609: #endif
610: }
611: return;
612: }
613:
614: writemsg(rfd, msg, msglen)
615: int rfd;
616: char *msg;
617: int msglen;
618: {
619: struct iovec iov[2];
620: u_short len = htons((u_short)msglen);
621:
622: iov[0].iov_base = (caddr_t)&len;
623: iov[0].iov_len = sizeof(len);
624: iov[1].iov_base = msg;
625: iov[1].iov_len = msglen;
626: if (writev(rfd, iov, 2) != sizeof(len) + msglen) {
627: #ifdef DEBUG
628: if (debug)
629: fprintf(ddt,"write failed %d\n", errno);
630: #endif
631: return (-1);
632: }
633: return (0);
634: }
635:
636: /*
637: * Test a datum for validity and return non-zero if it is out of date.
638: */
639: stale(dp)
640: register struct databuf *dp;
641: {
642: register struct zoneinfo *zp = &zones[dp->d_zone];
643:
644: switch (zp->z_type) {
645:
646: case Z_PRIMARY:
647: return (0);
648:
649: case Z_SECONDARY:
650: /*
651: * Check to see whether a secondary zone
652: * has expired; if so clear authority flag
653: * for zone and return true. If lastupdate
654: * is in the future, assume zone is up-to-date.
655: */
656: if ((long)(tt.tv_sec - zp->z_lastupdate) > (long)zp->z_expire) {
657: #ifdef DEBUG
658: if (debug)
659: fprintf(ddt,
660: "stale: secondary zone %s expired\n",
661: zp->z_origin);
662: #endif
663: syslog(LOG_ERR, "secondary zone \"%s\" expired\n",
664: zp->z_origin);
665: zp->z_auth = 0;
666: return (1);
667: }
668: return (0);
669:
670: case Z_CACHE:
671: #ifdef DEBUG
672: if (debug >= 3)
673: fprintf(ddt,"stale: ttl %d %d (x%x)\n",
674: dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags);
675: #endif
676: if (dp->d_flags & DB_F_HINT)
677: return(0);
678: return(dp->d_ttl < tt.tv_sec);
679:
680: }
681: /* NOTREACHED */
682: }
683:
684: /*
685: * Copy databuf into a resource record for replies.
686: * Return size of RR if OK, -1 if buffer is full.
687: */
688: make_rr(name, dp, buf, buflen, doadd)
689: char *name;
690: register struct databuf *dp;
691: char *buf;
692: int buflen, doadd;
693: {
694: register char *cp;
695: char *cp1, *sp;
696: struct zoneinfo *zp;
697: register long n;
698: register long ttl;
699: u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
700:
701: #ifdef DEBUG
702: if (debug >= 5)
703: fprintf(ddt,"make_rr(%s, %x, %x, %d, %d) %d zone %d ttl %d\n",
704: name, dp, buf,
705: buflen, doadd, dp->d_size, dp->d_zone, dp->d_ttl);
706: #endif
707:
708: zp = &zones[dp->d_zone];
709: /* check for outdated RR before updating dnptrs by dn_comp() (???) */
710: if (zp->z_type == Z_CACHE) {
711: ttl = dp->d_ttl - (u_long) tt.tv_sec;
712: if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) {
713: #ifdef DEBUG
714: /*XXX*/if (debug >= 3) fprintf(ddt,"make_rr: %d=>0, x%x\n", ttl, dp->d_flags);
715: #endif
716: ttl = 0;
717: }
718: } else {
719: if (dp->d_ttl)
720: ttl = dp->d_ttl;
721: else
722: ttl = zp->z_minimum; /* really default */
723: #ifdef notdef /* don't decrease ttl based on time since verification */
724: if (zp->z_type == Z_SECONDARY) {
725: /*
726: * Set ttl to value received from primary,
727: * less time since we verified it (but never
728: * less than a small positive value).
729: */
730: ttl -= tt.tv_sec - zp->z_lastupdate;
731: if (ttl <= 0)
732: ttl = 120;
733: }
734: #endif
735: }
736:
737: buflen -= RRFIXEDSZ;
738: if ((n = dn_comp(name, buf, buflen, (char **)dnptrs, (char **)edp)) < 0)
739: return (-1);
740: cp = buf + n;
741: buflen -= n;
742: PUTSHORT((u_short)dp->d_type, cp);
743: PUTSHORT((u_short)dp->d_class, cp);
744: PUTLONG(ttl, cp);
745: sp = cp;
746: cp += sizeof(u_short);
747: switch (dp->d_type) {
748: case T_CNAME:
749: case T_MG:
750: case T_MR:
751: case T_PTR:
752: if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs,
753: (char **)edp)) < 0)
754: return (-1);
755: PUTSHORT((u_short)n, sp);
756: cp += n;
757: break;
758:
759: case T_MB:
760: case T_NS:
761: /* Store domain name in answer */
762: if ((n = dn_comp(dp->d_data, cp, buflen, (char **)dnptrs,
763: (char **)edp)) < 0)
764: return (-1);
765: PUTSHORT((u_short)n, sp);
766: cp += n;
767: if (doadd)
768: addname(dp->d_data, dp->d_class);
769: break;
770:
771: case T_SOA:
772: case T_MINFO:
773: cp1 = dp->d_data;
774: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs,
775: (char **)edp)) < 0)
776: return (-1);
777: cp += n;
778: buflen -= dp->d_type == T_MINFO ? n : n + 5 * sizeof(u_long);
779: cp1 += strlen(cp1) + 1;
780: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs,
781: (char **)edp)) < 0)
782: return (-1);
783: cp += n;
784: if (dp->d_type == T_SOA) {
785: cp1 += strlen(cp1) + 1;
786: bcopy(cp1, cp,
787: (int)(n = dp->d_size - (cp1 - dp->d_data)));
788: cp += n;
789: }
790: n = (u_short)(cp - sp) - sizeof(u_short);
791: PUTSHORT((u_short)n, sp);
792: break;
793:
794: case T_MX:
795: /* cp1 == our data/ cp == data of RR */
796: cp1 = dp->d_data;
797:
798: /* copy preference */
799: bcopy(cp1,cp,sizeof(u_short));
800: cp += sizeof(u_short);
801: cp1 += sizeof(u_short);
802: buflen -= sizeof(u_short);
803:
804: if ((n = dn_comp(cp1, cp, buflen, (char **)dnptrs,
805: (char **)edp)) < 0)
806: return(-1);
807: cp += n;
808:
809: /* save data length */
810: n = (u_short)(cp - sp) - sizeof(u_short);
811: PUTSHORT((u_short)n, sp);
812: if (doadd)
813: addname(cp1, dp->d_class);
814: break;
815:
816: default:
817: if (dp->d_size > buflen)
818: return (-1);
819: bcopy(dp->d_data, cp, dp->d_size);
820: PUTSHORT((u_short)dp->d_size, sp);
821: cp += dp->d_size;
822: }
823: return (cp - buf);
824: }
825:
826: addname(name, class)
827: register char *name;
828: short class;
829: {
830: register struct addinfo *ap;
831: register int n;
832:
833: for (ap = addinfo, n = addcount; --n >= 0; ap++)
834: if (strcasecmp(ap->a_dname, name) == 0)
835: return;
836: /* add domain name to additional section */
837: if (addcount < NADDRECS) {
838: addcount++;
839: ap->a_dname = name;
840: ap->a_class = class;
841: }
842: }
843:
844: /*
845: * Lookup addresses for names in addinfo and put into the message's
846: * additional section.
847: */
848: doaddinfo(hp, msg, msglen)
849: HEADER *hp;
850: char *msg;
851: int msglen;
852: {
853: register struct namebuf *np;
854: register struct databuf *dp;
855: register struct addinfo *ap;
856: register char *cp;
857: struct hashbuf *htp;
858: char *fname;
859: int n, count, foundstale;
860:
861: #ifdef DEBUG
862: if (debug >= 3)
863: fprintf(ddt,"doaddinfo() addcount = %d\n", addcount);
864: #endif
865:
866: count = 0;
867: cp = msg;
868: for (ap = addinfo; --addcount >= 0; ap++) {
869: #ifdef DEBUG
870: if (debug >= 3)
871: fprintf(ddt,"do additional '%s'\n", ap->a_dname);
872: #endif
873: htp = hashtab; /* because "nlookup" stomps on arg. */
874: np = nlookup(ap->a_dname, &htp, &fname, 0);
875: if (np == NULL || fname != ap->a_dname)
876: continue;
877: #ifdef DEBUG
878: if (debug >= 3)
879: fprintf(ddt,"found it\n");
880: #endif
881: foundstale = 0;
882: /* look for the data */
883: for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
884: if (!match(dp, (int)ap->a_class, T_A))
885: continue;
886: if (stale(dp)) {
887: foundstale++;
888: #ifdef DEBUG
889: if (debug)
890: fprintf(ddt,"doaddinfo: stale entry '%s'%s\n",
891: np->n_dname,
892: (dp->d_flags&DB_F_HINT) ? " hint":"" );
893: #endif
894: continue;
895: }
896: /*
897: * Should be smart and eliminate duplicate
898: * data here. XXX
899: */
900: if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0)
901: break;
902: #ifdef DEBUG
903: if (debug >= 5)
904: fprintf(ddt,"addinfo: adding address data n = %d\n",
905: n);
906: #endif
907: cp += n;
908: msglen -= n;
909: count++;
910: }
911: if (foundstale) {
912: /* Cache invalidate the address RR's */
913: delete_all(np, (int)ap->a_class, T_A);
914: (void) sysquery(ap->a_dname, (int)ap->a_class, T_A);
915: }
916: }
917: hp->arcount = htons((u_short)count);
918: return (cp - msg);
919: }
920:
921: doaddauth(hp, cp, buflen, np, dp)
922: register HEADER *hp;
923: char *cp;
924: int buflen;
925: struct namebuf *np;
926: struct databuf *dp;
927: {
928: char dnbuf[MAXDNAME];
929: int n;
930:
931: getname(np, dnbuf, sizeof(dnbuf));
932: if (stale(dp) || (n = make_rr(dnbuf, dp, cp, buflen, 1)) <= 0) {
933: #ifdef DEBUG
934: if (debug)
935: fprintf(ddt,"doaddauth: can't add '%s' (%d)\n",
936: dnbuf, buflen);
937: #endif
938: return(0);
939: } else {
940: hp->nscount = htons(1);
941: return(n);
942: }
943: }
944:
945:
946: /*
947: * Get the domain name of 'np' and put in 'buf'. Bounds checking is done.
948: */
949: getname(np, buf, buflen)
950: struct namebuf *np;
951: char *buf;
952: int buflen;
953: {
954: register char *cp;
955: register int i;
956:
957: cp = buf;
958: while (np != NULL) {
959: if ((i = strlen(np->n_dname))+1 >= buflen) {
960: *cp = '\0';
961: syslog(LOG_ERR, "domain name too long: %s...\n", buf);
962: strcpy(buf, "Name_Too_Long");
963: return;
964: }
965: if (cp != buf)
966: *cp++ = '.';
967: (void) strcpy(cp, np->n_dname);
968: cp += i;
969: buflen -= (i+1);
970: np = np->n_parent;
971: }
972: *cp = '\0';
973: }
974:
975: /*
976: * Do a zone transfer. SOA record already sent.
977: */
978: doaxfr(np, rfp, isroot)
979: register struct namebuf *np;
980: FILE *rfp;
981: int isroot;
982: {
983: register struct databuf *dp;
984: register int n;
985: struct hashbuf *htp;
986: struct databuf *gdp; /* glue databuf */
987: struct namebuf *gnp; /* glue namebuf */
988: struct namebuf **npp, **nppend;
989: char msg[PACKETSZ];
990: char *cp;
991: char *fname;
992: char dname[MAXDNAME];
993: HEADER *hp = (HEADER *) msg;
994: int fndns;
995:
996: #ifdef DEBUG
997: if (debug && isroot)
998: fprintf(ddt,"doaxfr()\n");
999: #endif
1000: fndns = 0;
1001: hp->id = 0;
1002: hp->opcode = QUERY;
1003: hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0;
1004: hp->qr = 1;
1005: hp->rcode = NOERROR;
1006: hp->qdcount = 0;
1007: hp->ancount = htons(1);
1008: hp->nscount = 0;
1009: hp->arcount = 0;
1010: cp = msg + sizeof(HEADER);
1011: getname(np, dname, sizeof(dname));
1012:
1013: /* first do data records */
1014: for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
1015: /*
1016: * Skip the root SOA record (marks end of data);
1017: * don't send SOA for subdomains, as we're not sending them.
1018: */
1019: if (dp->d_type == T_SOA)
1020: continue;
1021: if (dp->d_type == T_NS)
1022: fndns = 1;
1023: if (dp->d_zone == 0 || stale(dp))
1024: continue;
1025: if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0)
1026: continue;
1027: fwritemsg(rfp, msg, n + sizeof(HEADER));
1028:
1029: if (dp->d_type == T_NS) {
1030: /* Glue the sub domains together by sending
1031: * the address records for the sub domain
1032: * name servers along.
1033: */
1034: htp = hashtab;
1035: cp = msg + sizeof(HEADER);
1036: gnp = nlookup(dp->d_data, &htp, &fname, 0);
1037: if (gnp == NULL || fname != dp->d_data)
1038: continue;
1039: for(gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) {
1040: if (gdp->d_type != T_A || stale(gdp))
1041: continue;
1042: if ((n = make_rr(fname, gdp, cp,
1043: sizeof(msg)-sizeof(HEADER), 0)) < 0)
1044: continue;
1045: fwritemsg(rfp, msg, n + sizeof(HEADER));
1046: }
1047: }
1048: }
1049:
1050: /* next do subdomains, unless delegated */
1051: if ((isroot == 0 && fndns) || np->n_hash == NULL)
1052: return;
1053: npp = np->n_hash->h_tab;
1054: nppend = npp + np->n_hash->h_size;
1055: while (npp < nppend) {
1056: for (np = *npp++; np != NULL; np = np->n_next) {
1057: doaxfr(np, rfp, 0);
1058: }
1059: }
1060: #ifdef DEBUG
1061: if (debug && isroot)
1062: fprintf(ddt,"exit doaxfr()\n");
1063: #endif
1064: }
1065:
1066: #ifdef ALLOW_UPDATES
1067: /*
1068: * Called by UPDATE{A,D,DA,M,MA} to initiate a dynamic update. If this is the
1069: * primary server for the zone being updated, we update the zone's serial
1070: * number and then call doupdate directly. If this is a secondary, we just
1071: * forward the update; this way, if the primary update fails (e.g., if the
1072: * primary is unavailable), we don't update the secondary; if the primary
1073: * update suceeds, ns_resp will get called with the response (when it comes
1074: * in), and then update the secondary's copy.
1075: */
1076: InitDynUpdate(hp, nsp, msg, msglen, startcp, from, qsp, dfd)
1077: register HEADER *hp;
1078: struct databuf *nsp[];
1079: char *msg;
1080: int msglen;
1081: u_char *startcp;
1082: struct sockaddr_in *from;
1083: struct qstream *qsp;
1084: int dfd;
1085: {
1086: struct zoneinfo *zp;
1087: char dnbuf[MAXDNAME];
1088: struct hashbuf *htp = hashtab; /* lookup relative to root */
1089: struct namebuf *np;
1090: struct databuf *olddp, *newdp, *dp;
1091: struct databuf **nspp;
1092: char *fname;
1093: register u_char *cp = startcp;
1094: short class, type;
1095: int n, size, zonenum;
1096: char ZoneName[MAXDNAME], *znp;
1097:
1098: if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) {
1099: #ifdef DEBUG
1100: if (debug)
1101: fprintf(ddt,"FORMERR InitDynUpdate expand name failed\n");
1102: #endif
1103: hp->rcode = FORMERR;
1104: return(FORMERR);
1105: }
1106: cp += n;
1107: GETSHORT(type, cp);
1108: if (type == T_SOA) { /* T_SOA updates not allowed */
1109: hp->rcode = REFUSED;
1110: #ifdef DEBUG
1111: if (debug)
1112: fprintf(ddt, "InitDynUpdate: REFUSED - SOA update\n");
1113: #endif
1114: return(REFUSED);
1115: }
1116: GETSHORT(class, cp);
1117: cp += sizeof(u_long);
1118: GETSHORT(size, cp);
1119: /****XXX - need bounds checking here ****/
1120: cp += size;
1121:
1122: if ((zonenum = findzone(dnbuf, class)) == 0) { /* zone not found */
1123: hp->rcode = NXDOMAIN;
1124: return(NXDOMAIN);
1125: }
1126: zp = &zones[zonenum];
1127:
1128: /* Disallow updates for which we aren't authoratative. Note: the
1129: following test doesn't work right: If it's for a non-local zone,
1130: we will think it's a primary but be unable to lookup the namebuf,
1131: thus returning 'NXDOMAIN' */
1132: if (zp->z_type != Z_PRIMARY && zp->z_type != Z_SECONDARY) {
1133: hp->rcode = REFUSED;
1134: #ifdef DEBUG
1135: if (debug)
1136: fprintf(ddt, "InitDynUpdate: REFUSED - non-primary, non-sedondary update\n");
1137: #endif
1138: return(REFUSED);
1139: }
1140: if (!(zp->z_state & Z_DYNAMIC)) {
1141: hp->rcode = REFUSED;
1142: #ifdef DEBUG
1143: if (debug)
1144: fprintf(ddt, "InitDynUpdate: REFUSED - dynamic flag not set for zone\n");
1145: #endif
1146: return(REFUSED);
1147: }
1148:
1149: /*
1150: * Lookup the zone namebuf. Lookup "xyz" not "xyz.", since
1151: * otherwise the lookup fails, because '.' may have a nil n_hash
1152: * associated with it.
1153: */
1154: strcpy(ZoneName, zp->z_origin);
1155: znp = &ZoneName[strlen(ZoneName) - 1];
1156: if (*znp == '.')
1157: *znp = NULL;
1158: np = nlookup(ZoneName, &htp, &fname, 0);
1159: if ((np == NULL) || (fname != ZoneName)) {
1160: #ifdef DEBUG
1161: if (debug)
1162: fprintf(ddt, "InitDynUpdate: lookup failed on zone (%s)\n",
1163: ZoneName);
1164: #endif DEBUG
1165: syslog(LOG_ERR, "InitDynUpdate: lookup failed on zone (%s)\n",
1166: ZoneName);
1167: hp->rcode = NXDOMAIN;
1168: return(NXDOMAIN);
1169: }
1170:
1171: /*
1172: * If this is the primary copy increment the serial number. Don't
1173: * increment the serial number if this is a secondary; this way, if 2
1174: * different secondaries both update the primary, they will both have
1175: * lower serial numbers than the primary has, and hence eventually
1176: * refresh and get all updates and become consistent.
1177: *
1178: * Note that the serial number must be incremented in both the zone
1179: * data structure and the zone's namebuf.
1180: */
1181: switch (zp->z_type) {
1182: case Z_SECONDARY: /* forward update to primary */
1183: nspp = nsp;
1184: dp = np->n_data;
1185: while (dp != NULL) {
1186: if (match(dp, class, T_NS)) {
1187: if (nspp < &nsp[NSMAX-1])
1188: *nspp++ = dp;
1189: else
1190: break;
1191: }
1192: dp = dp->d_next;
1193: }
1194: *nspp = NULL; /* Delimiter */
1195: if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL) < 0) {
1196: hp->rcode = SERVFAIL;
1197: return(SERVFAIL);
1198: }
1199: return(FORWARDED);
1200:
1201: case Z_PRIMARY:
1202: zp->z_serial++;
1203: olddp = np->n_data; /* old databuf */
1204: /* Find the SOA record */
1205: for (olddp = np->n_data; olddp != NULL; olddp = olddp->d_next)
1206: if (match(olddp, class, T_SOA))
1207: break;
1208: if (olddp == NULL) {
1209: #ifdef DEBUG
1210: if (debug)
1211: fprintf(ddt,"InitDynUpdate: Couldn't find SOA record for '%s'\n",
1212: ZoneName);
1213: #endif DEBUG
1214: syslog(LOG_ERR,
1215: "InitDynUpdate: Couldn't find SOA record for '%s'\n"
1216: ,
1217: ZoneName);
1218: hp->rcode = NXDOMAIN;
1219: return(NXDOMAIN);
1220: }
1221: newdp = savedata(olddp->d_class, olddp->d_type, olddp->d_ttl,
1222: olddp->d_data, olddp->d_size);
1223: newdp->d_zone = olddp->d_zone;
1224: cp = (u_char *)newdp->d_data;
1225: cp += strlen(cp) + 1; /* skip origin string */
1226: cp += strlen(cp) + 1; /* skip in-charge string */
1227: putlong((u_long)(zp->z_serial), cp);
1228: #ifdef DEBUG
1229: if (debug >= 4) {
1230: fprintf(ddt, "after stuffing data into newdp:\n");
1231: printSOAdata(newdp);
1232: }
1233: #endif DEBUG
1234:
1235: if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE,
1236: hashtab)) != NOERROR) {
1237: #ifdef DEBUG
1238: if (debug)
1239: fprintf(ddt,"InitDynUpdate: SOA update failed\n");
1240: #endif DEBUG
1241: hp->rcode = NOCHANGE;
1242: return(NOCHANGE);
1243: }
1244:
1245: /* Now update the RR itself */
1246: if (doupdate(msg, msglen, msg + sizeof(HEADER),
1247: zonenum, (struct databuf *)0, DB_NODATA) < 0) {
1248: #ifdef DEBUG
1249: if (debug)
1250: fprintf(ddt,"InitDynUpdate: doupdate failed\n");
1251: #endif DEBUG
1252: /* doupdate fills in rcode */
1253: return(hp->rcode);
1254: }
1255: zp->hasChanged++;
1256: return(NOERROR);
1257: }
1258: }
1259:
1260: #ifdef DEBUG
1261: /*
1262: * Print the contents of the data in databuf pointed to by dp for an SOA record
1263: */
1264: printSOAdata(dp)
1265: struct databuf *dp;
1266: {
1267: register u_char *cp;
1268:
1269: if (!debug)
1270: return; /* Otherwise fprintf to ddt will bomb */
1271: cp = (u_char *)dp->d_data;
1272: fprintf(ddt, "printSOAdata(%x): origin(%x)='%s'\n", dp, cp, cp);
1273: cp += strlen(cp) + 1; /* skip origin string */
1274: fprintf(ddt, "printSOAdata: in-charge(%x)='%s'\n", cp, cp);
1275: cp += strlen(cp) + 1; /* skip in-charge string */
1276: fprintf(ddt, "printSOAdata: serial(%x)=%d\n", cp, _getlong(cp));
1277: }
1278: #endif DEBUG
1279: #endif ALLOW_UPDATES
1280:
1281: struct databuf *
1282: rm_datum(dp, np, pdp)
1283: register struct databuf *pdp, *dp;
1284: register struct namebuf *np;
1285: {
1286: register struct databuf *ndp = dp->d_next;
1287:
1288: #ifdef DEBUG
1289: if (debug > 2)
1290: fprintf(ddt, "rm_datum(%x, %x, %x) -> %x\n",
1291: dp, np->n_data, pdp, ndp);
1292: #endif DEBUG
1293: if (pdp == NULL)
1294: np->n_data = ndp;
1295: else
1296: pdp->d_next = ndp;
1297: rminv(dp);
1298: (void) free((char *)dp);
1299: return(ndp);
1300: }
1301:
1302: startxfr(qsp, np, msg, msglen)
1303: struct qstream *qsp;
1304: struct namebuf *np;
1305: char *msg;
1306: int msglen;
1307: {
1308: register FILE *rfp;
1309: int fdstat;
1310:
1311: #ifdef DEBUG
1312: if (debug >= 5)
1313: fprintf(ddt,"startxfr()\n");
1314: #endif
1315: /*
1316: * child does the work while
1317: * the parent continues
1318: */
1319: if (fork() == 0) {
1320: #ifdef DEBUG
1321: if (debug >= 5)
1322: fprintf(ddt,"startxfr: child pid %d\n", getpid());
1323: #endif
1324: rfp = fdopen(qsp->s_rfd, "w");
1325: setproctitle("zone XFR to", qsp->s_rfd);
1326: fdstat = fcntl(qsp->s_rfd, F_GETFL, 0);
1327: if (fdstat != -1)
1328: (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~FNDELAY);
1329: fwritemsg(rfp, msg, msglen);
1330: doaxfr(np, rfp, 1);
1331: fwritemsg(rfp, msg, msglen);
1332: (void) fflush(rfp);
1333: exit(0);
1334: }
1335: sqrm(qsp);
1336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.