/* notify a slave that an area has changed. */ static void send_notify(char *slave, RR *soa, Request *req) { int i, len, n, reqno, status, fd; char *err; uchar ibuf[Maxudp+Udphdrsize], obuf[Maxudp+Udphdrsize]; RR *rp; Udphdr *up = (Udphdr*)obuf; DNSmsg repmsg; /* create the request */ reqno = rand(); n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno); /* get an address */ if(strcmp(ipattr(slave), "ip") == 0) { if (parseip(up->raddr, slave) == -1) dnslog("bad address %s to notify", slave); } else { rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status); if(rp == nil) rp = dnresolve(slave, Cin, Taaaa, req, nil, 0, 1, 1, &status); if(rp == nil) return; parseip(up->raddr, rp->ip->name); rrfreelist(rp); /* was rrfree */ } fd = udpport(nil); if(fd < 0) return; /* send 3 times or until we get anything back */ n += Udphdrsize; for(i = 0; i < 3; i++, freeanswers(&repmsg)){ dnslog("sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name); memset(&repmsg, 0, sizeof repmsg); if(write(fd, obuf, n) != n) break; alarm(2*1000); len = read(fd, ibuf, sizeof ibuf); alarm(0); if(len <= Udphdrsize) continue; err = convM2DNS(&ibuf[Udphdrsize], len, &repmsg, nil); if(err != nil) { free(err); continue; } if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify) break; } if (i < 3) freeanswers(&repmsg); close(fd); }
static int p_seprint(Msg *m) { char *e; if((e = convM2DNS(m->ps, m->pe-m->ps, &dm, nil)) != nil){ m->p = seprint(m->p, m->e, "error: %s", e); return 0; } m->p = seprint(m->p, m->e, "id=%d flags=%#ux", dm.id, dm.flags); donext(m); return 0; }
void main(int argc, char *argv[]) { int len, rcode; char tname[32]; char *err, *ext = ""; unsigned char buf[64*1024], callip[IPaddrlen]; DNSmsg reqmsg, repmsg; Request req; alarm(2*60*1000); cfg.cachedb = 1; ARGBEGIN{ case 'd': debug++; break; case 'f': dbfile = EARGF(usage()); break; case 'r': cfg.resolver = 1; break; case 'R': norecursion = 1; break; case 'x': ext = EARGF(usage()); break; default: usage(); break; }ARGEND if(debug < 2) debug = 0; if(argc > 0) getcaller(argv[0]); cfg.inside = 1; dninit(); snprint(mntpt, sizeof mntpt, "/net%s", ext); if(myipaddr(ipaddr, mntpt) < 0) sysfatal("can't read my ip address"); dnslog("dnstcp call from %s to %I", caller, ipaddr); memset(callip, 0, sizeof callip); parseip(callip, caller); db2cache(1); memset(&req, 0, sizeof req); setjmp(req.mret); req.isslave = 0; procsetname("main loop"); /* loop on requests */ for(;; putactivity(0)){ now = time(nil); memset(&repmsg, 0, sizeof repmsg); len = readmsg(0, buf, sizeof buf); if(len <= 0) break; getactivity(&req, 0); req.aborttime = timems() + S2MS(15*Min); rcode = 0; memset(&reqmsg, 0, sizeof reqmsg); err = convM2DNS(buf, len, &reqmsg, &rcode); if(err){ dnslog("server: input error: %s from %s", err, caller); free(err); break; } if (rcode == 0) { if(reqmsg.qdcount < 1){ dnslog("server: no questions from %s", caller); break; } else if(reqmsg.flags & Fresp){ dnslog("server: reply not request from %s", caller); break; } else if((reqmsg.flags & Omask) != Oquery){ dnslog("server: op %d from %s", reqmsg.flags & Omask, caller); break; } } if(debug) dnslog("[%d] %d: serve (%s) %d %s %s", getpid(), req.id, caller, reqmsg.id, reqmsg.qd->owner->name, rrname(reqmsg.qd->type, tname, sizeof tname)); /* loop through each question */ while(reqmsg.qd) if(reqmsg.qd->type == Taxfr) dnzone(&reqmsg, &repmsg, &req); else { dnserver(&reqmsg, &repmsg, &req, callip, rcode); reply(1, &repmsg, &req); rrfreelist(repmsg.qd); rrfreelist(repmsg.an); rrfreelist(repmsg.ns); rrfreelist(repmsg.ar); } rrfreelist(reqmsg.qd); /* qd will be nil */ rrfreelist(reqmsg.an); rrfreelist(reqmsg.ns); rrfreelist(reqmsg.ar); if(req.isslave){ putactivity(0); _exits(0); } } refreshmain(mntpt); }
/* * a process to act as a dns server for outside reqeusts */ void dnudpserver(char *mntpt) { volatile int fd, len, op, rcode; char *volatile err; volatile char tname[32]; volatile uchar buf[Udphdrsize + Maxudp + 1024]; volatile DNSmsg reqmsg, repmsg; Inprogress *volatile p; volatile Request req; Udphdr *volatile uh; /* * fork sharing text, data, and bss with parent. * stay in the same note group. */ switch(rfork(RFPROC|RFMEM|RFNOWAIT)){ case -1: break; case 0: break; default: return; } fd = -1; restart: procsetname("udp server announcing"); if(fd >= 0) close(fd); while((fd = udpannounce(mntpt)) < 0) sleep(5000); // procsetname("udp server"); memset(&req, 0, sizeof req); if(setjmp(req.mret)) putactivity(0); req.isslave = 0; req.id = 0; req.aborttime = 0; /* loop on requests */ for(;; putactivity(0)){ procsetname("served %d udp; %d alarms", stats.qrecvdudp, stats.alarms); memset(&repmsg, 0, sizeof repmsg); memset(&reqmsg, 0, sizeof reqmsg); alarm(60*1000); len = read(fd, buf, sizeof buf); alarm(0); if(len <= Udphdrsize) goto restart; redistrib(buf, len); uh = (Udphdr*)buf; len -= Udphdrsize; // dnslog("read received UDP from %I to %I", // ((Udphdr*)buf)->raddr, ((Udphdr*)buf)->laddr); getactivity(&req, 0); req.aborttime = timems() + Maxreqtm; // req.from = smprint("%I", ((Udphdr*)buf)->raddr); req.from = smprint("%I", buf); rcode = 0; stats.qrecvdudp++; err = convM2DNS(&buf[Udphdrsize], len, &reqmsg, &rcode); if(err){ /* first bytes in buf are source IP addr */ dnslog("server: input error: %s from %I", err, buf); free(err); goto freereq; } if (rcode == 0) if(reqmsg.qdcount < 1){ dnslog("server: no questions from %I", buf); goto freereq; } else if(reqmsg.flags & Fresp){ dnslog("server: reply not request from %I", buf); goto freereq; } op = reqmsg.flags & Omask; if(op != Oquery && op != Onotify){ dnslog("server: op %d from %I", reqmsg.flags & Omask, buf); goto freereq; } if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))) dnslog("%d: serve (%I/%d) %d %s %s", req.id, buf, uh->rport[0]<<8 | uh->rport[1], reqmsg.id, reqmsg.qd->owner->name, rrname(reqmsg.qd->type, tname, sizeof tname)); p = clientrxmit(&reqmsg, buf); if(p == nil){ if(debug) dnslog("%d: duplicate", req.id); goto freereq; } if (Logqueries) { RR *rr; for (rr = reqmsg.qd; rr; rr = rr->next) syslog(0, "dnsq", "id %d: (%I/%d) %d %s %s", req.id, buf, uh->rport[0]<<8 | uh->rport[1], reqmsg.id, reqmsg.qd->owner->name, rrname(reqmsg.qd->type, tname, sizeof tname)); } /* loop through each question */ while(reqmsg.qd){ memset(&repmsg, 0, sizeof repmsg); switch(op){ case Oquery: dnserver(&reqmsg, &repmsg, &req, buf, rcode); break; case Onotify: dnnotify(&reqmsg, &repmsg, &req); break; } /* send reply on fd to address in buf's udp hdr */ reply(fd, buf, &repmsg, &req); freeanswers(&repmsg); } p->inuse = 0; freereq: free(req.from); req.from = nil; freeanswers(&reqmsg); if(req.isslave){ putactivity(0); _exits(0); } } }