code: plan9front

Download patch

ref: 5de1f3d9cf30b0f3f96fdec267a393e7c33dc82b
parent: 2899b719ae11e4ae18fef3995cdb84c64ac60bc3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Nov 3 16:09:02 EDT 2021

ndb/dns: handle txt rr strings as binary, remove nullrr ndb code

txt and caa rr strings might contain binary control characters
such as newlines and double quotes which mess up the output
in ndb(6) format.
so handle them as binary blobs internally and escape special
characters as \DDD where D is a octal digit when printing.

txtrr() will unescape them when reading into internal
binary representation.

remove the undocumented nullrr ndb attribute parsing code.

--- a/sys/src/cmd/ndb/convDNS2M.c
+++ b/sys/src/cmd/ndb/convDNS2M.c
@@ -26,7 +26,7 @@
 #define NAME(x)		p = pname(p, ep, x, dp)
 #define LABEL(x)	p = pname(p, ep, x, nil)
 #define SYMBOL(x)	p = psym(p, ep, x)
-#define STRING(x)	p = pstr(p, ep, x)
+#define STRING(x, n)	p = pstr(p, ep, x, n)
 #define BYTES(x, n)	p = pbytes(p, ep, x, n)
 #define USHORT(x)	p = pushort(p, ep, x)
 #define UCHAR(x)	p = puchar(p, ep, x)
@@ -35,24 +35,21 @@
 #define V6ADDR(x)	p = pv6addr(p, ep, x)
 
 static uchar*
-psym(uchar *p, uchar *ep, char *np)
+pstr(uchar *p, uchar *ep, uchar *s, int n)
 {
-	int n;
-
-	n = strlen(np);
 	if(n >= Strlen)			/* DNS maximum length string */
-		n = Strlen - 1;
+		n = Strlen-1;
 	if(ep - p < n+1)		/* see if it fits in the buffer */
 		return ep+1;
 	*p++ = n;
-	memmove(p, np, n);
+	memmove(p, s, n);
 	return p + n;
 }
 
 static uchar*
-pstr(uchar *p, uchar *ep, char *np)
+psym(uchar *p, uchar *ep, char *np)
 {
-	return psym(p, ep, np);
+	return pstr(p, ep, (uchar*)np, strlen(np));
 }
 
 static uchar*
@@ -266,7 +263,7 @@
 		break;
 	case Ttxt:
 		for(t = rp->txt; t != nil; t = t->next)
-			STRING(t->p);
+			STRING(t->data, t->dlen);
 		break;
 	case Tnull:
 		BYTES(rp->null->data, rp->null->dlen);
--- a/sys/src/cmd/ndb/convM2DNS.c
+++ b/sys/src/cmd/ndb/convM2DNS.c
@@ -103,7 +103,7 @@
 	char addr[32];
 
 	if(sp->err)
-		return 0;
+		return nil;
 	if(sp->ep - sp->p < 4)
 		return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr");
 	snprint(addr, sizeof addr, "%V", sp->p);
@@ -117,7 +117,7 @@
 	char addr[64];
 
 	if(sp->err)
-		return 0;
+		return nil;
 	if(sp->ep - sp->p < IPaddrlen)
 		return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen,
 			"gv6addr");
@@ -133,11 +133,11 @@
 static DN*
 gsym(RR *rp, Scan *sp)
 {
+	char sym[Strlen];
 	int n;
-	char sym[Strlen+1];
 
 	if(sp->err)
-		return 0;
+		return nil;
 	n = 0;
 	if (sp->p < sp->ep)
 		n = *(sp->p++);
@@ -144,9 +144,9 @@
 	if(sp->ep - sp->p < n)
 		return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym");
 
-	if(n > Strlen){
+	if(n >= Strlen){
 		sp->err = "illegal string (symbol)";
-		return 0;
+		return nil;
 	}
 	strncpy(sym, (char*)sp->p, n);
 	sym[n] = 0;
@@ -164,11 +164,10 @@
 gstr(RR *rp, Scan *sp)
 {
 	int n;
-	char sym[Strlen+1];
 	Txt *t;
 
 	if(sp->err)
-		return 0;
+		return nil;
 	n = 0;
 	if (sp->p < sp->ep)
 		n = *(sp->p++);
@@ -175,19 +174,18 @@
 	if(sp->ep - sp->p < n)
 		return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr");
 
-	if(n > Strlen){
+	if(n >= Strlen){
 		sp->err = "illegal string";
-		return 0;
+		return nil;
 	}
-	strncpy(sym, (char*)sp->p, n);
-	sym[n] = 0;
-	if (strlen(sym) != n)
-		sp->err = "string shorter than declared length";
-	sp->p += n;
 
 	t = emalloc(sizeof(*t));
 	t->next = nil;
-	t->p = estrdup(sym);
+	t->dlen = n;
+	t->data = emalloc(n);
+	memmove(t->data, sp->p, n);
+	sp->p += n;
+
 	return t;
 }
 
--- a/sys/src/cmd/ndb/dblookup.c
+++ b/sys/src/cmd/ndb/dblookup.c
@@ -36,7 +36,6 @@
 static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*);
 static RR*	mxrr(Ndbtuple*, Ndbtuple*);
 static RR*	nsrr(Ndbtuple*, Ndbtuple*);
-static RR*	nullrr(Ndbtuple*, Ndbtuple*);
 static RR*	ptrrr(Ndbtuple*, Ndbtuple*);
 static RR*	soarr(Ndbtuple*, Ndbtuple*);
 static RR*	srvrr(Ndbtuple*, Ndbtuple*);
@@ -50,7 +49,6 @@
 	[Tcname]	1,
 	[Tmx]		1,
 	[Tns]		1,
-	[Tnull]		1,
 	[Tptr]		1,
 	[Tsoa]		1,
 	[Tsrv]		1,
@@ -228,10 +226,6 @@
 		attr2 = "ipv6";
 		f = addr6rr;
 		break;
-	case Tnull:
-		attr = "nullrr";
-		f = nullrr;
-		break;
 	case Tns:
 		attr = "ns";
 		f = nsrr;
@@ -246,7 +240,7 @@
 		break;
 	case Ttxt:
 		attr = "txt";
-		attr2 = "txtrr";	/* undocumented */
+		attr2 = "txtrr";	/* obsolete */
 		f = txtrr;
 		break;
 	case Tmx:
@@ -435,20 +429,10 @@
 	return rp;
 }
 
-static RR*
-nullrr(Ndbtuple*, Ndbtuple *pair)
-{
-	RR *rp;
-
-	rp = rralloc(Tnull);
-	rp->null->data = (uchar*)estrdup(pair->val);
-	rp->null->dlen = strlen((char*)rp->null->data);
-	return rp;
-}
 /*
- *  txt rr strings are at most 255 bytes long.  one
+ *  txt rr strings are at most Strlen-1 bytes long.  one
  *  can represent longer strings by multiple concatenated
- *  <= 255 byte ones.
+ *  < Strlen byte ones.
  */
 static RR*
 txtrr(Ndbtuple*, Ndbtuple *pair)
@@ -455,7 +439,7 @@
 {
 	RR *rp;
 	Txt *t, **l;
-	int i, len, sofar;
+	int i, n, len, sofar;
 
 	rp = rralloc(Ttxt);
 	l = &rp->txt;
@@ -466,14 +450,26 @@
 		t = emalloc(sizeof(*t));
 		t->next = nil;
 
-		i = len-sofar;
-		if(i > 255)
-			i = 255;
+		n = len-sofar;
+		if(n >= Strlen)
+			n = Strlen-1;
+		t->data = emalloc(n);
 
-		t->p = emalloc(i+1);
-		memmove(t->p, pair->val+sofar, i);
-		t->p[i] = 0;
-		sofar += i;
+		/* see bslashfmt() */
+		for(i = 0; i < n && sofar < len; i++){
+			uint c = pair->val[sofar++];
+			if(c == '\\' && sofar < len){
+				if(pair->val[sofar] >= '0' && pair->val[sofar] <= '7'){
+					c = pair->val[sofar++] - '0';
+					while(pair->val[sofar] >= '0' && pair->val[sofar] <= '7')
+						c = (c << 3) | (pair->val[sofar++] - '0');
+				} else {
+					c = pair->val[sofar++];
+				}
+			}
+			t->data[i] = c;
+		}
+		t->dlen = i;
 
 		*l = t;
 		l = &t->next;
@@ -672,9 +668,7 @@
 		rp = srvrr(entry, pair);
 	else if(strcmp(pair->attr, "cname") == 0)
 		rp = cnamerr(entry, pair);
-	else if(strcmp(pair->attr, "nullrr") == 0)
-		rp = nullrr(entry, pair);
-	else if(strcmp(pair->attr, "txtrr") == 0)	/* undocumented */
+	else if(strcmp(pair->attr, "txtrr") == 0)	/* obsolete */
 		rp = txtrr(entry, pair);
 	else if(strcmp(pair->attr, "txt") == 0)
 		rp = txtrr(entry, pair);
--- a/sys/src/cmd/ndb/dn.c
+++ b/sys/src/cmd/ndb/dn.c
@@ -139,7 +139,6 @@
 static ulong agefreq = Defagefreq;
 
 static int rrequiv(RR *r1, RR *r2);
-static int sencodefmt(Fmt*);
 
 static void
 ding(void*, char *msg)
@@ -157,9 +156,10 @@
 	fmtinstall('E', eipfmt);
 	fmtinstall('I', eipfmt);
 	fmtinstall('V', eipfmt);
+	fmtinstall('\\', bslashfmt);
 	fmtinstall('R', rrfmt);
 	fmtinstall('Q', rravfmt);
-	fmtinstall('H', sencodefmt);
+	fmtinstall('H', encodefmt);
 
 	dnvars.oldest = maxage;
 	dnvars.names = 0;
@@ -944,7 +944,9 @@
 		*l = nil;
 		for(t = rp->txt; t != nil; t = t->next){
 			nt = emalloc(sizeof(*nt));
-			nt->p = estrdup(t->p);
+			nt->dlen = t->dlen;
+			nt->data = emalloc(t->dlen);
+			memmove(nt->data, t->data, t->dlen);
 			nt->next = nil;
 			*l = nt;
 			l = &nt->next;
@@ -1195,6 +1197,47 @@
 }
 
 /*
+ *  txt rr strings can contain binary data such as
+ *  control characters and double quotes (") which would
+ *  collide with ndb(6) format.
+ *  escape special characters by encoding them as: \DDD
+ *  where D is a octal digit. backslash (\) is escaped
+ *  by doubling. valid utf8 is encoded verbatim.
+ */
+int
+bslashfmt(Fmt *f)
+{
+	int len, out, n, c;
+	uchar *data;
+
+	out = 0;
+	len = f->prec;
+	f->prec = 0;
+	f->flags &= ~FmtPrec;
+	data = va_arg(f->args, uchar*);
+	for(; len > 0; data += n, len -= n){
+		if(*data >= Runeself && fullrune((char*)data, len)){
+			Rune r;
+
+			n = chartorune(&r, (char*)data);
+			if(r != Runeerror){
+				out += fmtprint(f, "%C", r);
+				continue;
+			}
+		}
+		c = *data;
+		if(c < ' ' || c == '"' || c > '~')
+			out += fmtprint(f, "\\%.3o", c);
+		else if(c == '\\')
+			out += fmtprint(f, "\\\\");
+		else
+			out += fmtprint(f, "%c", c);
+		n = 1;
+	}
+	return out;
+}
+
+/*
  *  print conversion for rr records
  */
 int
@@ -1280,7 +1323,7 @@
 	case Ttxt:
 		fmtprint(&fstr, "\t");
 		for(t = rp->txt; t != nil; t = t->next)
-			fmtprint(&fstr, "%s", t->p);
+			fmtprint(&fstr, "%.*\\", t->dlen, t->data);
 		break;
 	case Trp:
 		fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
@@ -1314,9 +1357,9 @@
 		if (rp->caa == nil)
 			fmtprint(&fstr, "\t<null> <null> <null>");
 		else
-			fmtprint(&fstr, "\t%d %s %.*s",
+			fmtprint(&fstr, "\t%d %s %.*\\",
 				rp->caa->flags, dnname(rp->caa->tag),
-				rp->caa->dlen, (char*)rp->caa->data);
+				rp->caa->dlen, rp->caa->data);
 		break;
 	}
 out:
@@ -1416,7 +1459,7 @@
 	case Ttxt:
 		fmtprint(&fstr, " txt=\"");
 		for(t = rp->txt; t != nil; t = t->next)
-			fmtprint(&fstr, "%s", t->p);
+			fmtprint(&fstr, "%.*\\", t->dlen, t->data);
 		fmtprint(&fstr, "\"");
 		break;
 	case Trp:
@@ -1453,9 +1496,9 @@
 		if (rp->caa == nil)
 			fmtprint(&fstr, " flags=<null> tag=<null> caa=<null>");
 		else
-			fmtprint(&fstr, " flags=%d tag=%s caa=\"%.*s\"",
+			fmtprint(&fstr, " flags=%d tag=%s caa=\"%.*\\\"",
 				rp->caa->flags, dnname(rp->caa->tag),
-				rp->caa->dlen, (char*)rp->caa->data);
+				rp->caa->dlen, rp->caa->data);
 		break;
 	}
 out:
@@ -1574,14 +1617,14 @@
 static int
 txtequiv(Txt *a, Txt *b)
 {
-	char *ap, *ae, *bp, *be;
+	uchar *ap, *ae, *bp, *be;
 	int n;
 
 	for(ap = ae = bp = be = nil;;ap += n, bp += n){
-		while(a != nil && (ap == nil || (ap == ae && (a = a->next) != nil)))
-			ap = a->p, ae = ap + strlen(ap);
-		while(b != nil && (bp == nil || (bp == be && (b = b->next) != nil)))
-			bp = b->p, be = bp + strlen(bp);
+		while(a != nil && (ap == nil || (ap >= ae && (a = a->next) != nil)))
+			ap = a->data, ae = ap + a->dlen;
+		while(b != nil && (bp == nil || (bp >= be && (b = b->next) != nil)))
+			bp = b->data, be = bp + b->dlen;
 		if(a == b || a == nil || b == nil)
 			break;
 		n = ae - ap;
@@ -1709,61 +1752,6 @@
 	return first;
 }
 
-static int
-sencodefmt(Fmt *f)
-{
-	int i, len, ilen, rv;
-	char *out, *buf;
-	uchar *b;
-	char obuf[64];		/* rsc optimization */
-
-	if(!(f->flags&FmtPrec) || f->prec < 1)
-		goto error;
-
-	b = va_arg(f->args, uchar*);
-	if(b == nil)
-		goto error;
-
-	/* if it's a printable, go for it */
-	len = f->prec;
-	for(i = 0; i < len; i++)
-		if(!isprint(b[i]))
-			break;
-	if(i == len){
-		if(len >= sizeof obuf)
-			len = sizeof(obuf)-1;
-		memmove(obuf, b, len);
-		obuf[len] = 0;
-		fmtstrcpy(f, obuf);
-		return 0;
-	}
-
-	ilen = f->prec;
-	f->prec = 0;
-	f->flags &= ~FmtPrec;
-	len = 2*ilen + 1;
-	if(len > sizeof(obuf)){
-		buf = malloc(len);
-		if(buf == nil)
-			goto error;
-	} else
-		buf = obuf;
-
-	/* convert */
-	out = buf;
-	rv = enc16(out, len, b, ilen);
-	if(rv < 0)
-		goto error;
-
-	fmtstrcpy(f, buf);
-	if(buf != obuf)
-		free(buf);
-	return 0;
-
-error:
-	return fmtstrcpy(f, "<encodefmt>");
-}
-
 void*
 emalloc(int size)
 {
@@ -2048,7 +2036,7 @@
 	case Ttxt:
 		while(t = rp->txt){
 			rp->txt = t->next;
-			free(t->p);
+			free(t->data);
 			memset(t, 0, sizeof *t);	/* cause trouble */
 			free(t);
 		}
--- a/sys/src/cmd/ndb/dns.h
+++ b/sys/src/cmd/ndb/dns.h
@@ -251,7 +251,7 @@
 struct Txt
 {
 	Txt	*next;
-	char	*p;
+	Block;
 };
 
 /*
@@ -436,6 +436,7 @@
 extern int	traceactivity;
 extern char	*zonerefreshprogram;
 
+#pragma	varargck	type	"\\"	uchar*
 #pragma	varargck	type	"R"	RR*
 #pragma	varargck	type	"Q"	RR*
 
@@ -448,6 +449,7 @@
 
 void	abort(); /* char*, ... */;
 void	addserver(Server**, char*);
+int	bslashfmt(Fmt*);
 Server*	copyserverlist(Server*);
 void	db2cache(int);
 void	dnage(DN*);