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.
This commit is contained in:
cinap_lenrek 2021-11-03 20:09:02 +00:00
parent 2899b719ae
commit 5de1f3d9cf
5 changed files with 106 additions and 127 deletions

View file

@ -26,7 +26,7 @@ struct Dict
#define NAME(x) p = pname(p, ep, x, dp) #define NAME(x) p = pname(p, ep, x, dp)
#define LABEL(x) p = pname(p, ep, x, nil) #define LABEL(x) p = pname(p, ep, x, nil)
#define SYMBOL(x) p = psym(p, ep, x) #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 BYTES(x, n) p = pbytes(p, ep, x, n)
#define USHORT(x) p = pushort(p, ep, x) #define USHORT(x) p = pushort(p, ep, x)
#define UCHAR(x) p = puchar(p, ep, x) #define UCHAR(x) p = puchar(p, ep, x)
@ -35,24 +35,21 @@ struct Dict
#define V6ADDR(x) p = pv6addr(p, ep, x) #define V6ADDR(x) p = pv6addr(p, ep, x)
static uchar* 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 */ 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 */ if(ep - p < n+1) /* see if it fits in the buffer */
return ep+1; return ep+1;
*p++ = n; *p++ = n;
memmove(p, np, n); memmove(p, s, n);
return p + n; return p + n;
} }
static uchar* 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* static uchar*
@ -266,7 +263,7 @@ convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
break; break;
case Ttxt: case Ttxt:
for(t = rp->txt; t != nil; t = t->next) for(t = rp->txt; t != nil; t = t->next)
STRING(t->p); STRING(t->data, t->dlen);
break; break;
case Tnull: case Tnull:
BYTES(rp->null->data, rp->null->dlen); BYTES(rp->null->data, rp->null->dlen);

View file

@ -103,7 +103,7 @@ gv4addr(RR *rp, Scan *sp)
char addr[32]; char addr[32];
if(sp->err) if(sp->err)
return 0; return nil;
if(sp->ep - sp->p < 4) if(sp->ep - sp->p < 4)
return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr"); return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr");
snprint(addr, sizeof addr, "%V", sp->p); snprint(addr, sizeof addr, "%V", sp->p);
@ -117,7 +117,7 @@ gv6addr(RR *rp, Scan *sp)
char addr[64]; char addr[64];
if(sp->err) if(sp->err)
return 0; return nil;
if(sp->ep - sp->p < IPaddrlen) if(sp->ep - sp->p < IPaddrlen)
return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen, return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen,
"gv6addr"); "gv6addr");
@ -133,20 +133,20 @@ gv6addr(RR *rp, Scan *sp)
static DN* static DN*
gsym(RR *rp, Scan *sp) gsym(RR *rp, Scan *sp)
{ {
char sym[Strlen];
int n; int n;
char sym[Strlen+1];
if(sp->err) if(sp->err)
return 0; return nil;
n = 0; n = 0;
if (sp->p < sp->ep) if (sp->p < sp->ep)
n = *(sp->p++); n = *(sp->p++);
if(sp->ep - sp->p < n) if(sp->ep - sp->p < n)
return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym"); return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym");
if(n > Strlen){ if(n >= Strlen){
sp->err = "illegal string (symbol)"; sp->err = "illegal string (symbol)";
return 0; return nil;
} }
strncpy(sym, (char*)sp->p, n); strncpy(sym, (char*)sp->p, n);
sym[n] = 0; sym[n] = 0;
@ -164,30 +164,28 @@ static Txt*
gstr(RR *rp, Scan *sp) gstr(RR *rp, Scan *sp)
{ {
int n; int n;
char sym[Strlen+1];
Txt *t; Txt *t;
if(sp->err) if(sp->err)
return 0; return nil;
n = 0; n = 0;
if (sp->p < sp->ep) if (sp->p < sp->ep)
n = *(sp->p++); n = *(sp->p++);
if(sp->ep - sp->p < n) if(sp->ep - sp->p < n)
return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr"); return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr");
if(n > Strlen){ if(n >= Strlen){
sp->err = "illegal string"; 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 = emalloc(sizeof(*t));
t->next = nil; 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; return t;
} }

View file

@ -36,7 +36,6 @@ static RR* doaxfr(Ndb*, char*);
static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*); static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*);
static RR* mxrr(Ndbtuple*, Ndbtuple*); static RR* mxrr(Ndbtuple*, Ndbtuple*);
static RR* nsrr(Ndbtuple*, Ndbtuple*); static RR* nsrr(Ndbtuple*, Ndbtuple*);
static RR* nullrr(Ndbtuple*, Ndbtuple*);
static RR* ptrrr(Ndbtuple*, Ndbtuple*); static RR* ptrrr(Ndbtuple*, Ndbtuple*);
static RR* soarr(Ndbtuple*, Ndbtuple*); static RR* soarr(Ndbtuple*, Ndbtuple*);
static RR* srvrr(Ndbtuple*, Ndbtuple*); static RR* srvrr(Ndbtuple*, Ndbtuple*);
@ -50,7 +49,6 @@ static int implemented[] =
[Tcname] 1, [Tcname] 1,
[Tmx] 1, [Tmx] 1,
[Tns] 1, [Tns] 1,
[Tnull] 1,
[Tptr] 1, [Tptr] 1,
[Tsoa] 1, [Tsoa] 1,
[Tsrv] 1, [Tsrv] 1,
@ -228,10 +226,6 @@ dblookup1(char *name, int type, int auth, int ttl)
attr2 = "ipv6"; attr2 = "ipv6";
f = addr6rr; f = addr6rr;
break; break;
case Tnull:
attr = "nullrr";
f = nullrr;
break;
case Tns: case Tns:
attr = "ns"; attr = "ns";
f = nsrr; f = nsrr;
@ -246,7 +240,7 @@ dblookup1(char *name, int type, int auth, int ttl)
break; break;
case Ttxt: case Ttxt:
attr = "txt"; attr = "txt";
attr2 = "txtrr"; /* undocumented */ attr2 = "txtrr"; /* obsolete */
f = txtrr; f = txtrr;
break; break;
case Tmx: case Tmx:
@ -435,27 +429,17 @@ addrrr(Ndbtuple*, Ndbtuple *pair)
return rp; 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 * can represent longer strings by multiple concatenated
* <= 255 byte ones. * < Strlen byte ones.
*/ */
static RR* static RR*
txtrr(Ndbtuple*, Ndbtuple *pair) txtrr(Ndbtuple*, Ndbtuple *pair)
{ {
RR *rp; RR *rp;
Txt *t, **l; Txt *t, **l;
int i, len, sofar; int i, n, len, sofar;
rp = rralloc(Ttxt); rp = rralloc(Ttxt);
l = &rp->txt; l = &rp->txt;
@ -466,14 +450,26 @@ txtrr(Ndbtuple*, Ndbtuple *pair)
t = emalloc(sizeof(*t)); t = emalloc(sizeof(*t));
t->next = nil; t->next = nil;
i = len-sofar; n = len-sofar;
if(i > 255) if(n >= Strlen)
i = 255; n = Strlen-1;
t->data = emalloc(n);
t->p = emalloc(i+1); /* see bslashfmt() */
memmove(t->p, pair->val+sofar, i); for(i = 0; i < n && sofar < len; i++){
t->p[i] = 0; uint c = pair->val[sofar++];
sofar += i; 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;
l = &t->next; l = &t->next;
@ -672,9 +668,7 @@ dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair)
rp = srvrr(entry, pair); rp = srvrr(entry, pair);
else if(strcmp(pair->attr, "cname") == 0) else if(strcmp(pair->attr, "cname") == 0)
rp = cnamerr(entry, pair); rp = cnamerr(entry, pair);
else if(strcmp(pair->attr, "nullrr") == 0) else if(strcmp(pair->attr, "txtrr") == 0) /* obsolete */
rp = nullrr(entry, pair);
else if(strcmp(pair->attr, "txtrr") == 0) /* undocumented */
rp = txtrr(entry, pair); rp = txtrr(entry, pair);
else if(strcmp(pair->attr, "txt") == 0) else if(strcmp(pair->attr, "txt") == 0)
rp = txtrr(entry, pair); rp = txtrr(entry, pair);

View file

@ -139,7 +139,6 @@ Lock dnlock;
static ulong agefreq = Defagefreq; static ulong agefreq = Defagefreq;
static int rrequiv(RR *r1, RR *r2); static int rrequiv(RR *r1, RR *r2);
static int sencodefmt(Fmt*);
static void static void
ding(void*, char *msg) ding(void*, char *msg)
@ -157,9 +156,10 @@ dninit(void)
fmtinstall('E', eipfmt); fmtinstall('E', eipfmt);
fmtinstall('I', eipfmt); fmtinstall('I', eipfmt);
fmtinstall('V', eipfmt); fmtinstall('V', eipfmt);
fmtinstall('\\', bslashfmt);
fmtinstall('R', rrfmt); fmtinstall('R', rrfmt);
fmtinstall('Q', rravfmt); fmtinstall('Q', rravfmt);
fmtinstall('H', sencodefmt); fmtinstall('H', encodefmt);
dnvars.oldest = maxage; dnvars.oldest = maxage;
dnvars.names = 0; dnvars.names = 0;
@ -944,7 +944,9 @@ rrcopy(RR *rp, RR **last)
*l = nil; *l = nil;
for(t = rp->txt; t != nil; t = t->next){ for(t = rp->txt; t != nil; t = t->next){
nt = emalloc(sizeof(*nt)); 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; nt->next = nil;
*l = nt; *l = nt;
l = &nt->next; l = &nt->next;
@ -1194,6 +1196,47 @@ idnname(DN *dn, char *buf, int nbuf)
return name; return name;
} }
/*
* 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 * print conversion for rr records
*/ */
@ -1280,7 +1323,7 @@ rrfmt(Fmt *f)
case Ttxt: case Ttxt:
fmtprint(&fstr, "\t"); fmtprint(&fstr, "\t");
for(t = rp->txt; t != nil; t = t->next) for(t = rp->txt; t != nil; t = t->next)
fmtprint(&fstr, "%s", t->p); fmtprint(&fstr, "%.*\\", t->dlen, t->data);
break; break;
case Trp: case Trp:
fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp)); fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
@ -1314,9 +1357,9 @@ rrfmt(Fmt *f)
if (rp->caa == nil) if (rp->caa == nil)
fmtprint(&fstr, "\t<null> <null> <null>"); fmtprint(&fstr, "\t<null> <null> <null>");
else else
fmtprint(&fstr, "\t%d %s %.*s", fmtprint(&fstr, "\t%d %s %.*\\",
rp->caa->flags, dnname(rp->caa->tag), rp->caa->flags, dnname(rp->caa->tag),
rp->caa->dlen, (char*)rp->caa->data); rp->caa->dlen, rp->caa->data);
break; break;
} }
out: out:
@ -1416,7 +1459,7 @@ rravfmt(Fmt *f)
case Ttxt: case Ttxt:
fmtprint(&fstr, " txt=\""); fmtprint(&fstr, " txt=\"");
for(t = rp->txt; t != nil; t = t->next) for(t = rp->txt; t != nil; t = t->next)
fmtprint(&fstr, "%s", t->p); fmtprint(&fstr, "%.*\\", t->dlen, t->data);
fmtprint(&fstr, "\""); fmtprint(&fstr, "\"");
break; break;
case Trp: case Trp:
@ -1453,9 +1496,9 @@ rravfmt(Fmt *f)
if (rp->caa == nil) if (rp->caa == nil)
fmtprint(&fstr, " flags=<null> tag=<null> caa=<null>"); fmtprint(&fstr, " flags=<null> tag=<null> caa=<null>");
else 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->flags, dnname(rp->caa->tag),
rp->caa->dlen, (char*)rp->caa->data); rp->caa->dlen, rp->caa->data);
break; break;
} }
out: out:
@ -1574,14 +1617,14 @@ certequiv(Cert *a, Cert *b)
static int static int
txtequiv(Txt *a, Txt *b) txtequiv(Txt *a, Txt *b)
{ {
char *ap, *ae, *bp, *be; uchar *ap, *ae, *bp, *be;
int n; int n;
for(ap = ae = bp = be = nil;;ap += n, bp += n){ for(ap = ae = bp = be = nil;;ap += n, bp += n){
while(a != nil && (ap == nil || (ap == ae && (a = a->next) != nil))) while(a != nil && (ap == nil || (ap >= ae && (a = a->next) != nil)))
ap = a->p, ae = ap + strlen(ap); ap = a->data, ae = ap + a->dlen;
while(b != nil && (bp == nil || (bp == be && (b = b->next) != nil))) while(b != nil && (bp == nil || (bp >= be && (b = b->next) != nil)))
bp = b->p, be = bp + strlen(bp); bp = b->data, be = bp + b->dlen;
if(a == b || a == nil || b == nil) if(a == b || a == nil || b == nil)
break; break;
n = ae - ap; n = ae - ap;
@ -1709,61 +1752,6 @@ randomize(RR *rp)
return first; 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* void*
emalloc(int size) emalloc(int size)
{ {
@ -2048,7 +2036,7 @@ rrfree(RR *rp)
case Ttxt: case Ttxt:
while(t = rp->txt){ while(t = rp->txt){
rp->txt = t->next; rp->txt = t->next;
free(t->p); free(t->data);
memset(t, 0, sizeof *t); /* cause trouble */ memset(t, 0, sizeof *t); /* cause trouble */
free(t); free(t);
} }

View file

@ -251,7 +251,7 @@ struct Null
struct Txt struct Txt
{ {
Txt *next; Txt *next;
char *p; Block;
}; };
/* /*
@ -436,6 +436,7 @@ extern char *trace;
extern int traceactivity; extern int traceactivity;
extern char *zonerefreshprogram; extern char *zonerefreshprogram;
#pragma varargck type "\\" uchar*
#pragma varargck type "R" RR* #pragma varargck type "R" RR*
#pragma varargck type "Q" RR* #pragma varargck type "Q" RR*
@ -448,6 +449,7 @@ extern Lock dnlock;
void abort(); /* char*, ... */; void abort(); /* char*, ... */;
void addserver(Server**, char*); void addserver(Server**, char*);
int bslashfmt(Fmt*);
Server* copyserverlist(Server*); Server* copyserverlist(Server*);
void db2cache(int); void db2cache(int);
void dnage(DN*); void dnage(DN*);