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