dntcpserver.c (5554B)
1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include <bio.h> 5 #include <ndb.h> 6 #include <thread.h> 7 #include "dns.h" 8 9 static char adir[40]; 10 11 static int 12 readmsg(int fd, uchar *buf, int max) 13 { 14 int n; 15 uchar x[2]; 16 17 if(readn(fd, x, 2) != 2) 18 return -1; 19 n = (x[0]<<8) | x[1]; 20 if(n > max) 21 return -1; 22 if(readn(fd, buf, n) != n) 23 return -1; 24 return n; 25 } 26 27 static int 28 connreadmsg(int tfd, int *fd, uchar *buf, int max) 29 { 30 int n; 31 int lfd; 32 char ldir[40]; 33 34 lfd = listen(adir, ldir); 35 if (lfd < 0) 36 return -1; 37 *fd = accept(lfd, ldir); 38 if (*fd >= 0) 39 n = readmsg(*fd, buf, max); 40 else 41 n = -1; 42 close(lfd); 43 return n; 44 } 45 46 static int 47 reply(int fd, DNSmsg *rep, Request *req, NetConnInfo *caller) 48 { 49 int len; 50 char tname[32]; 51 uchar buf[4096]; 52 RR *rp; 53 54 if(debug){ 55 syslog(0, logfile, "%d: reply (%s) %s %s %ux", 56 req->id, caller ? caller->raddr : "unk", 57 rep->qd->owner->name, 58 rrname(rep->qd->type, tname, sizeof tname), 59 rep->flags); 60 for(rp = rep->an; rp; rp = rp->next) 61 syslog(0, logfile, "an %R", rp); 62 for(rp = rep->ns; rp; rp = rp->next) 63 syslog(0, logfile, "ns %R", rp); 64 for(rp = rep->ar; rp; rp = rp->next) 65 syslog(0, logfile, "ar %R", rp); 66 } 67 68 69 len = convDNS2M(rep, buf+2, sizeof(buf) - 2); 70 if(len <= 0) 71 abort(); /* "dnserver: converting reply" */; 72 buf[0] = len>>8; 73 buf[1] = len; 74 if(write(fd, buf, len+2) < 0){ 75 syslog(0, logfile, "sending reply: %r"); 76 return -1; 77 } 78 return 0; 79 } 80 81 /* 82 * Hash table for domain names. The hash is based only on the 83 * first element of the domain name. 84 */ 85 extern DN *ht[HTLEN]; 86 87 static int 88 numelem(char *name) 89 { 90 int i; 91 92 i = 1; 93 for(; *name; name++) 94 if(*name == '.') 95 i++; 96 return i; 97 } 98 99 static int 100 inzone(DN *dp, char *name, int namelen, int depth) 101 { 102 int n; 103 104 if(dp->name == 0) 105 return 0; 106 if(numelem(dp->name) != depth) 107 return 0; 108 n = strlen(dp->name); 109 if(n < namelen) 110 return 0; 111 if(strcmp(name, dp->name + n - namelen) != 0) 112 return 0; 113 if(n > namelen && dp->name[n - namelen - 1] != '.') 114 return 0; 115 return 1; 116 } 117 118 static int 119 dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req, int rfd, NetConnInfo *caller) 120 { 121 DN *dp, *ndp; 122 RR r, *rp; 123 int h, depth, found, nlen, rv; 124 125 rv = 0; 126 memset(repp, 0, sizeof(*repp)); 127 repp->id = reqp->id; 128 repp->flags = Fauth | Fresp | Fcanrec | Oquery; 129 repp->qd = reqp->qd; 130 reqp->qd = reqp->qd->next; 131 repp->qd->next = 0; 132 dp = repp->qd->owner; 133 134 /* send the soa */ 135 repp->an = rrlookup(dp, Tsoa, NOneg); 136 rv = reply(rfd, repp, req, caller); 137 if(repp->an == 0 || rv < 0) 138 goto out; 139 rrfreelist(repp->an); 140 141 nlen = strlen(dp->name); 142 143 /* construct a breadth first search of the name space (hard with a hash) */ 144 repp->an = &r; 145 for(depth = numelem(dp->name); ; depth++){ 146 found = 0; 147 for(h = 0; h < HTLEN; h++) 148 for(ndp = ht[h]; ndp; ndp = ndp->next) 149 if(inzone(ndp, dp->name, nlen, depth)){ 150 for(rp = ndp->rr; rp; rp = rp->next){ 151 /* there shouldn't be negatives, but just in case */ 152 if(rp->negative) 153 continue; 154 155 /* don't send an soa's, ns's are enough */ 156 if(rp->type == Tsoa) 157 continue; 158 159 r = *rp; 160 r.next = 0; 161 rv = reply(rfd, repp, req, caller); 162 if(rv < 0) 163 goto out; 164 } 165 found = 1; 166 } 167 if(!found) 168 break; 169 } 170 171 /* resend the soa */ 172 repp->an = rrlookup(dp, Tsoa, NOneg); 173 rv = reply(rfd, repp, req, caller); 174 out: 175 if (repp->an) 176 rrfreelist(repp->an); 177 rrfree(repp->qd); 178 return rv; 179 } 180 181 void 182 tcpproc(void *v) 183 { 184 int len, rv; 185 Request req; 186 DNSmsg reqmsg, repmsg; 187 char *err; 188 uchar buf[512]; 189 char tname[32]; 190 int fd, rfd; 191 NetConnInfo *caller; 192 193 rfd = -1; 194 fd = (uintptr)v; 195 caller = 0; 196 /* loop on requests */ 197 for(;; putactivity()){ 198 if (rfd == 1) 199 return; 200 close(rfd); 201 now = time(0); 202 memset(&repmsg, 0, sizeof(repmsg)); 203 if (fd == 0) { 204 len = readmsg(fd, buf, sizeof buf); 205 rfd = 1; 206 } else { 207 len = connreadmsg(fd, &rfd, buf, sizeof buf); 208 } 209 if(len <= 0) 210 continue; 211 freenetconninfo(caller); 212 caller = getnetconninfo(0, fd); 213 getactivity(&req); 214 req.aborttime = now + 15*Min; 215 err = convM2DNS(buf, len, &reqmsg); 216 if(err){ 217 syslog(0, logfile, "server: input error: %s from %I", err, buf); 218 continue; 219 } 220 if(reqmsg.qdcount < 1){ 221 syslog(0, logfile, "server: no questions from %I", buf); 222 continue; 223 } 224 if(reqmsg.flags & Fresp){ 225 syslog(0, logfile, "server: reply not request from %I", buf); 226 continue; 227 } 228 if((reqmsg.flags & Omask) != Oquery){ 229 syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf); 230 continue; 231 } 232 233 if(debug) 234 syslog(0, logfile, "%d: serve (%s) %d %s %s", 235 req.id, caller ? caller->raddr : 0, 236 reqmsg.id, 237 reqmsg.qd->owner->name, 238 rrname(reqmsg.qd->type, tname, sizeof tname)); 239 240 /* loop through each question */ 241 while(reqmsg.qd){ 242 if(reqmsg.qd->type == Taxfr){ 243 if(dnzone(&reqmsg, &repmsg, &req, rfd, caller) < 0) 244 break; 245 } else { 246 dnserver(&reqmsg, &repmsg, &req); 247 rv = reply(rfd, &repmsg, &req, caller); 248 rrfreelist(repmsg.qd); 249 rrfreelist(repmsg.an); 250 rrfreelist(repmsg.ns); 251 rrfreelist(repmsg.ar); 252 if(rv < 0) 253 break; 254 } 255 } 256 257 rrfreelist(reqmsg.qd); 258 rrfreelist(reqmsg.an); 259 rrfreelist(reqmsg.ns); 260 rrfreelist(reqmsg.ar); 261 } 262 } 263 264 enum { 265 Maxactivetcp = 4 266 }; 267 268 static int 269 tcpannounce(char *mntpt) 270 { 271 int fd; 272 273 USED(mntpt); 274 if((fd=announce(tcpaddr, adir)) < 0) 275 warning("announce %s: %r", tcpaddr); 276 return fd; 277 } 278 279 void 280 dntcpserver(void *v) 281 { 282 int i, fd; 283 284 while((fd = tcpannounce(v)) < 0) 285 sleep(5*1000); 286 287 for(i=0; i<Maxactivetcp; i++) 288 proccreate(tcpproc, (void*)(uintptr)fd, STACK); 289 }