code: plan9front

Download patch

ref: f67c4c85232b032f1825de30f4f943789257984e
parent: eb8fe8137b742646e9f3402149596eb8da62cc72
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Nov 1 17:57:08 EDT 2023

ndb/dns: add -L flag for local-recursive server

One might think that specifying the listen address
is enougth to prevent running a open resolver,
but this does not work for global IPv6 addresses.

The -L flag allows answering recursive queries
ONLY for IP addresses that are directly reachable
on a interface.

--- a/sys/man/8/ndb
+++ b/sys/man/8/ndb
@@ -57,7 +57,7 @@
 .br
 .B ndb/dns
 [
-.B -FnrR
+.B -FnrLR
 ] [
 .B -a
 .I maxage
@@ -400,9 +400,18 @@
 attributes name DNS servers to forward queries to.
 .TP
 .B -R
-ignore the `recursive' bit on incoming requests.
+ignore the `recursive' bit on all incoming requests.
 Do not complete lookups on behalf of remote systems.
 .TP
+.B -L
+ignore the `recursive' bit on incoming requests
+from non-local IP addresses.
+IP addresses are local when they are contained
+within the network prefix of an interface.
+This allows running as a authoritative server
+while also serving recursive queries for systems
+on local networks.
+.TP
 .B -s
 also answer domain requests sent to IP
 .I addrs
@@ -409,7 +418,8 @@
 on UDP/TCP port 53.
 If no IP
 .I addrs
-are given, listen on any interface on network mount point
+are given,
+listen on any interface on network mount point
 .IR netmtpt .
 .TP
 .B -x
--- a/sys/src/cmd/ndb/dblookup.c
+++ b/sys/src/cmd/ndb/dblookup.c
@@ -873,6 +873,23 @@
 	return 0;
 }
 
+int
+localip(uchar *ip)
+{
+	Ipifc *ifc;
+
+	qlock(&ipifclock);
+	for(ifc = ipifcs; ifc != nil; ifc = ifc->next){
+		if(ipremoteonifc(ifc, ip) != nil){
+			qunlock(&ipifclock);
+			return 1;
+		}
+	}
+	qunlock(&ipifclock);
+
+	return 0;
+}
+
 static void
 addlocaldnsserver(DN *dp, int class, char *addr, int i)
 {
--- a/sys/src/cmd/ndb/dns.c
+++ b/sys/src/cmd/ndb/dns.c
@@ -92,7 +92,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-FnrR] [-a maxage] [-f ndb-file] [-N target] "
+	fprint(2, "usage: %s [-FnrLR] [-a maxage] [-f ndb-file] [-N target] "
 		"[-x netmtpt] [-s [addrs...]]\n", argv0);
 	exits("usage");
 }
@@ -129,8 +129,13 @@
 	case 'r':
 		cfg.resolver = 1;
 		break;
+	case 'L':
+		cfg.localrecursive = 1;
+		cfg.nonrecursive = 0;
+		break;
 	case 'R':
 		cfg.nonrecursive = 1;
+		cfg.localrecursive = 0;
 		break;
 	case 's':
 		cfg.serve = 1;		/* serve network */
@@ -151,9 +156,10 @@
 	/* start syslog before we fork */
 	fmtinstall('F', fcallfmt);
 	dninit();
-	dnslog("starting %s%s%sdns %s%son %s",
+	dnslog("starting %s%s%s%sdns %s%son %s",
 		(cfg.cachedb? "caching ": ""),
 		(cfg.nonrecursive? "non-recursive ": ""),
+		(cfg.localrecursive? "local-recursive ": ""),
 		(cfg.serve?   "server ": ""),
 		(cfg.justforw? "forwarding-only ": ""),
 		(cfg.resolver? "resolver ": ""), mntpt);
--- a/sys/src/cmd/ndb/dns.h
+++ b/sys/src/cmd/ndb/dns.h
@@ -376,11 +376,12 @@
 
 typedef struct Cfg Cfg;
 struct Cfg {
-	int	cachedb;
-	int	resolver;
-	int	justforw;	/* flag: pure resolver, just forward queries */
-	int	serve;		/* flag: serve tcp udp queries */
-	int	nonrecursive;
+	char	cachedb;
+	char	resolver;
+	char	justforw;	/* flag: pure resolver, just forward queries */
+	char	serve;		/* flag: serve tcp udp queries */
+	char	nonrecursive;	/* flag: never serve recursive queries */
+	char	localrecursive;	/* flag: serve recursive queries for local ip's */
 };
 
 /* query stats */
@@ -496,7 +497,8 @@
 RR*	dblookup(char*, int, int, int, int);
 RR*	dnsservers(int);
 RR*	domainlist(int);
-int	myip(uchar *ip);
+int	myip(uchar *);
+int	localip(uchar *);
 int	opendatabase(void);
 
 /* dns.c */
--- a/sys/src/cmd/ndb/dnserver.c
+++ b/sys/src/cmd/ndb/dnserver.c
@@ -19,8 +19,6 @@
 
 	repp->id = reqp->id;
 	repp->flags = Fresp | (reqp->flags & Omask);
-	if(!cfg.nonrecursive && (reqp->flags & Omask) == Oquery)
-		repp->flags |= Fcanrec;
 	setercode(repp, Rok);
 
 	/* move one question from reqp to repp */
@@ -29,7 +27,7 @@
 	rp->next = nil;
 	repp->qd = rp;
 
-	if(rcode){
+	if(rcode != Rok || (reqp->flags & Omask) != Oquery){
 		dnslog("%d: server: response code %d %s, req from %I",
 			req->id, rcode, rcname(rcode), srcip);
 		/* provide feedback to clients who send us trash */
@@ -43,7 +41,6 @@
 		setercode(repp, Runimplimented);
 		return;
 	}
-
 	if(repp->qd->owner->class != Cin){
 		if(debug)
 			dnslog("%d: server: unsupported class %d from %I",
@@ -62,31 +59,31 @@
 			setercode(repp, Runimplimented);
 			return;
 		}
-	}
-	if(myarea == nil && cfg.nonrecursive) {
-		/* we don't recurse and we're not authoritative */
-		repp->flags &= ~(Fauth|Fcanrec);
-		neg = nil;
+		repp->flags |= Fauth;
+		neg = doextquery(repp, req, Dontrecurse);
 	} else {
-		int recurse = (reqp->flags & Frecurse) && (repp->flags & Fcanrec);
+		if(cfg.nonrecursive
+		|| cfg.localrecursive && !localip(srcip)){
+			/* we don't recurse and we're not authoritative */
+			neg = nil;
+		} else {
+			repp->flags |= Fcanrec;
+			if(reqp->flags & Frecurse){
+				neg = doextquery(repp, req, Recurse);
 
-		/*
-		 *  get the answer if we can, in *repp
-		 */
-		neg = doextquery(repp, req, recurse? Recurse: Dontrecurse);
+				/* pass on error codes */
+				if(repp->an == nil && repp->qd->owner->rr == nil){
+					repp->flags |= Fauth;
+					setercode(repp, repp->qd->owner->respcode);
+				}
+			} else
+				neg = doextquery(repp, req, Dontrecurse);
 
-		/* authority is transitive */
-		if(myarea || (repp->an && repp->an->auth))
-			repp->flags |= Fauth;
-
-		/* pass on error codes */
-		if(recurse && repp->an == nil && repp->qd->owner->rr == nil){
-			repp->flags |= Fauth;
-			setercode(repp, repp->qd->owner->respcode);
+			/* authority is transitive */
+			if(repp->an && repp->an->auth)
+				repp->flags |= Fauth;
 		}
-	}
 
-	if(myarea == nil){
 		/*
 		 *  add name server if we know
 		 */