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