1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include "dns.h" 5 6 int udpannounce(void); 7 static RR* getipaddr(DN*); 8 static void recurse(DNSmsg*, Request*); 9 static void local(DNSmsg*); 10 static void reply(int, uchar*, DNSmsg*); 11 static void hint(RR**, RR*); 12 13 extern char *logfile; 14 15 /* 16 * a process to act as a dns server for outside reqeusts 17 */ 18 void 19 dnserver(void) 20 { 21 int fd, len; 22 char *err; 23 RR *tp; 24 Request req; 25 DNSmsg reqmsg; 26 DNSmsg repmsg; 27 uchar buf[Udphdrsize + Maxudp]; 28 char tname[32]; 29 30 /* fork sharing text, data, and bss with parent */ 31 switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){ 32 case -1: 33 break; 34 case 0: 35 break; 36 default: 37 return; 38 } 39 40 while((fd = udpannounce()) < 0) 41 sleep(5000); 42 setjmp(req.mret); 43 req.isslave = 0; 44 45 /* loop on requests */ 46 for(;;){ 47 memset(&repmsg, 0, sizeof(repmsg)); 48 len = read(fd, buf, sizeof(buf)); 49 err = convM2DNS(&buf[Udphdrsize], len, &reqmsg); 50 if(err){ 51 syslog(0, logfile, "server: input error: %s from %I", err, buf); 52 continue; 53 } 54 if(reqmsg.qdcount < 1){ 55 syslog(0, logfile, "server: no questions from %I", buf); 56 } else if(reqmsg.flags & Fresp){ 57 syslog(0, logfile, "server: reply not request from %I", buf); 58 } else if(reqmsg.qd->owner->class != Cin){ 59 syslog(0, logfile, "server: class %d from %I", reqmsg.qd->owner->class, 60 buf); 61 memset(&repmsg, 0, sizeof(repmsg)); 62 repmsg.id = reqmsg.id; 63 repmsg.flags = Runimplimented | Fresp | Fcanrec | Oquery; 64 repmsg.qd = reqmsg.qd; 65 reply(fd, buf, &repmsg); 66 } else if((reqmsg.flags & Omask) != Oquery){ 67 syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf); 68 } else { 69 /* loop through each question */ 70 while(reqmsg.qd){ 71 if(debug) 72 syslog(0, logfile, "serve %s %s", 73 reqmsg.qd->owner->name, 74 rrname(reqmsg.qd->type, tname)); 75 memset(&repmsg, 0, sizeof(repmsg)); 76 repmsg.id = reqmsg.id; 77 repmsg.flags = Fresp | Fcanrec | Oquery; 78 repmsg.qd = reqmsg.qd; 79 reqmsg.qd = reqmsg.qd->next; 80 repmsg.qd->next = 0; 81 82 /* 83 * get the answer if we can 84 */ 85 if(reqmsg.flags & Frecurse) 86 recurse(&repmsg, &req); 87 else 88 local(&repmsg); 89 90 /* 91 * add ip addresses as hints 92 */ 93 for(tp = repmsg.ns; tp; tp = tp->next) 94 hint(&repmsg.ar, tp); 95 for(tp = repmsg.an; tp; tp = tp->next) 96 hint(&repmsg.ar, tp); 97 98 reply(fd, buf, &repmsg); 99 100 rrfreelist(repmsg.qd); 101 rrfreelist(repmsg.an); 102 rrfreelist(repmsg.ns); 103 rrfreelist(repmsg.ar); 104 } 105 } 106 rrfreelist(reqmsg.qd); 107 rrfreelist(reqmsg.an); 108 rrfreelist(reqmsg.ns); 109 rrfreelist(reqmsg.ar); 110 111 if(req.isslave) 112 _exits(0); 113 } 114 } 115 116 /* 117 * satisfy a recursive request. dnlookup will handle cnames. 118 */ 119 static void 120 recurse(DNSmsg *mp, Request *req) 121 { 122 int type; 123 char *name; 124 RR *cname; 125 126 name = mp->qd->owner->name; 127 type = mp->qd->type; 128 cname = 0; 129 rrcat(&mp->an, dnresolve(name, Cin, type, req, &cname), type); 130 if(cname) 131 rrcat(&mp->an, cname, Tcname); 132 if(mp->an && mp->an->auth) 133 mp->flags |= Fauth; 134 } 135 136 137 /* 138 * satisfy a request with local info only 139 */ 140 static void 141 local(DNSmsg *mp) 142 { 143 DN *dp, *nsdp; 144 RR *nsrp; 145 char *cp; 146 int type; 147 148 dp = mp->qd->owner; 149 type = mp->qd->type; 150 mp->flags |= Fauth; 151 152 /* in-addr.arpa queries are special */ 153 if(type == Tptr){ 154 rrcat(&mp->an, dbinaddr(dp), type); 155 if(mp->an) 156 return; 157 } 158 159 /* 160 * Quick grab, see if it's a 'relative to my domain' request. 161 * I'm not sure this is a good idea but our x-terminals want it. 162 */ 163 if(strchr(dp->name, '.') == 0){ 164 nsrp = dblookup(dp->name, dp->class, type, 1); 165 if(nsrp){ 166 rrcat(&mp->an, nsrp, type); 167 return; 168 } 169 } 170 171 /* 172 * walk up the domain name looking for 173 * a name server for the domain. 174 */ 175 for(cp = dp->name; /* mp->an==0 && */ cp; cp = walkup(cp)){ 176 /* look for ns in cache and database */ 177 nsdp = dnlookup(cp, dp->class, 0); 178 nsrp = 0; 179 if(nsdp) 180 nsrp = rrlookup(nsdp, Tns); 181 if(nsrp == 0) 182 nsrp = dblookup(cp, dp->class, Tns, 0); 183 if(nsrp == 0) 184 continue; 185 186 if(nsrp->local){ 187 /* local domains resolved from this db */ 188 if(nsrp->db) /* free database rr's */ 189 rrfreelist(nsrp); 190 rrcat(&mp->an, dblookup(dp->name, Cin, type, 1), type); 191 } else { 192 /* just return the name of a name server to use */ 193 rrcat(&mp->ns, nsrp, Tns); 194 } 195 196 break; 197 } 198 } 199 200 static void 201 reply(int fd, uchar *buf, DNSmsg *rep) 202 { 203 int len; 204 char tname[32]; 205 206 if(debug) 207 syslog(0, logfile, "reply (%I/%d) %s %s an %R ns %R ar %R", 208 buf, ((buf[4])<<8)+buf[5], rep->qd->owner->name, 209 rrname(rep->qd->type, tname), rep->an, rep->ns, rep->ar); 210 211 len = convDNS2M(rep, &buf[Udphdrsize], Maxudp); 212 if(len <= 0) 213 fatal("dnserver: converting reply"); 214 len += Udphdrsize; 215 if(write(fd, buf, len) != len) 216 fatal("dnserver: sending reply"); 217 } 218 219 static void 220 hint(RR **last, RR *rp) 221 { 222 switch(rp->type){ 223 case Tns: 224 case Tmx: 225 case Tmb: 226 case Tmf: 227 case Tmd: 228 rrcat(last, dblookup(rp->host->name, Cin, Ta, 0), Ta); 229 break; 230 } 231 } 232 233 /* 234 * get ip addresses without looking off machine 235 */ 236 static RR* 237 getipaddr(DN *dp) 238 { 239 RR *rp; 240 241 /* first try the cache */ 242 rp = rrlookup(dp, Ta); 243 if(rp) 244 return rp; 245 246 /* then try on disk db */ 247 return dblookup(dp->name, dp->class, Ta, 0); 248 } 249 250 /* 251 * announce on udp port and set message style interface 252 */ 253 static char *hmsg = "headers"; 254 255 int 256 udpannounce(void) 257 { 258 int data, ctl; 259 char dir[64]; 260 char datafile[64+6]; 261 262 /* get a udp port */ 263 ctl = announce("udp!*!dns", dir); 264 if(ctl < 0){ 265 warning("can't announce on udp port"); 266 return -1; 267 } 268 snprint(datafile, sizeof(datafile), "%s/data", dir); 269 270 /* turn on header style interface */ 271 if(write(ctl, hmsg, strlen(hmsg)) , 0) 272 fatal(hmsg); 273 data = open(datafile, ORDWR); 274 if(data < 0){ 275 close(ctl); 276 warning("can't announce on udp port"); 277 return -1; 278 } 279 280 close(ctl); 281 return data; 282 } 283