BSD 4_3_Reno release
[unix-history] / usr / src / usr.sbin / named / ns_req.c
CommitLineData
95f51977 1/*
1c15e888 2 * Copyright (c) 1986, 1988, 1990 Regents of the University of California.
ca67e7b4
C
3 * All rights reserved.
4 *
1c15e888
C
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.
95f51977
C
18 */
19
ca67e7b4 20#ifndef lint
1c15e888 21static char sccsid[] = "@(#)ns_req.c 4.44 (Berkeley) 6/27/90";
ca67e7b4
C
22#endif /* not lint */
23
95f51977 24#include <stdio.h>
ca67e7b4 25#include <sys/param.h>
95f51977
C
26#include <sys/uio.h>
27#include <sys/time.h>
ca67e7b4 28#include <sys/socket.h>
95f51977
C
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
ca67e7b4
C
38extern int debug;
39extern FILE *ddt;
40
95f51977
C
41struct addinfo {
42 char *a_dname; /* domain name */
43 u_short a_class; /* class for address */
44};
45
46struct addinfo addinfo[NADDRECS]; /* additional info records */
47int addcount; /* number of names in addinfo */
ca67e7b4
C
48int xfr_disabled = 0; /* set to disable zone xfrs */
49int needs_prime_cache = 0; /* set if we need a priming */
95f51977 50
ca67e7b4 51u_char *dnptrs[20]; /* ptrs to dnames in message for dn_comp */
95f51977 52
ca67e7b4
C
53extern time_t retrytime();
54extern struct qinfo *sysquery();
55extern char *localdomain; /* XXX */
95f51977
C
56extern int errno;
57/*
58 * Process request using database; assemble and send response.
59 */
ca67e7b4
C
60ns_req(msg, msglen, buflen, qsp, from, dfd)
61 u_char *msg;
95f51977
C
62 int msglen, buflen;
63 struct qstream *qsp;
64 struct sockaddr_in *from;
ca67e7b4 65 int dfd;
95f51977
C
66{
67 register HEADER *hp;
ca67e7b4
C
68 register u_char *cp;
69 struct namebuf *np;
95f51977 70 register struct databuf *dp;
95f51977 71 struct hashbuf *htp;
ca67e7b4
C
72 struct netinfo *lp;
73 char *fname, *answers;
74 u_char *eom, *omsg;
95f51977 75 char dnbuf[MAXDNAME], *dname;
ca67e7b4
C
76 u_char **dpp;
77 int n, class, type, count, foundname, founddata, omsglen, cname = 0;
95f51977 78 u_short id;
ca67e7b4 79 struct databuf *nsp[NSMAX];
95f51977 80 struct qinfo *qp;
95f51977 81 extern struct qinfo *qhead;
ca67e7b4 82 extern struct netinfo *local();
95f51977
C
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);
ca67e7b4
C
95
96 /* Now is a safe time for housekeeping */
97 if (needs_prime_cache)
98 prime_cache();
95f51977
C
99 return;
100 }
101
95f51977 102 hp->rcode = NOERROR;
ca67e7b4
C
103 cp = msg + sizeof(HEADER);
104 eom = msg + msglen;
95f51977
C
105 dpp = dnptrs;
106 *dpp++ = msg;
107 addcount = 0;
108
95f51977
C
109 switch (hp->opcode) {
110 case QUERY:
ca67e7b4
C
111#ifdef STATS
112 stats[S_QUERIES].cnt++;
113#endif
95f51977
C
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;
ca67e7b4 125 goto finish;
95f51977
C
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;
ca67e7b4 133 if ((n = dn_expand(msg, eom, cp, dnbuf,
95f51977
C
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;
ca67e7b4 140 goto finish;
95f51977
C
141 }
142 cp += n;
ca67e7b4
C
143 GETSHORT(type, cp);
144 GETSHORT(class, cp);
145 if (cp > eom) {
95f51977
C
146#ifdef DEBUG
147 if (debug)
ca67e7b4 148 fprintf(ddt,"FORMERR Query message length short\n");
95f51977
C
149#endif
150 hp->rcode = FORMERR;
ca67e7b4 151 goto finish;
95f51977
C
152 }
153#ifdef DEBUG
ca67e7b4 154 if (cp < eom)
95f51977 155 if (debug > 5)
ca67e7b4 156 fprintf(ddt,"message length > received message\n");
95f51977 157#endif
ca67e7b4
C
158
159#ifdef STATS
160 if ((type > T_ANY) || (type < 0))
161 typestats[0]++; /* Bad type */
162 else
163 typestats[type]++;
95f51977
C
164#endif
165 /*
166 * Process query.
167 */
168 if (type == T_AXFR) {
169 /* refuse request if not a TCP connection */
ca67e7b4
C
170 if (qsp == QSTREAM_NULL || xfr_disabled) {
171#ifdef DEBUG
172 if (debug)
173 fprintf(ddt,"T_AXFR via UDP refused\n");
174#endif
95f51977 175 hp->rcode = REFUSED;
ca67e7b4 176 goto finish;
95f51977 177 }
ca67e7b4
C
178 dnptrs[0] = NULL; /* don't compress names */
179 hp->rd = 0; /* recursion not possible */
95f51977
C
180 }
181 buflen -= msglen;
182 count = 0;
183 foundname = 0;
184 founddata = 0;
185 dname = dnbuf;
ca67e7b4 186try_again:
95f51977
C
187#ifdef DEBUG
188 if (debug)
ca67e7b4
C
189 fprintf(ddt,"req: nlookup(%s) id %d type=%d\n",
190 dname, hp->id, type);
95f51977
C
191#endif
192 htp = hashtab; /* lookup relative to root */
ca67e7b4
C
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 */
95f51977
C
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 */
ca67e7b4
C
208 if (np == NULL && localdomain && index(dname, '.') == NULL) {
209 (void) strcat(dname,".");
210 (void) strcat(dname, localdomain);
95f51977 211#ifdef DEBUG
ca67e7b4
C
212 if (debug)
213 fprintf(ddt,"req: nlookup(%s) type=%d\n",
214 dname, type);
95f51977 215#endif
ca67e7b4
C
216 htp = hashtab;
217 np = nlookup(dname, &htp, &fname, 0);
95f51977 218 }
ca67e7b4
C
219 /* END XXX */
220 if (np == NULL || fname != dname)
221 goto fetchns;
95f51977 222
ca67e7b4
C
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) {
1c15e888
C
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 }
ca67e7b4 243 goto try_again;
95f51977 244 }
ca67e7b4 245 founddata = 1;
95f51977 246#ifdef DEBUG
ca67e7b4
C
247 if (debug >= 3) {
248 fprintf(ddt,"req: foundname = %d count = %d ", foundname, count);
95f51977
C
249 fprintf(ddt,"founddata = %d cname = %d\n",founddata, cname);
250 }
251#endif
ca67e7b4
C
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
272fetchns:
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 */
1c15e888 278 nsp[0] = NULL;
ca67e7b4
C
279 switch (findns(&np, class, nsp, &count)) {
280 case NXDOMAIN:
281 if (!foundname)
282 hp->rcode = NXDOMAIN;
95f51977 283#ifdef DEBUG
ca67e7b4
C
284 if (debug >= 3)
285 fprintf(ddt,"req: leaving (%s, rcode %d)\n",
286 dname, hp->rcode);
95f51977 287#endif
ca67e7b4
C
288 if (class != C_ANY) {
289 hp->aa = 1;
1c15e888 290 /* XXX
ca67e7b4
C
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.
95f51977 294 */
ca67e7b4
C
295 if (foundname == 0 && np) {
296 n = doaddauth(hp, cp, buflen, np, nsp[0]);
297 cp += n;
298 buflen -= n;
95f51977 299 }
95f51977 300 }
ca67e7b4
C
301 goto finish;
302
303 case SERVFAIL:
1c15e888
C
304 if (!founddata) {
305 hp->rcode = SERVFAIL;
306 goto finish;
307 }
95f51977 308 }
ca67e7b4 309
95f51977 310 /*
ca67e7b4
C
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.
95f51977 314 */
ca67e7b4
C
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) {
95f51977
C
337#ifdef DEBUG
338 if (debug)
ca67e7b4 339 fprintf(ddt,"ns_req: malloc fail\n");
95f51977 340#endif
ca67e7b4 341 syslog(LOG_ERR, "ns_req: Out Of Memory");
95f51977
C
342 hp->rcode = SERVFAIL;
343 break;
344 }
ca67e7b4
C
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) {
1c15e888 357 qp->q_cname = cname;
ca67e7b4
C
358 qp->q_cmsg = (char *)omsg;
359 qp->q_cmsglen = omsglen;
95f51977 360 qp->q_id = id;
95f51977 361 }
ca67e7b4
C
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;
95f51977 372 }
ca67e7b4
C
373 /* Now is a safe time for housekeeping */
374 if (needs_prime_cache)
375 prime_cache();
376 return;
95f51977
C
377
378 case IQUERY: {
379 register struct invbuf *ip;
380 register int i;
381 int dlen, alen;
382 char anbuf[PACKETSZ], *data;
383
ca67e7b4
C
384#ifdef STATS
385 stats[S_IQUERIES].cnt++;
386#endif
387 hp->ancount = htons(hp->ancount);
388 if (hp->ancount != 1 ||
95f51977
C
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;
ca67e7b4 399 goto finish;
95f51977
C
400 }
401 /*
402 * Skip domain name, get class, and type.
403 */
ca67e7b4 404 if ((n = dn_skipname(cp, eom)) < 0) {
95f51977
C
405#ifdef DEBUG
406 if (debug)
407 fprintf(ddt,"FORMERR IQuery packet name problem\n");
408#endif
409 hp->rcode = FORMERR;
ca67e7b4 410 goto finish;
95f51977
C
411 }
412 cp += n;
ca67e7b4
C
413 GETSHORT(type, cp);
414 GETSHORT(class, cp);
415 cp += sizeof(u_long);
416 GETSHORT(dlen, cp);
417 cp += dlen;
418 if (cp != eom) {
95f51977
C
419#ifdef DEBUG
420 if (debug)
421 fprintf(ddt,"FORMERR IQuery message length off\n");
422#endif
423 hp->rcode = FORMERR;
ca67e7b4 424 goto finish;
95f51977
C
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 }
ca67e7b4
C
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);
95f51977 444 data = anbuf + alen - dlen;
ca67e7b4 445 cp = (u_char *)fname;
95f51977
C
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));
ca67e7b4
C
464#ifdef DEBUG
465 if (debug > 2)
466 fprintf(ddt,"req: IQuery found %s\n",
467 dnbuf);
468#endif
95f51977
C
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;
ca67e7b4
C
478 PUTSHORT((u_short)dp->d_type, cp);
479 PUTSHORT((u_short)dp->d_class, cp);
95f51977
C
480 buflen -= n;
481 count++;
482 }
483 }
484 }
ca67e7b4
C
485#ifdef DEBUG
486 if (debug)
487 fprintf(ddt,"req: IQuery %d records\n", count);
488#endif
95f51977
C
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
ca67e7b4
C
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
95f51977
C
526
527 case ZONEREF:
528#ifdef DEBUG
529 if (debug)
530 fprintf(ddt,"Refresh Zone\n");
531#endif
532
533 default:
ca67e7b4
C
534#ifdef DEBUG
535 if (debug >= 2)
536 fprintf(ddt,"Opcode %d not implemented\n", hp->opcode);
537#endif
95f51977
C
538 hp->qdcount = 0;
539 hp->ancount = 0;
540 hp->nscount = 0;
541 hp->arcount = 0;
ca67e7b4 542 hp->rcode = NOTIMP;
95f51977
C
543 }
544finish:
ca67e7b4
C
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
95f51977
C
558 hp->qr = 1; /* set Response flag */
559 hp->ra = 1; /* Recursion is Available */
ca67e7b4
C
560 hp->ancount = htons(hp->ancount);
561 if (addcount) {
562 n = doaddinfo(hp, cp, buflen);
563 cp += n;
564 buflen -= n;
565 }
566
95f51977 567#ifdef DEBUG
ca67e7b4
C
568 if (debug) {
569 fprintf(ddt,"req: answer -> %s %d (%d) id=%d %s\n",
1c15e888
C
570 inet_ntoa(from->sin_addr),
571 qsp == QSTREAM_NULL ? dfd : qsp->s_rfd,
572 ntohs(from->sin_port),
ca67e7b4
C
573 ntohs(hp->id), local(from) == NULL ? "Remote" : "Local");
574 }
95f51977
C
575 if (debug >= 10)
576 fp_query(msg, ddt);
ca67e7b4 577#endif DEBUG
95f51977 578 if (qsp == QSTREAM_NULL) {
ca67e7b4
C
579 if (sendto(dfd, msg, cp-msg, 0, (struct sockaddr *)from,
580 sizeof(*from))< 0){
95f51977
C
581#ifdef DEBUG
582 if (debug)
ca67e7b4
C
583 fprintf(ddt,"error returning msg errno=%d\n",errno);
584#endif DEBUG
95f51977 585 }
ca67e7b4
C
586#ifdef STATS
587 stats[S_OUTPKTS].cnt++;
588#endif
95f51977
C
589 } else {
590 (void) writemsg(qsp->s_rfd, msg, cp - msg);
1c15e888 591 sq_done(qsp);
95f51977 592 }
ca67e7b4
C
593 if (needs_prime_cache)
594 prime_cache(); /* Now is a safe time */
95f51977
C
595}
596
597fwritemsg(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
95f51977
C
610 }
611 return;
612}
613
614writemsg(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
95f51977
C
631 return (-1);
632 }
633 return (0);
634}
635
ca67e7b4
C
636/*
637 * Test a datum for validity and return non-zero if it is out of date.
638 */
639stale(dp)
640register 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:
1c15e888
C
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);
ca67e7b4
C
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);
1c15e888 678 return(dp->d_ttl < tt.tv_sec);
ca67e7b4
C
679
680 }
681 /* NOTREACHED */
682}
683
95f51977
C
684/*
685 * Copy databuf into a resource record for replies.
ca67e7b4 686 * Return size of RR if OK, -1 if buffer is full.
95f51977
C
687 */
688make_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;
95f51977 695 char *cp1, *sp;
ca67e7b4 696 struct zoneinfo *zp;
95f51977 697 register long n;
ca67e7b4
C
698 register long ttl;
699 u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
95f51977
C
700
701#ifdef DEBUG
702 if (debug >= 5)
ca67e7b4
C
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);
95f51977
C
706#endif
707
ca67e7b4 708 zp = &zones[dp->d_zone];
1c15e888 709 /* check for outdated RR before updating dnptrs by dn_comp() (???) */
ca67e7b4 710 if (zp->z_type == Z_CACHE) {
95f51977 711 ttl = dp->d_ttl - (u_long) tt.tv_sec;
1c15e888 712 if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) {
ca67e7b4 713#ifdef DEBUG
1c15e888 714/*XXX*/if (debug >= 3) fprintf(ddt,"make_rr: %d=>0, x%x\n", ttl, dp->d_flags);
ca67e7b4 715#endif
1c15e888 716 ttl = 0;
ca67e7b4 717 }
95f51977 718 } else {
1c15e888 719 if (dp->d_ttl)
95f51977 720 ttl = dp->d_ttl;
1c15e888
C
721 else
722 ttl = zp->z_minimum; /* really default */
723#ifdef notdef /* don't decrease ttl based on time since verification */
ca67e7b4
C
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 }
1c15e888 734#endif
95f51977
C
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;
ca67e7b4
C
742 PUTSHORT((u_short)dp->d_type, cp);
743 PUTSHORT((u_short)dp->d_class, cp);
744 PUTLONG(ttl, cp);
95f51977
C
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);
ca67e7b4 755 PUTSHORT((u_short)n, sp);
95f51977
C
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);
ca67e7b4 765 PUTSHORT((u_short)n, sp);
95f51977 766 cp += n;
ca67e7b4
C
767 if (doadd)
768 addname(dp->d_data, dp->d_class);
95f51977
C
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 }
ca67e7b4
C
790 n = (u_short)(cp - sp) - sizeof(u_short);
791 PUTSHORT((u_short)n, sp);
95f51977
C
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 */
ca67e7b4
C
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;
95f51977
C
815
816 default:
817 if (dp->d_size > buflen)
818 return (-1);
819 bcopy(dp->d_data, cp, dp->d_size);
ca67e7b4 820 PUTSHORT((u_short)dp->d_size, sp);
95f51977
C
821 cp += dp->d_size;
822 }
823 return (cp - buf);
824}
825
ca67e7b4
C
826addname(name, class)
827register char *name;
828short 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
95f51977
C
844/*
845 * Lookup addresses for names in addinfo and put into the message's
846 * additional section.
847 */
848doaddinfo(hp, msg, msglen)
849 HEADER *hp;
850 char *msg;
851 int msglen;
852{
95f51977
C
853 register struct namebuf *np;
854 register struct databuf *dp;
ca67e7b4
C
855 register struct addinfo *ap;
856 register char *cp;
95f51977 857 struct hashbuf *htp;
95f51977 858 char *fname;
ca67e7b4 859 int n, count, foundstale;
95f51977
C
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
ca67e7b4 870 if (debug >= 3)
95f51977
C
871 fprintf(ddt,"do additional '%s'\n", ap->a_dname);
872#endif
ca67e7b4 873 htp = hashtab; /* because "nlookup" stomps on arg. */
95f51977
C
874 np = nlookup(ap->a_dname, &htp, &fname, 0);
875 if (np == NULL || fname != ap->a_dname)
876 continue;
877#ifdef DEBUG
ca67e7b4 878 if (debug >= 3)
95f51977
C
879 fprintf(ddt,"found it\n");
880#endif
ca67e7b4 881 foundstale = 0;
95f51977 882 /* look for the data */
ca67e7b4
C
883 for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
884 if (!match(dp, (int)ap->a_class, T_A))
95f51977 885 continue;
ca67e7b4
C
886 if (stale(dp)) {
887 foundstale++;
95f51977
C
888#ifdef DEBUG
889 if (debug)
ca67e7b4
C
890 fprintf(ddt,"doaddinfo: stale entry '%s'%s\n",
891 np->n_dname,
892 (dp->d_flags&DB_F_HINT) ? " hint":"" );
95f51977 893#endif
95f51977
C
894 continue;
895 }
ca67e7b4
C
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;
95f51977
C
902#ifdef DEBUG
903 if (debug >= 5)
ca67e7b4
C
904 fprintf(ddt,"addinfo: adding address data n = %d\n",
905 n);
95f51977
C
906#endif
907 cp += n;
908 msglen -= n;
909 count++;
ca67e7b4
C
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);
95f51977
C
915 }
916 }
917 hp->arcount = htons((u_short)count);
918 return (cp - msg);
919}
920
ca67e7b4
C
921doaddauth(hp, cp, buflen, np, dp)
922 register HEADER *hp;
923 char *cp;
924 int buflen;
925 struct namebuf *np;
95f51977 926 struct databuf *dp;
95f51977 927{
ca67e7b4
C
928 char dnbuf[MAXDNAME];
929 int n;
95f51977 930
ca67e7b4
C
931 getname(np, dnbuf, sizeof(dnbuf));
932 if (stale(dp) || (n = make_rr(dnbuf, dp, cp, buflen, 1)) <= 0) {
95f51977 933#ifdef DEBUG
ca67e7b4
C
934 if (debug)
935 fprintf(ddt,"doaddauth: can't add '%s' (%d)\n",
936 dnbuf, buflen);
95f51977 937#endif
ca67e7b4
C
938 return(0);
939 } else {
940 hp->nscount = htons(1);
941 return(n);
95f51977 942 }
95f51977
C
943}
944
ca67e7b4 945
95f51977 946/*
ca67e7b4 947 * Get the domain name of 'np' and put in 'buf'. Bounds checking is done.
95f51977
C
948 */
949getname(np, buf, buflen)
950 struct namebuf *np;
951 char *buf;
952 int buflen;
953{
954 register char *cp;
ca67e7b4 955 register int i;
95f51977
C
956
957 cp = buf;
958 while (np != NULL) {
ca67e7b4
C
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 }
95f51977
C
965 if (cp != buf)
966 *cp++ = '.';
967 (void) strcpy(cp, np->n_dname);
ca67e7b4
C
968 cp += i;
969 buflen -= (i+1);
95f51977
C
970 np = np->n_parent;
971 }
972 *cp = '\0';
973}
974
975/*
976 * Do a zone transfer. SOA record already sent.
977 */
978doaxfr(np, rfp, isroot)
979 register struct namebuf *np;
980 FILE *rfp;
981 int isroot;
982{
983 register struct databuf *dp;
984 register int n;
ca67e7b4
C
985 struct hashbuf *htp;
986 struct databuf *gdp; /* glue databuf */
987 struct namebuf *gnp; /* glue namebuf */
95f51977
C
988 struct namebuf **npp, **nppend;
989 char msg[PACKETSZ];
95f51977 990 char *cp;
ca67e7b4 991 char *fname;
95f51977 992 char dname[MAXDNAME];
ca67e7b4 993 HEADER *hp = (HEADER *) msg;
95f51977
C
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;
ca67e7b4
C
1003 hp->aa = hp->tc = hp->ra = hp->pr = hp->rd = 0;
1004 hp->qr = 1;
95f51977
C
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) {
ca67e7b4
C
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)
95f51977 1022 fndns = 1;
ca67e7b4 1023 if (dp->d_zone == 0 || stale(dp))
95f51977 1024 continue;
ca67e7b4 1025 if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0)
95f51977
C
1026 continue;
1027 fwritemsg(rfp, msg, n + sizeof(HEADER));
ca67e7b4
C
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 }
95f51977
C
1048 }
1049
ca67e7b4
C
1050 /* next do subdomains, unless delegated */
1051 if ((isroot == 0 && fndns) || np->n_hash == NULL)
95f51977
C
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}
ca67e7b4
C
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 */
1076InitDynUpdate(hp, nsp, msg, msglen, startcp, from, qsp, dfd)
1077 register HEADER *hp;
1078 struct databuf *nsp[];
1079 char *msg;
1080 int msglen;
1c15e888 1081 u_char *startcp;
ca67e7b4
C
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;
ca67e7b4
C
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);
ca67e7b4
C
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 }
1c15e888
C
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 }
ca67e7b4
C
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;
1c15e888 1224 cp = (u_char *)newdp->d_data;
ca67e7b4
C
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 */
1264printSOAdata(dp)
1265 struct databuf *dp;
1266{
1267 register u_char *cp;
1268
1269 if (!debug)
1270 return; /* Otherwise fprintf to ddt will bomb */
1c15e888 1271 cp = (u_char *)dp->d_data;
ca67e7b4
C
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
1281struct databuf *
1282rm_datum(dp, np, pdp)
1283register struct databuf *pdp, *dp;
1284register 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
1302startxfr(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 }
1c15e888 1335 sqrm(qsp);
ca67e7b4 1336}