Provoked by grumbles from http://www.dnsreport.com, implementation proved by Geoff, but this code is down to me. -Steve Notes: Wed Mar 29 17:11:05 EST 2006 rsc You're about two days too late. Dave just implemented this and we just started running almost identical code on our outside interfaces. It will appear today or tomorrow. Amazing timing. Reference: /n/sources/patch/sorry/dns-no-recurse Date: Wed Mar 29 23:51:03 CES 2006 Signed-off-by: steve@quintile.net Reviewed-by: rsc --- /sys/src/cmd/ndb/dnstcp.c Wed Mar 29 23:43:40 2006 +++ /sys/src/cmd/ndb/dnstcp.c Wed Mar 29 23:43:37 2006 @@ -12,6 +12,7 @@ char *dbfile; int debug; int cachedb = 1; +int public; /* do not offer or implement recursive lookups over IP */ int testing; int traceactivity; int needrefresh; @@ -31,6 +32,13 @@ static void refreshmain(char*); void +usage(void) +{ + fprint(2, "usage: %s [-rp] [-f ndb-file] [-x netmtpt]\n", argv0); + exits("usage"); +} + +void main(int argc, char *argv[]) { int len; @@ -41,7 +49,11 @@ char *err; char *ext = ""; + public = 0; ARGBEGIN{ + case 'p': + public = 1; + break; case 'd': debug++; break; @@ -54,6 +66,9 @@ case 'x': ext = ARGF(); break; + default: + usage(); + break; }ARGEND if(debug < 2) @@ -234,10 +249,12 @@ memset(repp, 0, sizeof(*repp)); repp->id = reqp->id; - repp->flags = Fauth | Fresp | Fcanrec | Oquery; repp->qd = reqp->qd; reqp->qd = reqp->qd->next; repp->qd->next = 0; + repp->flags = Fauth | Fresp | Oquery; + if(!public) + repp->flags |= Fcanrec; dp = repp->qd->owner; /* send the soa */ --- /sys/src/cmd/ndb/dns.c Wed Mar 29 23:43:54 2006 +++ /sys/src/cmd/ndb/dns.c Wed Mar 29 23:43:50 2006 @@ -67,6 +67,7 @@ ulong now; int testing; char *trace; +int public; /* do not offer or implement recursive lookups over IP */ int needrefresh; int resolver; uchar ipaddr[IPaddrlen]; /* my ip address */ @@ -103,7 +104,7 @@ void usage(void) { - fprint(2, "usage: %s [-rs] [-f ndb-file] [-x netmtpt]\n", argv0); + fprint(2, "usage: %s [-rsp] [-f ndb-file] [-x netmtpt]\n", argv0); exits("usage"); } @@ -115,10 +116,14 @@ char ext[Maxpath]; char *p; + public = 0; serve = 0; setnetmtpt(mntpt, sizeof(mntpt), nil); ext[0] = 0; ARGBEGIN{ + case 'p': + public = 1; + break; case 'd': debug = 1; traceactivity = 1; --- /sys/src/cmd/ndb/dnsdebug.c Wed Mar 29 23:44:09 2006 +++ /sys/src/cmd/ndb/dnsdebug.c Wed Mar 29 23:44:06 2006 @@ -22,6 +22,7 @@ int debug; int cachedb; ulong now; +int public; /* do not offer or implement recursive lookups over IP */ int testing; int traceactivity; char *trace; @@ -49,9 +50,13 @@ char *p; char *f[4]; + public = 0; strcpy(mntpt, "/net"); ARGBEGIN{ + case 'p': + public = 1; + break; case 'r': resolver = 1; break; --- /sys/src/cmd/ndb/dnserver.c Wed Mar 29 23:44:25 2006 +++ /sys/src/cmd/ndb/dnserver.c Wed Mar 29 23:44:23 2006 @@ -24,7 +24,9 @@ memset(repp, 0, sizeof(*repp)); repp->id = reqp->id; - repp->flags = Fresp | Fcanrec | Oquery; + repp->flags = Fresp | Oquery; + if(!public) + repp->flags |= Fcanrec; /* move one question from reqp to repp */ tp = reqp->qd; @@ -32,29 +34,42 @@ tp->next = 0; repp->qd = tp; + if((reqp->flags & Frecurse) != 0 && !public){ + syslog(0, logfile, "server: recursive lookup refused"); + repp->flags = Rrefused | Fresp | Oquery; + return; + } + if(!rrsupported(repp->qd->type)){ syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname)); - repp->flags = Runimplimented | Fresp | Fcanrec | Oquery; + repp->flags = Runimplimented | Fresp | Oquery; + if(!public) + repp->flags |= Fcanrec; + return; } if(repp->qd->owner->class != Cin){ syslog(0, logfile, "server: class %d", repp->qd->owner->class); - repp->flags = Runimplimented | Fresp | Fcanrec | Oquery; + repp->flags = Runimplimented | Fresp | Oquery; + if(!public) + repp->flags |= Fcanrec; return; } myarea = inmyarea(repp->qd->owner->name); if(myarea != nil && (repp->qd->type == Tixfr || repp->qd->type == Taxfr)){ syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname)); - repp->flags = Runimplimented | Fresp | Fcanrec | Oquery; + repp->flags = Runimplimented | Fresp | Oquery; + if(!public) + repp->flags |= Fcanrec; return; } /* * get the answer if we can */ - if(reqp->flags & Frecurse) + if((reqp->flags & Frecurse) && !public) neg = doextquery(repp, req, Recurse); else neg = doextquery(repp, req, Dontrecurse); @@ -67,7 +82,7 @@ if(repp->an == 0){ dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0); if(dp->rr == 0) - if(reqp->flags & Frecurse) + if((reqp->flags & Frecurse) && !public) repp->flags |= dp->nonexistent|Fauth; } --- /sys/man/8/ndb Wed Mar 29 23:44:45 2006 +++ /sys/man/8/ndb Wed Mar 29 23:44:42 2006 @@ -43,7 +43,7 @@ .br .B ndb/dns [ -.B -rsn +.B -pnrs ] [ .B -f .I dbfile @@ -59,9 +59,11 @@ .br .B ndb/dnsdebug [ -.B -rx -] -[ [ +.B -pr +] [ +.B -x +.I netmtpt +] [ .BI @ server ] .I domain-name @@ -69,6 +71,17 @@ .I type ] ] .br +.B ndb/dnstcp +[ +.B -pr +] [ +.B -f +.I dbfile +] [ +.B -x +.I netmtpt +] +.br .B ndb/mkdb .SH DESCRIPTION The network database holds administrative information used by @@ -188,17 +201,22 @@ default .BR /lib/ndb/local . .TP -.B -x -specifies the mount point of the -network. -.TP -.B -s -also answer domain requests sent to UDP port 53. +.B -p +deny recursive lookups via UDP, use on public access +interfaces to prevent dns poisoning and distributed denial +of service attacks. .TP .B -n whenever a zone that we serve changes, send UDP NOTIFY messages to any dns slaves for that zone. .TP +.B -s +also answer domain requests sent to UDP port 53. +.TP +.B -x +specifies the mount point of the +network. +.TP .B -z whenever we receive a UDP NOTIFY message, run .I program @@ -428,6 +446,12 @@ The .B -r option is the same as for +.IR ndb/dns . +.PP +.I Ndb/dnstcp +serves the same protocol for TCP connections, usually +started by /rc/bin/service/tcp53. +It takes a subset of the options of .IR ndb/dns . .PP .I Ndb/mkdb