1 /* 2 * dnstcp - serve dns via tcp 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <ip.h> 7 #include "dns.h" 8 9 Cfg cfg; 10 11 char *caller = ""; 12 char *dbfile; 13 int debug; 14 uchar ipaddr[IPaddrlen]; /* my ip address */ 15 char *logfile = "dns"; 16 int maxage = 60*60; 17 char mntpt[Maxpath]; 18 int needrefresh; 19 ulong now; 20 vlong nowns; 21 int testing; 22 int traceactivity; 23 char *zonerefreshprogram; 24 25 static int readmsg(int, uchar*, int); 26 static void reply(int, DNSmsg*, Request*); 27 static void dnzone(DNSmsg*, DNSmsg*, Request*); 28 static void getcaller(char*); 29 static void refreshmain(char*); 30 31 void 32 usage(void) 33 { 34 fprint(2, "usage: %s [-rR] [-f ndb-file] [-x netmtpt] [conndir]\n", argv0); 35 exits("usage"); 36 } 37 38 void 39 main(int argc, char *argv[]) 40 { 41 volatile int len, rcode; 42 volatile char tname[32]; 43 char *volatile err, *volatile ext = ""; 44 volatile uchar buf[64*1024], callip[IPaddrlen]; 45 volatile DNSmsg reqmsg, repmsg; 46 volatile Request req; 47 48 alarm(2*60*1000); 49 cfg.cachedb = 1; 50 ARGBEGIN{ 51 case 'd': 52 debug++; 53 break; 54 case 'f': 55 dbfile = EARGF(usage()); 56 break; 57 case 'r': 58 cfg.resolver = 1; 59 break; 60 case 'R': 61 norecursion = 1; 62 break; 63 case 'x': 64 ext = EARGF(usage()); 65 break; 66 default: 67 usage(); 68 break; 69 }ARGEND 70 71 if(debug < 2) 72 debug = 0; 73 74 if(argc > 0) 75 getcaller(argv[0]); 76 77 cfg.inside = 1; 78 dninit(); 79 80 snprint(mntpt, sizeof mntpt, "/net%s", ext); 81 if(myipaddr(ipaddr, mntpt) < 0) 82 sysfatal("can't read my ip address"); 83 dnslog("dnstcp call from %s to %I", caller, ipaddr); 84 memset(callip, 0, sizeof callip); 85 parseip(callip, caller); 86 87 db2cache(1); 88 89 memset(&req, 0, sizeof req); 90 setjmp(req.mret); 91 req.isslave = 0; 92 procsetname("main loop"); 93 94 /* loop on requests */ 95 for(;; putactivity(0)){ 96 now = time(nil); 97 memset(&repmsg, 0, sizeof repmsg); 98 len = readmsg(0, buf, sizeof buf); 99 if(len <= 0) 100 break; 101 102 getactivity(&req, 0); 103 req.aborttime = timems() + S2MS(15*Min); 104 rcode = 0; 105 memset(&reqmsg, 0, sizeof reqmsg); 106 err = convM2DNS(buf, len, &reqmsg, &rcode); 107 if(err){ 108 dnslog("server: input error: %s from %s", err, caller); 109 free(err); 110 break; 111 } 112 if (rcode == 0) 113 if(reqmsg.qdcount < 1){ 114 dnslog("server: no questions from %s", caller); 115 break; 116 } else if(reqmsg.flags & Fresp){ 117 dnslog("server: reply not request from %s", 118 caller); 119 break; 120 } else if((reqmsg.flags & Omask) != Oquery){ 121 dnslog("server: op %d from %s", 122 reqmsg.flags & Omask, caller); 123 break; 124 } 125 if(debug) 126 dnslog("[%d] %d: serve (%s) %d %s %s", 127 getpid(), req.id, caller, 128 reqmsg.id, reqmsg.qd->owner->name, 129 rrname(reqmsg.qd->type, tname, sizeof tname)); 130 131 /* loop through each question */ 132 while(reqmsg.qd) 133 if(reqmsg.qd->type == Taxfr) 134 dnzone(&reqmsg, &repmsg, &req); 135 else { 136 dnserver(&reqmsg, &repmsg, &req, callip, rcode); 137 reply(1, &repmsg, &req); 138 rrfreelist(repmsg.qd); 139 rrfreelist(repmsg.an); 140 rrfreelist(repmsg.ns); 141 rrfreelist(repmsg.ar); 142 } 143 rrfreelist(reqmsg.qd); /* qd will be nil */ 144 rrfreelist(reqmsg.an); 145 rrfreelist(reqmsg.ns); 146 rrfreelist(reqmsg.ar); 147 148 if(req.isslave){ 149 putactivity(0); 150 _exits(0); 151 } 152 } 153 refreshmain(mntpt); 154 } 155 156 static int 157 readmsg(int fd, uchar *buf, int max) 158 { 159 int n; 160 uchar x[2]; 161 162 if(readn(fd, x, 2) != 2) 163 return -1; 164 n = x[0]<<8 | x[1]; 165 if(n > max) 166 return -1; 167 if(readn(fd, buf, n) != n) 168 return -1; 169 return n; 170 } 171 172 static void 173 reply(int fd, DNSmsg *rep, Request *req) 174 { 175 int len, rv; 176 char tname[32]; 177 uchar buf[64*1024]; 178 RR *rp; 179 180 if(debug){ 181 dnslog("%d: reply (%s) %s %s %ux", 182 req->id, caller, 183 rep->qd->owner->name, 184 rrname(rep->qd->type, tname, sizeof tname), 185 rep->flags); 186 for(rp = rep->an; rp; rp = rp->next) 187 dnslog("an %R", rp); 188 for(rp = rep->ns; rp; rp = rp->next) 189 dnslog("ns %R", rp); 190 for(rp = rep->ar; rp; rp = rp->next) 191 dnslog("ar %R", rp); 192 } 193 194 195 len = convDNS2M(rep, buf+2, sizeof(buf) - 2); 196 buf[0] = len>>8; 197 buf[1] = len; 198 rv = write(fd, buf, len+2); 199 if(rv != len+2){ 200 dnslog("[%d] sending reply: %d instead of %d", getpid(), rv, 201 len+2); 202 exits(0); 203 } 204 } 205 206 /* 207 * Hash table for domain names. The hash is based only on the 208 * first element of the domain name. 209 */ 210 extern DN *ht[HTLEN]; 211 212 static int 213 numelem(char *name) 214 { 215 int i; 216 217 i = 1; 218 for(; *name; name++) 219 if(*name == '.') 220 i++; 221 return i; 222 } 223 224 int 225 inzone(DN *dp, char *name, int namelen, int depth) 226 { 227 int n; 228 229 if(dp->name == nil) 230 return 0; 231 if(numelem(dp->name) != depth) 232 return 0; 233 n = strlen(dp->name); 234 if(n < namelen) 235 return 0; 236 if(strcmp(name, dp->name + n - namelen) != 0) 237 return 0; 238 if(n > namelen && dp->name[n - namelen - 1] != '.') 239 return 0; 240 return 1; 241 } 242 243 static void 244 dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req) 245 { 246 DN *dp, *ndp; 247 RR r, *rp; 248 int h, depth, found, nlen; 249 250 memset(repp, 0, sizeof(*repp)); 251 repp->id = reqp->id; 252 repp->qd = reqp->qd; 253 reqp->qd = reqp->qd->next; 254 repp->qd->next = 0; 255 repp->flags = Fauth | Fresp | Oquery; 256 if(!norecursion) 257 repp->flags |= Fcanrec; 258 dp = repp->qd->owner; 259 260 /* send the soa */ 261 repp->an = rrlookup(dp, Tsoa, NOneg); 262 reply(1, repp, req); 263 if(repp->an == 0) 264 goto out; 265 rrfreelist(repp->an); 266 repp->an = nil; 267 268 nlen = strlen(dp->name); 269 270 /* construct a breadth-first search of the name space (hard with a hash) */ 271 repp->an = &r; 272 for(depth = numelem(dp->name); ; depth++){ 273 found = 0; 274 for(h = 0; h < HTLEN; h++) 275 for(ndp = ht[h]; ndp; ndp = ndp->next) 276 if(inzone(ndp, dp->name, nlen, depth)){ 277 for(rp = ndp->rr; rp; rp = rp->next){ 278 /* 279 * there shouldn't be negatives, 280 * but just in case. 281 * don't send any soa's, 282 * ns's are enough. 283 */ 284 if (rp->negative || 285 rp->type == Tsoa) 286 continue; 287 r = *rp; 288 r.next = 0; 289 reply(1, repp, req); 290 } 291 found = 1; 292 } 293 if(!found) 294 break; 295 } 296 297 /* resend the soa */ 298 repp->an = rrlookup(dp, Tsoa, NOneg); 299 reply(1, repp, req); 300 rrfreelist(repp->an); 301 repp->an = nil; 302 out: 303 rrfree(repp->qd); 304 repp->qd = nil; 305 } 306 307 static void 308 getcaller(char *dir) 309 { 310 int fd, n; 311 static char remote[128]; 312 313 snprint(remote, sizeof(remote), "%s/remote", dir); 314 fd = open(remote, OREAD); 315 if(fd < 0) 316 return; 317 n = read(fd, remote, sizeof remote - 1); 318 close(fd); 319 if(n <= 0) 320 return; 321 if(remote[n-1] == '\n') 322 n--; 323 remote[n] = 0; 324 caller = remote; 325 } 326 327 static void 328 refreshmain(char *net) 329 { 330 int fd; 331 char file[128]; 332 333 snprint(file, sizeof(file), "%s/dns", net); 334 if(debug) 335 dnslog("refreshing %s", file); 336 fd = open(file, ORDWR); 337 if(fd < 0) 338 dnslog("can't refresh %s", file); 339 else { 340 fprint(fd, "refresh"); 341 close(fd); 342 } 343 } 344 345 /* 346 * the following varies between dnsdebug and dns 347 */ 348 void 349 logreply(int id, uchar *addr, DNSmsg *mp) 350 { 351 RR *rp; 352 353 dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr, 354 mp->flags & Fauth? " auth": "", 355 mp->flags & Ftrunc? " trunc": "", 356 mp->flags & Frecurse? " rd": "", 357 mp->flags & Fcanrec? " ra": "", 358 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": ""); 359 for(rp = mp->qd; rp != nil; rp = rp->next) 360 dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name); 361 for(rp = mp->an; rp != nil; rp = rp->next) 362 dnslog("%d: rcvd %I an %R", id, addr, rp); 363 for(rp = mp->ns; rp != nil; rp = rp->next) 364 dnslog("%d: rcvd %I ns %R", id, addr, rp); 365 for(rp = mp->ar; rp != nil; rp = rp->next) 366 dnslog("%d: rcvd %I ar %R", id, addr, rp); 367 } 368 369 void 370 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) 371 { 372 char buf[12]; 373 374 dnslog("%d.%d: sending to %I/%s %s %s", 375 id, subid, addr, sname, rname, rrname(type, buf, sizeof buf)); 376 } 377 378 RR* 379 getdnsservers(int class) 380 { 381 return dnsservers(class); 382 } 383