URI:
       tdnserver.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdnserver.c (3719B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <ip.h>
            4 #include <bio.h>
            5 #include <ndb.h>
            6 #include "dns.h"
            7 
            8 static RR*        doextquery(DNSmsg*, Request*, int);
            9 static void        hint(RR**, RR*);
           10 
           11 extern char *logfile;
           12 
           13 /*
           14  *  answer a dns request
           15  */
           16 void
           17 dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
           18 {
           19         RR *tp, *neg;
           20         char *cp;
           21         DN *nsdp, *dp;
           22         Area *myarea;
           23         char tname[32];
           24 
           25         dncheck(nil, 1);
           26 
           27         memset(repp, 0, sizeof(*repp));
           28         repp->id = reqp->id;
           29         repp->flags = Fresp | Fcanrec | Oquery;
           30 
           31         /* move one question from reqp to repp */
           32         tp = reqp->qd;
           33         reqp->qd = tp->next;
           34         tp->next = 0;
           35         repp->qd = tp;
           36 
           37         if(!rrsupported(repp->qd->type)){
           38                 syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
           39                 repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
           40                 return;
           41         }
           42 
           43         if(repp->qd->owner->class != Cin){
           44                 syslog(0, logfile, "server: class %d", repp->qd->owner->class);
           45                 repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
           46                 return;
           47         }
           48 
           49         myarea = inmyarea(repp->qd->owner->name);
           50         if(myarea != nil && (repp->qd->type == Tixfr || repp->qd->type == Taxfr)){
           51                 syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
           52                 repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
           53                 return;
           54         }
           55 
           56         /*
           57          *  get the answer if we can
           58          */
           59         if(reqp->flags & Frecurse)
           60                 neg = doextquery(repp, req, Recurse);
           61         else
           62                 neg = doextquery(repp, req, Dontrecurse);
           63 
           64         /* authority is transitive */
           65         if(myarea != nil || (repp->an && repp->an->auth))
           66                 repp->flags |= Fauth;
           67 
           68         /* pass on error codes */
           69         if(repp->an == 0){
           70                 dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
           71                 if(dp->rr == 0)
           72                         if(reqp->flags & Frecurse)
           73                                 repp->flags |= dp->nonexistent|Fauth;
           74         }
           75 
           76         if(myarea == nil){
           77                 /*
           78                  *  add name server if we know
           79                  */
           80                 for(cp = repp->qd->owner->name; cp; cp = walkup(cp)){
           81                         nsdp = dnlookup(cp, repp->qd->owner->class, 0);
           82                         if(nsdp == 0)
           83                                 continue;
           84 
           85                         repp->ns = rrlookup(nsdp, Tns, OKneg);
           86                         if(repp->ns){
           87                                 /* don't pass on anything we know is wrong */
           88                                 if(repp->ns->negative){
           89                                         rrfreelist(repp->ns);
           90                                         repp->ns = nil;
           91                                 }
           92                                 break;
           93                         }
           94 
           95                         repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
           96                         if(repp->ns)
           97                                 break;
           98                 }
           99         }
          100 
          101         /*
          102          *  add ip addresses as hints
          103          */
          104         if(repp->qd->type != Taxfr && repp->qd->type != Tixfr){
          105                 for(tp = repp->ns; tp; tp = tp->next)
          106                         hint(&repp->ar, tp);
          107                 for(tp = repp->an; tp; tp = tp->next)
          108                         hint(&repp->ar, tp);
          109         }
          110 
          111         /*
          112          *  add an soa to the authority section to help client with negative caching
          113          */
          114         if(repp->an == nil){
          115                 if(myarea != nil){
          116                         rrcopy(myarea->soarr, &tp);
          117                         rrcat(&repp->ns, tp);
          118                 } else if(neg != nil) {
          119                         if(neg->negsoaowner != nil)
          120                                 rrcat(&repp->ns, rrlookup(neg->negsoaowner, Tsoa, NOneg));
          121                         repp->flags |= neg->negrcode;
          122                 }
          123         }
          124 
          125         /*
          126          *  get rid of duplicates
          127          */
          128         unique(repp->an);
          129         unique(repp->ns);
          130         unique(repp->ar);
          131 
          132         rrfreelist(neg);
          133 
          134         dncheck(nil, 1);
          135 }
          136 
          137 /*
          138  *  satisfy a recursive request.  dnlookup will handle cnames.
          139  */
          140 static RR*
          141 doextquery(DNSmsg *mp, Request *req, int recurse)
          142 {
          143         int type;
          144         char *name;
          145         RR *rp, *neg;
          146 
          147         name = mp->qd->owner->name;
          148         type = mp->qd->type;
          149         rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
          150 
          151         /* don't return soa hints as answers, it's wrong */
          152         if(rp && rp->db && !rp->auth && rp->type == Tsoa)
          153                 rrfreelist(rp);
          154 
          155         /* don't let negative cached entries escape */
          156         neg = rrremneg(&rp);
          157         rrcat(&mp->an, rp);
          158         return neg;
          159 }
          160 
          161 static void
          162 hint(RR **last, RR *rp)
          163 {
          164         RR *hp;
          165 
          166         switch(rp->type){
          167         case Tns:
          168         case Tmx:
          169         case Tmb:
          170         case Tmf:
          171         case Tmd:
          172                 hp = rrlookup(rp->host, Ta, NOneg);
          173                 if(hp == nil)
          174                         hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
          175                 rrcat(last, hp);
          176                 break;
          177         }
          178 }