shithub: riscv

Download patch

ref: 7ddda493c0c5370902148e20c579dd2d213f0a69
parent: 679a253931804caf4de436c5cdab8d34f178d779
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Oct 9 02:02:36 EDT 2018

ndb/dnstcp: restrict DNS zone transfers to clients listed as dnsslave=

initial idea from Steve Simon, but doesnt require reverse
lookup of the callers ip address.

--- a/sys/man/8/ndb
+++ b/sys/man/8/ndb
@@ -77,7 +77,7 @@
 .br
 .B ndb/dnstcp
 [
-.B -rR
+.B -arR
 ] [
 .B -f
 .I dbfile
@@ -664,6 +664,12 @@
 .BR -R ;
 acting as a pure resolver is enabled by
 .BR -r .
+Unless the
+.B -a
+flag is provided, clients requesting DNS zone transfer must be listed
+with a
+.B dnsslave
+attribute for the relevant domain.
 If
 .I conn-dir
 is provided, it is assumed to be a directory within
--- a/sys/src/cmd/ndb/dnstcp.c
+++ b/sys/src/cmd/ndb/dnstcp.c
@@ -3,6 +3,8 @@
  */
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
+#include <ndb.h>
 #include <ip.h>
 #include "dns.h"
 
@@ -10,6 +12,7 @@
 
 char	*caller = "";
 char	*dbfile;
+int	anyone;
 int	debug;
 char	*logfile = "dns";
 int	maxage = 60*60;
@@ -17,13 +20,12 @@
 int	needrefresh;
 ulong	now;
 vlong	nowns;
-int	testing;
 int	traceactivity;
 char	*zonerefreshprogram;
 
 static int	readmsg(int, uchar*, int);
 static void	reply(int, DNSmsg*, Request*);
-static void	dnzone(DNSmsg*, DNSmsg*, Request*);
+static void	dnzone(DNSmsg*, DNSmsg*, Request*, uchar*);
 static void	getcaller(char*);
 static void	refreshmain(char*);
 
@@ -30,7 +32,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-rR] [-f ndb-file] [-x netmtpt] [conndir]\n", argv0);
+	fprint(2, "usage: %s [-adrR] [-f ndbfile] [-x netmtpt] [conndir]\n", argv0);
 	exits("usage");
 }
 
@@ -44,9 +46,11 @@
 	volatile DNSmsg reqmsg, repmsg;
 	volatile Request req;
 
-	alarm(2*60*1000);
 	cfg.cachedb = 1;
 	ARGBEGIN{
+	case 'a':
+		anyone++;
+		break;
 	case 'd':
 		debug++;
 		break;
@@ -82,6 +86,7 @@
 	memset(callip, 0, sizeof callip);
 	parseip(callip, caller);
 
+	srand(truerand());
 	db2cache(1);
 
 	memset(&req, 0, sizeof req);
@@ -89,6 +94,8 @@
 	req.isslave = 0;
 	procsetname("main loop");
 
+	alarm(10*1000);
+
 	/* loop on requests */
 	for(;; putactivity(0)){
 		now = time(nil);
@@ -135,7 +142,7 @@
 		/* loop through each question */
 		while(reqmsg.qd)
 			if(reqmsg.qd->type == Taxfr)
-				dnzone(&reqmsg, &repmsg, &req);
+				dnzone(&reqmsg, &repmsg, &req, callip);
 			else {
 				dnserver(&reqmsg, &repmsg, &req, callip, rcode);
 				reply(1, &repmsg, &req);
@@ -244,8 +251,37 @@
 	return 1;
 }
 
+static Server*
+findserver(uchar *srcip, Server *servers, Request *req)
+{
+	uchar ip[IPaddrlen];
+	RR *list, *rp;
+
+	for(; servers != nil; servers = servers->next){
+		if(strcmp(ipattr(servers->name), "ip") == 0){
+			if(parseip(ip, servers->name) == -1)
+				continue;
+			if(ipcmp(srcip, ip) == 0)
+				return servers;
+			continue;
+		}
+		list = dnresolve(servers->name, Cin, Ta, req, nil, 0, 1, 1, nil);
+		rrcat(&list, dnresolve(servers->name, Cin, Taaaa, req, nil, 0, 1, 1, nil));
+		for(rp = list; rp != nil; rp = rp->next){
+			if(parseip(ip, rp->ip->name) == -1)
+				continue;
+			if(ipcmp(srcip, ip) == 0)
+				break;
+		}
+		rrfreelist(list);
+		if(rp != nil)
+			return servers;
+	}
+	return nil;
+}
+
 static void
-dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
+dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req, uchar *srcip)
 {
 	DN *dp, *ndp;
 	RR r, *rp;
@@ -264,8 +300,14 @@
 	/* send the soa */
 	repp->an = rrlookup(dp, Tsoa, NOneg);
 	reply(1, repp, req);
-	if(repp->an == 0)
+	if(repp->an == nil)
 		goto out;
+	if(!anyone && !myip(srcip) && findserver(srcip, repp->an->soa->slaves, req) == nil){
+		dnslog("dnstcp: %I axfr %s - not a dnsslave", srcip, dp->name);
+		rrfreelist(repp->an);
+		repp->an = nil;
+		goto out;
+	}
 	rrfreelist(repp->an);
 	repp->an = nil;