ndb/dns: fix netmkaddr() race, dnlock consistency, strcpy, cleanups

This commit is contained in:
cinap_lenrek 2012-08-26 01:51:46 +02:00
parent 19219d5a95
commit 8f0ec8b725
4 changed files with 61 additions and 76 deletions

View file

@ -152,7 +152,8 @@ pname(uchar *p, uchar *ep, char *np, Dict *dp)
/* add to dp->buf */ /* add to dp->buf */
i = strlen(np); i = strlen(np);
if(dp->ep + i + 1 < &dp->buf[sizeof dp->buf]){ if(dp->ep + i + 1 < &dp->buf[sizeof dp->buf]){
strcpy(dp->ep, np); memmove(dp->ep, np, i);
dp->ep[i] = 0;
dp->x[dp->n].name = dp->ep; dp->x[dp->n].name = dp->ep;
last = dp->ep; last = dp->ep;
dp->x[dp->n].offset = p - dp->start; dp->x[dp->n].offset = p - dp->start;

View file

@ -1933,10 +1933,11 @@ estrdup(char *s)
int size; int size;
char *p; char *p;
size = strlen(s)+1; size = strlen(s);
p = malloc(size); p = malloc(size+1);
if(p == nil) if(p == nil)
error("out of memory"); error("out of memory");
memmove(p, s, size); memmove(p, s, size);
p[size] = 0;
return p; return p;
} }

View file

@ -990,10 +990,8 @@ rrlookup(DN *dp, int type, int flag)
assert(rp->magic == RRmagic && rp->cached); assert(rp->magic == RRmagic && rp->cached);
if(rp->db) if(rp->db)
if(rp->auth) if(rp->auth)
if(tsame(type, rp->type)) { if(tsame(type, rp->type))
last = rrcopy(rp, last); last = rrcopy(rp, last);
// setmalloctag(*last, getcallerpc(&dp));
}
} }
if(first) if(first)
goto out; goto out;
@ -1045,9 +1043,6 @@ rrlookup(DN *dp, int type, int flag)
out: out:
unique(first); unique(first);
unlock(&dnlock); unlock(&dnlock);
// dnslog("rrlookup(%s) -> %#p\t# in-core only", dp->name, first);
// if (first)
// setmalloctag(first, getcallerpc(&dp));
return first; return first;
} }
@ -1787,11 +1782,12 @@ estrdup(char *s)
int size; int size;
char *p; char *p;
size = strlen(s)+1; size = strlen(s);
p = mallocz(size, 0); p = mallocz(size+1, 0);
if(p == nil) if(p == nil)
abort(); abort();
memmove(p, s, size); memmove(p, s, size);
p[size] = 0;
setmalloctag(p, getcallerpc(&s)); setmalloctag(p, getcallerpc(&s));
return p; return p;
} }
@ -1877,14 +1873,17 @@ void
addserver(Server **l, char *name) addserver(Server **l, char *name)
{ {
Server *s; Server *s;
int n;
while(*l) while(*l)
l = &(*l)->next; l = &(*l)->next;
s = malloc(sizeof(Server)+strlen(name)+1); n = strlen(name);
s = malloc(sizeof(Server)+n+1);
if(s == nil) if(s == nil)
return; return;
s->name = (char*)(s+1); s->name = (char*)(s+1);
strcpy(s->name, name); memmove(s->name, name, n);
s->name[n] = 0;
s->next = nil; s->next = nil;
*l = s; *l = s;
} }
@ -1941,6 +1940,7 @@ freeserverlist(Server *s)
for(; s != nil; s = next){ for(; s != nil; s = next){
next = s->next; next = s->next;
memset(s, 0, sizeof *s); /* cause trouble */
free(s); free(s);
} }
} }

View file

@ -9,7 +9,6 @@
#include "dns.h" #include "dns.h"
typedef struct Dest Dest; typedef struct Dest Dest;
typedef struct Ipaddr Ipaddr;
typedef struct Query Query; typedef struct Query Query;
enum enum
@ -44,11 +43,6 @@ enum
enum { Hurry, Patient, }; enum { Hurry, Patient, };
enum { Outns, Inns, }; enum { Outns, Inns, };
struct Ipaddr {
Ipaddr *next;
uchar ip[IPaddrlen];
};
struct Dest struct Dest
{ {
uchar a[IPaddrlen]; /* ip address */ uchar a[IPaddrlen]; /* ip address */
@ -185,8 +179,11 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
rrfreelist(rrremneg(&rp)); rrfreelist(rrremneg(&rp));
unlock(&dnlock); unlock(&dnlock);
} }
if(drp != nil) if(drp != nil){
lock(&dnlock);
rrfreelist(drp); rrfreelist(drp);
unlock(&dnlock);
}
procsetname(procname); procsetname(procname);
free(procname); free(procname);
return rp; return rp;
@ -210,15 +207,16 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
if(rp == nil) if(rp == nil)
break; break;
lock(&dnlock);
/* rp->host == nil shouldn't happen, but does */ /* rp->host == nil shouldn't happen, but does */
if(rp->negative || rp->host == nil){ if(rp->negative || rp->host == nil){
rrfreelist(rp); rrfreelist(rp);
unlock(&dnlock);
rp = nil; rp = nil;
break; break;
} }
name = rp->host->name; name = rp->host->name;
lock(&dnlock);
if(cn) if(cn)
rrcat(cn, rp); rrcat(cn, rp);
else else
@ -336,6 +334,7 @@ netqueryns(Query *qp, int depth, RR *nsrp)
qp->nsrp = nsrp; qp->nsrp = nsrp;
rv = netquery(qp, depth); rv = netquery(qp, depth);
qp->nsrp = nil; /* prevent accidents */
lock(&dnlock); lock(&dnlock);
rrfreelist(nsrp); rrfreelist(nsrp);
unlock(&dnlock); unlock(&dnlock);
@ -492,13 +491,8 @@ dnresolve1(char *name, int class, int type, Request *req, int depth,
* we should have found its data in memory by now. * we should have found its data in memory by now.
*/ */
area = inmyarea(dp->name); area = inmyarea(dp->name);
if (area || strncmp(dp->name, "local#", 6) == 0) { if (area || strncmp(dp->name, "local#", 6) == 0)
// char buf[32];
// dnslog("%s %s: no data in area %s", dp->name,
// rrname(type, buf, sizeof buf), area->soarr->owner->name);
return nil; return nil;
}
qp = emalloc(sizeof *qp); qp = emalloc(sizeof *qp);
queryinit(qp, dp, type, req); queryinit(qp, dp, type, req);
@ -567,7 +561,7 @@ udpport(char *mtpt)
char ds[64], adir[64]; char ds[64], adir[64];
/* get a udp port */ /* get a udp port */
snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net")); snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt && *mtpt) ? mtpt : "/net");
ctl = announce(ds, adir); ctl = announce(ds, adir);
if(ctl < 0){ if(ctl < 0){
/* warning("can't get udp port"); */ /* warning("can't get udp port"); */
@ -624,13 +618,12 @@ mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
hnputs(uh->rport, 53); hnputs(uh->rport, 53);
/* make request and convert it to output format */ /* make request and convert it to output format */
memset(&m, 0, sizeof m);
rp = rralloc(type); rp = rralloc(type);
rp->owner = dp; rp->owner = dp;
memset(&m, 0, sizeof m);
initdnsmsg(&m, rp, flags, reqno); initdnsmsg(&m, rp, flags, reqno);
len = convDNS2M(&m, &buf[Udphdrsize], Maxudp); len = convDNS2M(&m, &buf[Udphdrsize], Maxudp);
rrfreelistptr(&m.qd); rrfreelist(rp);
memset(&m, 0, sizeof m); /* cause trouble */
return len; return len;
} }
@ -658,12 +651,13 @@ readnet(Query *qp, int medium, uchar *ibuf, uvlong endms, uchar **replyp,
uchar lenbuf[2]; uchar lenbuf[2];
len = -1; /* pessimism */ len = -1; /* pessimism */
*replyp = nil;
memset(srcip, 0, IPaddrlen);
ms = endms - NS2MS(startns); ms = endms - NS2MS(startns);
if (ms <= 0) if (ms <= 0)
return -1; /* taking too long */ return -1; /* taking too long */
reply = ibuf; reply = ibuf;
memset(srcip, 0, IPaddrlen);
alarm(ms); alarm(ms);
if (medium == Udp) if (medium == Udp)
if (qp->udpfd < 0) if (qp->udpfd < 0)
@ -725,10 +719,6 @@ readreply(Query *qp, int medium, ushort req, uchar *ibuf, DNSmsg *mp,
RR *rp; RR *rp;
queryck(qp); queryck(qp);
memset(mp, 0, sizeof *mp);
memset(srcip, 0, sizeof srcip);
if (0)
len = -1;
for (; timems() < endms && for (; timems() < endms &&
(len = readnet(qp, medium, ibuf, endms, &reply, srcip)) >= 0; (len = readnet(qp, medium, ibuf, endms, &reply, srcip)) >= 0;
freeanswers(mp)){ freeanswers(mp)){
@ -782,6 +772,7 @@ readreply(Query *qp, int medium, ushort req, uchar *ibuf, DNSmsg *mp,
"ns %s", qp->dp->name, "ns %s", qp->dp->name,
rp->host->name); rp->host->name);
} }
memset(mp, 0, sizeof *mp);
return -1; return -1;
} }
@ -922,7 +913,9 @@ cacheneg(DN *dp, int type, int rcode, RR *soarr)
DN *soaowner; DN *soaowner;
ulong ttl; ulong ttl;
qlock(&stats);
stats.negcached++; stats.negcached++;
qunlock(&stats);
/* no cache time specified, don't make anything up */ /* no cache time specified, don't make anything up */
if(soarr != nil){ if(soarr != nil){
@ -976,30 +969,33 @@ setdestoutns(Dest *p, int n)
static int static int
mydnsquery(Query *qp, int medium, uchar *udppkt, int len) mydnsquery(Query *qp, int medium, uchar *udppkt, int len)
{ {
int rv = -1, nfd; int rv, nfd;
char *domain; char *domain;
char conndir[40], net[40]; char conndir[40], addr[128];
uchar belen[2]; uchar belen[2];
NetConnInfo *nci; NetConnInfo *nci;
rv = -1;
queryck(qp); queryck(qp);
domain = smprint("%I", udppkt); domain = smprint("%I", udppkt);
if (domain == nil) {
warning("mydnsquery: no memory for domain");
return rv;
}
if (myaddr(domain)) { if (myaddr(domain)) {
dnslog("mydnsquery: trying to send to myself (%s); bzzzt", dnslog("mydnsquery: trying to send to myself (%s); bzzzt",
domain); domain);
free(domain); free(domain);
return rv; return rv;
} }
switch (medium) { switch (medium) {
case Udp: case Udp:
free(domain);
nfd = dup(qp->udpfd, -1); nfd = dup(qp->udpfd, -1);
if (nfd < 0) { if (nfd < 0) {
warning("mydnsquery: qp->udpfd %d: %r", qp->udpfd); warning("mydnsquery: qp->udpfd %d: %r", qp->udpfd);
close(qp->udpfd); /* ensure it's closed */ close(qp->udpfd); /* ensure it's closed */
qp->udpfd = -1; /* poison it */ qp->udpfd = -1; /* poison it */
return rv; break;
} }
close(nfd); close(nfd);
@ -1010,25 +1006,26 @@ mydnsquery(Query *qp, int medium, uchar *udppkt, int len)
len+Udphdrsize) len+Udphdrsize)
warning("sending udp msg: %r"); warning("sending udp msg: %r");
else { else {
qlock(&stats);
stats.qsent++; stats.qsent++;
qunlock(&stats);
rv = 0; rv = 0;
} }
} }
break; break;
case Tcp: case Tcp:
/* send via TCP & keep fd around for reply */ /* send via TCP & keep fd around for reply */
snprint(net, sizeof net, "%s/tcp", parseip(qp->tcpip, domain);
(mntpt[0] != '\0'? mntpt: "/net")); snprint(addr, sizeof addr, "%s/tcp!%s!dns",
(mntpt && *mntpt) ? mntpt : "/net",
domain);
alarm(10*1000); alarm(10*1000);
qp->tcpfd = rv = dial(netmkaddr(domain, net, "dns"), nil, qp->tcpfd = dial(addr, nil, conndir, &qp->tcpctlfd);
conndir, &qp->tcpctlfd);
alarm(0); alarm(0);
if (qp->tcpfd < 0) { if (qp->tcpfd < 0) {
dnslog("can't dial tcp!%s!dns: %r", domain); dnslog("can't dial %s: %r", addr);
free(domain);
break; break;
} }
free(domain);
nci = getnetconninfo(conndir, qp->tcpfd); nci = getnetconninfo(conndir, qp->tcpfd);
if (nci) { if (nci) {
parseip(qp->tcpip, nci->rsys); parseip(qp->tcpip, nci->rsys);
@ -1042,10 +1039,11 @@ mydnsquery(Query *qp, int medium, uchar *udppkt, int len)
if (write(qp->tcpfd, belen, 2) != 2 || if (write(qp->tcpfd, belen, 2) != 2 ||
write(qp->tcpfd, udppkt + Udphdrsize, len) != len) write(qp->tcpfd, udppkt + Udphdrsize, len) != len)
warning("sending tcp msg: %r"); warning("sending tcp msg: %r");
else
rv = 0;
break; break;
default:
sysfatal("mydnsquery: bad medium");
} }
free(domain);
return rv; return rv;
} }
@ -1183,7 +1181,6 @@ static int
procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p) procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p)
{ {
int rv; int rv;
// int lcktype;
char buf[32]; char buf[32];
DN *ndp; DN *ndp;
Query *nqp; Query *nqp;
@ -1307,21 +1304,10 @@ procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p)
} }
procsetname("recursive query for %s %s", qp->dp->name, procsetname("recursive query for %s %s", qp->dp->name,
rrname(qp->type, buf, sizeof buf)); rrname(qp->type, buf, sizeof buf));
/*
* we're called from udpquery, called from
* netquery, which current holds qp->dp->querylck,
* so release it now and acquire it upon return.
*/
// lcktype = qtype2lck(qp->type); /* someday try this again */
// qunlock(&qp->dp->querylck[lcktype]);
nqp = emalloc(sizeof *nqp); nqp = emalloc(sizeof *nqp);
queryinit(nqp, qp->dp, qp->type, qp->req); queryinit(nqp, qp->dp, qp->type, qp->req);
nqp->nsrp = tp; rv = netqueryns(nqp, depth+1, tp);
rv = netquery(nqp, depth+1);
// qlock(&qp->dp->querylck[lcktype]);
rrfreelist(nqp->nsrp);
querydestroy(nqp); querydestroy(nqp);
free(nqp); free(nqp);
return rv; return rv;
@ -1348,7 +1334,7 @@ tcpquery(Query *qp, DNSmsg *mp, int depth, uchar *ibuf, uchar *obuf, int len,
qlock(&qp->tcplock); qlock(&qp->tcplock);
memmove(obuf, ibuf, IPaddrlen); /* send back to respondent */ memmove(obuf, ibuf, IPaddrlen); /* send back to respondent */
/* sets qp->tcpip from obuf's udp header */ memset(mp, 0, sizeof *mp);
if (xmitquery(qp, Tcp, depth, obuf, inns, len) < 0 || if (xmitquery(qp, Tcp, depth, obuf, inns, len) < 0 ||
readreply(qp, Tcp, req, ibuf, mp, endms) < 0) readreply(qp, Tcp, req, ibuf, mp, endms) < 0)
rv = -1; rv = -1;
@ -1526,6 +1512,8 @@ udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
static QLock mntlck; static QLock mntlck;
static ulong lastmount; static ulong lastmount;
rv = -1;
/* use alloced buffers rather than ones from the stack */ /* use alloced buffers rather than ones from the stack */
ibuf = emalloc(64*1024); /* max. tcp reply size */ ibuf = emalloc(64*1024); /* max. tcp reply size */
obuf = emalloc(Maxudp+Udphdrsize); obuf = emalloc(Maxudp+Udphdrsize);
@ -1557,7 +1545,7 @@ udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
if (fd < 0) { if (fd < 0) {
dnslog("can't get udpport for %s query of name %s: %r", dnslog("can't get udpport for %s query of name %s: %r",
mntpt, qp->dp->name); mntpt, qp->dp->name);
sysfatal("out of udp conversations"); /* we're buggered */ goto Out;
} }
/* /*
@ -1576,9 +1564,10 @@ udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
qp->udpfd = fd; qp->udpfd = fd;
rv = queryns(qp, depth, ibuf, obuf, wait, inns); rv = queryns(qp, depth, ibuf, obuf, wait, inns);
close(fd);
qp->udpfd = -1; qp->udpfd = -1;
close(fd);
Out:
free(obuf); free(obuf);
free(ibuf); free(ibuf);
return rv; return rv;
@ -1681,8 +1670,6 @@ netquery(Query *qp, int depth)
rv = udpquery(qp, "/net.alt", depth, Patient, Outns); rv = udpquery(qp, "/net.alt", depth, Patient, Outns);
} }
// if (rv == Answnone) /* could ask /net.alt/dns directly */
// askoutdns(dp, qp->type);
if(lock && qlp) { if(lock && qlp) {
qlock(qlp); qlock(qlp);
@ -1699,23 +1686,19 @@ seerootns(void)
int rv; int rv;
char root[] = ""; char root[] = "";
Request req; Request req;
RR *rr; RR *rr, *nsrp;
Query *qp; Query *qp;
memset(&req, 0, sizeof req); memset(&req, 0, sizeof req);
req.isslave = 1; req.isslave = 1;
req.aborttime = timems() + Maxreqtm; req.aborttime = timems() + Maxreqtm;
req.from = "internal"; req.from = "internal";
qp = emalloc(sizeof *qp); qp = emalloc(sizeof *qp);
queryinit(qp, dnlookup(root, Cin, 1), Tns, &req); queryinit(qp, dnlookup(root, Cin, 1), Tns, &req);
qp->nsrp = dblookup(root, Cin, Tns, 0, 0); nsrp = dblookup(root, Cin, Tns, 0, 0);
for (rr = qp->nsrp; rr != nil; rr = rr->next) /* DEBUG */ for (rr = nsrp; rr != nil; rr = rr->next) /* DEBUG */
dnslog("seerootns query nsrp: %R", rr); dnslog("seerootns query nsrp: %R", rr);
rv = netqueryns(qp, 0, nsrp); /* lookup ". ns" using nsrp */
rv = netquery(qp, 0); /* lookup ". ns" using qp->nsrp */
rrfreelist(qp->nsrp);
querydestroy(qp); querydestroy(qp);
free(qp); free(qp);
return rv; return rv;