]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/dn.c
ndb/dns: add support for internationalized domain names
[plan9front.git] / sys / src / cmd / ndb / dn.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <pool.h>
5 #include <ctype.h>
6 #include "dns.h"
7
8 /*
9  *  this comment used to say `our target is 4000 names cached, this should
10  *  be larger on large servers'.  dns at Bell Labs starts off with
11  *  about 1780 names.
12  *
13  * aging seems to corrupt the cache, so raise the trigger from 4000 until we
14  * figure it out.
15  */
16 enum {
17         /* these settings will trigger frequent aging */
18         Deftarget       = 4000,
19         Minage          =  5*Min,
20         Defagefreq      = 15*Min,       /* age names this often (seconds) */
21 };
22
23 /*
24  *  Hash table for domain names.  The hash is based only on the
25  *  first element of the domain name.
26  */
27 DN *ht[HTLEN];
28
29 static struct {
30         Lock;
31         ulong   names;          /* names allocated */
32         ulong   oldest;         /* longest we'll leave a name around */
33         int     active;
34         int     mutex;
35         ushort  id;             /* same size as in packet */
36 } dnvars;
37
38 /* names of RR types */
39 char *rrtname[] =
40 {
41 [Ta]            "ip",
42 [Tns]           "ns",
43 [Tmd]           "md",
44 [Tmf]           "mf",
45 [Tcname]        "cname",
46 [Tsoa]          "soa",
47 [Tmb]           "mb",
48 [Tmg]           "mg",
49 [Tmr]           "mr",
50 [Tnull]         "null",
51 [Twks]          "wks",
52 [Tptr]          "ptr",
53 [Thinfo]        "hinfo",
54 [Tminfo]        "minfo",
55 [Tmx]           "mx",
56 [Ttxt]          "txt",
57 [Trp]           "rp",
58 [Tafsdb]        "afsdb",
59 [Tx25]          "x.25",
60 [Tisdn]         "isdn",
61 [Trt]           "rt",
62 [Tnsap]         "nsap",
63 [Tnsapptr]      "nsap-ptr",
64 [Tsig]          "sig",
65 [Tkey]          "key",
66 [Tpx]           "px",
67 [Tgpos]         "gpos",
68 [Taaaa]         "ipv6",
69 [Tloc]          "loc",
70 [Tnxt]          "nxt",
71 [Teid]          "eid",
72 [Tnimloc]       "nimrod",
73 [Tsrv]          "srv",
74 [Tatma]         "atma",
75 [Tnaptr]        "naptr",
76 [Tkx]           "kx",
77 [Tcert]         "cert",
78 [Ta6]           "a6",
79 [Tdname]        "dname",
80 [Tsink]         "sink",
81 [Topt]          "opt",
82 [Tapl]          "apl",
83 [Tds]           "ds",
84 [Tsshfp]        "sshfp",
85 [Tipseckey]     "ipseckey",
86 [Trrsig]        "rrsig",
87 [Tnsec]         "nsec",
88 [Tdnskey]       "dnskey",
89 [Tspf]          "spf",
90 [Tuinfo]        "uinfo",
91 [Tuid]          "uid",
92 [Tgid]          "gid",
93 [Tunspec]       "unspec",
94 [Ttkey]         "tkey",
95 [Ttsig]         "tsig",
96 [Tixfr]         "ixfr",
97 [Taxfr]         "axfr",
98 [Tmailb]        "mailb",
99 [Tmaila]        "maila",
100 [Tall]          "all",
101                 0,
102 };
103
104 /* names of response codes */
105 char *rname[Rmask+1] =
106 {
107 [Rok]                   "ok",
108 [Rformat]               "format error",
109 [Rserver]               "server failure",
110 [Rname]                 "bad name",
111 [Runimplimented]        "unimplemented",
112 [Rrefused]              "we don't like you",
113 [Ryxdomain]             "name should not exist",
114 [Ryxrrset]              "rr set should not exist",
115 [Rnxrrset]              "rr set should exist",
116 [Rnotauth]              "not authorative",
117 [Rnotzone]              "not in zone",
118 [Rbadvers]              "bad opt version",
119 /* [Rbadsig]            "bad signature", */
120 [Rbadkey]               "bad key",
121 [Rbadtime]              "bad signature time",
122 [Rbadmode]              "bad mode",
123 [Rbadname]              "duplicate key name",
124 [Rbadalg]               "bad algorithm",
125 };
126 unsigned nrname = nelem(rname);
127
128 /* names of op codes */
129 char *opname[] =
130 {
131 [Oquery]        "query",
132 [Oinverse]      "inverse query (retired)",
133 [Ostatus]       "status",
134 [Oupdate]       "update",
135 };
136
137 ulong target = Deftarget;
138 Lock    dnlock;
139
140 static ulong agefreq = Defagefreq;
141
142 static int rrequiv(RR *r1, RR *r2);
143 static int sencodefmt(Fmt*);
144
145 static void
146 ding(void*, char *msg)
147 {
148         if(strstr(msg, "alarm") != nil) {
149                 stats.alarms++;
150                 noted(NCONT);           /* resume with system call error */
151         } else
152                 noted(NDFLT);           /* die */
153 }
154
155 void
156 dninit(void)
157 {
158         fmtinstall('E', eipfmt);
159         fmtinstall('I', eipfmt);
160         fmtinstall('V', eipfmt);
161         fmtinstall('R', rrfmt);
162         fmtinstall('Q', rravfmt);
163         fmtinstall('H', sencodefmt);
164
165         dnvars.oldest = maxage;
166         dnvars.names = 0;
167         dnvars.id = truerand(); /* don't start with same id every time */
168
169         notify(ding);
170 }
171
172 /*
173  *  hash for a domain name
174  */
175 static ulong
176 dnhash(char *name)
177 {
178         ulong hash;
179         uchar *val = (uchar*)name;
180
181         for(hash = 0; *val; val++)
182                 hash = hash*13 + tolower(*val)-'a';
183         return hash % HTLEN;
184 }
185
186 /*
187  *  lookup a symbol.  if enter is not zero and the name is
188  *  not found, create it.
189  */
190 DN*
191 dnlookup(char *name, int class, int enter)
192 {
193         DN **l;
194         DN *dp;
195
196         l = &ht[dnhash(name)];
197         lock(&dnlock);
198         for(dp = *l; dp; dp = dp->next) {
199                 assert(dp->magic == DNmagic);
200                 if(dp->class == class && cistrcmp(dp->name, name) == 0){
201                         dp->referenced = now;
202                         unlock(&dnlock);
203                         return dp;
204                 }
205                 l = &dp->next;
206         }
207
208         if(!enter){
209                 unlock(&dnlock);
210                 return 0;
211         }
212         dnvars.names++;
213         dp = emalloc(sizeof(*dp));
214         dp->magic = DNmagic;
215         dp->name = estrdup(name);
216         dp->class = class;
217         dp->rr = nil;
218         dp->referenced = now;
219         /* add new DN to tail of the hash list.  *l points to last next ptr. */
220         dp->next = nil;
221         *l = dp;
222         unlock(&dnlock);
223
224         return dp;
225 }
226
227 DN*
228 idnlookup(char *name, int class, int enter)
229 {
230         char dom[Domlen];
231
232         if(utf2idn(name, dom, sizeof dom) != nil)
233                 name = dom;
234         return dnlookup(name, class, enter);
235 }
236
237 static int
238 rrsame(RR *rr1, RR *rr2)
239 {
240         return rr1 == rr2 || rr2 && rrequiv(rr1, rr2) &&
241                 rr1->db == rr2->db && rr1->auth == rr2->auth;
242 }
243
244 static int
245 rronlist(RR *rp, RR *lp)
246 {
247         for(; lp; lp = lp->next)
248                 if (rrsame(lp, rp))
249                         return 1;
250         return 0;
251 }
252
253 /*
254  * dump the stats
255  */
256 void
257 dnstats(char *file)
258 {
259         int i, fd;
260
261         fd = create(file, OWRITE, 0666);
262         if(fd < 0)
263                 return;
264
265         qlock(&stats);
266         fprint(fd, "# system %s\n", sysname());
267         fprint(fd, "# slave procs high-water mark\t%lud\n", stats.slavehiwat);
268         fprint(fd, "# queries received by 9p\t%lud\n", stats.qrecvd9p);
269         fprint(fd, "# queries received by udp\t%lud\n", stats.qrecvdudp);
270         fprint(fd, "# queries answered from memory\t%lud\n", stats.answinmem);
271         fprint(fd, "# queries sent by udp\t%lud\n", stats.qsent);
272         for (i = 0; i < nelem(stats.under10ths); i++)
273                 if (stats.under10ths[i] || i == nelem(stats.under10ths) - 1)
274                         fprint(fd, "# responses arriving within %.1f s.\t%lud\n",
275                                 (double)(i+1)/10, stats.under10ths[i]);
276         fprint(fd, "\n# queries sent & timed-out\t%lud\n", stats.tmout);
277         fprint(fd, "# cname queries timed-out\t%lud\n", stats.tmoutcname);
278         fprint(fd, "# ipv6  queries timed-out\t%lud\n", stats.tmoutv6);
279         fprint(fd, "\n# negative answers received\t%lud\n", stats.negans);
280         fprint(fd, "# negative answers w Rserver set\t%lud\n", stats.negserver);
281         fprint(fd, "# negative answers w bad delegation\t%lud\n",
282                 stats.negbaddeleg);
283         fprint(fd, "# negative answers w bad delegation & no answers\t%lud\n",
284                 stats.negbdnoans);
285         fprint(fd, "# negative answers w no Rname set\t%lud\n", stats.negnorname);
286         fprint(fd, "# negative answers cached\t%lud\n", stats.negcached);
287         qunlock(&stats);
288
289         lock(&dnlock);
290         fprint(fd, "\n# domain names %lud target %lud\n", dnvars.names, target);
291         unlock(&dnlock);
292         close(fd);
293 }
294
295 /*
296  *  dump the cache
297  */
298 void
299 dndump(char *file)
300 {
301         int i, fd;
302         DN *dp;
303         RR *rp;
304
305         fd = create(file, OWRITE, 0666);
306         if(fd < 0)
307                 return;
308
309         lock(&dnlock);
310         for(i = 0; i < HTLEN; i++)
311                 for(dp = ht[i]; dp; dp = dp->next){
312                         fprint(fd, "%s\n", dp->name);
313                         for(rp = dp->rr; rp; rp = rp->next) {
314                                 fprint(fd, "\t%R %c%c %ld/%lud\n",
315                                         rp, rp->auth? 'A': 'U',
316                                         rp->db? 'D': 'N', (long)(rp->expire - now), rp->ttl);
317                                 if (rronlist(rp, rp->next))
318                                         fprint(fd, "*** duplicate:\n");
319                         }
320                 }
321         unlock(&dnlock);
322         close(fd);
323 }
324
325 /*
326  *  purge all records
327  */
328 void
329 dnpurge(void)
330 {
331         DN *dp;
332         RR *rp, *srp;
333         int i;
334
335         lock(&dnlock);
336
337         for(i = 0; i < HTLEN; i++)
338                 for(dp = ht[i]; dp; dp = dp->next){
339                         srp = rp = dp->rr;
340                         dp->rr = nil;
341                         for(; rp != nil; rp = rp->next)
342                                 rp->cached = 0;
343                         rrfreelist(srp);
344                 }
345
346         unlock(&dnlock);
347 }
348
349 /*
350  *  delete head of *l and free the old head.
351  *  call with dnlock held.
352  */
353 static void
354 rrdelhead(RR **l)
355 {
356         RR *rp;
357
358         if (canlock(&dnlock))
359                 abort();        /* rrdelhead called with dnlock not held */
360         rp = *l;
361         if(rp == nil)
362                 return;
363         *l = rp->next;          /* unlink head */
364         rp->cached = 0;         /* avoid blowing an assertion in rrfree */
365         rrfree(rp);
366 }
367
368 /*
369  *  check the age of resource records, free any that have timed out.
370  *  call with dnlock held.
371  */
372 void
373 dnage(DN *dp)
374 {
375         RR **l, *rp;
376         ulong diff;
377
378         if (canlock(&dnlock))
379                 abort();        /* dnage called with dnlock not held */
380         diff = now - dp->referenced;
381         if(diff < Reserved || dp->mark != 0)
382                 return;
383
384         l = &dp->rr;
385         while ((rp = *l) != nil){
386                 assert(rp->magic == RRmagic && rp->cached);
387                 if(!rp->db && ((long)(rp->expire - now) <= 0 || diff > dnvars.oldest))
388                         rrdelhead(l); /* rp == *l before; *l == rp->next after */
389                 else
390                         l = &rp->next;
391         }
392 }
393
394 #define MARK(dp)        { if (dp) (dp)->mark |= 2; }
395
396 /* mark a domain name and those in its RRs as never to be aged */
397 void
398 dnagenever(DN *dp)
399 {
400         RR *rp;
401
402         lock(&dnlock);
403
404         /* mark all referenced domain names */
405         MARK(dp);
406         for(rp = dp->rr; rp; rp = rp->next){
407                 MARK(rp->owner);
408                 if(rp->negative){
409                         MARK(rp->negsoaowner);
410                         continue;
411                 }
412                 switch(rp->type){
413                 case Thinfo:
414                         MARK(rp->cpu);
415                         MARK(rp->os);
416                         break;
417                 case Ttxt:
418                         break;
419                 case Tcname:
420                 case Tmb:
421                 case Tmd:
422                 case Tmf:
423                 case Tns:
424                 case Tmx:
425                 case Tsrv:
426                         MARK(rp->host);
427                         break;
428                 case Tmg:
429                 case Tmr:
430                         MARK(rp->mb);
431                         break;
432                 case Tminfo:
433                         MARK(rp->rmb);
434                         MARK(rp->mb);
435                         break;
436                 case Trp:
437                         MARK(rp->rmb);
438                         MARK(rp->rp);
439                         break;
440                 case Ta:
441                 case Taaaa:
442                         MARK(rp->ip);
443                         break;
444                 case Tptr:
445                         MARK(rp->ptr);
446                         break;
447                 case Tsoa:
448                         MARK(rp->host);
449                         MARK(rp->rmb);
450                         break;
451                 case Tsig:
452                         MARK(rp->sig->signer);
453                         break;
454                 }
455         }
456
457         unlock(&dnlock);
458 }
459
460 #define REF(dp) { if (dp) (dp)->mark |= 1; }
461
462 /*
463  *  periodicly sweep for old records and remove unreferenced domain names
464  *
465  *  only called when all other threads are locked out
466  */
467 void
468 dnageall(int doit)
469 {
470         DN *dp, **l;
471         int i;
472         RR *rp;
473         static ulong nextage;
474
475         if(dnvars.names < target || ((long)(nextage - now) > 0 && !doit)){
476                 dnvars.oldest = maxage;
477                 return;
478         }
479
480         if(dnvars.names >= target) {
481                 dnslog("more names (%lud) than target (%lud)", dnvars.names,
482                         target);
483                 dnvars.oldest /= 2;
484                 if (dnvars.oldest < Minage)
485                         dnvars.oldest = Minage;         /* don't be silly */
486         }
487         if (agefreq > dnvars.oldest / 2)
488                 nextage = now + dnvars.oldest / 2;
489         else
490                 nextage = now + (ulong)agefreq;
491
492         lock(&dnlock);
493
494         /* time out all old entries (and set refs to 0) */
495         for(i = 0; i < HTLEN; i++)
496                 for(dp = ht[i]; dp; dp = dp->next){
497                         dp->mark &= ~1;
498                         dnage(dp);
499                 }
500
501         /* mark all referenced domain names */
502         for(i = 0; i < HTLEN; i++)
503                 for(dp = ht[i]; dp; dp = dp->next)
504                         for(rp = dp->rr; rp; rp = rp->next){
505                                 REF(rp->owner);
506                                 if(rp->negative){
507                                         REF(rp->negsoaowner);
508                                         continue;
509                                 }
510                                 switch(rp->type){
511                                 case Thinfo:
512                                         REF(rp->cpu);
513                                         REF(rp->os);
514                                         break;
515                                 case Ttxt:
516                                         break;
517                                 case Tcname:
518                                 case Tmb:
519                                 case Tmd:
520                                 case Tmf:
521                                 case Tns:
522                                 case Tmx:
523                                 case Tsrv:
524                                         REF(rp->host);
525                                         break;
526                                 case Tmg:
527                                 case Tmr:
528                                         REF(rp->mb);
529                                         break;
530                                 case Tminfo:
531                                         REF(rp->rmb);
532                                         REF(rp->mb);
533                                         break;
534                                 case Trp:
535                                         REF(rp->rmb);
536                                         REF(rp->rp);
537                                         break;
538                                 case Ta:
539                                 case Taaaa:
540                                         REF(rp->ip);
541                                         break;
542                                 case Tptr:
543                                         REF(rp->ptr);
544                                         break;
545                                 case Tsoa:
546                                         REF(rp->host);
547                                         REF(rp->rmb);
548                                         break;
549                                 case Tsig:
550                                         REF(rp->sig->signer);
551                                         break;
552                                 }
553                         }
554
555         /* sweep and remove unreferenced domain names */
556         for(i = 0; i < HTLEN; i++){
557                 l = &ht[i];
558                 for(dp = *l; dp; dp = *l){
559                         if(dp->rr == nil && dp->mark == 0){
560                                 assert(dp->magic == DNmagic);
561                                 *l = dp->next;
562
563                                 free(dp->name);
564                                 memset(dp, 0, sizeof *dp); /* cause trouble */
565                                 dp->magic = ~DNmagic;
566                                 free(dp);
567
568                                 dnvars.names--;
569                                 continue;
570                         }
571                         l = &dp->next;
572                 }
573         }
574
575         unlock(&dnlock);
576 }
577
578 /*
579  *  timeout all database records (used when rereading db)
580  */
581 void
582 dnagedb(void)
583 {
584         DN *dp;
585         int i;
586         RR *rp;
587
588         lock(&dnlock);
589
590         /* time out all database entries */
591         for(i = 0; i < HTLEN; i++)
592                 for(dp = ht[i]; dp; dp = dp->next) {
593                         dp->mark = 0;
594                         for(rp = dp->rr; rp; rp = rp->next)
595                                 if(rp->db)
596                                         rp->expire = 0;
597                 }
598
599         unlock(&dnlock);
600 }
601
602 /*
603  *  mark all local db records about my area as authoritative,
604  *  delete timed out ones
605  */
606 void
607 dnauthdb(void)
608 {
609         int i;
610         ulong minttl;
611         Area *area;
612         DN *dp;
613         RR *rp, **l;
614
615         lock(&dnlock);
616
617         /* time out all database entries */
618         for(i = 0; i < HTLEN; i++)
619                 for(dp = ht[i]; dp; dp = dp->next){
620                         area = inmyarea(dp->name);
621                         l = &dp->rr;
622                         for(rp = *l; rp; rp = *l){
623                                 if(rp->db){
624                                         if(rp->expire == 0){
625                                                 rrdelhead(l);
626                                                 continue;
627                                         }
628                                         if(area){
629                                                 minttl = area->soarr->soa->minttl;
630                                                 if(rp->ttl < minttl)
631                                                         rp->ttl = minttl;
632                                                 rp->auth = 1;
633                                         }
634                                 }
635                                 l = &rp->next;
636                         }
637                 }
638
639         unlock(&dnlock);
640 }
641
642 /*
643  *  keep track of other processes to know if we can
644  *  garbage collect.  block while garbage collecting.
645  */
646 int
647 getactivity(Request *req, int recursive)
648 {
649         int rv;
650
651         if(traceactivity)
652                 dnslog("get: %d active by pid %d from %p",
653                         dnvars.active, getpid(), getcallerpc(&req));
654         lock(&dnvars);
655         /*
656          * can't block here if we're already holding one
657          * of the dnvars.active (recursive).  will deadlock.
658          */
659         while(!recursive && dnvars.mutex){
660                 unlock(&dnvars);
661                 sleep(100);                     /* tune; was 200 */
662                 lock(&dnvars);
663         }
664         rv = ++dnvars.active;
665         now = time(nil);
666         nowns = nsec();
667         req->id = ++dnvars.id;
668         req->aux = nil;
669         unlock(&dnvars);
670
671         return rv;
672 }
673 void
674 putactivity(int recursive)
675 {
676         static ulong lastclean;
677
678         if(traceactivity)
679                 dnslog("put: %d active by pid %d",
680                         dnvars.active, getpid());
681         lock(&dnvars);
682         dnvars.active--;
683         assert(dnvars.active >= 0); /* "dnvars.active %d", dnvars.active */
684
685         /*
686          *  clean out old entries and check for new db periodicly
687          *  can't block here if being called to let go a "recursive" lock
688          *  or we'll deadlock waiting for ourselves to give up the dnvars.active.
689          */
690         if (recursive || dnvars.mutex ||
691             (needrefresh == 0 && dnvars.active > 0)){
692                 unlock(&dnvars);
693                 return;
694         }
695
696         /* wait till we're alone */
697         dnvars.mutex = 1;
698         while(dnvars.active > 0){
699                 unlock(&dnvars);
700                 sleep(100);             /* tune; was 100 */
701                 lock(&dnvars);
702         }
703         unlock(&dnvars);
704
705         dncheck();
706
707         db2cache(needrefresh);
708         dncheck();
709
710         dnageall(0);
711
712         dncheck();
713
714         /* let others back in */
715         lastclean = now;
716         needrefresh = 0;
717         dnvars.mutex = 0;
718 }
719
720 int
721 rrlistlen(RR *rp)
722 {
723         int n;
724
725         n = 0;
726         for(; rp; rp = rp->next)
727                 ++n;
728         return n;
729 }
730
731 /*
732  *  Attach a single resource record to a domain name (new->owner).
733  *      - Avoid duplicates with already present RR's
734  *      - Chain all RR's of the same type adjacent to one another
735  *      - chain authoritative RR's ahead of non-authoritative ones
736  *      - remove any expired RR's
737  *  If new is a stale duplicate, rrfree it.
738  *  Must be called with dnlock held.
739  */
740 static void
741 rrattach1(RR *new, int auth)
742 {
743         RR **l;
744         RR *rp;
745         DN *dp;
746         ulong ttl;
747
748         assert(new->magic == RRmagic && !new->cached);
749
750         dp = new->owner;
751         assert(dp != nil && dp->magic == DNmagic);
752         new->auth |= auth;
753         new->next = 0;
754
755         /*
756          * try not to let responses expire before we
757          * can use them to complete this query, by extending
758          * past (or nearly past) expiration time.
759          */
760         if(new->db)
761                 ttl = Year;
762         else
763                 ttl = new->ttl;
764         if(ttl <= Min)
765                 ttl = 10*Min;
766         new->expire = now + ttl;
767
768         /*
769          *  find first rr of the right type
770          */
771         l = &dp->rr;
772         for(rp = *l; rp; rp = *l){
773                 assert(rp->magic == RRmagic && rp->cached);
774                 if(rp->type == new->type)
775                         break;
776                 l = &rp->next;
777         }
778
779         /*
780          *  negative entries replace positive entries
781          *  positive entries replace negative entries
782          *  newer entries replace older entries with the same fields
783          *
784          *  look farther ahead than just the next entry when looking
785          *  for duplicates; RRs of a given type can have different rdata
786          *  fields (e.g. multiple NS servers).
787          */
788         while ((rp = *l) != nil){
789                 assert(rp->magic == RRmagic && rp->cached);
790                 if(rp->type != new->type)
791                         break;
792
793                 if(rp->db == new->db && rp->auth == new->auth){
794                         /* negative drives out positive and vice versa */
795                         if(rp->negative != new->negative) {
796                                 /* rp == *l before; *l == rp->next after */
797                                 rrdelhead(l);
798                                 continue;       
799                         }
800                         /* all things equal, pick the newer one */
801                         else if(rp->arg0 == new->arg0 && rp->arg1 == new->arg1){
802                                 /* old drives out new */
803                                 if((long)(rp->expire - new->expire) > 0) {
804                                         rrfree(new);
805                                         return;
806                                 }
807                                 /* rp == *l before; *l == rp->next after */
808                                 rrdelhead(l);
809                                 continue;
810                         }
811                         /*
812                          *  Hack for pointer records.  This makes sure
813                          *  the ordering in the list reflects the ordering
814                          *  received or read from the database
815                          */
816                         else if(rp->type == Tptr &&
817                             !rp->negative && !new->negative &&
818                             rp->ptr->ordinal > new->ptr->ordinal)
819                                 break;
820                 }
821                 l = &rp->next;
822         }
823
824         if (rronlist(new, rp)) {
825                 /* should not happen; duplicates were processed above */
826                 dnslog("adding duplicate %R to list of %R; aborting", new, rp);
827                 abort();
828         }
829         /*
830          *  add to chain
831          */
832         new->cached = 1;
833         new->next = rp;
834         *l = new;
835 }
836
837 /*
838  *  Attach a list of resource records to a domain name.
839  *  May rrfree any stale duplicate RRs; dismembers the list.
840  *  Upon return, every RR in the list will have been rrfree-d
841  *  or attached to its domain name.
842  *  See rrattach1 for properties preserved.
843  */
844 void
845 rrattach(RR *rp, int auth)
846 {
847         RR *next;
848         DN *dp;
849
850         lock(&dnlock);
851         for(; rp; rp = next){
852                 next = rp->next;
853                 rp->next = nil;
854                 dp = rp->owner;
855                 /* avoid any outside spoofing */
856                 if(cfg.cachedb && !rp->db && inmyarea(dp->name))
857                         rrfree(rp);
858                 else
859                         rrattach1(rp, auth);
860         }
861         unlock(&dnlock);
862 }
863
864 RR**
865 rrcopy(RR *rp, RR **last)
866 {
867         RR *nrp;
868         SOA *soa;
869         Srv *srv;
870         Key *key;
871         Cert *cert;
872         Sig *sig;
873         Null *null;
874         Txt *t, *nt, **l;
875
876         assert(rp->magic == RRmagic);
877         nrp = rralloc(rp->type);
878         switch(rp->type){
879         case Tsoa:
880                 soa = nrp->soa;
881                 *nrp = *rp;
882                 nrp->soa = soa;
883                 *soa = *rp->soa;
884                 soa->slaves = copyserverlist(rp->soa->slaves);
885                 break;
886         case Tsrv:
887                 srv = nrp->srv;
888                 *nrp = *rp;
889                 nrp->srv = srv;
890                 *srv = *rp->srv;
891                 break;
892         case Tkey:
893                 key = nrp->key;
894                 *nrp = *rp;
895                 nrp->key = key;
896                 *key = *rp->key;
897                 key->data = emalloc(key->dlen);
898                 memmove(key->data, rp->key->data, rp->key->dlen);
899                 break;
900         case Tcert:
901                 cert = nrp->cert;
902                 *nrp = *rp;
903                 nrp->cert = cert;
904                 *cert = *rp->cert;
905                 cert->data = emalloc(cert->dlen);
906                 memmove(cert->data, rp->cert->data, rp->cert->dlen);
907                 break;
908         case Tsig:
909                 sig = nrp->sig;
910                 *nrp = *rp;
911                 nrp->sig = sig;
912                 *sig = *rp->sig;
913                 sig->data = emalloc(sig->dlen);
914                 memmove(sig->data, rp->sig->data, rp->sig->dlen);
915                 break;
916         case Tnull:
917                 null = nrp->null;
918                 *nrp = *rp;
919                 nrp->null = null;
920                 *null = *rp->null;
921                 null->data = emalloc(null->dlen);
922                 memmove(null->data, rp->null->data, rp->null->dlen);
923                 break;
924         case Ttxt:
925                 *nrp = *rp;
926                 l = &nrp->txt;
927                 *l = nil;
928                 for(t = rp->txt; t != nil; t = t->next){
929                         nt = emalloc(sizeof(*nt));
930                         nt->p = estrdup(t->p);
931                         nt->next = nil;
932                         *l = nt;
933                         l = &nt->next;
934                 }
935                 break;
936         default:
937                 *nrp = *rp;
938                 break;
939         }
940         nrp->pc = getcallerpc(&rp);
941         setmalloctag(nrp, nrp->pc);
942         nrp->cached = 0;
943         nrp->next = nil;
944         *last = nrp;
945         return &nrp->next;
946 }
947
948 /*
949  *  lookup a resource record of a particular type and
950  *  class attached to a domain name.  Return copies.
951  *
952  *  Priority ordering is:
953  *      db authoritative
954  *      not timed out network authoritative
955  *      not timed out network unauthoritative
956  *      unauthoritative db
957  *
958  *  if flag NOneg is set, don't return negative cached entries.
959  *  return nothing instead.
960  */
961 RR*
962 rrlookup(DN *dp, int type, int flag)
963 {
964         RR *rp, *first, **last;
965
966         assert(dp->magic == DNmagic);
967
968         first = nil;
969         last = &first;
970         lock(&dnlock);
971
972         /* try for an authoritative db entry */
973         for(rp = dp->rr; rp; rp = rp->next){
974                 assert(rp->magic == RRmagic && rp->cached);
975                 if(rp->db)
976                 if(rp->auth)
977                 if(tsame(type, rp->type))
978                         last = rrcopy(rp, last);
979         }
980         if(first)
981                 goto out;
982
983         /* try for a living authoritative network entry */
984         for(rp = dp->rr; rp; rp = rp->next){
985                 if(!rp->db)
986                 if(rp->auth)
987                 if((long)(rp->expire - now) > 0)
988                 if(tsame(type, rp->type)){
989                         if(flag == NOneg && rp->negative)
990                                 goto out;
991                         last = rrcopy(rp, last);
992                 }
993         }
994         if(first)
995                 goto out;
996
997         /* try for a living unauthoritative network entry */
998         for(rp = dp->rr; rp; rp = rp->next){
999                 if(!rp->db)
1000                 if((long)(rp->expire - now) > 0)
1001                 if(tsame(type, rp->type)){
1002                         if(flag == NOneg && rp->negative)
1003                                 goto out;
1004                         last = rrcopy(rp, last);
1005                 }
1006         }
1007         if(first)
1008                 goto out;
1009
1010         /* try for an unauthoritative db entry */
1011         for(rp = dp->rr; rp; rp = rp->next){
1012                 if(rp->db)
1013                 if(tsame(type, rp->type))
1014                         last = rrcopy(rp, last);
1015         }
1016         if(first)
1017                 goto out;
1018
1019         /* otherwise, settle for anything we got (except for negative caches) */
1020         for(rp = dp->rr; rp; rp = rp->next)
1021                 if(tsame(type, rp->type)){
1022                         if(rp->negative)
1023                                 goto out;
1024                         last = rrcopy(rp, last);
1025                 }
1026
1027 out:
1028         unlock(&dnlock);
1029         unique(first);
1030         return first;
1031 }
1032
1033 /*
1034  *  convert an ascii RR type name to its integer representation
1035  */
1036 int
1037 rrtype(char *atype)
1038 {
1039         int i;
1040
1041         for(i = 0; i <= Tall; i++)
1042                 if(rrtname[i] && strcmp(rrtname[i], atype) == 0)
1043                         return i;
1044
1045         /* make any a synonym for all */
1046         if(strcmp(atype, "any") == 0)
1047                 return Tall;
1048         else if(isascii(atype[0]) && isdigit(atype[0]))
1049                 return atoi(atype);
1050         else
1051                 return -1;
1052 }
1053
1054 /*
1055  *  return 0 if not a supported rr type
1056  */
1057 int
1058 rrsupported(int type)
1059 {
1060         if(type < 0 || type >Tall)
1061                 return 0;
1062         return rrtname[type] != nil;
1063 }
1064
1065 /*
1066  *  compare 2 types
1067  */
1068 int
1069 tsame(int t1, int t2)
1070 {
1071         return t1 == t2 || t1 == Tall;
1072 }
1073
1074 /*
1075  *  Add resource records to a list.
1076  */
1077 RR*
1078 rrcat(RR **start, RR *rp)
1079 {
1080         RR *olp, *nlp;
1081         RR **last;
1082
1083         /* check for duplicates */
1084         for (olp = *start; 0 && olp; olp = olp->next)
1085                 for (nlp = rp; nlp; nlp = nlp->next)
1086                         if (rrsame(nlp, olp))
1087                                 dnslog("rrcat: duplicate RR: %R", nlp);
1088         USED(olp);
1089
1090         last = start;
1091         while(*last != nil)
1092                 last = &(*last)->next;
1093
1094         *last = rp;
1095         return *start;
1096 }
1097
1098 RR*
1099 rrremfilter(RR **l, int (*filter)(RR*, void*), void *arg)
1100 {
1101         RR *first, *rp;
1102         RR **nl;
1103
1104         first = nil;
1105         nl = &first;
1106         while(*l != nil){
1107                 rp = *l;
1108                 if((*filter)(rp, arg)){
1109                         *l = rp->next;
1110                         *nl = rp;
1111                         nl = &rp->next;
1112                         *nl = nil;
1113                 } else
1114                         l = &(*l)->next;
1115         }
1116
1117         return first;
1118 }
1119
1120 static int
1121 filterneg(RR *rp, void*)
1122 {
1123         return rp->negative;
1124 }
1125 static int
1126 filtertype(RR *rp, void *arg)
1127 {
1128         return rp->type == *((int*)arg);
1129 }
1130 static int
1131 filterowner(RR *rp, void *arg)
1132 {
1133         return rp->owner == (DN*)arg;
1134 }
1135
1136 /*
1137  *  remove negative cache rr's from an rr list
1138  */
1139 RR*
1140 rrremneg(RR **l)
1141 {
1142         return rrremfilter(l, filterneg, nil);
1143 }
1144
1145 /*
1146  *  remove rr's of a particular type from an rr list
1147  */
1148 RR*
1149 rrremtype(RR **l, int type)
1150 {
1151         return rrremfilter(l, filtertype, &type);
1152 }
1153
1154 /*
1155  *  remove rr's of a particular owner from an rr list
1156  */
1157 RR*
1158 rrremowner(RR **l, DN *owner)
1159 {
1160         return rrremfilter(l, filterowner, owner);
1161 }
1162
1163 static char *
1164 dnname(DN *dn)
1165 {
1166         return dn? dn->name: "<null>";
1167 }
1168
1169 static char *
1170 idnname(DN *dn, char *buf, int nbuf)
1171 {
1172         char *name;
1173
1174         name = dnname(dn);
1175         if(idn2utf(name, buf, nbuf) != nil)
1176                 return buf;
1177         return name;
1178 }
1179
1180 /*
1181  *  print conversion for rr records
1182  */
1183 int
1184 rrfmt(Fmt *f)
1185 {
1186         int rv;
1187         char *strp;
1188         char buf[Domlen];
1189         Fmt fstr;
1190         RR *rp;
1191         Server *s;
1192         SOA *soa;
1193         Srv *srv;
1194         Txt *t;
1195
1196         fmtstrinit(&fstr);
1197
1198         rp = va_arg(f->args, RR*);
1199         if(rp == nil){
1200                 fmtprint(&fstr, "<null>");
1201                 goto out;
1202         }
1203
1204         fmtprint(&fstr, "%s %s", dnname(rp->owner),
1205                 rrname(rp->type, buf, sizeof buf));
1206
1207         if(rp->negative){
1208                 fmtprint(&fstr, "\tnegative - rcode %d", rp->negrcode);
1209                 goto out;
1210         }
1211
1212         switch(rp->type){
1213         case Thinfo:
1214                 fmtprint(&fstr, "\t%s %s", dnname(rp->cpu), dnname(rp->os));
1215                 break;
1216         case Tcname:
1217         case Tmb:
1218         case Tmd:
1219         case Tmf:
1220         case Tns:
1221                 fmtprint(&fstr, "\t%s", dnname(rp->host));
1222                 break;
1223         case Tmg:
1224         case Tmr:
1225                 fmtprint(&fstr, "\t%s", dnname(rp->mb));
1226                 break;
1227         case Tminfo:
1228                 fmtprint(&fstr, "\t%s %s", dnname(rp->mb), dnname(rp->rmb));
1229                 break;
1230         case Tmx:
1231                 fmtprint(&fstr, "\t%lud %s", rp->pref, dnname(rp->host));
1232                 break;
1233         case Ta:
1234         case Taaaa:
1235                 fmtprint(&fstr, "\t%s", dnname(rp->ip));
1236                 break;
1237         case Tptr:
1238                 fmtprint(&fstr, "\t%s", dnname(rp->ptr));
1239                 break;
1240         case Tsoa:
1241                 soa = rp->soa;
1242                 fmtprint(&fstr, "\t%s %s %lud %lud %lud %lud %lud",
1243                         dnname(rp->host), dnname(rp->rmb),
1244                         (soa? soa->serial: 0),
1245                         (soa? soa->refresh: 0), (soa? soa->retry: 0),
1246                         (soa? soa->expire: 0), (soa? soa->minttl: 0));
1247                 if (soa)
1248                         for(s = soa->slaves; s != nil; s = s->next)
1249                                 fmtprint(&fstr, " %s", s->name);
1250                 break;
1251         case Tsrv:
1252                 srv = rp->srv;
1253                 fmtprint(&fstr, "\t%ud %ud %ud %s",
1254                         (srv? srv->pri: 0), (srv? srv->weight: 0),
1255                         rp->port, dnname(rp->host));
1256                 break;
1257         case Tnull:
1258                 if (rp->null == nil)
1259                         fmtprint(&fstr, "\t<null>");
1260                 else
1261                         fmtprint(&fstr, "\t%.*H", rp->null->dlen,
1262                                 rp->null->data);
1263                 break;
1264         case Ttxt:
1265                 fmtprint(&fstr, "\t");
1266                 for(t = rp->txt; t != nil; t = t->next)
1267                         fmtprint(&fstr, "%s", t->p);
1268                 break;
1269         case Trp:
1270                 fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
1271                 break;
1272         case Tkey:
1273                 if (rp->key == nil)
1274                         fmtprint(&fstr, "\t<null> <null> <null>");
1275                 else
1276                         fmtprint(&fstr, "\t%d %d %d", rp->key->flags,
1277                                 rp->key->proto, rp->key->alg);
1278                 break;
1279         case Tsig:
1280                 if (rp->sig == nil)
1281                         fmtprint(&fstr,
1282                    "\t<null> <null> <null> <null> <null> <null> <null> <null>");
1283                 else
1284                         fmtprint(&fstr, "\t%d %d %d %lud %lud %lud %d %s",
1285                                 rp->sig->type, rp->sig->alg, rp->sig->labels,
1286                                 rp->sig->ttl, rp->sig->exp, rp->sig->incep,
1287                                 rp->sig->tag, dnname(rp->sig->signer));
1288                 break;
1289         case Tcert:
1290                 if (rp->cert == nil)
1291                         fmtprint(&fstr, "\t<null> <null> <null>");
1292                 else
1293                         fmtprint(&fstr, "\t%d %d %d",
1294                                 rp->cert->type, rp->cert->tag, rp->cert->alg);
1295                 break;
1296         }
1297 out:
1298         strp = fmtstrflush(&fstr);
1299         rv = fmtstrcpy(f, strp);
1300         free(strp);
1301         return rv;
1302 }
1303
1304 /*
1305  *  print conversion for rr records in attribute value form
1306  */
1307 int
1308 rravfmt(Fmt *f)
1309 {
1310         int rv, quote;
1311         char buf[Domlen], *strp;
1312         Fmt fstr;
1313         RR *rp;
1314         Server *s;
1315         SOA *soa;
1316         Srv *srv;
1317         Txt *t;
1318
1319         fmtstrinit(&fstr);
1320
1321         rp = va_arg(f->args, RR*);
1322         if(rp == nil){
1323                 fmtprint(&fstr, "<null>");
1324                 goto out;
1325         }
1326
1327         if(rp->type == Tptr)
1328                 fmtprint(&fstr, "ptr=%s", dnname(rp->owner));
1329         else
1330                 fmtprint(&fstr, "dom=%s", idnname(rp->owner, buf, sizeof(buf)));
1331
1332         switch(rp->type){
1333         case Thinfo:
1334                 fmtprint(&fstr, " cpu=%s os=%s",
1335                         idnname(rp->cpu, buf, sizeof(buf)),
1336                         idnname(rp->os, buf, sizeof(buf)));
1337                 break;
1338         case Tcname:
1339                 fmtprint(&fstr, " cname=%s", idnname(rp->host, buf, sizeof(buf)));
1340                 break;
1341         case Tmb:
1342         case Tmd:
1343         case Tmf:
1344                 fmtprint(&fstr, " mbox=%s", idnname(rp->host, buf, sizeof(buf)));
1345                 break;
1346         case Tns:
1347                 fmtprint(&fstr,  " ns=%s", idnname(rp->host, buf, sizeof(buf)));
1348                 break;
1349         case Tmg:
1350         case Tmr:
1351                 fmtprint(&fstr, " mbox=%s", idnname(rp->mb, buf, sizeof(buf)));
1352                 break;
1353         case Tminfo:
1354                 fmtprint(&fstr, " mbox=%s mbox=%s",
1355                         idnname(rp->mb, buf, sizeof(buf)),
1356                         idnname(rp->rmb, buf, sizeof(buf)));
1357                 break;
1358         case Tmx:
1359                 fmtprint(&fstr, " pref=%lud mx=%s", rp->pref,
1360                         idnname(rp->host, buf, sizeof(buf)));
1361                 break;
1362         case Ta:
1363         case Taaaa:
1364                 fmtprint(&fstr, " ip=%s", dnname(rp->ip));
1365                 break;
1366         case Tptr:
1367                 fmtprint(&fstr, " dom=%s", dnname(rp->ptr));
1368                 break;
1369         case Tsoa:
1370                 soa = rp->soa;
1371                 fmtprint(&fstr,
1372 " ns=%s mbox=%s serial=%lud refresh=%lud retry=%lud expire=%lud ttl=%lud",
1373                         idnname(rp->host, buf, sizeof(buf)),
1374                         idnname(rp->rmb, buf, sizeof(buf)),
1375                         (soa? soa->serial: 0),
1376                         (soa? soa->refresh: 0), (soa? soa->retry: 0),
1377                         (soa? soa->expire: 0), (soa? soa->minttl: 0));
1378                 for(s = soa->slaves; s != nil; s = s->next)
1379                         fmtprint(&fstr, " dnsslave=%s", s->name);
1380                 break;
1381         case Tsrv:
1382                 srv = rp->srv;
1383                 fmtprint(&fstr, " pri=%ud weight=%ud port=%ud target=%s",
1384                         (srv? srv->pri: 0), (srv? srv->weight: 0),
1385                         rp->port, idnname(rp->host, buf, sizeof(buf)));
1386                 break;
1387         case Tnull:
1388                 if (rp->null == nil)
1389                         fmtprint(&fstr, " null=<null>");
1390                 else
1391                         fmtprint(&fstr, " null=%.*H", rp->null->dlen,
1392                                 rp->null->data);
1393                 break;
1394         case Ttxt:
1395                 fmtprint(&fstr, " txt=");
1396                 quote = 0;
1397                 for(t = rp->txt; t != nil; t = t->next)
1398                         if(strchr(t->p, ' '))
1399                                 quote = 1;
1400                 if(quote)
1401                         fmtprint(&fstr, "\"");
1402                 for(t = rp->txt; t != nil; t = t->next)
1403                         fmtprint(&fstr, "%s", t->p);
1404                 if(quote)
1405                         fmtprint(&fstr, "\"");
1406                 break;
1407         case Trp:
1408                 fmtprint(&fstr, " rp=%s txt=%s",
1409                         idnname(rp->rmb, buf, sizeof(buf)),
1410                         idnname(rp->rp, buf, sizeof(buf)));
1411                 break;
1412         case Tkey:
1413                 if (rp->key == nil)
1414                         fmtprint(&fstr, " flags=<null> proto=<null> alg=<null>");
1415                 else
1416                         fmtprint(&fstr, " flags=%d proto=%d alg=%d",
1417                                 rp->key->flags, rp->key->proto, rp->key->alg);
1418                 break;
1419         case Tsig:
1420                 if (rp->sig == nil)
1421                         fmtprint(&fstr,
1422 " type=<null> alg=<null> labels=<null> ttl=<null> exp=<null> incep=<null> tag=<null> signer=<null>");
1423                 else
1424                         fmtprint(&fstr,
1425 " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d signer=%s",
1426                                 rp->sig->type, rp->sig->alg, rp->sig->labels,
1427                                 rp->sig->ttl, rp->sig->exp, rp->sig->incep,
1428                                 rp->sig->tag, idnname(rp->sig->signer, buf, sizeof(buf)));
1429                 break;
1430         case Tcert:
1431                 if (rp->cert == nil)
1432                         fmtprint(&fstr, " type=<null> tag=<null> alg=<null>");
1433                 else
1434                         fmtprint(&fstr, " type=%d tag=%d alg=%d",
1435                                 rp->cert->type, rp->cert->tag, rp->cert->alg);
1436                 break;
1437         }
1438 out:
1439         strp = fmtstrflush(&fstr);
1440         rv = fmtstrcpy(f, strp);
1441         free(strp);
1442         return rv;
1443 }
1444
1445 void
1446 warning(char *fmt, ...)
1447 {
1448         char dnserr[256];
1449         va_list arg;
1450
1451         va_start(arg, fmt);
1452         vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
1453         va_end(arg);
1454         syslog(1, logfile, dnserr);             /* on console too */
1455 }
1456
1457 void
1458 dnslog(char *fmt, ...)
1459 {
1460         char dnserr[256];
1461         va_list arg;
1462
1463         va_start(arg, fmt);
1464         vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
1465         va_end(arg);
1466         syslog(0, logfile, dnserr);
1467 }
1468
1469 /*
1470  * based on libthread's threadsetname, but drags in less library code.
1471  * actually just sets the arguments displayed.
1472  */
1473 void
1474 procsetname(char *fmt, ...)
1475 {
1476         int fd;
1477         char *cmdname;
1478         char buf[128];
1479         va_list arg;
1480
1481         va_start(arg, fmt);
1482         cmdname = vsmprint(fmt, arg);
1483         va_end(arg);
1484         if (cmdname == nil)
1485                 return;
1486         snprint(buf, sizeof buf, "#p/%d/args", getpid());
1487         if((fd = open(buf, OWRITE)) >= 0){
1488                 write(fd, cmdname, strlen(cmdname)+1);
1489                 close(fd);
1490         }
1491         free(cmdname);
1492 }
1493
1494 /*
1495  *  create a slave process to handle a request to avoid one request blocking
1496  *  another
1497  */
1498 void
1499 slave(Request *req)
1500 {
1501         int ppid, procs;
1502
1503         if(req->isslave)
1504                 return;         /* we're already a slave process */
1505
1506         /*
1507          * These calls to putactivity cannot block.
1508          * After getactivity(), the current process is counted
1509          * twice in dnvars.active (one will pass to the child).
1510          * If putactivity tries to wait for dnvars.active == 0,
1511          * it will never happen.
1512          */
1513
1514         /* limit parallelism */
1515         procs = getactivity(req, 1);
1516         if(procs > stats.slavehiwat)
1517                 stats.slavehiwat = procs;
1518         if(procs > Maxactive){
1519                 if(traceactivity)
1520                         dnslog("[%d] too much activity", getpid());
1521                 putactivity(1);
1522                 return;
1523         }
1524
1525         /*
1526          * parent returns to main loop, child does the work.
1527          * don't change note group.
1528          */
1529         ppid = getpid();
1530         switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
1531         case -1:
1532                 putactivity(1);
1533                 break;
1534         case 0:
1535                 procsetname("request slave of pid %d", ppid);
1536                 if(traceactivity)
1537                         dnslog("[%d] take activity from %d", getpid(), ppid);
1538                 req->isslave = 1;       /* why not `= getpid()'? */
1539                 break;
1540         default:
1541                 /*
1542                  * this relies on rfork producing separate, initially-identical
1543                  * stacks, thus giving us two copies of `req', one in each
1544                  * process.
1545                  */
1546                 alarm(0);
1547                 longjmp(req->mret, 1);
1548         }
1549 }
1550
1551 /*
1552  *  chasing down double free's
1553  */
1554 void
1555 dncheck(void)
1556 {
1557         int i;
1558         DN *dp;
1559         RR *rp;
1560
1561         if(!testing)
1562                 return;
1563
1564         lock(&dnlock);
1565         poolcheck(mainmem);
1566         for(i = 0; i < HTLEN; i++)
1567                 for(dp = ht[i]; dp; dp = dp->next){
1568                         assert(dp->magic == DNmagic);
1569                         for(rp = dp->rr; rp; rp = rp->next){
1570                                 assert(rp->magic == RRmagic);
1571                                 assert(rp->cached);
1572                                 assert(rp->owner == dp);
1573                                 /* also check for duplicate rrs */
1574                                 if (rronlist(rp, rp->next)) {
1575                                         dnslog("%R duplicates its next chain "
1576                                                 "(%R); aborting", rp, rp->next);
1577                                         abort();
1578                                 }
1579                         }
1580                 }
1581         unlock(&dnlock);
1582 }
1583
1584 static int
1585 rrequiv(RR *r1, RR *r2)
1586 {
1587         return r1->owner == r2->owner
1588                 && r1->type == r2->type
1589                 && r1->arg0 == r2->arg0
1590                 && r1->arg1 == r2->arg1;
1591 }
1592
1593 void
1594 unique(RR *rp)
1595 {
1596         RR **l, *nrp;
1597
1598         for(; rp; rp = rp->next){
1599                 l = &rp->next;
1600                 for(nrp = *l; nrp; nrp = *l)
1601                         if(rrequiv(rp, nrp)){
1602                                 *l = nrp->next;
1603                                 rrfree(nrp);
1604                         } else
1605                                 l = &nrp->next;
1606         }
1607 }
1608
1609 /*
1610  *  true if second domain is subsumed by the first
1611  */
1612 int
1613 subsume(char *higher, char *lower)
1614 {
1615         int hn, ln;
1616
1617         ln = strlen(lower);
1618         hn = strlen(higher);
1619         if (ln < hn || cistrcmp(lower + ln - hn, higher) != 0 ||
1620             ln > hn && hn != 0 && lower[ln - hn - 1] != '.')
1621                 return 0;
1622         return 1;
1623 }
1624
1625 /*
1626  *  randomize the order we return items to provide some
1627  *  load balancing for servers.
1628  *
1629  *  only randomize the first class of entries
1630  */
1631 RR*
1632 randomize(RR *rp)
1633 {
1634         RR *first, *last, *x, *base;
1635         ulong n;
1636
1637         if(rp == nil || rp->next == nil)
1638                 return rp;
1639
1640         /* just randomize addresses, mx's and ns's */
1641         for(x = rp; x; x = x->next)
1642                 if(x->type != Ta && x->type != Taaaa &&
1643                     x->type != Tmx && x->type != Tns)
1644                         return rp;
1645
1646         base = rp;
1647
1648         n = rand();
1649         last = first = nil;
1650         while(rp != nil){
1651                 /* stop randomizing if we've moved past our class */
1652                 if(base->auth != rp->auth || base->db != rp->db){
1653                         last->next = rp;
1654                         break;
1655                 }
1656
1657                 /* unchain */
1658                 x = rp;
1659                 rp = x->next;
1660                 x->next = nil;
1661
1662                 if(n&1){
1663                         /* add to tail */
1664                         if(last == nil)
1665                                 first = x;
1666                         else
1667                                 last->next = x;
1668                         last = x;
1669                 } else {
1670                         /* add to head */
1671                         if(last == nil)
1672                                 last = x;
1673                         x->next = first;
1674                         first = x;
1675                 }
1676
1677                 /* reroll the dice */
1678                 n >>= 1;
1679         }
1680
1681         return first;
1682 }
1683
1684 static int
1685 sencodefmt(Fmt *f)
1686 {
1687         int i, len, ilen, rv;
1688         char *out, *buf;
1689         uchar *b;
1690         char obuf[64];          /* rsc optimization */
1691
1692         if(!(f->flags&FmtPrec) || f->prec < 1)
1693                 goto error;
1694
1695         b = va_arg(f->args, uchar*);
1696         if(b == nil)
1697                 goto error;
1698
1699         /* if it's a printable, go for it */
1700         len = f->prec;
1701         for(i = 0; i < len; i++)
1702                 if(!isprint(b[i]))
1703                         break;
1704         if(i == len){
1705                 if(len >= sizeof obuf)
1706                         len = sizeof(obuf)-1;
1707                 memmove(obuf, b, len);
1708                 obuf[len] = 0;
1709                 fmtstrcpy(f, obuf);
1710                 return 0;
1711         }
1712
1713         ilen = f->prec;
1714         f->prec = 0;
1715         f->flags &= ~FmtPrec;
1716         switch(f->r){
1717         case '<':
1718                 len = (8*ilen+4)/5 + 3;
1719                 break;
1720         case '[':
1721                 len = (8*ilen+5)/6 + 4;
1722                 break;
1723         case 'H':
1724                 len = 2*ilen + 1;
1725                 break;
1726         default:
1727                 goto error;
1728         }
1729
1730         if(len > sizeof(obuf)){
1731                 buf = malloc(len);
1732                 if(buf == nil)
1733                         goto error;
1734         } else
1735                 buf = obuf;
1736
1737         /* convert */
1738         out = buf;
1739         switch(f->r){
1740         case '<':
1741                 rv = enc32(out, len, b, ilen);
1742                 break;
1743         case '[':
1744                 rv = enc64(out, len, b, ilen);
1745                 break;
1746         case 'H':
1747                 rv = enc16(out, len, b, ilen);
1748                 break;
1749         default:
1750                 rv = -1;
1751                 break;
1752         }
1753         if(rv < 0)
1754                 goto error;
1755
1756         fmtstrcpy(f, buf);
1757         if(buf != obuf)
1758                 free(buf);
1759         return 0;
1760
1761 error:
1762         return fmtstrcpy(f, "<encodefmt>");
1763 }
1764
1765 void*
1766 emalloc(int size)
1767 {
1768         char *x;
1769
1770         x = mallocz(size, 1);
1771         if(x == nil)
1772                 abort();
1773         setmalloctag(x, getcallerpc(&size));
1774         return x;
1775 }
1776
1777 char*
1778 estrdup(char *s)
1779 {
1780         int size;
1781         char *p;
1782
1783         size = strlen(s);
1784         p = mallocz(size+1, 0);
1785         if(p == nil)
1786                 abort();
1787         memmove(p, s, size);
1788         p[size] = 0;
1789         setmalloctag(p, getcallerpc(&s));
1790         return p;
1791 }
1792
1793 /*
1794  *  create a pointer record
1795  */
1796 static RR*
1797 mkptr(DN *dp, char *ptr, ulong ttl)
1798 {
1799         DN *ipdp;
1800         RR *rp;
1801
1802         ipdp = dnlookup(ptr, Cin, 1);
1803
1804         rp = rralloc(Tptr);
1805         rp->ptr = dp;
1806         rp->owner = ipdp;
1807         rp->db = 1;
1808         if(ttl)
1809                 rp->ttl = ttl;
1810         return rp;
1811 }
1812
1813 void    bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes);
1814
1815 /*
1816  *  look for all ip addresses in this network and make
1817  *  pointer records for them.
1818  */
1819 void
1820 dnptr(uchar *net, uchar *mask, char *dom, int forwtype, int subdoms, int ttl)
1821 {
1822         int i, j, len;
1823         char *p, *e;
1824         char ptr[Domlen];
1825         uchar *ipp;
1826         uchar ip[IPaddrlen], nnet[IPaddrlen];
1827         uchar nibip[IPaddrlen*2];
1828         DN *dp;
1829         RR *rp, *nrp, *first, **l;
1830
1831         l = &first;
1832         first = nil;
1833         for(i = 0; i < HTLEN; i++)
1834                 for(dp = ht[i]; dp; dp = dp->next)
1835                         for(rp = dp->rr; rp; rp = rp->next){
1836                                 if(rp->type != forwtype || rp->negative)
1837                                         continue;
1838                                 parseip(ip, rp->ip->name);
1839                                 maskip(ip, mask, nnet);
1840                                 if(ipcmp(net, nnet) != 0)
1841                                         continue;
1842
1843                                 ipp = ip;
1844                                 len = IPaddrlen;
1845                                 if (forwtype == Taaaa) {
1846                                         bytes2nibbles(nibip, ip, IPaddrlen);
1847                                         ipp = nibip;
1848                                         len = 2*IPaddrlen;
1849                                 }
1850
1851                                 p = ptr;
1852                                 e = ptr+sizeof(ptr);
1853                                 for(j = len - 1; j >= len - subdoms; j--)
1854                                         p = seprint(p, e, (forwtype == Ta?
1855                                                 "%d.": "%x."), ipp[j]);
1856                                 seprint(p, e, "%s", dom);
1857
1858                                 nrp = mkptr(dp, ptr, ttl);
1859                                 *l = nrp;
1860                                 l = &nrp->next;
1861                         }
1862
1863         for(rp = first; rp != nil; rp = nrp){
1864                 nrp = rp->next;
1865                 rp->next = nil;
1866                 dp = rp->owner;
1867                 rrattach(rp, Authoritative);
1868                 dnagenever(dp);
1869         }
1870 }
1871
1872 void
1873 addserver(Server **l, char *name)
1874 {
1875         Server *s;
1876         int n;
1877
1878         while(*l)
1879                 l = &(*l)->next;
1880         n = strlen(name);
1881         s = malloc(sizeof(Server)+n+1);
1882         if(s == nil)
1883                 return;
1884         s->name = (char*)(s+1);
1885         memmove(s->name, name, n);
1886         s->name[n] = 0;
1887         s->next = nil;
1888         *l = s;
1889 }
1890
1891 Server*
1892 copyserverlist(Server *s)
1893 {
1894         Server *ns;
1895
1896         for(ns = nil; s != nil; s = s->next)
1897                 addserver(&ns, s->name);
1898         return ns;
1899 }
1900
1901
1902 /* from here down is copied to ip/snoopy/dns.c periodically to update it */
1903
1904 /*
1905  *  convert an integer RR type to it's ascii name
1906  */
1907 char*
1908 rrname(int type, char *buf, int len)
1909 {
1910         char *t;
1911
1912         t = nil;
1913         if(type >= 0 && type <= Tall)
1914                 t = rrtname[type];
1915         if(t==nil){
1916                 snprint(buf, len, "%d", type);
1917                 t = buf;
1918         }
1919         return t;
1920 }
1921
1922 /*
1923  *  free a list of resource records and any related structs
1924  */
1925 void
1926 rrfreelist(RR *rp)
1927 {
1928         RR *next;
1929
1930         for(; rp; rp = next){
1931                 next = rp->next;
1932                 rrfree(rp);
1933         }
1934 }
1935
1936 void
1937 freeserverlist(Server *s)
1938 {
1939         Server *next;
1940
1941         for(; s != nil; s = next){
1942                 next = s->next;
1943                 memset(s, 0, sizeof *s);        /* cause trouble */
1944                 free(s);
1945         }
1946 }
1947
1948 /*
1949  *  allocate a resource record of a given type
1950  */
1951 RR*
1952 rralloc(int type)
1953 {
1954         RR *rp;
1955
1956         rp = emalloc(sizeof(*rp));
1957         rp->magic = RRmagic;
1958         rp->pc = getcallerpc(&type);
1959         rp->type = type;
1960         if (rp->type != type)
1961                 dnslog("rralloc: bogus type %d", type);
1962         setmalloctag(rp, rp->pc);
1963         switch(type){
1964         case Tsoa:
1965                 rp->soa = emalloc(sizeof(*rp->soa));
1966                 rp->soa->slaves = nil;
1967                 setmalloctag(rp->soa, rp->pc);
1968                 break;
1969         case Tsrv:
1970                 rp->srv = emalloc(sizeof(*rp->srv));
1971                 setmalloctag(rp->srv, rp->pc);
1972                 break;
1973         case Tkey:
1974                 rp->key = emalloc(sizeof(*rp->key));
1975                 setmalloctag(rp->key, rp->pc);
1976                 break;
1977         case Tcert:
1978                 rp->cert = emalloc(sizeof(*rp->cert));
1979                 setmalloctag(rp->cert, rp->pc);
1980                 break;
1981         case Tsig:
1982                 rp->sig = emalloc(sizeof(*rp->sig));
1983                 setmalloctag(rp->sig, rp->pc);
1984                 break;
1985         case Tnull:
1986                 rp->null = emalloc(sizeof(*rp->null));
1987                 setmalloctag(rp->null, rp->pc);
1988                 break;
1989         }
1990         rp->ttl = 0;
1991         rp->expire = 0;
1992         rp->next = 0;
1993         return rp;
1994 }
1995
1996 /*
1997  *  free a resource record and any related structs
1998  */
1999 void
2000 rrfree(RR *rp)
2001 {
2002         Txt *t;
2003
2004         assert(rp->magic == RRmagic && !rp->cached);
2005
2006         switch(rp->type){
2007         case Tsoa:
2008                 freeserverlist(rp->soa->slaves);
2009                 memset(rp->soa, 0, sizeof *rp->soa);    /* cause trouble */
2010                 free(rp->soa);
2011                 break;
2012         case Tsrv:
2013                 memset(rp->srv, 0, sizeof *rp->srv);    /* cause trouble */
2014                 free(rp->srv);
2015                 break;
2016         case Tkey:
2017                 free(rp->key->data);
2018                 memset(rp->key, 0, sizeof *rp->key);    /* cause trouble */
2019                 free(rp->key);
2020                 break;
2021         case Tcert:
2022                 free(rp->cert->data);
2023                 memset(rp->cert, 0, sizeof *rp->cert);  /* cause trouble */
2024                 free(rp->cert);
2025                 break;
2026         case Tsig:
2027                 free(rp->sig->data);
2028                 memset(rp->sig, 0, sizeof *rp->sig);    /* cause trouble */
2029                 free(rp->sig);
2030                 break;
2031         case Tnull:
2032                 free(rp->null->data);
2033                 memset(rp->null, 0, sizeof *rp->null);  /* cause trouble */
2034                 free(rp->null);
2035                 break;
2036         case Ttxt:
2037                 while(t = rp->txt){
2038                         rp->txt = t->next;
2039                         free(t->p);
2040                         memset(t, 0, sizeof *t);        /* cause trouble */
2041                         free(t);
2042                 }
2043                 break;
2044         }
2045
2046         memset(rp, 0, sizeof *rp);              /* cause trouble */
2047         rp->magic = ~RRmagic;
2048         free(rp);
2049 }