add dns
This commit is contained in:
parent
cff43a06f2
commit
3e0d8fb3ea
380
src/cmd/ndb/convDNS2M.c
Executable file
380
src/cmd/ndb/convDNS2M.c
Executable file
@ -0,0 +1,380 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a dictionary of domain names for packing messages
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Ndict= 64,
|
||||||
|
};
|
||||||
|
typedef struct Dict Dict;
|
||||||
|
struct Dict
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
ushort offset; /* pointer to packed name in message */
|
||||||
|
char *name; /* pointer to unpacked name in buf */
|
||||||
|
} x[Ndict];
|
||||||
|
int n; /* size of dictionary */
|
||||||
|
uchar *start; /* start of packed message */
|
||||||
|
char buf[4*1024]; /* buffer for unpacked names */
|
||||||
|
char *ep; /* first free char in buf */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NAME(x) p = pname(p, ep, x, dp)
|
||||||
|
#define SYMBOL(x) p = psym(p, ep, x)
|
||||||
|
#define STRING(x) p = pstr(p, ep, x)
|
||||||
|
#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)
|
||||||
|
#define ULONG(x) p = pulong(p, ep, x)
|
||||||
|
#define V4ADDR(x) p = pv4addr(p, ep, x)
|
||||||
|
#define V6ADDR(x) p = pv6addr(p, ep, x)
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
psym(uchar *p, uchar *ep, char *np)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = strlen(np);
|
||||||
|
if(n >= Strlen) /* DNS maximum length string */
|
||||||
|
n = Strlen - 1;
|
||||||
|
if(ep - p < n+1) /* see if it fits in the buffer */
|
||||||
|
return ep+1;
|
||||||
|
*p++ = n;
|
||||||
|
memcpy(p, np, n);
|
||||||
|
return p + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pstr(uchar *p, uchar *ep, char *np)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = strlen(np);
|
||||||
|
if(n >= Strlen) /* DNS maximum length string */
|
||||||
|
n = Strlen - 1;
|
||||||
|
if(ep - p < n+1) /* see if it fits in the buffer */
|
||||||
|
return ep+1;
|
||||||
|
*p++ = n;
|
||||||
|
memcpy(p, np, n);
|
||||||
|
return p + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pbytes(uchar *p, uchar *ep, uchar *np, int n)
|
||||||
|
{
|
||||||
|
if(ep - p < n)
|
||||||
|
return ep+1;
|
||||||
|
memcpy(p, np, n);
|
||||||
|
return p + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
puchar(uchar *p, uchar *ep, int val)
|
||||||
|
{
|
||||||
|
if(ep - p < 1)
|
||||||
|
return ep+1;
|
||||||
|
*p++ = val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pushort(uchar *p, uchar *ep, int val)
|
||||||
|
{
|
||||||
|
if(ep - p < 2)
|
||||||
|
return ep+1;
|
||||||
|
*p++ = val>>8;
|
||||||
|
*p++ = val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pulong(uchar *p, uchar *ep, int val)
|
||||||
|
{
|
||||||
|
if(ep - p < 4)
|
||||||
|
return ep+1;
|
||||||
|
*p++ = val>>24;
|
||||||
|
*p++ = val>>16;
|
||||||
|
*p++ = val>>8;
|
||||||
|
*p++ = val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pv4addr(uchar *p, uchar *ep, char *name)
|
||||||
|
{
|
||||||
|
uchar ip[IPaddrlen];
|
||||||
|
|
||||||
|
if(ep - p < 4)
|
||||||
|
return ep+1;
|
||||||
|
parseip(ip, name);
|
||||||
|
v6tov4(p, ip);
|
||||||
|
return p + 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pv6addr(uchar *p, uchar *ep, char *name)
|
||||||
|
{
|
||||||
|
if(ep - p < IPaddrlen)
|
||||||
|
return ep+1;
|
||||||
|
parseip(p, name);
|
||||||
|
return p + IPaddrlen;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
pname(uchar *p, uchar *ep, char *np, Dict *dp)
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
int i;
|
||||||
|
char *last; /* last component packed */
|
||||||
|
|
||||||
|
if(strlen(np) >= Domlen) /* make sure we don't exceed DNS limits */
|
||||||
|
return ep+1;
|
||||||
|
|
||||||
|
last = 0;
|
||||||
|
while(*np){
|
||||||
|
/* look through every component in the dictionary for a match */
|
||||||
|
for(i = 0; i < dp->n; i++){
|
||||||
|
if(strcmp(np, dp->x[i].name) == 0){
|
||||||
|
if(ep - p < 2)
|
||||||
|
return ep+1;
|
||||||
|
*p++ = (dp->x[i].offset>>8) | 0xc0;
|
||||||
|
*p++ = dp->x[i].offset;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if there's room, enter this name in dictionary */
|
||||||
|
if(dp->n < Ndict){
|
||||||
|
if(last){
|
||||||
|
/* the whole name is already in dp->buf */
|
||||||
|
last = strchr(last, '.') + 1;
|
||||||
|
dp->x[dp->n].name = last;
|
||||||
|
dp->x[dp->n].offset = p - dp->start;
|
||||||
|
dp->n++;
|
||||||
|
} else {
|
||||||
|
/* add to dp->buf */
|
||||||
|
i = strlen(np);
|
||||||
|
if(dp->ep + i + 1 < &dp->buf[sizeof(dp->buf)]){
|
||||||
|
strcpy(dp->ep, np);
|
||||||
|
dp->x[dp->n].name = dp->ep;
|
||||||
|
last = dp->ep;
|
||||||
|
dp->x[dp->n].offset = p - dp->start;
|
||||||
|
dp->ep += i + 1;
|
||||||
|
dp->n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put next component into message */
|
||||||
|
cp = strchr(np, '.');
|
||||||
|
if(cp == 0){
|
||||||
|
i = strlen(np);
|
||||||
|
cp = np + i; /* point to null terminator */
|
||||||
|
} else {
|
||||||
|
i = cp - np;
|
||||||
|
cp++; /* point past '.' */
|
||||||
|
}
|
||||||
|
if(ep-p < i+1)
|
||||||
|
return ep+1;
|
||||||
|
*p++ = i; /* count of chars in label */
|
||||||
|
memcpy(p, np, i);
|
||||||
|
np = cp;
|
||||||
|
p += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p >= ep)
|
||||||
|
return ep+1;
|
||||||
|
*p++ = 0; /* add top level domain */
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
|
||||||
|
{
|
||||||
|
uchar *lp, *data;
|
||||||
|
int len, ttl;
|
||||||
|
Txt *t;
|
||||||
|
|
||||||
|
NAME(rp->owner->name);
|
||||||
|
USHORT(rp->type);
|
||||||
|
USHORT(rp->owner->class);
|
||||||
|
|
||||||
|
/* egregious overuse of ttl (it's absolute time in the cache) */
|
||||||
|
if(rp->db)
|
||||||
|
ttl = rp->ttl;
|
||||||
|
else
|
||||||
|
ttl = rp->ttl - now;
|
||||||
|
if(ttl < 0)
|
||||||
|
ttl = 0;
|
||||||
|
ULONG(ttl);
|
||||||
|
|
||||||
|
lp = p; /* leave room for the rdata length */
|
||||||
|
p += 2;
|
||||||
|
data = p;
|
||||||
|
|
||||||
|
if(data >= ep)
|
||||||
|
return p+1;
|
||||||
|
|
||||||
|
switch(rp->type){
|
||||||
|
case Thinfo:
|
||||||
|
SYMBOL(rp->cpu->name);
|
||||||
|
SYMBOL(rp->os->name);
|
||||||
|
break;
|
||||||
|
case Tcname:
|
||||||
|
case Tmb:
|
||||||
|
case Tmd:
|
||||||
|
case Tmf:
|
||||||
|
case Tns:
|
||||||
|
NAME(rp->host->name);
|
||||||
|
break;
|
||||||
|
case Tmg:
|
||||||
|
case Tmr:
|
||||||
|
NAME(rp->mb->name);
|
||||||
|
break;
|
||||||
|
case Tminfo:
|
||||||
|
NAME(rp->rmb->name);
|
||||||
|
NAME(rp->mb->name);
|
||||||
|
break;
|
||||||
|
case Tmx:
|
||||||
|
USHORT(rp->pref);
|
||||||
|
NAME(rp->host->name);
|
||||||
|
break;
|
||||||
|
case Ta:
|
||||||
|
V4ADDR(rp->ip->name);
|
||||||
|
break;
|
||||||
|
case Taaaa:
|
||||||
|
V6ADDR(rp->ip->name);
|
||||||
|
break;
|
||||||
|
case Tptr:
|
||||||
|
NAME(rp->ptr->name);
|
||||||
|
break;
|
||||||
|
case Tsoa:
|
||||||
|
NAME(rp->host->name);
|
||||||
|
NAME(rp->rmb->name);
|
||||||
|
ULONG(rp->soa->serial);
|
||||||
|
ULONG(rp->soa->refresh);
|
||||||
|
ULONG(rp->soa->retry);
|
||||||
|
ULONG(rp->soa->expire);
|
||||||
|
ULONG(rp->soa->minttl);
|
||||||
|
break;
|
||||||
|
case Ttxt:
|
||||||
|
for(t = rp->txt; t != nil; t = t->next)
|
||||||
|
STRING(t->p);
|
||||||
|
break;
|
||||||
|
case Tnull:
|
||||||
|
BYTES(rp->null->data, rp->null->dlen);
|
||||||
|
break;
|
||||||
|
case Trp:
|
||||||
|
NAME(rp->rmb->name);
|
||||||
|
NAME(rp->rp->name);
|
||||||
|
break;
|
||||||
|
case Tkey:
|
||||||
|
USHORT(rp->key->flags);
|
||||||
|
UCHAR(rp->key->proto);
|
||||||
|
UCHAR(rp->key->alg);
|
||||||
|
BYTES(rp->key->data, rp->key->dlen);
|
||||||
|
break;
|
||||||
|
case Tsig:
|
||||||
|
USHORT(rp->sig->type);
|
||||||
|
UCHAR(rp->sig->alg);
|
||||||
|
UCHAR(rp->sig->labels);
|
||||||
|
ULONG(rp->sig->ttl);
|
||||||
|
ULONG(rp->sig->exp);
|
||||||
|
ULONG(rp->sig->incep);
|
||||||
|
USHORT(rp->sig->tag);
|
||||||
|
NAME(rp->sig->signer->name);
|
||||||
|
BYTES(rp->sig->data, rp->sig->dlen);
|
||||||
|
break;
|
||||||
|
case Tcert:
|
||||||
|
USHORT(rp->cert->type);
|
||||||
|
USHORT(rp->cert->tag);
|
||||||
|
UCHAR(rp->cert->alg);
|
||||||
|
BYTES(rp->cert->data, rp->cert->dlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stuff in the rdata section length */
|
||||||
|
len = p - data;
|
||||||
|
*lp++ = len >> 8;
|
||||||
|
*lp = len;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
convQ2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
|
||||||
|
{
|
||||||
|
NAME(rp->owner->name);
|
||||||
|
USHORT(rp->type);
|
||||||
|
USHORT(rp->owner->class);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uchar*
|
||||||
|
rrloop(RR *rp, int *countp, uchar *p, uchar *ep, Dict *dp, int quest)
|
||||||
|
{
|
||||||
|
uchar *np;
|
||||||
|
|
||||||
|
*countp = 0;
|
||||||
|
for(; rp && p < ep; rp = rp->next){
|
||||||
|
if(quest)
|
||||||
|
np = convQ2M(rp, p, ep, dp);
|
||||||
|
else
|
||||||
|
np = convRR2M(rp, p, ep, dp);
|
||||||
|
if(np > ep)
|
||||||
|
break;
|
||||||
|
p = np;
|
||||||
|
(*countp)++;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert into a message
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
convDNS2M(DNSmsg *m, uchar *buf, int len)
|
||||||
|
{
|
||||||
|
uchar *p, *ep, *np;
|
||||||
|
Dict d;
|
||||||
|
|
||||||
|
d.n = 0;
|
||||||
|
d.start = buf;
|
||||||
|
d.ep = d.buf;
|
||||||
|
memset(buf, 0, len);
|
||||||
|
m->qdcount = m->ancount = m->nscount = m->arcount = 0;
|
||||||
|
|
||||||
|
/* first pack in the RR's so we can get real counts */
|
||||||
|
p = buf + 12;
|
||||||
|
ep = buf + len;
|
||||||
|
p = rrloop(m->qd, &m->qdcount, p, ep, &d, 1);
|
||||||
|
p = rrloop(m->an, &m->ancount, p, ep, &d, 0);
|
||||||
|
p = rrloop(m->ns, &m->nscount, p, ep, &d, 0);
|
||||||
|
p = rrloop(m->ar, &m->arcount, p, ep, &d, 0);
|
||||||
|
if(p > ep)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* now pack the rest */
|
||||||
|
np = p;
|
||||||
|
p = buf;
|
||||||
|
ep = buf + len;
|
||||||
|
USHORT(m->id);
|
||||||
|
USHORT(m->flags);
|
||||||
|
USHORT(m->qdcount);
|
||||||
|
USHORT(m->ancount);
|
||||||
|
USHORT(m->nscount);
|
||||||
|
USHORT(m->arcount);
|
||||||
|
if(p > ep)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return np - buf;
|
||||||
|
}
|
||||||
460
src/cmd/ndb/convM2DNS.c
Executable file
460
src/cmd/ndb/convM2DNS.c
Executable file
@ -0,0 +1,460 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
typedef struct Scan Scan;
|
||||||
|
struct Scan
|
||||||
|
{
|
||||||
|
uchar *base;
|
||||||
|
uchar *p;
|
||||||
|
uchar *ep;
|
||||||
|
char *err;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NAME(x) gname(x, sp)
|
||||||
|
#define SYMBOL(x) (x = gsym(sp))
|
||||||
|
#define STRING(x) (x = gstr(sp))
|
||||||
|
#define USHORT(x) (x = gshort(sp))
|
||||||
|
#define ULONG(x) (x = glong(sp))
|
||||||
|
#define UCHAR(x) (x = gchar(sp))
|
||||||
|
#define V4ADDR(x) (x = gv4addr(sp))
|
||||||
|
#define V6ADDR(x) (x = gv6addr(sp))
|
||||||
|
#define BYTES(x, y) (y = gbytes(sp, &x, len - (sp->p - data)))
|
||||||
|
|
||||||
|
static char *toolong = "too long";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a ushort/ulong
|
||||||
|
*/
|
||||||
|
static ushort
|
||||||
|
gchar(Scan *sp)
|
||||||
|
{
|
||||||
|
ushort x;
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
if(sp->ep - sp->p < 1){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
x = sp->p[0];
|
||||||
|
sp->p += 1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
static ushort
|
||||||
|
gshort(Scan *sp)
|
||||||
|
{
|
||||||
|
ushort x;
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
if(sp->ep - sp->p < 2){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
x = (sp->p[0]<<8) | sp->p[1];
|
||||||
|
sp->p += 2;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
static ulong
|
||||||
|
glong(Scan *sp)
|
||||||
|
{
|
||||||
|
ulong x;
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
if(sp->ep - sp->p < 4){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3];
|
||||||
|
sp->p += 4;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get an ip address
|
||||||
|
*/
|
||||||
|
static DN*
|
||||||
|
gv4addr(Scan *sp)
|
||||||
|
{
|
||||||
|
char addr[32];
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
if(sp->ep - sp->p < 4){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
snprint(addr, sizeof(addr), "%V", sp->p);
|
||||||
|
sp->p += 4;
|
||||||
|
|
||||||
|
return dnlookup(addr, Cin, 1);
|
||||||
|
}
|
||||||
|
static DN*
|
||||||
|
gv6addr(Scan *sp)
|
||||||
|
{
|
||||||
|
char addr[64];
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
if(sp->ep - sp->p < IPaddrlen){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
snprint(addr, sizeof(addr), "%I", sp->p);
|
||||||
|
sp->p += IPaddrlen;
|
||||||
|
|
||||||
|
return dnlookup(addr, Cin, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a string. make it an internal symbol.
|
||||||
|
*/
|
||||||
|
static DN*
|
||||||
|
gsym(Scan *sp)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char sym[Strlen+1];
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
n = *(sp->p++);
|
||||||
|
if(sp->p+n > sp->ep){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n > Strlen){
|
||||||
|
sp->err = "illegal string";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strncpy(sym, (char*)sp->p, n);
|
||||||
|
sym[n] = 0;
|
||||||
|
sp->p += n;
|
||||||
|
|
||||||
|
return dnlookup(sym, Csym, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a string. don't make it an internal symbol.
|
||||||
|
*/
|
||||||
|
static Txt*
|
||||||
|
gstr(Scan *sp)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char sym[Strlen+1];
|
||||||
|
Txt *t;
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
n = *(sp->p++);
|
||||||
|
if(sp->p+n > sp->ep){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n > Strlen){
|
||||||
|
sp->err = "illegal string";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strncpy(sym, (char*)sp->p, n);
|
||||||
|
sym[n] = 0;
|
||||||
|
sp->p += n;
|
||||||
|
|
||||||
|
t = emalloc(sizeof(*t));
|
||||||
|
t->next = nil;
|
||||||
|
t->p = estrdup(sym);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a sequence of bytes
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
gbytes(Scan *sp, uchar **p, int n)
|
||||||
|
{
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
if(sp->p+n > sp->ep || n < 0){
|
||||||
|
sp->err = toolong;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*p = emalloc(n);
|
||||||
|
memmove(*p, sp->p, n);
|
||||||
|
sp->p += n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get a domain name. 'to' must point to a buffer at least Domlen+1 long.
|
||||||
|
*/
|
||||||
|
static char*
|
||||||
|
gname(char *to, Scan *sp)
|
||||||
|
{
|
||||||
|
int len, off;
|
||||||
|
int pointer;
|
||||||
|
int n;
|
||||||
|
char *tostart;
|
||||||
|
char *toend;
|
||||||
|
uchar *p;
|
||||||
|
|
||||||
|
tostart = to;
|
||||||
|
if(sp->err)
|
||||||
|
goto err;
|
||||||
|
pointer = 0;
|
||||||
|
p = sp->p;
|
||||||
|
toend = to + Domlen;
|
||||||
|
for(len = 0; *p; len += pointer ? 0 : (n+1)){
|
||||||
|
if((*p & 0xc0) == 0xc0){
|
||||||
|
/* pointer to other spot in message */
|
||||||
|
if(pointer++ > 10){
|
||||||
|
sp->err = "pointer loop";
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
off = ((p[0]<<8) + p[1]) & 0x3ff;
|
||||||
|
p = sp->base + off;
|
||||||
|
if(p >= sp->ep){
|
||||||
|
sp->err = "bad pointer";
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
n = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
n = *p++;
|
||||||
|
if(len + n < Domlen - 1){
|
||||||
|
if(to + n > toend){
|
||||||
|
sp->err = toolong;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
memmove(to, p, n);
|
||||||
|
to += n;
|
||||||
|
}
|
||||||
|
p += n;
|
||||||
|
if(*p){
|
||||||
|
if(to >= toend){
|
||||||
|
sp->err = toolong;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
*to++ = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*to = 0;
|
||||||
|
if(pointer)
|
||||||
|
sp->p += len + 2; /* + 2 for pointer */
|
||||||
|
else
|
||||||
|
sp->p += len + 1; /* + 1 for the null domain */
|
||||||
|
return tostart;
|
||||||
|
err:
|
||||||
|
*tostart = 0;
|
||||||
|
return tostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert the next RR from a message
|
||||||
|
*/
|
||||||
|
static RR*
|
||||||
|
convM2RR(Scan *sp)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
int type;
|
||||||
|
int class;
|
||||||
|
uchar *data;
|
||||||
|
int len;
|
||||||
|
char dname[Domlen+1];
|
||||||
|
Txt *t, **l;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
NAME(dname);
|
||||||
|
USHORT(type);
|
||||||
|
USHORT(class);
|
||||||
|
|
||||||
|
rp = rralloc(type);
|
||||||
|
rp->owner = dnlookup(dname, class, 1);
|
||||||
|
rp->type = type;
|
||||||
|
|
||||||
|
ULONG(rp->ttl);
|
||||||
|
rp->ttl += now;
|
||||||
|
USHORT(len);
|
||||||
|
data = sp->p;
|
||||||
|
|
||||||
|
if(sp->p + len > sp->ep)
|
||||||
|
sp->err = toolong;
|
||||||
|
if(sp->err){
|
||||||
|
rrfree(rp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(type){
|
||||||
|
default:
|
||||||
|
/* unknown type, just ignore it */
|
||||||
|
sp->p = data + len;
|
||||||
|
rrfree(rp);
|
||||||
|
goto retry;
|
||||||
|
case Thinfo:
|
||||||
|
SYMBOL(rp->cpu);
|
||||||
|
SYMBOL(rp->os);
|
||||||
|
break;
|
||||||
|
case Tcname:
|
||||||
|
case Tmb:
|
||||||
|
case Tmd:
|
||||||
|
case Tmf:
|
||||||
|
case Tns:
|
||||||
|
rp->host = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
break;
|
||||||
|
case Tmg:
|
||||||
|
case Tmr:
|
||||||
|
rp->mb = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
break;
|
||||||
|
case Tminfo:
|
||||||
|
rp->rmb = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
rp->mb = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
break;
|
||||||
|
case Tmx:
|
||||||
|
USHORT(rp->pref);
|
||||||
|
rp->host = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
break;
|
||||||
|
case Ta:
|
||||||
|
V4ADDR(rp->ip);
|
||||||
|
break;
|
||||||
|
case Taaaa:
|
||||||
|
V6ADDR(rp->ip);
|
||||||
|
break;
|
||||||
|
case Tptr:
|
||||||
|
rp->ptr = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
break;
|
||||||
|
case Tsoa:
|
||||||
|
rp->host = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
rp->rmb = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
ULONG(rp->soa->serial);
|
||||||
|
ULONG(rp->soa->refresh);
|
||||||
|
ULONG(rp->soa->retry);
|
||||||
|
ULONG(rp->soa->expire);
|
||||||
|
ULONG(rp->soa->minttl);
|
||||||
|
break;
|
||||||
|
case Ttxt:
|
||||||
|
l = &rp->txt;
|
||||||
|
*l = nil;
|
||||||
|
while(sp->p-data < len){
|
||||||
|
STRING(t);
|
||||||
|
*l = t;
|
||||||
|
l = &t->next;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Tnull:
|
||||||
|
BYTES(rp->null->data, rp->null->dlen);
|
||||||
|
break;
|
||||||
|
case Trp:
|
||||||
|
rp->rmb = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
rp->rp = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
break;
|
||||||
|
case Tkey:
|
||||||
|
USHORT(rp->key->flags);
|
||||||
|
UCHAR(rp->key->proto);
|
||||||
|
UCHAR(rp->key->alg);
|
||||||
|
BYTES(rp->key->data, rp->key->dlen);
|
||||||
|
break;
|
||||||
|
case Tsig:
|
||||||
|
USHORT(rp->sig->type);
|
||||||
|
UCHAR(rp->sig->alg);
|
||||||
|
UCHAR(rp->sig->labels);
|
||||||
|
ULONG(rp->sig->ttl);
|
||||||
|
ULONG(rp->sig->exp);
|
||||||
|
ULONG(rp->sig->incep);
|
||||||
|
USHORT(rp->sig->tag);
|
||||||
|
rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
|
||||||
|
BYTES(rp->sig->data, rp->sig->dlen);
|
||||||
|
break;
|
||||||
|
case Tcert:
|
||||||
|
USHORT(rp->cert->type);
|
||||||
|
USHORT(rp->cert->tag);
|
||||||
|
UCHAR(rp->cert->alg);
|
||||||
|
BYTES(rp->cert->data, rp->cert->dlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(sp->p - data != len)
|
||||||
|
sp->err = "bad RR len";
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert the next question from a message
|
||||||
|
*/
|
||||||
|
static RR*
|
||||||
|
convM2Q(Scan *sp)
|
||||||
|
{
|
||||||
|
char dname[Domlen+1];
|
||||||
|
int type;
|
||||||
|
int class;
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
NAME(dname);
|
||||||
|
USHORT(type);
|
||||||
|
USHORT(class);
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rp = rralloc(type);
|
||||||
|
rp->owner = dnlookup(dname, class, 1);
|
||||||
|
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RR*
|
||||||
|
rrloop(Scan *sp, int count, int quest)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static char errbuf[64];
|
||||||
|
RR *first, *rp, **l;
|
||||||
|
|
||||||
|
if(sp->err)
|
||||||
|
return 0;
|
||||||
|
l = &first;
|
||||||
|
first = 0;
|
||||||
|
for(i = 0; i < count; i++){
|
||||||
|
rp = quest ? convM2Q(sp) : convM2RR(sp);
|
||||||
|
if(rp == 0)
|
||||||
|
break;
|
||||||
|
if(sp->err){
|
||||||
|
rrfree(rp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*l = rp;
|
||||||
|
l = &rp->next;
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert the next DNS from a message stream
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
convM2DNS(uchar *buf, int len, DNSmsg *m)
|
||||||
|
{
|
||||||
|
Scan scan;
|
||||||
|
Scan *sp;
|
||||||
|
char *err;
|
||||||
|
|
||||||
|
scan.base = buf;
|
||||||
|
scan.p = buf;
|
||||||
|
scan.ep = buf + len;
|
||||||
|
scan.err = 0;
|
||||||
|
sp = &scan;
|
||||||
|
memset(m, 0, sizeof(DNSmsg));
|
||||||
|
USHORT(m->id);
|
||||||
|
USHORT(m->flags);
|
||||||
|
USHORT(m->qdcount);
|
||||||
|
USHORT(m->ancount);
|
||||||
|
USHORT(m->nscount);
|
||||||
|
USHORT(m->arcount);
|
||||||
|
m->qd = rrloop(sp, m->qdcount, 1);
|
||||||
|
m->an = rrloop(sp, m->ancount, 0);
|
||||||
|
m->ns = rrloop(sp, m->nscount, 0);
|
||||||
|
err = scan.err; /* live with bad ar's */
|
||||||
|
m->ar = rrloop(sp, m->arcount, 0);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
946
src/cmd/ndb/dblookup.c
Executable file
946
src/cmd/ndb/dblookup.c
Executable file
@ -0,0 +1,946 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
static Ndb *db;
|
||||||
|
|
||||||
|
static RR* dblookup1(char*, int, int, int);
|
||||||
|
static RR* addrrr(Ndbtuple*, Ndbtuple*);
|
||||||
|
static RR* nsrr(Ndbtuple*, Ndbtuple*);
|
||||||
|
static RR* cnamerr(Ndbtuple*, Ndbtuple*);
|
||||||
|
static RR* mxrr(Ndbtuple*, Ndbtuple*);
|
||||||
|
static RR* soarr(Ndbtuple*, Ndbtuple*);
|
||||||
|
static RR* ptrrr(Ndbtuple*, Ndbtuple*);
|
||||||
|
static Ndbtuple* look(Ndbtuple*, Ndbtuple*, char*);
|
||||||
|
static RR* doaxfr(Ndb*, char*);
|
||||||
|
static RR* nullrr(Ndbtuple *entry, Ndbtuple *pair);
|
||||||
|
static RR* txtrr(Ndbtuple *entry, Ndbtuple *pair);
|
||||||
|
static Lock dblock;
|
||||||
|
static void createptrs(void);
|
||||||
|
|
||||||
|
static int implemented[Tall] =
|
||||||
|
{
|
||||||
|
[Ta] 1,
|
||||||
|
[Tns] 1,
|
||||||
|
[Tsoa] 1,
|
||||||
|
[Tmx] 1,
|
||||||
|
[Tptr] 1,
|
||||||
|
[Tcname] 1,
|
||||||
|
[Tnull] 1,
|
||||||
|
[Ttxt] 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
nstrcpy(char *to, char *from, int len)
|
||||||
|
{
|
||||||
|
strncpy(to, from, len);
|
||||||
|
to[len-1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
opendatabase(void)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
Ndb *xdb;
|
||||||
|
|
||||||
|
if(db == nil){
|
||||||
|
snprint(buf, sizeof(buf), "%s/ndb", mntpt);
|
||||||
|
xdb = ndbopen(dbfile);
|
||||||
|
if(xdb != nil)
|
||||||
|
xdb->nohash = 1;
|
||||||
|
db = ndbcat(ndbopen(buf), xdb);
|
||||||
|
}
|
||||||
|
if(db == nil)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lookup an RR in the network database, look for matches
|
||||||
|
* against both the domain name and the wildcarded domain name.
|
||||||
|
*
|
||||||
|
* the lock makes sure only one process can be accessing the data
|
||||||
|
* base at a time. This is important since there's a lot of
|
||||||
|
* shared state there.
|
||||||
|
*
|
||||||
|
* e.g. for x.research.bell-labs.com, first look for a match against
|
||||||
|
* the x.research.bell-labs.com. If nothing matches, try *.research.bell-labs.com.
|
||||||
|
*/
|
||||||
|
RR*
|
||||||
|
dblookup(char *name, int class, int type, int auth, int ttl)
|
||||||
|
{
|
||||||
|
RR *rp, *tp;
|
||||||
|
char buf[256];
|
||||||
|
char *wild, *cp;
|
||||||
|
DN *dp, *ndp;
|
||||||
|
int err;
|
||||||
|
static int parallel;
|
||||||
|
static int parfd[2];
|
||||||
|
static char token[1];
|
||||||
|
|
||||||
|
/* so far only internet lookups are implemented */
|
||||||
|
if(class != Cin)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err = Rname;
|
||||||
|
|
||||||
|
if(type == Tall){
|
||||||
|
rp = 0;
|
||||||
|
for (type = Ta; type < Tall; type++)
|
||||||
|
if(implemented[type])
|
||||||
|
rrcat(&rp, dblookup(name, class, type, auth, ttl));
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock(&dblock);
|
||||||
|
dp = dnlookup(name, class, 1);
|
||||||
|
if(opendatabase() < 0)
|
||||||
|
goto out;
|
||||||
|
if(dp->rr)
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
/* first try the given name */
|
||||||
|
rp = 0;
|
||||||
|
if(cachedb)
|
||||||
|
rp = rrlookup(dp, type, NOneg);
|
||||||
|
else
|
||||||
|
rp = dblookup1(name, type, auth, ttl);
|
||||||
|
if(rp)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* try lower case version */
|
||||||
|
for(cp = name; *cp; cp++)
|
||||||
|
*cp = tolower(*cp);
|
||||||
|
if(cachedb)
|
||||||
|
rp = rrlookup(dp, type, NOneg);
|
||||||
|
else
|
||||||
|
rp = dblookup1(name, type, auth, ttl);
|
||||||
|
if(rp)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* walk the domain name trying the wildcard '*' at each position */
|
||||||
|
for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){
|
||||||
|
snprint(buf, sizeof(buf), "*%s", wild);
|
||||||
|
ndp = dnlookup(buf, class, 1);
|
||||||
|
if(ndp->rr)
|
||||||
|
err = 0;
|
||||||
|
if(cachedb)
|
||||||
|
rp = rrlookup(ndp, type, NOneg);
|
||||||
|
else
|
||||||
|
rp = dblookup1(buf, type, auth, ttl);
|
||||||
|
if(rp)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
/* add owner to uncached records */
|
||||||
|
if(rp){
|
||||||
|
for(tp = rp; tp; tp = tp->next)
|
||||||
|
tp->owner = dp;
|
||||||
|
} else {
|
||||||
|
/* don't call it non-existent if it's not ours */
|
||||||
|
if(err == Rname && !inmyarea(name))
|
||||||
|
err = Rserver;
|
||||||
|
dp->nonexistent = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock(&dblock);
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lookup an RR in the network database
|
||||||
|
*/
|
||||||
|
static RR*
|
||||||
|
dblookup1(char *name, int type, int auth, int ttl)
|
||||||
|
{
|
||||||
|
Ndbtuple *t, *nt;
|
||||||
|
RR *rp, *list, **l;
|
||||||
|
Ndbs s;
|
||||||
|
char dname[Domlen];
|
||||||
|
char *attr;
|
||||||
|
DN *dp;
|
||||||
|
RR *(*f)(Ndbtuple*, Ndbtuple*);
|
||||||
|
int found, x;
|
||||||
|
|
||||||
|
dp = 0;
|
||||||
|
switch(type){
|
||||||
|
case Tptr:
|
||||||
|
attr = "ptr";
|
||||||
|
f = ptrrr;
|
||||||
|
break;
|
||||||
|
case Ta:
|
||||||
|
attr = "ip";
|
||||||
|
f = addrrr;
|
||||||
|
break;
|
||||||
|
case Tnull:
|
||||||
|
attr = "nullrr";
|
||||||
|
f = nullrr;
|
||||||
|
break;
|
||||||
|
case Tns:
|
||||||
|
attr = "ns";
|
||||||
|
f = nsrr;
|
||||||
|
break;
|
||||||
|
case Tsoa:
|
||||||
|
attr = "soa";
|
||||||
|
f = soarr;
|
||||||
|
break;
|
||||||
|
case Tmx:
|
||||||
|
attr = "mx";
|
||||||
|
f = mxrr;
|
||||||
|
break;
|
||||||
|
case Tcname:
|
||||||
|
attr = "cname";
|
||||||
|
f = cnamerr;
|
||||||
|
break;
|
||||||
|
case Taxfr:
|
||||||
|
case Tixfr:
|
||||||
|
return doaxfr(db, name);
|
||||||
|
default:
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find a matching entry in the database
|
||||||
|
*/
|
||||||
|
free(ndbgetvalue(db, &s, "dom", name, attr, &t));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hack for local names
|
||||||
|
*/
|
||||||
|
if(t == 0 && strchr(name, '.') == 0)
|
||||||
|
free(ndbgetvalue(db, &s, "sys", name, attr, &t));
|
||||||
|
if(t == 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
/* search whole entry for default domain name */
|
||||||
|
strncpy(dname, name, sizeof dname);
|
||||||
|
for(nt = t; nt; nt = nt->entry)
|
||||||
|
if(strcmp(nt->attr, "dom") == 0){
|
||||||
|
nstrcpy(dname, nt->val, sizeof dname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ttl is maximum of soa minttl and entry's ttl ala rfc883 */
|
||||||
|
nt = look(t, s.t, "ttl");
|
||||||
|
if(nt){
|
||||||
|
x = atoi(nt->val);
|
||||||
|
if(x > ttl)
|
||||||
|
ttl = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default ttl is one day */
|
||||||
|
if(ttl < 0)
|
||||||
|
ttl = DEFTTL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The database has 2 levels of precedence; line and entry.
|
||||||
|
* Pairs on the same line bind tighter than pairs in the
|
||||||
|
* same entry, so we search the line first.
|
||||||
|
*/
|
||||||
|
found = 0;
|
||||||
|
list = 0;
|
||||||
|
l = &list;
|
||||||
|
for(nt = s.t;; ){
|
||||||
|
if(found == 0 && strcmp(nt->attr, "dom") == 0){
|
||||||
|
nstrcpy(dname, nt->val, sizeof dname);
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
if(cistrcmp(attr, nt->attr) == 0){
|
||||||
|
rp = (*f)(t, nt);
|
||||||
|
rp->auth = auth;
|
||||||
|
rp->db = 1;
|
||||||
|
if(ttl)
|
||||||
|
rp->ttl = ttl;
|
||||||
|
if(dp == 0)
|
||||||
|
dp = dnlookup(dname, Cin, 1);
|
||||||
|
rp->owner = dp;
|
||||||
|
*l = rp;
|
||||||
|
l = &rp->next;
|
||||||
|
nt->ptr = 1;
|
||||||
|
}
|
||||||
|
nt = nt->line;
|
||||||
|
if(nt == s.t)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* search whole entry */
|
||||||
|
for(nt = t; nt; nt = nt->entry)
|
||||||
|
if(nt->ptr == 0 && cistrcmp(attr, nt->attr) == 0){
|
||||||
|
rp = (*f)(t, nt);
|
||||||
|
rp->db = 1;
|
||||||
|
if(ttl)
|
||||||
|
rp->ttl = ttl;
|
||||||
|
rp->auth = auth;
|
||||||
|
if(dp == 0)
|
||||||
|
dp = dnlookup(dname, Cin, 1);
|
||||||
|
rp->owner = dp;
|
||||||
|
*l = rp;
|
||||||
|
l = &rp->next;
|
||||||
|
}
|
||||||
|
ndbfree(t);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* make various types of resource records from a database entry
|
||||||
|
*/
|
||||||
|
static RR*
|
||||||
|
addrrr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
uchar addr[IPaddrlen];
|
||||||
|
|
||||||
|
USED(entry);
|
||||||
|
parseip(addr, pair->val);
|
||||||
|
if(isv4(addr))
|
||||||
|
rp = rralloc(Ta);
|
||||||
|
else
|
||||||
|
rp = rralloc(Taaaa);
|
||||||
|
rp->ip = dnlookup(pair->val, Cin, 1);
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
static RR*
|
||||||
|
nullrr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
USED(entry);
|
||||||
|
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
|
||||||
|
* can represent longer strings by multiple concatenated
|
||||||
|
* <= 255 byte ones.
|
||||||
|
*/
|
||||||
|
static RR*
|
||||||
|
txtrr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
Txt *t, **l;
|
||||||
|
int i, len, sofar;
|
||||||
|
|
||||||
|
USED(entry);
|
||||||
|
rp = rralloc(Ttxt);
|
||||||
|
l = &rp->txt;
|
||||||
|
rp->txt = nil;
|
||||||
|
len = strlen(pair->val);
|
||||||
|
sofar = 0;
|
||||||
|
while(len > sofar){
|
||||||
|
t = emalloc(sizeof(*t));
|
||||||
|
t->next = nil;
|
||||||
|
|
||||||
|
i = len-sofar;
|
||||||
|
if(i > 255)
|
||||||
|
i = 255;
|
||||||
|
|
||||||
|
t->p = emalloc(i+1);
|
||||||
|
memmove(t->p, pair->val+sofar, i);
|
||||||
|
t->p[i] = 0;
|
||||||
|
sofar += i;
|
||||||
|
|
||||||
|
*l = t;
|
||||||
|
l = &t->next;
|
||||||
|
}
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
static RR*
|
||||||
|
cnamerr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
USED(entry);
|
||||||
|
rp = rralloc(Tcname);
|
||||||
|
rp->host = dnlookup(pair->val, Cin, 1);
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
static RR*
|
||||||
|
mxrr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR * rp;
|
||||||
|
|
||||||
|
rp = rralloc(Tmx);
|
||||||
|
rp->host = dnlookup(pair->val, Cin, 1);
|
||||||
|
pair = look(entry, pair, "pref");
|
||||||
|
if(pair)
|
||||||
|
rp->pref = atoi(pair->val);
|
||||||
|
else
|
||||||
|
rp->pref = 1;
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
static RR*
|
||||||
|
nsrr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
Ndbtuple *t;
|
||||||
|
|
||||||
|
rp = rralloc(Tns);
|
||||||
|
rp->host = dnlookup(pair->val, Cin, 1);
|
||||||
|
t = look(entry, pair, "soa");
|
||||||
|
if(t && t->val[0] == 0)
|
||||||
|
rp->local = 1;
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
static RR*
|
||||||
|
ptrrr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
USED(entry);
|
||||||
|
rp = rralloc(Tns);
|
||||||
|
rp->ptr = dnlookup(pair->val, Cin, 1);
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
static RR*
|
||||||
|
soarr(Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
Ndbtuple *ns, *mb, *t;
|
||||||
|
char mailbox[Domlen];
|
||||||
|
Ndb *ndb;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
rp = rralloc(Tsoa);
|
||||||
|
rp->soa->serial = 1;
|
||||||
|
for(ndb = db; ndb; ndb = ndb->next)
|
||||||
|
if(ndb->mtime > rp->soa->serial)
|
||||||
|
rp->soa->serial = ndb->mtime;
|
||||||
|
rp->soa->refresh = Day;
|
||||||
|
rp->soa->retry = Hour;
|
||||||
|
rp->soa->expire = Day;
|
||||||
|
rp->soa->minttl = Day;
|
||||||
|
t = look(entry, pair, "ttl");
|
||||||
|
if(t)
|
||||||
|
rp->soa->minttl = atoi(t->val);
|
||||||
|
t = look(entry, pair, "refresh");
|
||||||
|
if(t)
|
||||||
|
rp->soa->refresh = atoi(t->val);
|
||||||
|
t = look(entry, pair, "serial");
|
||||||
|
if(t)
|
||||||
|
rp->soa->serial = strtoul(t->val, 0, 10);
|
||||||
|
|
||||||
|
ns = look(entry, pair, "ns");
|
||||||
|
if(ns == 0)
|
||||||
|
ns = look(entry, pair, "dom");
|
||||||
|
rp->host = dnlookup(ns->val, Cin, 1);
|
||||||
|
|
||||||
|
/* accept all of:
|
||||||
|
* mbox=person
|
||||||
|
* mbox=person@machine.dom
|
||||||
|
* mbox=person.machine.dom
|
||||||
|
*/
|
||||||
|
mb = look(entry, pair, "mbox");
|
||||||
|
if(mb == nil)
|
||||||
|
mb = look(entry, pair, "mb");
|
||||||
|
if(mb){
|
||||||
|
if(strchr(mb->val, '.')) {
|
||||||
|
p = strchr(mb->val, '@');
|
||||||
|
if(p != nil)
|
||||||
|
*p = '.';
|
||||||
|
rp->rmb = dnlookup(mb->val, Cin, 1);
|
||||||
|
} else {
|
||||||
|
snprint(mailbox, sizeof(mailbox), "%s.%s",
|
||||||
|
mb->val, ns->val);
|
||||||
|
rp->rmb = dnlookup(mailbox, Cin, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snprint(mailbox, sizeof(mailbox), "postmaster.%s",
|
||||||
|
ns->val);
|
||||||
|
rp->rmb = dnlookup(mailbox, Cin, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hang dns slaves off of the soa. this is
|
||||||
|
* for managing the area.
|
||||||
|
*/
|
||||||
|
for(t = entry; t != nil; t = t->entry)
|
||||||
|
if(strcmp(t->attr, "dnsslave") == 0)
|
||||||
|
addserver(&rp->soa->slaves, t->val);
|
||||||
|
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for a pair with the given attribute. look first on the same line,
|
||||||
|
* then in the whole entry.
|
||||||
|
*/
|
||||||
|
static Ndbtuple*
|
||||||
|
look(Ndbtuple *entry, Ndbtuple *line, char *attr)
|
||||||
|
{
|
||||||
|
Ndbtuple *nt;
|
||||||
|
|
||||||
|
/* first look on same line (closer binding) */
|
||||||
|
for(nt = line;;){
|
||||||
|
if(cistrcmp(attr, nt->attr) == 0)
|
||||||
|
return nt;
|
||||||
|
nt = nt->line;
|
||||||
|
if(nt == line)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* search whole tuple */
|
||||||
|
for(nt = entry; nt; nt = nt->entry)
|
||||||
|
if(cistrcmp(attr, nt->attr) == 0)
|
||||||
|
return nt;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RR**
|
||||||
|
linkrr(RR *rp, DN *dp, RR **l)
|
||||||
|
{
|
||||||
|
rp->owner = dp;
|
||||||
|
rp->auth = 1;
|
||||||
|
rp->db = 1;
|
||||||
|
*l = rp;
|
||||||
|
return &rp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* these are answered specially by the tcp version */
|
||||||
|
static RR*
|
||||||
|
doaxfr(Ndb *db, char *name)
|
||||||
|
{
|
||||||
|
USED(db);
|
||||||
|
USED(name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read the all the soa's from the database to determine area's.
|
||||||
|
* this is only used when we're not caching the database.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dbfile2area(Ndb *db)
|
||||||
|
{
|
||||||
|
Ndbtuple *t;
|
||||||
|
|
||||||
|
if(debug)
|
||||||
|
syslog(0, logfile, "rereading %s", db->file);
|
||||||
|
Bseek(&db->b, 0, 0);
|
||||||
|
while(t = ndbparse(db)){
|
||||||
|
ndbfree(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read the database into the cache
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
Ndbtuple *t;
|
||||||
|
static ulong ord;
|
||||||
|
|
||||||
|
rp = 0;
|
||||||
|
if(cistrcmp(pair->attr, "ip") == 0){
|
||||||
|
dp->ordinal = ord++;
|
||||||
|
rp = addrrr(entry, pair);
|
||||||
|
} else if(cistrcmp(pair->attr, "ns") == 0){
|
||||||
|
rp = nsrr(entry, pair);
|
||||||
|
} else if(cistrcmp(pair->attr, "soa") == 0){
|
||||||
|
rp = soarr(entry, pair);
|
||||||
|
addarea(dp, rp, pair);
|
||||||
|
} else if(cistrcmp(pair->attr, "mx") == 0){
|
||||||
|
rp = mxrr(entry, pair);
|
||||||
|
} else if(cistrcmp(pair->attr, "cname") == 0){
|
||||||
|
rp = cnamerr(entry, pair);
|
||||||
|
} else if(cistrcmp(pair->attr, "nullrr") == 0){
|
||||||
|
rp = nullrr(entry, pair);
|
||||||
|
} else if(cistrcmp(pair->attr, "txtrr") == 0){
|
||||||
|
rp = txtrr(entry, pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rp == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rp->owner = dp;
|
||||||
|
rp->db = 1;
|
||||||
|
t = look(entry, pair, "ttl");
|
||||||
|
if(t)
|
||||||
|
rp->ttl = atoi(t->val);
|
||||||
|
rrattach(rp, 0);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
dbtuple2cache(Ndbtuple *t)
|
||||||
|
{
|
||||||
|
Ndbtuple *et, *nt;
|
||||||
|
DN *dp;
|
||||||
|
|
||||||
|
for(et = t; et; et = et->entry){
|
||||||
|
if(strcmp(et->attr, "dom") == 0){
|
||||||
|
dp = dnlookup(et->val, Cin, 1);
|
||||||
|
|
||||||
|
/* first same line */
|
||||||
|
for(nt = et->line; nt != et; nt = nt->line){
|
||||||
|
dbpair2cache(dp, t, nt);
|
||||||
|
nt->ptr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* then rest of entry */
|
||||||
|
for(nt = t; nt; nt = nt->entry){
|
||||||
|
if(nt->ptr == 0)
|
||||||
|
dbpair2cache(dp, t, nt);
|
||||||
|
nt->ptr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
dbfile2cache(Ndb *db)
|
||||||
|
{
|
||||||
|
Ndbtuple *t;
|
||||||
|
|
||||||
|
if(debug)
|
||||||
|
syslog(0, logfile, "rereading %s", db->file);
|
||||||
|
Bseek(&db->b, 0, 0);
|
||||||
|
while(t = ndbparse(db)){
|
||||||
|
dbtuple2cache(t);
|
||||||
|
ndbfree(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void
|
||||||
|
db2cache(int doit)
|
||||||
|
{
|
||||||
|
Ndb *ndb;
|
||||||
|
Dir *d;
|
||||||
|
ulong youngest, temp;
|
||||||
|
static ulong lastcheck;
|
||||||
|
static ulong lastyoungest;
|
||||||
|
|
||||||
|
/* no faster than once every 2 minutes */
|
||||||
|
if(now < lastcheck + 2*Min && !doit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
refresh_areas(owned);
|
||||||
|
|
||||||
|
lock(&dblock);
|
||||||
|
|
||||||
|
if(opendatabase() < 0){
|
||||||
|
unlock(&dblock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* file may be changing as we are reading it, so loop till
|
||||||
|
* mod times are consistent.
|
||||||
|
*
|
||||||
|
* we don't use the times in the ndb records because they may
|
||||||
|
* change outside of refreshing our cached knowledge.
|
||||||
|
*/
|
||||||
|
for(;;){
|
||||||
|
lastcheck = now;
|
||||||
|
youngest = 0;
|
||||||
|
for(ndb = db; ndb; ndb = ndb->next){
|
||||||
|
/* the dirfstat avoids walking the mount table each time */
|
||||||
|
if((d = dirfstat(Bfildes(&ndb->b))) != nil ||
|
||||||
|
(d = dirstat(ndb->file)) != nil){
|
||||||
|
temp = d->mtime; /* ulong vs int crap */
|
||||||
|
if(temp > youngest)
|
||||||
|
youngest = temp;
|
||||||
|
free(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!doit && youngest == lastyoungest){
|
||||||
|
unlock(&dblock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* forget our area definition */
|
||||||
|
freearea(&owned);
|
||||||
|
freearea(&delegated);
|
||||||
|
|
||||||
|
/* reopen all the files (to get oldest for time stamp) */
|
||||||
|
for(ndb = db; ndb; ndb = ndb->next)
|
||||||
|
ndbreopen(ndb);
|
||||||
|
|
||||||
|
if(cachedb){
|
||||||
|
/* mark all db records as timed out */
|
||||||
|
dnagedb();
|
||||||
|
|
||||||
|
/* read in new entries */
|
||||||
|
for(ndb = db; ndb; ndb = ndb->next)
|
||||||
|
dbfile2cache(ndb);
|
||||||
|
|
||||||
|
/* mark as authentic anything in our domain */
|
||||||
|
dnauthdb();
|
||||||
|
|
||||||
|
/* remove old entries */
|
||||||
|
dnageall(1);
|
||||||
|
} else {
|
||||||
|
/* read all the soa's to get database defaults */
|
||||||
|
for(ndb = db; ndb; ndb = ndb->next)
|
||||||
|
dbfile2area(ndb);
|
||||||
|
}
|
||||||
|
|
||||||
|
doit = 0;
|
||||||
|
lastyoungest = youngest;
|
||||||
|
createptrs();
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock(&dblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern uchar ipaddr[IPaddrlen];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get all my xxx
|
||||||
|
*/
|
||||||
|
Ndbtuple*
|
||||||
|
lookupinfo(char *attr)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
char *a[2];
|
||||||
|
static Ndbtuple *t;
|
||||||
|
|
||||||
|
snprint(buf, sizeof buf, "%I", ipaddr);
|
||||||
|
a[0] = attr;
|
||||||
|
|
||||||
|
lock(&dblock);
|
||||||
|
if(opendatabase() < 0){
|
||||||
|
unlock(&dblock);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
t = ndbipinfo(db, "ip", buf, a, 1);
|
||||||
|
unlock(&dblock);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *localservers = "local#dns#servers";
|
||||||
|
char *localserverprefix = "local#dns#server";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return non-zero is this is a bad delegation
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
baddelegation(RR *rp, RR *nsrp, uchar *addr)
|
||||||
|
{
|
||||||
|
Ndbtuple *nt;
|
||||||
|
static Ndbtuple *t;
|
||||||
|
|
||||||
|
if(t == nil)
|
||||||
|
t = lookupinfo("dom");
|
||||||
|
if(t == nil)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(; rp; rp = rp->next){
|
||||||
|
if(rp->type != Tns)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* see if delegation is looping */
|
||||||
|
if(nsrp)
|
||||||
|
if(rp->owner != nsrp->owner)
|
||||||
|
if(subsume(rp->owner->name, nsrp->owner->name) &&
|
||||||
|
strcmp(nsrp->owner->name, localservers) != 0){
|
||||||
|
syslog(0, logfile, "delegation loop %R -> %R from %I", nsrp, rp, addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see if delegating to us what we don't own */
|
||||||
|
for(nt = t; nt != nil; nt = nt->entry)
|
||||||
|
if(rp->host && cistrcmp(rp->host->name, nt->val) == 0)
|
||||||
|
break;
|
||||||
|
if(nt != nil && !inmyarea(rp->owner->name)){
|
||||||
|
syslog(0, logfile, "bad delegation %R from %I", rp, addr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
|
||||||
|
{
|
||||||
|
DN *nsdp;
|
||||||
|
RR *rp;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
/* ns record for name server, make up an impossible name */
|
||||||
|
rp = rralloc(Tns);
|
||||||
|
snprint(buf, sizeof(buf), "%s%d", localserverprefix, i);
|
||||||
|
nsdp = dnlookup(buf, class, 1);
|
||||||
|
rp->host = nsdp;
|
||||||
|
rp->owner = dp;
|
||||||
|
rp->local = 1;
|
||||||
|
rp->db = 1;
|
||||||
|
rp->ttl = 10*Min;
|
||||||
|
rrattach(rp, 1);
|
||||||
|
|
||||||
|
print("dns %s\n", ipaddr);
|
||||||
|
/* A record */
|
||||||
|
rp = rralloc(Ta);
|
||||||
|
rp->ip = dnlookup(ipaddr, class, 1);
|
||||||
|
rp->owner = nsdp;
|
||||||
|
rp->local = 1;
|
||||||
|
rp->db = 1;
|
||||||
|
rp->ttl = 10*Min;
|
||||||
|
rrattach(rp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return list of dns server addresses to use when
|
||||||
|
* acting just as a resolver.
|
||||||
|
*/
|
||||||
|
RR*
|
||||||
|
dnsservers(int class)
|
||||||
|
{
|
||||||
|
Ndbtuple *t, *nt;
|
||||||
|
RR *nsrp;
|
||||||
|
DN *dp;
|
||||||
|
char *p;
|
||||||
|
int i, n;
|
||||||
|
char *buf, *args[5];
|
||||||
|
|
||||||
|
dp = dnlookup(localservers, class, 1);
|
||||||
|
nsrp = rrlookup(dp, Tns, NOneg);
|
||||||
|
if(nsrp != nil)
|
||||||
|
return nsrp;
|
||||||
|
|
||||||
|
p = getenv("DNSSERVER");
|
||||||
|
if(p != nil){
|
||||||
|
buf = estrdup(p);
|
||||||
|
n = tokenize(buf, args, nelem(args));
|
||||||
|
for(i = 0; i < n; i++)
|
||||||
|
addlocaldnsserver(dp, class, args[i], i);
|
||||||
|
free(buf);
|
||||||
|
} else {
|
||||||
|
t = lookupinfo("@dns");
|
||||||
|
if(t == nil)
|
||||||
|
return nil;
|
||||||
|
i = 0;
|
||||||
|
for(nt = t; nt != nil; nt = nt->entry){
|
||||||
|
addlocaldnsserver(dp, class, nt->val, i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ndbfree(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rrlookup(dp, Tns, NOneg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
addlocaldnsdomain(DN *dp, int class, char *domain)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
/* A record */
|
||||||
|
rp = rralloc(Tptr);
|
||||||
|
rp->ptr = dnlookup(domain, class, 1);
|
||||||
|
rp->owner = dp;
|
||||||
|
rp->db = 1;
|
||||||
|
rp->ttl = 10*Min;
|
||||||
|
rrattach(rp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return list of domains to use when resolving names without '.'s
|
||||||
|
*/
|
||||||
|
RR*
|
||||||
|
domainlist(int class)
|
||||||
|
{
|
||||||
|
Ndbtuple *t, *nt;
|
||||||
|
RR *rp;
|
||||||
|
DN *dp;
|
||||||
|
|
||||||
|
dp = dnlookup("local#dns#domains", class, 1);
|
||||||
|
rp = rrlookup(dp, Tptr, NOneg);
|
||||||
|
if(rp != nil)
|
||||||
|
return rp;
|
||||||
|
|
||||||
|
t = lookupinfo("dnsdomain");
|
||||||
|
if(t == nil)
|
||||||
|
return nil;
|
||||||
|
for(nt = t; nt != nil; nt = nt->entry)
|
||||||
|
addlocaldnsdomain(dp, class, nt->val);
|
||||||
|
ndbfree(t);
|
||||||
|
|
||||||
|
return rrlookup(dp, Tptr, NOneg);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *v4ptrdom = ".in-addr.arpa";
|
||||||
|
char *v6ptrdom = ".ip6.arpa"; /* ip6.int deprecated, rfc 3152 */
|
||||||
|
|
||||||
|
char *attribs[] = {
|
||||||
|
"ipmask",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create ptrs that are in our areas
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
createptrs(void)
|
||||||
|
{
|
||||||
|
int len, dlen, n;
|
||||||
|
Area *s;
|
||||||
|
char *f[40];
|
||||||
|
char buf[Domlen+1];
|
||||||
|
uchar net[IPaddrlen];
|
||||||
|
uchar mask[IPaddrlen];
|
||||||
|
char ipa[48];
|
||||||
|
Ndbtuple *t, *nt;
|
||||||
|
|
||||||
|
dlen = strlen(v4ptrdom);
|
||||||
|
for(s = owned; s; s = s->next){
|
||||||
|
len = strlen(s->soarr->owner->name);
|
||||||
|
if(len <= dlen)
|
||||||
|
continue;
|
||||||
|
if(cistrcmp(s->soarr->owner->name+len-dlen, v4ptrdom) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* get mask and net value */
|
||||||
|
strncpy(buf, s->soarr->owner->name, sizeof(buf));
|
||||||
|
buf[sizeof(buf)-1] = 0;
|
||||||
|
n = getfields(buf, f, nelem(f), 0, ".");
|
||||||
|
memset(mask, 0xff, IPaddrlen);
|
||||||
|
ipmove(net, v4prefix);
|
||||||
|
switch(n){
|
||||||
|
case 3: /* /8 */
|
||||||
|
net[IPv4off] = atoi(f[0]);
|
||||||
|
mask[IPv4off+1] = 0;
|
||||||
|
mask[IPv4off+2] = 0;
|
||||||
|
mask[IPv4off+3] = 0;
|
||||||
|
break;
|
||||||
|
case 4: /* /16 */
|
||||||
|
net[IPv4off] = atoi(f[1]);
|
||||||
|
net[IPv4off+1] = atoi(f[0]);
|
||||||
|
mask[IPv4off+2] = 0;
|
||||||
|
mask[IPv4off+3] = 0;
|
||||||
|
break;
|
||||||
|
case 5: /* /24 */
|
||||||
|
net[IPv4off] = atoi(f[2]);
|
||||||
|
net[IPv4off+1] = atoi(f[1]);
|
||||||
|
net[IPv4off+2] = atoi(f[0]);
|
||||||
|
mask[IPv4off+3] = 0;
|
||||||
|
break;
|
||||||
|
case 6: /* rfc2317 */
|
||||||
|
net[IPv4off] = atoi(f[3]);
|
||||||
|
net[IPv4off+1] = atoi(f[2]);
|
||||||
|
net[IPv4off+2] = atoi(f[1]);
|
||||||
|
net[IPv4off+3] = atoi(f[0]);
|
||||||
|
sprint(ipa, "%I", net);
|
||||||
|
t = ndbipinfo(db, "ip", ipa, attribs, 1);
|
||||||
|
if(t == nil) /* could be a reverse with no forward */
|
||||||
|
continue;
|
||||||
|
nt = look(t, t, "ipmask");
|
||||||
|
if(nt == nil){ /* we're confused */
|
||||||
|
ndbfree(t);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parseipmask(mask, nt->val);
|
||||||
|
n = 5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* go through all domain entries looking for RR's in this network and create ptrs */
|
||||||
|
dnptr(net, mask, s->soarr->owner->name, 6-n, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
1563
src/cmd/ndb/dn.c
Executable file
1563
src/cmd/ndb/dn.c
Executable file
File diff suppressed because it is too large
Load Diff
130
src/cmd/ndb/dnarea.c
Executable file
130
src/cmd/ndb/dnarea.c
Executable file
@ -0,0 +1,130 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
Area *owned;
|
||||||
|
Area *delegated;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* true if a name is in our area
|
||||||
|
*/
|
||||||
|
Area*
|
||||||
|
inmyarea(char *name)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
Area *s, *d;
|
||||||
|
|
||||||
|
len = strlen(name);
|
||||||
|
for(s = owned; s; s = s->next){
|
||||||
|
if(s->len > len)
|
||||||
|
continue;
|
||||||
|
if(cistrcmp(s->soarr->owner->name, name + len - s->len) == 0)
|
||||||
|
if(len == s->len || name[len - s->len - 1] == '.')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(s == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(d = delegated; d; d = d->next){
|
||||||
|
if(d->len > len)
|
||||||
|
continue;
|
||||||
|
if(cistrcmp(d->soarr->owner->name, name + len - d->len) == 0)
|
||||||
|
if(len == d->len || name[len - d->len - 1] == '.')
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* our area is the part of the domain tree that
|
||||||
|
* we serve
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
addarea(DN *dp, RR *rp, Ndbtuple *t)
|
||||||
|
{
|
||||||
|
Area **l, *s;
|
||||||
|
|
||||||
|
if(t->val[0])
|
||||||
|
l = &delegated;
|
||||||
|
else
|
||||||
|
l = &owned;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The area contains a copy of the soa rr that created it.
|
||||||
|
* The owner of the the soa rr should stick around as long
|
||||||
|
* as the area does.
|
||||||
|
*/
|
||||||
|
s = emalloc(sizeof(*s));
|
||||||
|
s->len = strlen(dp->name);
|
||||||
|
rrcopy(rp, &s->soarr);
|
||||||
|
s->soarr->owner = dp;
|
||||||
|
s->soarr->db = 1;
|
||||||
|
s->soarr->ttl = Hour;
|
||||||
|
s->neednotify = 1;
|
||||||
|
s->needrefresh = 0;
|
||||||
|
|
||||||
|
syslog(0, logfile, "new area %s", dp->name);
|
||||||
|
|
||||||
|
s->next = *l;
|
||||||
|
*l = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freearea(Area **l)
|
||||||
|
{
|
||||||
|
Area *s;
|
||||||
|
|
||||||
|
while(s = *l){
|
||||||
|
*l = s->next;
|
||||||
|
rrfree(s->soarr);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* refresh all areas that need it
|
||||||
|
* this entails running a command 'zonerefreshprogram'. This could
|
||||||
|
* copy over databases from elsewhere or just do a zone transfer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
refresh_areas(Area *s)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
Waitmsg *w;
|
||||||
|
|
||||||
|
for(; s != nil; s = s->next){
|
||||||
|
if(!s->needrefresh)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(zonerefreshprogram == nil){
|
||||||
|
s->needrefresh = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(pid = fork()){
|
||||||
|
case -1:
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
execl(zonerefreshprogram, "zonerefresh", s->soarr->owner->name, 0);
|
||||||
|
exits(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for(;;){
|
||||||
|
w = wait();
|
||||||
|
if(w == nil)
|
||||||
|
break;
|
||||||
|
if(w->pid == pid){
|
||||||
|
if(w->msg == nil || *w->msg == 0)
|
||||||
|
s->needrefresh = 0;
|
||||||
|
free(w);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
160
src/cmd/ndb/dnnotify.c
Executable file
160
src/cmd/ndb/dnnotify.c
Executable file
@ -0,0 +1,160 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
/* get a notification from another system of a changed zone */
|
||||||
|
void
|
||||||
|
dnnotify(DNSmsg *reqp, DNSmsg *repp, Request *r)
|
||||||
|
{
|
||||||
|
RR *tp;
|
||||||
|
Area *a;
|
||||||
|
|
||||||
|
USED(r);
|
||||||
|
/* move one question from reqp to repp */
|
||||||
|
memset(repp, 0, sizeof(*repp));
|
||||||
|
tp = reqp->qd;
|
||||||
|
reqp->qd = tp->next;
|
||||||
|
tp->next = 0;
|
||||||
|
repp->qd = tp;
|
||||||
|
repp->id = reqp->id;
|
||||||
|
repp->flags = Fresp | Onotify | Fauth;
|
||||||
|
|
||||||
|
/* anything to do? */
|
||||||
|
if(zonerefreshprogram == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* make sure its the right type */
|
||||||
|
if(repp->qd->type != Tsoa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
syslog(0, logfile, "notification for %s", repp->qd->owner->name);
|
||||||
|
|
||||||
|
/* is it something we care about? */
|
||||||
|
a = inmyarea(repp->qd->owner->name);
|
||||||
|
if(a == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
syslog(0, logfile, "serial old %lud new %lud", a->soarr->soa->serial, repp->qd->soa->serial);
|
||||||
|
|
||||||
|
/* do nothing if it didn't change */
|
||||||
|
if(a->soarr->soa->serial== repp->qd->soa->serial)
|
||||||
|
return;
|
||||||
|
|
||||||
|
a->needrefresh = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ding(void *u, char *msg)
|
||||||
|
{
|
||||||
|
USED(u);
|
||||||
|
|
||||||
|
if(strstr(msg, "alarm"))
|
||||||
|
noted(NCONT);
|
||||||
|
else
|
||||||
|
noted(NDFLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* notify a slave that an area has changed. */
|
||||||
|
static void
|
||||||
|
send_notify(char *slave, RR *soa, Request *req)
|
||||||
|
{
|
||||||
|
int i, len, n, reqno, status, fd;
|
||||||
|
uchar obuf[Maxudp+OUdphdrsize];
|
||||||
|
uchar ibuf[Maxudp+OUdphdrsize];
|
||||||
|
RR *rp;
|
||||||
|
OUdphdr *up = (OUdphdr*)obuf;
|
||||||
|
char *err;
|
||||||
|
DNSmsg repmsg;
|
||||||
|
|
||||||
|
/* create the request */
|
||||||
|
reqno = rand();
|
||||||
|
n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno);
|
||||||
|
|
||||||
|
/* get an address */
|
||||||
|
if(strcmp(ipattr(slave), "ip") == 0) {
|
||||||
|
parseip(up->raddr, slave);
|
||||||
|
} else {
|
||||||
|
rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status);
|
||||||
|
if(rp == nil)
|
||||||
|
return;
|
||||||
|
parseip(up->raddr, rp->ip->name);
|
||||||
|
rrfree(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = udpport();
|
||||||
|
if(fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
notify(ding);
|
||||||
|
|
||||||
|
/* send 3 times or until we get anything back */
|
||||||
|
for(i = 0; i < 3; i++){
|
||||||
|
syslog(0, logfile, "sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name);
|
||||||
|
if(udpwrite(fd, (OUdphdr*)obuf, obuf+OUdphdrsize, n) != n)
|
||||||
|
break;
|
||||||
|
alarm(2*1000);
|
||||||
|
len = udpread(fd, (Udphdr*)ibuf, ibuf+OUdphdrsize, Maxudp);
|
||||||
|
alarm(0);
|
||||||
|
if(len <= OUdphdrsize)
|
||||||
|
continue;
|
||||||
|
err = convM2DNS(&ibuf[OUdphdrsize], len, &repmsg);
|
||||||
|
if(err != nil)
|
||||||
|
continue;
|
||||||
|
if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send notifies for any updated areas */
|
||||||
|
static void
|
||||||
|
notify_areas(Area *a, Request *req)
|
||||||
|
{
|
||||||
|
Server *s;
|
||||||
|
|
||||||
|
for(; a != nil; a = a->next){
|
||||||
|
if(!a->neednotify)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* send notifies to all slaves */
|
||||||
|
for(s = a->soarr->soa->slaves; s != nil; s = s->next)
|
||||||
|
send_notify(s->name, a->soarr, req);
|
||||||
|
a->neednotify = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* process to notify other servers of changes
|
||||||
|
* (also reads in new databases)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
notifyproc(void)
|
||||||
|
{
|
||||||
|
Request req;
|
||||||
|
static int already;
|
||||||
|
|
||||||
|
if(already)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
|
||||||
|
case -1:
|
||||||
|
return;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.isslave = 1; /* son't fork off subprocesses */
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
getactivity(&req);
|
||||||
|
notify_areas(owned, &req);
|
||||||
|
putactivity();
|
||||||
|
sleep(60*1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
753
src/cmd/ndb/dnresolve.c
Executable file
753
src/cmd/ndb/dnresolve.c
Executable file
@ -0,0 +1,753 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Maxdest= 24, /* maximum destinations for a request message */
|
||||||
|
Maxtrans= 3, /* maximum transmissions to a server */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int netquery(DN*, int, RR*, Request*, int);
|
||||||
|
static RR* dnresolve1(char*, int, int, Request*, int, int);
|
||||||
|
|
||||||
|
char *LOG = "dns";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lookup 'type' info for domain name 'name'. If it doesn't exist, try
|
||||||
|
* looking it up as a canonical name.
|
||||||
|
*/
|
||||||
|
RR*
|
||||||
|
dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, int recurse, int rooted, int *status)
|
||||||
|
{
|
||||||
|
RR *rp, *nrp, *drp;
|
||||||
|
DN *dp;
|
||||||
|
int loops;
|
||||||
|
char nname[Domlen];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
*status = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hack for systems that don't have resolve search
|
||||||
|
* lists. Just look up the simple name in the database.
|
||||||
|
*/
|
||||||
|
if(!rooted && strchr(name, '.') == 0){
|
||||||
|
rp = nil;
|
||||||
|
drp = domainlist(class);
|
||||||
|
for(nrp = drp; nrp != nil; nrp = nrp->next){
|
||||||
|
snprint(nname, sizeof(nname), "%s.%s", name, nrp->ptr->name);
|
||||||
|
rp = dnresolve(nname, class, type, req,cn, depth, recurse, rooted, status);
|
||||||
|
rrfreelist(rrremneg(&rp));
|
||||||
|
if(rp != nil)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(drp != nil)
|
||||||
|
rrfree(drp);
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try the name directly
|
||||||
|
*/
|
||||||
|
rp = dnresolve1(name, class, type, req, depth, recurse);
|
||||||
|
if(rp)
|
||||||
|
return randomize(rp);
|
||||||
|
|
||||||
|
/* try it as a canonical name if we weren't told the name didn't exist */
|
||||||
|
dp = dnlookup(name, class, 0);
|
||||||
|
if(type != Tptr && dp->nonexistent != Rname){
|
||||||
|
for(loops=0; rp == nil && loops < 32; loops++){
|
||||||
|
rp = dnresolve1(name, class, Tcname, req, depth, recurse);
|
||||||
|
if(rp == nil)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(rp->negative){
|
||||||
|
rrfreelist(rp);
|
||||||
|
rp = nil;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = rp->host->name;
|
||||||
|
if(cn)
|
||||||
|
rrcat(cn, rp);
|
||||||
|
else
|
||||||
|
rrfreelist(rp);
|
||||||
|
|
||||||
|
rp = dnresolve1(name, class, type, req, depth, recurse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* distinction between not found and not good */
|
||||||
|
if(rp == 0 && status != 0 && dp->nonexistent != 0)
|
||||||
|
*status = dp->nonexistent;
|
||||||
|
|
||||||
|
return randomize(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RR*
|
||||||
|
dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse)
|
||||||
|
{
|
||||||
|
DN *dp, *nsdp;
|
||||||
|
RR *rp, *nsrp, *dbnsrp;
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
if(debug)
|
||||||
|
syslog(0, LOG, "dnresolve1 %s %d %d", name, type, class);
|
||||||
|
|
||||||
|
/* only class Cin implemented so far */
|
||||||
|
if(class != Cin)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dp = dnlookup(name, class, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try the cache first
|
||||||
|
*/
|
||||||
|
rp = rrlookup(dp, type, OKneg);
|
||||||
|
if(rp){
|
||||||
|
if(rp->db){
|
||||||
|
/* unauthenticated db entries are hints */
|
||||||
|
if(rp->auth)
|
||||||
|
return rp;
|
||||||
|
} else {
|
||||||
|
/* cached entry must still be valid */
|
||||||
|
if(rp->ttl > now){
|
||||||
|
/* but Tall entries are special */
|
||||||
|
if(type != Tall || rp->query == Tall)
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rrfreelist(rp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try the cache for a canonical name. if found punt
|
||||||
|
* since we'll find it during the canonical name search
|
||||||
|
* in dnresolve().
|
||||||
|
*/
|
||||||
|
if(type != Tcname){
|
||||||
|
rp = rrlookup(dp, Tcname, NOneg);
|
||||||
|
rrfreelist(rp);
|
||||||
|
if(rp)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we're running as just a resolver, go to our
|
||||||
|
* designated name servers
|
||||||
|
*/
|
||||||
|
if(resolver){
|
||||||
|
nsrp = randomize(getdnsservers(class));
|
||||||
|
if(nsrp != nil) {
|
||||||
|
if(netquery(dp, type, nsrp, req, depth+1)){
|
||||||
|
rrfreelist(nsrp);
|
||||||
|
return rrlookup(dp, type, OKneg);
|
||||||
|
}
|
||||||
|
rrfreelist(nsrp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* walk up the domain name looking for
|
||||||
|
* a name server for the domain.
|
||||||
|
*/
|
||||||
|
for(cp = name; cp; cp = walkup(cp)){
|
||||||
|
/*
|
||||||
|
* if this is a local (served by us) domain,
|
||||||
|
* return answer
|
||||||
|
*/
|
||||||
|
dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0));
|
||||||
|
if(dbnsrp && dbnsrp->local){
|
||||||
|
rp = dblookup(name, class, type, 1, dbnsrp->ttl);
|
||||||
|
rrfreelist(dbnsrp);
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if recursion isn't set, just accept local
|
||||||
|
* entries
|
||||||
|
*/
|
||||||
|
if(recurse == Dontrecurse){
|
||||||
|
if(dbnsrp)
|
||||||
|
rrfreelist(dbnsrp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for ns in cache */
|
||||||
|
nsdp = dnlookup(cp, class, 0);
|
||||||
|
nsrp = nil;
|
||||||
|
if(nsdp)
|
||||||
|
nsrp = randomize(rrlookup(nsdp, Tns, NOneg));
|
||||||
|
|
||||||
|
/* if the entry timed out, ignore it */
|
||||||
|
if(nsrp && nsrp->ttl < now){
|
||||||
|
rrfreelist(nsrp);
|
||||||
|
nsrp = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nsrp){
|
||||||
|
rrfreelist(dbnsrp);
|
||||||
|
|
||||||
|
/* try the name servers found in cache */
|
||||||
|
if(netquery(dp, type, nsrp, req, depth+1)){
|
||||||
|
rrfreelist(nsrp);
|
||||||
|
return rrlookup(dp, type, OKneg);
|
||||||
|
}
|
||||||
|
rrfreelist(nsrp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use ns from db */
|
||||||
|
if(dbnsrp){
|
||||||
|
/* try the name servers found in db */
|
||||||
|
if(netquery(dp, type, dbnsrp, req, depth+1)){
|
||||||
|
/* we got an answer */
|
||||||
|
rrfreelist(dbnsrp);
|
||||||
|
return rrlookup(dp, type, NOneg);
|
||||||
|
}
|
||||||
|
rrfreelist(dbnsrp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* settle for a non-authoritative answer */
|
||||||
|
rp = rrlookup(dp, type, OKneg);
|
||||||
|
if(rp)
|
||||||
|
return rp;
|
||||||
|
|
||||||
|
/* noone answered. try the database, we might have a chance. */
|
||||||
|
return dblookup(name, class, type, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* walk a domain name one element to the right. return a pointer to that element.
|
||||||
|
* in other words, return a pointer to the parent domain name.
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
walkup(char *name)
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
cp = strchr(name, '.');
|
||||||
|
if(cp)
|
||||||
|
return cp+1;
|
||||||
|
else if(*name)
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a udpport for requests and replies.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
udpport(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if((fd = dial("udp!0!53", nil, nil, nil)) < 0)
|
||||||
|
warning("can't get udp port");
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
|
||||||
|
{
|
||||||
|
DNSmsg m;
|
||||||
|
int len;
|
||||||
|
OUdphdr *uh = (OUdphdr*)buf;
|
||||||
|
|
||||||
|
/* stuff port number into output buffer */
|
||||||
|
memset(uh, 0, sizeof(*uh));
|
||||||
|
hnputs(uh->rport, 53);
|
||||||
|
|
||||||
|
/* make request and convert it to output format */
|
||||||
|
memset(&m, 0, sizeof(m));
|
||||||
|
m.flags = flags;
|
||||||
|
m.id = reqno;
|
||||||
|
m.qd = rralloc(type);
|
||||||
|
m.qd->owner = dp;
|
||||||
|
m.qd->type = type;
|
||||||
|
len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp);
|
||||||
|
if(len < 0)
|
||||||
|
abort(); /* "can't convert" */;
|
||||||
|
rrfree(m.qd);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for alarms in readreply */
|
||||||
|
static void
|
||||||
|
ding(void *x, char *msg)
|
||||||
|
{
|
||||||
|
USED(x);
|
||||||
|
if(strcmp(msg, "alarm") == 0)
|
||||||
|
noted(NCONT);
|
||||||
|
else
|
||||||
|
noted(NDFLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
freeanswers(DNSmsg *mp)
|
||||||
|
{
|
||||||
|
rrfreelist(mp->qd);
|
||||||
|
rrfreelist(mp->an);
|
||||||
|
rrfreelist(mp->ns);
|
||||||
|
rrfreelist(mp->ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read replies to a request. ignore any of the wrong type. wait at most 5 seconds.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
readreply(int fd, DN *dp, int type, ushort req,
|
||||||
|
uchar *ibuf, DNSmsg *mp, ulong endtime, Request *reqp)
|
||||||
|
{
|
||||||
|
char *err;
|
||||||
|
int len;
|
||||||
|
ulong now;
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
notify(ding);
|
||||||
|
|
||||||
|
for(; ; freeanswers(mp)){
|
||||||
|
now = time(0);
|
||||||
|
if(now >= endtime)
|
||||||
|
return -1; /* timed out */
|
||||||
|
|
||||||
|
/* timed read */
|
||||||
|
alarm((endtime - now) * 1000);
|
||||||
|
len = udpread(fd, (OUdphdr*)ibuf, ibuf+OUdphdrsize, Maxudpin);
|
||||||
|
alarm(0);
|
||||||
|
if(len < 0)
|
||||||
|
return -1; /* timed out */
|
||||||
|
|
||||||
|
/* convert into internal format */
|
||||||
|
memset(mp, 0, sizeof(*mp));
|
||||||
|
err = convM2DNS(&ibuf[OUdphdrsize], len, mp);
|
||||||
|
if(err){
|
||||||
|
syslog(0, LOG, "input err %s: %I", err, ibuf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(debug)
|
||||||
|
logreply(reqp->id, ibuf, mp);
|
||||||
|
|
||||||
|
/* answering the right question? */
|
||||||
|
if(mp->id != req){
|
||||||
|
syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id,
|
||||||
|
mp->id, req, ibuf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(mp->qd == 0){
|
||||||
|
syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(mp->qd->owner != dp){
|
||||||
|
syslog(0, LOG, "%d: owner %s instead of %s: %I", reqp->id,
|
||||||
|
mp->qd->owner->name, dp->name, ibuf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(mp->qd->type != type){
|
||||||
|
syslog(0, LOG, "%d: type %d instead of %d: %I", reqp->id,
|
||||||
|
mp->qd->type, type, ibuf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember what request this is in answer to */
|
||||||
|
for(rp = mp->an; rp; rp = rp->next)
|
||||||
|
rp->query = type;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* never reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return non-0 if first list includes second list
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
contains(RR *rp1, RR *rp2)
|
||||||
|
{
|
||||||
|
RR *trp1, *trp2;
|
||||||
|
|
||||||
|
for(trp2 = rp2; trp2; trp2 = trp2->next){
|
||||||
|
for(trp1 = rp1; trp1; trp1 = trp1->next){
|
||||||
|
if(trp1->type == trp2->type)
|
||||||
|
if(trp1->host == trp2->host)
|
||||||
|
if(trp1->owner == trp2->owner)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(trp1 == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct Dest Dest;
|
||||||
|
struct Dest
|
||||||
|
{
|
||||||
|
uchar a[IPaddrlen]; /* ip address */
|
||||||
|
DN *s; /* name server */
|
||||||
|
int nx; /* number of transmissions */
|
||||||
|
int code;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return multicast version if any
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ipisbm(uchar *ip)
|
||||||
|
{
|
||||||
|
if(isv4(ip)){
|
||||||
|
if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
|
||||||
|
return 4;
|
||||||
|
if(ipcmp(ip, IPv4bcast) == 0)
|
||||||
|
return 4;
|
||||||
|
} else {
|
||||||
|
if(ip[0] == 0xff)
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get next server address
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
|
||||||
|
{
|
||||||
|
RR *rp, *arp, *trp;
|
||||||
|
Dest *cur;
|
||||||
|
|
||||||
|
if(nd >= Maxdest)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* look for a server whose address we already know.
|
||||||
|
* if we find one, mark it so we ignore this on
|
||||||
|
* subsequent passes.
|
||||||
|
*/
|
||||||
|
arp = 0;
|
||||||
|
for(rp = nsrp; rp; rp = rp->next){
|
||||||
|
assert(rp->magic == RRmagic);
|
||||||
|
if(rp->marker)
|
||||||
|
continue;
|
||||||
|
arp = rrlookup(rp->host, Ta, NOneg);
|
||||||
|
if(arp){
|
||||||
|
rp->marker = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
arp = dblookup(rp->host->name, Cin, Ta, 0, 0);
|
||||||
|
if(arp){
|
||||||
|
rp->marker = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if the cache and database lookup didn't find any new
|
||||||
|
* server addresses, try resolving one via the network.
|
||||||
|
* Mark any we try to resolve so we don't try a second time.
|
||||||
|
*/
|
||||||
|
if(arp == 0){
|
||||||
|
for(rp = nsrp; rp; rp = rp->next){
|
||||||
|
if(rp->marker)
|
||||||
|
continue;
|
||||||
|
rp->marker = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* avoid loops looking up a server under itself
|
||||||
|
*/
|
||||||
|
if(subsume(rp->owner->name, rp->host->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, depth+1, Recurse, 1, 0);
|
||||||
|
rrfreelist(rrremneg(&arp));
|
||||||
|
if(arp)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use any addresses that we found */
|
||||||
|
for(trp = arp; trp; trp = trp->next){
|
||||||
|
if(nd >= Maxdest)
|
||||||
|
break;
|
||||||
|
cur = &dest[nd];
|
||||||
|
parseip(cur->a, trp->ip->name);
|
||||||
|
if(ipisbm(cur->a))
|
||||||
|
continue;
|
||||||
|
cur->nx = 0;
|
||||||
|
cur->s = trp->owner;
|
||||||
|
cur->code = Rtimeout;
|
||||||
|
nd++;
|
||||||
|
}
|
||||||
|
rrfreelist(arp);
|
||||||
|
return nd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cache negative responses
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
cacheneg(DN *dp, int type, int rcode, RR *soarr)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
DN *soaowner;
|
||||||
|
ulong ttl;
|
||||||
|
|
||||||
|
/* no cache time specified, don' make anything up */
|
||||||
|
if(soarr != nil){
|
||||||
|
if(soarr->next != nil){
|
||||||
|
rrfreelist(soarr->next);
|
||||||
|
soarr->next = nil;
|
||||||
|
}
|
||||||
|
soaowner = soarr->owner;
|
||||||
|
} else
|
||||||
|
soaowner = nil;
|
||||||
|
|
||||||
|
/* the attach can cause soarr to be freed so mine it now */
|
||||||
|
if(soarr != nil && soarr->soa != nil)
|
||||||
|
ttl = soarr->soa->minttl+now;
|
||||||
|
else
|
||||||
|
ttl = 5*Min;
|
||||||
|
|
||||||
|
/* add soa and negative RR to the database */
|
||||||
|
rrattach(soarr, 1);
|
||||||
|
|
||||||
|
rp = rralloc(type);
|
||||||
|
rp->owner = dp;
|
||||||
|
rp->negative = 1;
|
||||||
|
rp->negsoaowner = soaowner;
|
||||||
|
rp->negrcode = rcode;
|
||||||
|
rp->ttl = ttl;
|
||||||
|
rrattach(rp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* query name servers. If the name server returns a pointer to another
|
||||||
|
* name server, recurse.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *ibuf, uchar *obuf)
|
||||||
|
{
|
||||||
|
int ndest, j, len, replywaits, rv;
|
||||||
|
ushort req;
|
||||||
|
RR *tp, *soarr;
|
||||||
|
Dest *p, *l, *np;
|
||||||
|
DN *ndp;
|
||||||
|
Dest dest[Maxdest];
|
||||||
|
DNSmsg m;
|
||||||
|
ulong endtime;
|
||||||
|
|
||||||
|
/* pack request into a message */
|
||||||
|
req = rand();
|
||||||
|
len = mkreq(dp, type, obuf, Frecurse|Oquery, req);
|
||||||
|
|
||||||
|
/* no server addresses yet */
|
||||||
|
l = dest;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* transmit requests and wait for answers.
|
||||||
|
* at most Maxtrans attempts to each address.
|
||||||
|
* each cycle send one more message than the previous.
|
||||||
|
*/
|
||||||
|
for(ndest = 1; ndest < Maxdest; ndest++){
|
||||||
|
p = dest;
|
||||||
|
|
||||||
|
endtime = time(0);
|
||||||
|
if(endtime >= reqp->aborttime)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* get a server address if we need one */
|
||||||
|
if(ndest > l - p){
|
||||||
|
j = serveraddrs(nsrp, dest, l - p, depth, reqp);
|
||||||
|
l = &dest[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no servers, punt */
|
||||||
|
if(l == dest)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* send to first 'ndest' destinations */
|
||||||
|
j = 0;
|
||||||
|
for(; p < &dest[ndest] && p < l; p++){
|
||||||
|
/* skip destinations we've finished with */
|
||||||
|
if(p->nx >= Maxtrans)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
j++;
|
||||||
|
|
||||||
|
/* exponential backoff of requests */
|
||||||
|
if((1<<p->nx) > ndest)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memmove(obuf, p->a, sizeof(p->a));
|
||||||
|
if(debug)
|
||||||
|
logsend(reqp->id, depth, obuf, p->s->name,
|
||||||
|
dp->name, type);
|
||||||
|
{Udphdr *uh = (Udphdr*)obuf;
|
||||||
|
print("send %I %I %d %d\n", uh->raddr, uh->laddr, nhgets(uh->rport), nhgets(uh->lport));
|
||||||
|
}
|
||||||
|
if(udpwrite(fd, (OUdphdr*)obuf, obuf+OUdphdrsize, len) < 0)
|
||||||
|
warning("sending udp msg %r");
|
||||||
|
p->nx++;
|
||||||
|
}
|
||||||
|
if(j == 0)
|
||||||
|
break; /* no destinations left */
|
||||||
|
|
||||||
|
/* wait up to 5 seconds for replies */
|
||||||
|
endtime = time(0) + 5;
|
||||||
|
if(endtime > reqp->aborttime)
|
||||||
|
endtime = reqp->aborttime;
|
||||||
|
|
||||||
|
for(replywaits = 0; replywaits < ndest; replywaits++){
|
||||||
|
if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0)
|
||||||
|
break; /* timed out */
|
||||||
|
|
||||||
|
/* find responder */
|
||||||
|
for(p = dest; p < l; p++)
|
||||||
|
if(memcmp(p->a, ibuf, sizeof(p->a)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* remove all addrs of responding server from list */
|
||||||
|
for(np = dest; np < l; np++)
|
||||||
|
if(np->s == p->s)
|
||||||
|
p->nx = Maxtrans;
|
||||||
|
|
||||||
|
/* ignore any error replies */
|
||||||
|
if((m.flags & Rmask) == Rserver){
|
||||||
|
rrfreelist(m.qd);
|
||||||
|
rrfreelist(m.an);
|
||||||
|
rrfreelist(m.ar);
|
||||||
|
rrfreelist(m.ns);
|
||||||
|
if(p != l)
|
||||||
|
p->code = Rserver;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ignore any bad delegations */
|
||||||
|
if(m.ns && baddelegation(m.ns, nsrp, ibuf)){
|
||||||
|
rrfreelist(m.ns);
|
||||||
|
m.ns = nil;
|
||||||
|
if(m.an == nil){
|
||||||
|
rrfreelist(m.qd);
|
||||||
|
rrfreelist(m.ar);
|
||||||
|
if(p != l)
|
||||||
|
p->code = Rserver;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* remove any soa's from the authority section */
|
||||||
|
soarr = rrremtype(&m.ns, Tsoa);
|
||||||
|
|
||||||
|
/* incorporate answers */
|
||||||
|
if(m.an)
|
||||||
|
rrattach(m.an, (m.flags & Fauth) ? 1 : 0);
|
||||||
|
if(m.ar)
|
||||||
|
rrattach(m.ar, 0);
|
||||||
|
if(m.ns){
|
||||||
|
ndp = m.ns->owner;
|
||||||
|
rrattach(m.ns, 0);
|
||||||
|
} else
|
||||||
|
ndp = 0;
|
||||||
|
|
||||||
|
/* free the question */
|
||||||
|
if(m.qd)
|
||||||
|
rrfreelist(m.qd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Any reply from an authoritative server,
|
||||||
|
* or a positive reply terminates the search
|
||||||
|
*/
|
||||||
|
if(m.an != nil || (m.flags & Fauth)){
|
||||||
|
if(m.an == nil && (m.flags & Rmask) == Rname)
|
||||||
|
dp->nonexistent = Rname;
|
||||||
|
else
|
||||||
|
dp->nonexistent = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cache any negative responses, free soarr
|
||||||
|
*/
|
||||||
|
if((m.flags & Fauth) && m.an == nil)
|
||||||
|
cacheneg(dp, type, (m.flags & Rmask), soarr);
|
||||||
|
else
|
||||||
|
rrfreelist(soarr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
rrfreelist(soarr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we've been given better name servers
|
||||||
|
* recurse
|
||||||
|
*/
|
||||||
|
if(m.ns){
|
||||||
|
tp = rrlookup(ndp, Tns, NOneg);
|
||||||
|
if(!contains(nsrp, tp)){
|
||||||
|
rv = netquery(dp, type, tp, reqp, depth+1);
|
||||||
|
rrfreelist(tp);
|
||||||
|
return rv;
|
||||||
|
} else
|
||||||
|
rrfreelist(tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if all servers returned failure, propogate it */
|
||||||
|
dp->nonexistent = Rserver;
|
||||||
|
for(p = dest; p < l; p++)
|
||||||
|
if(p->code != Rserver)
|
||||||
|
dp->nonexistent = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Qarg Qarg;
|
||||||
|
struct Qarg
|
||||||
|
{
|
||||||
|
DN *dp;
|
||||||
|
int type;
|
||||||
|
RR *nsrp;
|
||||||
|
Request *reqp;
|
||||||
|
int depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth)
|
||||||
|
{
|
||||||
|
uchar *obuf;
|
||||||
|
uchar *ibuf;
|
||||||
|
RR *rp;
|
||||||
|
int fd, rv;
|
||||||
|
|
||||||
|
if(depth > 12)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* use alloced buffers rather than ones from the stack */
|
||||||
|
ibuf = emalloc(Maxudpin+OUdphdrsize);
|
||||||
|
obuf = emalloc(Maxudp+OUdphdrsize);
|
||||||
|
|
||||||
|
slave(reqp);
|
||||||
|
|
||||||
|
/* prepare server RR's for incremental lookup */
|
||||||
|
for(rp = nsrp; rp; rp = rp->next)
|
||||||
|
rp->marker = 0;
|
||||||
|
|
||||||
|
fd = udpport();
|
||||||
|
if(fd < 0)
|
||||||
|
return 0;
|
||||||
|
rv = netquery1(fd, dp, type, nsrp, reqp, depth, ibuf, obuf);
|
||||||
|
close(fd);
|
||||||
|
free(ibuf);
|
||||||
|
free(obuf);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
882
src/cmd/ndb/dns.c
Executable file
882
src/cmd/ndb/dns.c
Executable file
@ -0,0 +1,882 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <auth.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Maxrequest= 1024,
|
||||||
|
Ncache= 8,
|
||||||
|
Maxpath= 128,
|
||||||
|
Maxreply= 512,
|
||||||
|
Maxrrr= 16,
|
||||||
|
Maxfdata= 8192,
|
||||||
|
|
||||||
|
Qdir= 0,
|
||||||
|
Qdns= 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Mfile Mfile;
|
||||||
|
typedef struct Job Job;
|
||||||
|
typedef struct Network Network;
|
||||||
|
|
||||||
|
int vers; /* incremented each clone/attach */
|
||||||
|
|
||||||
|
struct Mfile
|
||||||
|
{
|
||||||
|
Mfile *next; /* next free mfile */
|
||||||
|
int ref;
|
||||||
|
|
||||||
|
char *user;
|
||||||
|
Qid qid;
|
||||||
|
int fid;
|
||||||
|
|
||||||
|
int type; /* reply type */
|
||||||
|
char reply[Maxreply];
|
||||||
|
ushort rr[Maxrrr]; /* offset of rr's */
|
||||||
|
ushort nrr; /* number of rr's */
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// active local requests
|
||||||
|
//
|
||||||
|
struct Job
|
||||||
|
{
|
||||||
|
Job *next;
|
||||||
|
int flushed;
|
||||||
|
Fcall request;
|
||||||
|
Fcall reply;
|
||||||
|
};
|
||||||
|
Lock joblock;
|
||||||
|
Job *joblist;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Lock lk;
|
||||||
|
Mfile *inuse; /* active mfile's */
|
||||||
|
} mfalloc;
|
||||||
|
|
||||||
|
int haveip;
|
||||||
|
int mfd[2];
|
||||||
|
int debug;
|
||||||
|
int traceactivity;
|
||||||
|
int cachedb;
|
||||||
|
ulong now;
|
||||||
|
int testing;
|
||||||
|
char *trace;
|
||||||
|
int needrefresh;
|
||||||
|
int resolver;
|
||||||
|
uchar ipaddr[IPaddrlen]; /* my ip address */
|
||||||
|
int maxage;
|
||||||
|
char *zonerefreshprogram;
|
||||||
|
int sendnotifies;
|
||||||
|
|
||||||
|
void rversion(Job*);
|
||||||
|
void rauth(Job*);
|
||||||
|
void rflush(Job*);
|
||||||
|
void rattach(Job*, Mfile*);
|
||||||
|
char* rwalk(Job*, Mfile*);
|
||||||
|
void ropen(Job*, Mfile*);
|
||||||
|
void rcreate(Job*, Mfile*);
|
||||||
|
void rread(Job*, Mfile*);
|
||||||
|
void rwrite(Job*, Mfile*, Request*);
|
||||||
|
void rclunk(Job*, Mfile*);
|
||||||
|
void rremove(Job*, Mfile*);
|
||||||
|
void rstat(Job*, Mfile*);
|
||||||
|
void rwstat(Job*, Mfile*);
|
||||||
|
void sendmsg(Job*, char*);
|
||||||
|
void mountinit(char*, char*);
|
||||||
|
void io(void);
|
||||||
|
int fillreply(Mfile*, int);
|
||||||
|
Job* newjob(void);
|
||||||
|
void freejob(Job*);
|
||||||
|
void setext(char*, int, char*);
|
||||||
|
|
||||||
|
char *logfile = "dns";
|
||||||
|
char *dbfile;
|
||||||
|
char mntpt[Maxpath];
|
||||||
|
char *LOG;
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: %s [-rs] [-f ndb-file] [-x netmtpt]\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int serve;
|
||||||
|
char servefile[Maxpath];
|
||||||
|
char ext[Maxpath];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
serve = 0;
|
||||||
|
// setnetmtpt(mntpt, sizeof(mntpt), nil);
|
||||||
|
ext[0] = 0;
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'd':
|
||||||
|
debug = 1;
|
||||||
|
traceactivity = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
p = ARGF();
|
||||||
|
if(p == nil)
|
||||||
|
usage();
|
||||||
|
dbfile = p;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
haveip = 1;
|
||||||
|
parseip(ipaddr, EARGF(usage()));
|
||||||
|
break;
|
||||||
|
// case 'x':
|
||||||
|
// p = ARGF();
|
||||||
|
// if(p == nil)
|
||||||
|
// usage();
|
||||||
|
// setnetmtpt(mntpt, sizeof(mntpt), p);
|
||||||
|
// setext(ext, sizeof(ext), mntpt);
|
||||||
|
// break;
|
||||||
|
case 'r':
|
||||||
|
resolver = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
serve = 1; /* serve network */
|
||||||
|
cachedb = 1;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
p = ARGF();
|
||||||
|
if(p == nil)
|
||||||
|
usage();
|
||||||
|
maxage = atoi(p);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
testing = 1;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
zonerefreshprogram = ARGF();
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
sendnotifies = 1;
|
||||||
|
break;
|
||||||
|
}ARGEND
|
||||||
|
USED(argc);
|
||||||
|
USED(argv);
|
||||||
|
|
||||||
|
//if(testing) mainmem->flags |= POOL_NOREUSE;
|
||||||
|
#define RFREND 0
|
||||||
|
rfork(RFREND|RFNOTEG);
|
||||||
|
|
||||||
|
/* start syslog before we fork */
|
||||||
|
fmtinstall('F', fcallfmt);
|
||||||
|
dninit();
|
||||||
|
if(!haveip && myipaddr(ipaddr, mntpt) < 0)
|
||||||
|
sysfatal("can't read my ip address");
|
||||||
|
|
||||||
|
syslog(0, logfile, "starting dns on %I", ipaddr);
|
||||||
|
|
||||||
|
opendatabase();
|
||||||
|
|
||||||
|
/*
|
||||||
|
snprint(servefile, sizeof(servefile), "#s/dns%s", ext);
|
||||||
|
unmount(servefile, mntpt);
|
||||||
|
remove(servefile);
|
||||||
|
*/
|
||||||
|
mountinit(servefile, mntpt);
|
||||||
|
|
||||||
|
now = time(0);
|
||||||
|
srand(now*getpid());
|
||||||
|
db2cache(1);
|
||||||
|
|
||||||
|
if(serve)
|
||||||
|
proccreate(dnudpserver, mntpt, STACK);
|
||||||
|
if(sendnotifies)
|
||||||
|
notifyproc();
|
||||||
|
|
||||||
|
io();
|
||||||
|
syslog(0, logfile, "io returned, exiting");
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
myipaddr(uchar *ip, char *net)
|
||||||
|
{
|
||||||
|
ipmove(ip, ipaddr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if a mount point is specified, set the cs extention to be the mount point
|
||||||
|
* with '_'s replacing '/'s
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
setext(char *ext, int n, char *p)
|
||||||
|
{
|
||||||
|
int i, c;
|
||||||
|
|
||||||
|
n--;
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
|
c = p[i];
|
||||||
|
if(c == 0)
|
||||||
|
break;
|
||||||
|
if(c == '/')
|
||||||
|
c = '_';
|
||||||
|
ext[i] = c;
|
||||||
|
}
|
||||||
|
ext[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mountinit(char *service, char *mntpt)
|
||||||
|
{
|
||||||
|
int p[2];
|
||||||
|
|
||||||
|
if(pipe(p) < 0)
|
||||||
|
abort(); /* "pipe failed" */;
|
||||||
|
switch(rfork(RFFDG|RFPROC|RFNAMEG)){
|
||||||
|
case 0:
|
||||||
|
close(p[1]);
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
abort(); /* "fork failed\n" */;
|
||||||
|
default:
|
||||||
|
close(p[0]);
|
||||||
|
|
||||||
|
if(post9pservice(p[1], "dns") < 0)
|
||||||
|
fprint(2, "post9pservice dns: %r\n");
|
||||||
|
_exits(0);
|
||||||
|
}
|
||||||
|
mfd[0] = mfd[1] = p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
Mfile*
|
||||||
|
newfid(int fid, int needunused)
|
||||||
|
{
|
||||||
|
Mfile *mf;
|
||||||
|
|
||||||
|
lock(&mfalloc.lk);
|
||||||
|
for(mf = mfalloc.inuse; mf != nil; mf = mf->next){
|
||||||
|
if(mf->fid == fid){
|
||||||
|
unlock(&mfalloc.lk);
|
||||||
|
if(needunused)
|
||||||
|
return nil;
|
||||||
|
return mf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mf = emalloc(sizeof(*mf));
|
||||||
|
if(mf == nil)
|
||||||
|
sysfatal("out of memory");
|
||||||
|
mf->fid = fid;
|
||||||
|
mf->next = mfalloc.inuse;
|
||||||
|
mfalloc.inuse = mf;
|
||||||
|
unlock(&mfalloc.lk);
|
||||||
|
return mf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freefid(Mfile *mf)
|
||||||
|
{
|
||||||
|
Mfile **l;
|
||||||
|
|
||||||
|
lock(&mfalloc.lk);
|
||||||
|
for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next){
|
||||||
|
if(*l == mf){
|
||||||
|
*l = mf->next;
|
||||||
|
if(mf->user)
|
||||||
|
free(mf->user);
|
||||||
|
free(mf);
|
||||||
|
unlock(&mfalloc.lk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sysfatal("freeing unused fid");
|
||||||
|
}
|
||||||
|
|
||||||
|
Mfile*
|
||||||
|
copyfid(Mfile *mf, int fid)
|
||||||
|
{
|
||||||
|
Mfile *nmf;
|
||||||
|
|
||||||
|
nmf = newfid(fid, 1);
|
||||||
|
if(nmf == nil)
|
||||||
|
return nil;
|
||||||
|
nmf->fid = fid;
|
||||||
|
nmf->user = estrdup(mf->user);
|
||||||
|
nmf->qid.type = mf->qid.type;
|
||||||
|
nmf->qid.path = mf->qid.path;
|
||||||
|
nmf->qid.vers = vers++;
|
||||||
|
return nmf;
|
||||||
|
}
|
||||||
|
|
||||||
|
Job*
|
||||||
|
newjob(void)
|
||||||
|
{
|
||||||
|
Job *job;
|
||||||
|
|
||||||
|
job = emalloc(sizeof(*job));
|
||||||
|
lock(&joblock);
|
||||||
|
job->next = joblist;
|
||||||
|
joblist = job;
|
||||||
|
job->request.tag = -1;
|
||||||
|
unlock(&joblock);
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freejob(Job *job)
|
||||||
|
{
|
||||||
|
Job **l;
|
||||||
|
|
||||||
|
lock(&joblock);
|
||||||
|
for(l = &joblist; *l; l = &(*l)->next){
|
||||||
|
if((*l) == job){
|
||||||
|
*l = job->next;
|
||||||
|
free(job);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock(&joblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flushjob(int tag)
|
||||||
|
{
|
||||||
|
Job *job;
|
||||||
|
|
||||||
|
lock(&joblock);
|
||||||
|
for(job = joblist; job; job = job->next){
|
||||||
|
if(job->request.tag == tag && job->request.type != Tflush){
|
||||||
|
job->flushed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock(&joblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
io(void)
|
||||||
|
{
|
||||||
|
long n;
|
||||||
|
Mfile *mf;
|
||||||
|
uchar mdata[IOHDRSZ + Maxfdata];
|
||||||
|
Request req;
|
||||||
|
Job *job;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a slave process is sometimes forked to wait for replies from other
|
||||||
|
* servers. The master process returns immediately via a longjmp
|
||||||
|
* through 'mret'.
|
||||||
|
*/
|
||||||
|
if(setjmp(req.mret))
|
||||||
|
putactivity();
|
||||||
|
req.isslave = 0;
|
||||||
|
for(;;){
|
||||||
|
n = read9pmsg(mfd[0], mdata, sizeof mdata);
|
||||||
|
if(n<=0){
|
||||||
|
syslog(0, logfile, "error reading mntpt: %r");
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
job = newjob();
|
||||||
|
if(convM2S(mdata, n, &job->request) != n){
|
||||||
|
freejob(job);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mf = newfid(job->request.fid, 0);
|
||||||
|
if(debug)
|
||||||
|
syslog(0, logfile, "%F", &job->request);
|
||||||
|
|
||||||
|
getactivity(&req);
|
||||||
|
req.aborttime = now + 60; /* don't spend more than 60 seconds */
|
||||||
|
|
||||||
|
switch(job->request.type){
|
||||||
|
default:
|
||||||
|
syslog(1, logfile, "unknown request type %d", job->request.type);
|
||||||
|
break;
|
||||||
|
case Tversion:
|
||||||
|
rversion(job);
|
||||||
|
break;
|
||||||
|
case Tauth:
|
||||||
|
rauth(job);
|
||||||
|
break;
|
||||||
|
case Tflush:
|
||||||
|
rflush(job);
|
||||||
|
break;
|
||||||
|
case Tattach:
|
||||||
|
rattach(job, mf);
|
||||||
|
break;
|
||||||
|
case Twalk:
|
||||||
|
rwalk(job, mf);
|
||||||
|
break;
|
||||||
|
case Topen:
|
||||||
|
ropen(job, mf);
|
||||||
|
break;
|
||||||
|
case Tcreate:
|
||||||
|
rcreate(job, mf);
|
||||||
|
break;
|
||||||
|
case Tread:
|
||||||
|
rread(job, mf);
|
||||||
|
break;
|
||||||
|
case Twrite:
|
||||||
|
rwrite(job, mf, &req);
|
||||||
|
break;
|
||||||
|
case Tclunk:
|
||||||
|
rclunk(job, mf);
|
||||||
|
break;
|
||||||
|
case Tremove:
|
||||||
|
rremove(job, mf);
|
||||||
|
break;
|
||||||
|
case Tstat:
|
||||||
|
rstat(job, mf);
|
||||||
|
break;
|
||||||
|
case Twstat:
|
||||||
|
rwstat(job, mf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
freejob(job);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* slave processes die after replying
|
||||||
|
*/
|
||||||
|
if(req.isslave){
|
||||||
|
putactivity();
|
||||||
|
_exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
putactivity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rversion(Job *job)
|
||||||
|
{
|
||||||
|
if(job->request.msize > IOHDRSZ + Maxfdata)
|
||||||
|
job->reply.msize = IOHDRSZ + Maxfdata;
|
||||||
|
else
|
||||||
|
job->reply.msize = job->request.msize;
|
||||||
|
if(strncmp(job->request.version, "9P2000", 6) != 0)
|
||||||
|
sendmsg(job, "unknown 9P version");
|
||||||
|
else{
|
||||||
|
job->reply.version = "9P2000";
|
||||||
|
sendmsg(job, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rauth(Job *job)
|
||||||
|
{
|
||||||
|
sendmsg(job, "dns: authentication not required");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* don't flush till all the slaves are done
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
rflush(Job *job)
|
||||||
|
{
|
||||||
|
flushjob(job->request.oldtag);
|
||||||
|
sendmsg(job, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rattach(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
if(mf->user != nil)
|
||||||
|
free(mf->user);
|
||||||
|
mf->user = estrdup(job->request.uname);
|
||||||
|
mf->qid.vers = vers++;
|
||||||
|
mf->qid.type = QTDIR;
|
||||||
|
mf->qid.path = 0LL;
|
||||||
|
job->reply.qid = mf->qid;
|
||||||
|
sendmsg(job, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
rwalk(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
char *err;
|
||||||
|
char **elems;
|
||||||
|
int nelems;
|
||||||
|
int i;
|
||||||
|
Mfile *nmf;
|
||||||
|
Qid qid;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
nmf = nil;
|
||||||
|
elems = job->request.wname;
|
||||||
|
nelems = job->request.nwname;
|
||||||
|
job->reply.nwqid = 0;
|
||||||
|
|
||||||
|
if(job->request.newfid != job->request.fid){
|
||||||
|
/* clone fid */
|
||||||
|
if(job->request.newfid<0){
|
||||||
|
err = "clone newfid out of range";
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
nmf = copyfid(mf, job->request.newfid);
|
||||||
|
if(nmf == nil){
|
||||||
|
err = "clone bad newfid";
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
mf = nmf;
|
||||||
|
}
|
||||||
|
/* else nmf will be nil */
|
||||||
|
|
||||||
|
qid = mf->qid;
|
||||||
|
if(nelems > 0){
|
||||||
|
/* walk fid */
|
||||||
|
for(i=0; i<nelems && i<MAXWELEM; i++){
|
||||||
|
if((qid.type & QTDIR) == 0){
|
||||||
|
err = "not a directory";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
|
||||||
|
qid.type = QTDIR;
|
||||||
|
qid.path = Qdir;
|
||||||
|
Found:
|
||||||
|
job->reply.wqid[i] = qid;
|
||||||
|
job->reply.nwqid++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(strcmp(elems[i], "dns") == 0){
|
||||||
|
qid.type = QTFILE;
|
||||||
|
qid.path = Qdns;
|
||||||
|
goto Found;
|
||||||
|
}
|
||||||
|
err = "file does not exist";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send:
|
||||||
|
if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
|
||||||
|
freefid(nmf);
|
||||||
|
if(err == nil)
|
||||||
|
mf->qid = qid;
|
||||||
|
sendmsg(job, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ropen(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
int mode;
|
||||||
|
char *err;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
mode = job->request.mode;
|
||||||
|
if(mf->qid.type & QTDIR){
|
||||||
|
if(mode)
|
||||||
|
err = "permission denied";
|
||||||
|
}
|
||||||
|
job->reply.qid = mf->qid;
|
||||||
|
job->reply.iounit = 0;
|
||||||
|
sendmsg(job, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rcreate(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
USED(mf);
|
||||||
|
sendmsg(job, "creation permission denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rread(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
int i, n, cnt;
|
||||||
|
long off;
|
||||||
|
Dir dir;
|
||||||
|
uchar buf[Maxfdata];
|
||||||
|
char *err;
|
||||||
|
long clock;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
err = 0;
|
||||||
|
off = job->request.offset;
|
||||||
|
cnt = job->request.count;
|
||||||
|
if(mf->qid.type & QTDIR){
|
||||||
|
clock = time(0);
|
||||||
|
if(off == 0){
|
||||||
|
dir.name = "dns";
|
||||||
|
dir.qid.type = QTFILE;
|
||||||
|
dir.qid.vers = vers;
|
||||||
|
dir.qid.path = Qdns;
|
||||||
|
dir.mode = 0666;
|
||||||
|
dir.length = 0;
|
||||||
|
dir.uid = mf->user;
|
||||||
|
dir.gid = mf->user;
|
||||||
|
dir.muid = mf->user;
|
||||||
|
dir.atime = clock; /* wrong */
|
||||||
|
dir.mtime = clock; /* wrong */
|
||||||
|
n = convD2M(&dir, buf, sizeof buf);
|
||||||
|
}
|
||||||
|
job->reply.data = (char*)buf;
|
||||||
|
} else {
|
||||||
|
for(i = 1; i <= mf->nrr; i++)
|
||||||
|
if(mf->rr[i] > off)
|
||||||
|
break;
|
||||||
|
if(i > mf->nrr)
|
||||||
|
goto send;
|
||||||
|
if(off + cnt > mf->rr[i])
|
||||||
|
n = mf->rr[i] - off;
|
||||||
|
else
|
||||||
|
n = cnt;
|
||||||
|
job->reply.data = mf->reply + off;
|
||||||
|
}
|
||||||
|
send:
|
||||||
|
job->reply.count = n;
|
||||||
|
sendmsg(job, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rwrite(Job *job, Mfile *mf, Request *req)
|
||||||
|
{
|
||||||
|
int cnt, rooted, status;
|
||||||
|
long n;
|
||||||
|
char *err, *p, *atype;
|
||||||
|
RR *rp, *tp, *neg;
|
||||||
|
int wantsav;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
cnt = job->request.count;
|
||||||
|
if(mf->qid.type & QTDIR){
|
||||||
|
err = "can't write directory";
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
if(cnt >= Maxrequest){
|
||||||
|
err = "request too long";
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
job->request.data[cnt] = 0;
|
||||||
|
if(cnt > 0 && job->request.data[cnt-1] == '\n')
|
||||||
|
job->request.data[cnt-1] = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* special commands
|
||||||
|
*/
|
||||||
|
if(strncmp(job->request.data, "debug", 5)==0 && job->request.data[5] == 0){
|
||||||
|
debug ^= 1;
|
||||||
|
goto send;
|
||||||
|
} else if(strncmp(job->request.data, "dump", 4)==0 && job->request.data[4] == 0){
|
||||||
|
dndump("/lib/ndb/dnsdump");
|
||||||
|
goto send;
|
||||||
|
} else if(strncmp(job->request.data, "refresh", 7)==0 && job->request.data[7] == 0){
|
||||||
|
needrefresh = 1;
|
||||||
|
goto send;
|
||||||
|
// } else if(strncmp(job->request.data, "poolcheck", 9)==0 && job->request.data[9] == 0){
|
||||||
|
// poolcheck(mainmem);
|
||||||
|
// goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kill previous reply
|
||||||
|
*/
|
||||||
|
mf->nrr = 0;
|
||||||
|
mf->rr[0] = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* break up request (into a name and a type)
|
||||||
|
*/
|
||||||
|
atype = strchr(job->request.data, ' ');
|
||||||
|
if(atype == 0){
|
||||||
|
err = "illegal request";
|
||||||
|
goto send;
|
||||||
|
} else
|
||||||
|
*atype++ = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tracing request
|
||||||
|
*/
|
||||||
|
if(strcmp(atype, "trace") == 0){
|
||||||
|
if(trace)
|
||||||
|
free(trace);
|
||||||
|
if(*job->request.data)
|
||||||
|
trace = estrdup(job->request.data);
|
||||||
|
else
|
||||||
|
trace = 0;
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
mf->type = rrtype(atype);
|
||||||
|
if(mf->type < 0){
|
||||||
|
err = "unknown type";
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = atype - 2;
|
||||||
|
if(p >= job->request.data && *p == '.'){
|
||||||
|
rooted = 1;
|
||||||
|
*p = 0;
|
||||||
|
} else
|
||||||
|
rooted = 0;
|
||||||
|
|
||||||
|
p = job->request.data;
|
||||||
|
if(*p == '!'){
|
||||||
|
wantsav = 1;
|
||||||
|
p++;
|
||||||
|
} else
|
||||||
|
wantsav = 0;
|
||||||
|
dncheck(0, 1);
|
||||||
|
rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
|
||||||
|
dncheck(0, 1);
|
||||||
|
neg = rrremneg(&rp);
|
||||||
|
if(neg){
|
||||||
|
status = neg->negrcode;
|
||||||
|
rrfreelist(neg);
|
||||||
|
}
|
||||||
|
if(rp == 0){
|
||||||
|
switch(status){
|
||||||
|
case Rname:
|
||||||
|
err = "name does not exist";
|
||||||
|
break;
|
||||||
|
case Rserver:
|
||||||
|
err = "dns failure";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = "resource does not exist";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lock(&joblock);
|
||||||
|
if(!job->flushed){
|
||||||
|
/* format data to be read later */
|
||||||
|
n = 0;
|
||||||
|
mf->nrr = 0;
|
||||||
|
for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
|
||||||
|
tsame(mf->type, tp->type); tp = tp->next){
|
||||||
|
mf->rr[mf->nrr++] = n;
|
||||||
|
if(wantsav)
|
||||||
|
n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
|
||||||
|
else
|
||||||
|
n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
|
||||||
|
}
|
||||||
|
mf->rr[mf->nrr] = n;
|
||||||
|
}
|
||||||
|
unlock(&joblock);
|
||||||
|
rrfreelist(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
send:
|
||||||
|
dncheck(0, 1);
|
||||||
|
job->reply.count = cnt;
|
||||||
|
sendmsg(job, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rclunk(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
freefid(mf);
|
||||||
|
sendmsg(job, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rremove(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
USED(mf);
|
||||||
|
sendmsg(job, "remove permission denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rstat(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
Dir dir;
|
||||||
|
uchar buf[IOHDRSZ+Maxfdata];
|
||||||
|
|
||||||
|
if(mf->qid.type & QTDIR){
|
||||||
|
dir.name = ".";
|
||||||
|
dir.mode = DMDIR|0555;
|
||||||
|
} else {
|
||||||
|
dir.name = "dns";
|
||||||
|
dir.mode = 0666;
|
||||||
|
}
|
||||||
|
dir.qid = mf->qid;
|
||||||
|
dir.length = 0;
|
||||||
|
dir.uid = mf->user;
|
||||||
|
dir.gid = mf->user;
|
||||||
|
dir.muid = mf->user;
|
||||||
|
dir.atime = dir.mtime = time(0);
|
||||||
|
job->reply.nstat = convD2M(&dir, buf, sizeof buf);
|
||||||
|
job->reply.stat = buf;
|
||||||
|
sendmsg(job, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rwstat(Job *job, Mfile *mf)
|
||||||
|
{
|
||||||
|
USED(mf);
|
||||||
|
sendmsg(job, "wstat permission denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sendmsg(Job *job, char *err)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
uchar mdata[IOHDRSZ + Maxfdata];
|
||||||
|
char ename[ERRMAX];
|
||||||
|
|
||||||
|
if(err){
|
||||||
|
job->reply.type = Rerror;
|
||||||
|
snprint(ename, sizeof(ename), "dns: %s", err);
|
||||||
|
job->reply.ename = ename;
|
||||||
|
}else{
|
||||||
|
job->reply.type = job->request.type+1;
|
||||||
|
}
|
||||||
|
job->reply.tag = job->request.tag;
|
||||||
|
n = convS2M(&job->reply, mdata, sizeof mdata);
|
||||||
|
if(n == 0){
|
||||||
|
syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
lock(&joblock);
|
||||||
|
if(job->flushed == 0)
|
||||||
|
if(write(mfd[1], mdata, n)!=n)
|
||||||
|
sysfatal("mount write");
|
||||||
|
unlock(&joblock);
|
||||||
|
if(debug)
|
||||||
|
syslog(0, logfile, "%F %d", &job->reply, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the following varies between dnsdebug and dns
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
logreply(int id, uchar *addr, DNSmsg *mp)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
syslog(0, LOG, "%d: rcvd %I flags:%s%s%s%s%s", id, addr,
|
||||||
|
mp->flags & Fauth ? " auth" : "",
|
||||||
|
mp->flags & Ftrunc ? " trunc" : "",
|
||||||
|
mp->flags & Frecurse ? " rd" : "",
|
||||||
|
mp->flags & Fcanrec ? " ra" : "",
|
||||||
|
mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
|
||||||
|
" nx" : "");
|
||||||
|
for(rp = mp->qd; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I qd %s", id, addr, rp->owner->name);
|
||||||
|
for(rp = mp->an; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I an %R", id, addr, rp);
|
||||||
|
for(rp = mp->ns; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I ns %R", id, addr, rp);
|
||||||
|
for(rp = mp->ar; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I ar %R", id, addr, rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
|
||||||
|
{
|
||||||
|
char buf[12];
|
||||||
|
|
||||||
|
syslog(0, LOG, "%d.%d: sending to %I/%s %s %s",
|
||||||
|
id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
RR*
|
||||||
|
getdnsservers(int class)
|
||||||
|
{
|
||||||
|
return dnsservers(class);
|
||||||
|
}
|
||||||
403
src/cmd/ndb/dns.h
Executable file
403
src/cmd/ndb/dns.h
Executable file
@ -0,0 +1,403 @@
|
|||||||
|
#define OUdphdrsize Udphdrsize
|
||||||
|
#define OUdphdr Udphdr
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/* RR types */
|
||||||
|
Ta= 1,
|
||||||
|
Tns= 2,
|
||||||
|
Tmd= 3,
|
||||||
|
Tmf= 4,
|
||||||
|
Tcname= 5,
|
||||||
|
Tsoa= 6,
|
||||||
|
Tmb= 7,
|
||||||
|
Tmg= 8,
|
||||||
|
Tmr= 9,
|
||||||
|
Tnull= 10,
|
||||||
|
Twks= 11,
|
||||||
|
Tptr= 12,
|
||||||
|
Thinfo= 13,
|
||||||
|
Tminfo= 14,
|
||||||
|
Tmx= 15,
|
||||||
|
Ttxt= 16,
|
||||||
|
Trp= 17,
|
||||||
|
Tsig= 24,
|
||||||
|
Tkey= 25,
|
||||||
|
Taaaa= 28,
|
||||||
|
Tcert= 37,
|
||||||
|
|
||||||
|
/* query types (all RR types are also queries) */
|
||||||
|
Tixfr= 251, /* incremental zone transfer */
|
||||||
|
Taxfr= 252, /* zone transfer */
|
||||||
|
Tmailb= 253, /* { Tmb, Tmg, Tmr } */
|
||||||
|
Tall= 255, /* all records */
|
||||||
|
|
||||||
|
/* classes */
|
||||||
|
Csym= 0, /* internal symbols */
|
||||||
|
Cin= 1, /* internet */
|
||||||
|
Ccs, /* CSNET (obsolete) */
|
||||||
|
Cch, /* Chaos net */
|
||||||
|
Chs, /* Hesiod (?) */
|
||||||
|
|
||||||
|
/* class queries (all class types are also queries) */
|
||||||
|
Call= 255, /* all classes */
|
||||||
|
|
||||||
|
/* opcodes */
|
||||||
|
Oquery= 0<<11, /* normal query */
|
||||||
|
Oinverse= 1<<11, /* inverse query */
|
||||||
|
Ostatus= 2<<11, /* status request */
|
||||||
|
Onotify= 4<<11, /* notify slaves of updates */
|
||||||
|
Omask= 0xf<<11, /* mask for opcode */
|
||||||
|
|
||||||
|
/* response codes */
|
||||||
|
Rok= 0,
|
||||||
|
Rformat= 1, /* format error */
|
||||||
|
Rserver= 2, /* server failure (e.g. no answer from something) */
|
||||||
|
Rname= 3, /* bad name */
|
||||||
|
Runimplimented= 4, /* unimplemented */
|
||||||
|
Rrefused= 5, /* we don't like you */
|
||||||
|
Rmask= 0xf, /* mask for response */
|
||||||
|
Rtimeout= 0x10, /* timeout sending (for internal use only) */
|
||||||
|
|
||||||
|
/* bits in flag word (other than opcode and response) */
|
||||||
|
Fresp= 1<<15, /* message is a response */
|
||||||
|
Fauth= 1<<10, /* true if an authoritative response */
|
||||||
|
Ftrunc= 1<<9, /* truncated message */
|
||||||
|
Frecurse= 1<<8, /* request recursion */
|
||||||
|
Fcanrec= 1<<7, /* server can recurse */
|
||||||
|
|
||||||
|
Domlen= 256, /* max domain name length (with NULL) */
|
||||||
|
Labellen= 256, /* max domain label length (with NULL) */
|
||||||
|
Strlen= 256, /* max string length (with NULL) */
|
||||||
|
Iplen= 32, /* max ascii ip address length (with NULL) */
|
||||||
|
|
||||||
|
/* time to live values (in seconds) */
|
||||||
|
Min= 60,
|
||||||
|
Hour= 60*Min, /* */
|
||||||
|
Day= 24*Hour, /* Ta, Tmx */
|
||||||
|
Week= 7*Day, /* Tsoa, Tns */
|
||||||
|
Year= 52*Week,
|
||||||
|
DEFTTL= Day,
|
||||||
|
|
||||||
|
/* reserved time (can't be timed out earlier) */
|
||||||
|
Reserved= 5*Min,
|
||||||
|
|
||||||
|
/* packet sizes */
|
||||||
|
Maxudp= 512, /* maximum bytes per udp message */
|
||||||
|
Maxudpin= 2048, /* maximum bytes per udp message */
|
||||||
|
|
||||||
|
/* length of domain name hash table */
|
||||||
|
HTLEN= 4*1024,
|
||||||
|
|
||||||
|
RRmagic= 0xdeadbabe,
|
||||||
|
DNmagic= 0xa110a110,
|
||||||
|
|
||||||
|
/* parallelism */
|
||||||
|
Maxactive= 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DN DN;
|
||||||
|
typedef struct DNSmsg DNSmsg;
|
||||||
|
typedef struct RR RR;
|
||||||
|
typedef struct SOA SOA;
|
||||||
|
typedef struct Area Area;
|
||||||
|
typedef struct Request Request;
|
||||||
|
typedef struct Key Key;
|
||||||
|
typedef struct Cert Cert;
|
||||||
|
typedef struct Sig Sig;
|
||||||
|
typedef struct Null Null;
|
||||||
|
typedef struct Server Server;
|
||||||
|
typedef struct Txt Txt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a structure to track a request and any slave process handling it
|
||||||
|
*/
|
||||||
|
struct Request
|
||||||
|
{
|
||||||
|
int isslave; /* pid of slave */
|
||||||
|
ulong aborttime; /* time at which we give up */
|
||||||
|
jmp_buf mret; /* where master jumps to after starting a slave */
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a domain name
|
||||||
|
*/
|
||||||
|
struct DN
|
||||||
|
{
|
||||||
|
DN *next; /* hash collision list */
|
||||||
|
ulong magic;
|
||||||
|
char *name; /* owner */
|
||||||
|
RR *rr; /* resource records off this name */
|
||||||
|
ulong referenced; /* time last referenced */
|
||||||
|
ulong lookuptime; /* last time we tried to get a better value */
|
||||||
|
ushort class; /* RR class */
|
||||||
|
char refs; /* for mark and sweep */
|
||||||
|
char nonexistent; /* true if we get an authoritative nx for this domain */
|
||||||
|
ulong ordinal;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* security info
|
||||||
|
*/
|
||||||
|
struct Key
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
int proto;
|
||||||
|
int alg;
|
||||||
|
int dlen;
|
||||||
|
uchar *data;
|
||||||
|
};
|
||||||
|
struct Cert
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
int tag;
|
||||||
|
int alg;
|
||||||
|
int dlen;
|
||||||
|
uchar *data;
|
||||||
|
};
|
||||||
|
struct Sig
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
int alg;
|
||||||
|
int labels;
|
||||||
|
ulong ttl;
|
||||||
|
ulong exp;
|
||||||
|
ulong incep;
|
||||||
|
int tag;
|
||||||
|
DN *signer;
|
||||||
|
int dlen;
|
||||||
|
uchar *data;
|
||||||
|
};
|
||||||
|
struct Null
|
||||||
|
{
|
||||||
|
int dlen;
|
||||||
|
uchar *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* text strings
|
||||||
|
*/
|
||||||
|
struct Txt
|
||||||
|
{
|
||||||
|
Txt *next;
|
||||||
|
char *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* an unpacked resource record
|
||||||
|
*/
|
||||||
|
struct RR
|
||||||
|
{
|
||||||
|
RR *next;
|
||||||
|
ulong magic;
|
||||||
|
DN *owner; /* domain that owns this resource record */
|
||||||
|
uchar negative; /* this is a cached negative response */
|
||||||
|
ulong pc;
|
||||||
|
ulong ttl; /* time to live to be passed on */
|
||||||
|
ulong expire; /* time this entry expires locally */
|
||||||
|
ushort type; /* RR type */
|
||||||
|
ushort query; /* query tyis is in response to */
|
||||||
|
uchar auth; /* authoritative */
|
||||||
|
uchar db; /* from database */
|
||||||
|
uchar cached; /* rr in cache */
|
||||||
|
ulong marker; /* used locally when scanning rrlists */
|
||||||
|
union {
|
||||||
|
DN *negsoaowner; /* soa for cached negative response */
|
||||||
|
DN *host; /* hostname - soa, cname, mb, md, mf, mx, ns */
|
||||||
|
DN *cpu; /* cpu type - hinfo */
|
||||||
|
DN *mb; /* mailbox - mg, minfo */
|
||||||
|
DN *ip; /* ip addrss - a */
|
||||||
|
DN *rp; /* rp arg - rp */
|
||||||
|
int cruftlen;
|
||||||
|
ulong arg0;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
int negrcode; /* response code for cached negative response */
|
||||||
|
DN *rmb; /* responsible maibox - minfo, soa, rp */
|
||||||
|
DN *ptr; /* pointer to domain name - ptr */
|
||||||
|
DN *os; /* operating system - hinfo */
|
||||||
|
ulong pref; /* preference value - mx */
|
||||||
|
ulong local; /* ns served from local database - ns */
|
||||||
|
ulong arg1;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
SOA *soa; /* soa timers - soa */
|
||||||
|
Key *key;
|
||||||
|
Cert *cert;
|
||||||
|
Sig *sig;
|
||||||
|
Null *null;
|
||||||
|
Txt *txt;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* list of servers
|
||||||
|
*/
|
||||||
|
struct Server
|
||||||
|
{
|
||||||
|
Server *next;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* timers for a start of authenticated record
|
||||||
|
*/
|
||||||
|
struct SOA
|
||||||
|
{
|
||||||
|
ulong serial; /* zone serial # (sec) - soa */
|
||||||
|
ulong refresh; /* zone refresh interval (sec) - soa */
|
||||||
|
ulong retry; /* zone retry interval (sec) - soa */
|
||||||
|
ulong expire; /* time to expiration (sec) - soa */
|
||||||
|
ulong minttl; /* minimum time to live for any entry (sec) - soa */
|
||||||
|
Server *slaves; /* slave servers */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* domain messages
|
||||||
|
*/
|
||||||
|
struct DNSmsg
|
||||||
|
{
|
||||||
|
ushort id;
|
||||||
|
int flags;
|
||||||
|
int qdcount; /* questions */
|
||||||
|
RR *qd;
|
||||||
|
int ancount; /* answers */
|
||||||
|
RR *an;
|
||||||
|
int nscount; /* name servers */
|
||||||
|
RR *ns;
|
||||||
|
int arcount; /* hints */
|
||||||
|
RR *ar;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* definition of local area for dblookup
|
||||||
|
*/
|
||||||
|
struct Area
|
||||||
|
{
|
||||||
|
Area *next;
|
||||||
|
|
||||||
|
int len; /* strlen(area->soarr->owner->name) */
|
||||||
|
RR *soarr; /* soa defining this area */
|
||||||
|
int neednotify;
|
||||||
|
int needrefresh;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Recurse,
|
||||||
|
Dontrecurse,
|
||||||
|
NOneg,
|
||||||
|
OKneg,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* dn.c */
|
||||||
|
extern char *rrtname[];
|
||||||
|
extern char *rname[];
|
||||||
|
extern char *opname[];
|
||||||
|
extern void db2cache(int);
|
||||||
|
extern void dninit(void);
|
||||||
|
extern DN* dnlookup(char*, int, int);
|
||||||
|
extern void dnage(DN*);
|
||||||
|
extern void dnageall(int);
|
||||||
|
extern void dnagedb(void);
|
||||||
|
extern void dnauthdb(void);
|
||||||
|
extern void dnget(void);
|
||||||
|
extern void dnpurge(void);
|
||||||
|
extern void dnput(void);
|
||||||
|
extern Area* inmyarea(char*);
|
||||||
|
extern void rrattach(RR*, int);
|
||||||
|
extern RR* rralloc(int);
|
||||||
|
extern void rrfree(RR*);
|
||||||
|
extern void rrfreelist(RR*);
|
||||||
|
extern RR* rrlookup(DN*, int, int);
|
||||||
|
extern RR* rrcat(RR**, RR*);
|
||||||
|
extern RR** rrcopy(RR*, RR**);
|
||||||
|
extern RR* rrremneg(RR**);
|
||||||
|
extern RR* rrremtype(RR**, int);
|
||||||
|
extern int rrfmt(Fmt*);
|
||||||
|
extern int rravfmt(Fmt*);
|
||||||
|
extern int rrsupported(int);
|
||||||
|
extern int rrtype(char*);
|
||||||
|
extern char* rrname(int, char*, int);
|
||||||
|
extern int tsame(int, int);
|
||||||
|
extern void dndump(char*);
|
||||||
|
extern int getactivity(Request*);
|
||||||
|
extern void putactivity(void);
|
||||||
|
extern void abort(); /* char*, ... */;
|
||||||
|
extern void warning(char*, ...);
|
||||||
|
extern void slave(Request*);
|
||||||
|
extern void dncheck(void*, int);
|
||||||
|
extern void unique(RR*);
|
||||||
|
extern int subsume(char*, char*);
|
||||||
|
extern RR* randomize(RR*);
|
||||||
|
extern void* emalloc(int);
|
||||||
|
extern char* estrdup(char*);
|
||||||
|
extern void dnptr(uchar*, uchar*, char*, int, int);
|
||||||
|
extern void addserver(Server**, char*);
|
||||||
|
extern Server* copyserverlist(Server*);
|
||||||
|
extern void freeserverlist(Server*);
|
||||||
|
|
||||||
|
/* dnarea.c */
|
||||||
|
extern void refresh_areas(Area*);
|
||||||
|
extern void freearea(Area**);
|
||||||
|
extern void addarea(DN *dp, RR *rp, Ndbtuple *t);
|
||||||
|
|
||||||
|
/* dblookup.c */
|
||||||
|
extern RR* dblookup(char*, int, int, int, int);
|
||||||
|
extern RR* dbinaddr(DN*, int);
|
||||||
|
extern int baddelegation(RR*, RR*, uchar*);
|
||||||
|
extern RR* dnsservers(int);
|
||||||
|
extern RR* domainlist(int);
|
||||||
|
extern int opendatabase(void);
|
||||||
|
|
||||||
|
/* dns.c */
|
||||||
|
extern char* walkup(char*);
|
||||||
|
extern RR* getdnsservers(int);
|
||||||
|
extern void logreply(int, uchar*, DNSmsg*);
|
||||||
|
extern void logsend(int, int, uchar*, char*, char*, int);
|
||||||
|
|
||||||
|
/* dnresolve.c */
|
||||||
|
extern RR* dnresolve(char*, int, int, Request*, RR**, int, int, int, int*);
|
||||||
|
extern int udpport(void);
|
||||||
|
extern int mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno);
|
||||||
|
|
||||||
|
/* dnserver.c */
|
||||||
|
extern void dnserver(DNSmsg*, DNSmsg*, Request*);
|
||||||
|
extern void dnudpserver(void*);
|
||||||
|
extern void dntcpserver(char*);
|
||||||
|
|
||||||
|
/* dnnotify.c */
|
||||||
|
extern void dnnotify(DNSmsg*, DNSmsg*, Request*);
|
||||||
|
extern void notifyproc(void);
|
||||||
|
|
||||||
|
/* convDNS2M.c */
|
||||||
|
extern int convDNS2M(DNSmsg*, uchar*, int);
|
||||||
|
|
||||||
|
/* convM2DNS.c */
|
||||||
|
extern char* convM2DNS(uchar*, int, DNSmsg*);
|
||||||
|
|
||||||
|
/* malloc.c */
|
||||||
|
extern void mallocsanity(void*);
|
||||||
|
extern void lasthist(void*, int, ulong);
|
||||||
|
|
||||||
|
extern int debug;
|
||||||
|
extern int traceactivity;
|
||||||
|
extern char *trace;
|
||||||
|
extern int testing; /* test cache whenever removing a DN */
|
||||||
|
extern int cachedb;
|
||||||
|
extern int needrefresh;
|
||||||
|
extern char *dbfile;
|
||||||
|
extern char mntpt[];
|
||||||
|
extern char *logfile;
|
||||||
|
extern int resolver;
|
||||||
|
extern int maxage; /* age of oldest entry in cache (secs) */
|
||||||
|
extern char *zonerefreshprogram;
|
||||||
|
extern int sendnotifies;
|
||||||
|
extern ulong now; /* time base */
|
||||||
|
extern Area *owned;
|
||||||
|
extern Area *delegated;
|
||||||
|
|
||||||
|
#pragma varargck type "R" RR*
|
||||||
|
#pragma varargck type "Q" RR*
|
||||||
|
|
||||||
473
src/cmd/ndb/dnsdebug.c
Executable file
473
src/cmd/ndb/dnsdebug.c
Executable file
@ -0,0 +1,473 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Maxrequest= 128,
|
||||||
|
Ncache= 8,
|
||||||
|
Maxpath= 128,
|
||||||
|
Maxreply= 512,
|
||||||
|
Maxrrr= 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *servername;
|
||||||
|
static RR *serverrr;
|
||||||
|
static RR *serveraddrs;
|
||||||
|
|
||||||
|
int debug;
|
||||||
|
int cachedb;
|
||||||
|
ulong now;
|
||||||
|
int testing;
|
||||||
|
int traceactivity;
|
||||||
|
char *trace;
|
||||||
|
int needrefresh;
|
||||||
|
int resolver;
|
||||||
|
uchar ipaddr[IPaddrlen]; /* my ip address */
|
||||||
|
int maxage;
|
||||||
|
char *logfile = "dns";
|
||||||
|
char *dbfile;
|
||||||
|
char mntpt[Maxpath];
|
||||||
|
char *zonerefreshprogram;
|
||||||
|
|
||||||
|
int prettyrrfmt(Fmt*);
|
||||||
|
void preloadserveraddrs(void);
|
||||||
|
void squirrelserveraddrs(void);
|
||||||
|
int setserver(char*);
|
||||||
|
void doquery(char*, char*);
|
||||||
|
void docmd(int, char**);
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
Biobuf in;
|
||||||
|
char *p;
|
||||||
|
char *f[4];
|
||||||
|
|
||||||
|
strcpy(mntpt, "/net");
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'r':
|
||||||
|
resolver = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
dbfile = "/lib/ndb/external";
|
||||||
|
strcpy(mntpt, "/net.alt");
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
dbfile = ARGF();
|
||||||
|
break;
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
now = time(0);
|
||||||
|
dninit();
|
||||||
|
fmtinstall('R', prettyrrfmt);
|
||||||
|
if(myipaddr(ipaddr, mntpt) < 0)
|
||||||
|
sysfatal("can't read my ip address");
|
||||||
|
opendatabase();
|
||||||
|
|
||||||
|
if(resolver)
|
||||||
|
squirrelserveraddrs();
|
||||||
|
|
||||||
|
debug = 1;
|
||||||
|
|
||||||
|
if(argc > 0){
|
||||||
|
docmd(argc, argv);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Binit(&in, 0, OREAD);
|
||||||
|
for(print("> "); p = Brdline(&in, '\n'); print("> ")){
|
||||||
|
p[Blinelen(&in)-1] = 0;
|
||||||
|
n = tokenize(p, f, 3);
|
||||||
|
if(n<1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* flush the cache */
|
||||||
|
dnpurge();
|
||||||
|
|
||||||
|
docmd(n, f);
|
||||||
|
|
||||||
|
}
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
longtime(long t)
|
||||||
|
{
|
||||||
|
int d, h, m, n;
|
||||||
|
static char x[128];
|
||||||
|
|
||||||
|
for(d = 0; t >= 24*60*60; t -= 24*60*60)
|
||||||
|
d++;
|
||||||
|
for(h = 0; t >= 60*60; t -= 60*60)
|
||||||
|
h++;
|
||||||
|
for(m = 0; t >= 60; t -= 60)
|
||||||
|
m++;
|
||||||
|
n = 0;
|
||||||
|
if(d)
|
||||||
|
n += sprint(x, "%d day ", d);
|
||||||
|
if(h)
|
||||||
|
n += sprint(x+n, "%d hr ", h);
|
||||||
|
if(m)
|
||||||
|
n += sprint(x+n, "%d min ", m);
|
||||||
|
if(t || n == 0)
|
||||||
|
sprint(x+n, "%ld sec", t);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
prettyrrfmt(Fmt *f)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
char buf[3*Domlen];
|
||||||
|
char *p, *e;
|
||||||
|
Txt *t;
|
||||||
|
|
||||||
|
rp = va_arg(f->args, RR*);
|
||||||
|
if(rp == 0){
|
||||||
|
strcpy(buf, "<null>");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
e = buf + sizeof(buf);
|
||||||
|
p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name,
|
||||||
|
longtime(rp->db ? rp->ttl : (rp->ttl-now)),
|
||||||
|
rrname(rp->type, buf, sizeof buf));
|
||||||
|
|
||||||
|
if(rp->negative){
|
||||||
|
seprint(p, e, "negative rcode %d\n", rp->negrcode);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(rp->type){
|
||||||
|
case Thinfo:
|
||||||
|
seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name);
|
||||||
|
break;
|
||||||
|
case Tcname:
|
||||||
|
case Tmb:
|
||||||
|
case Tmd:
|
||||||
|
case Tmf:
|
||||||
|
case Tns:
|
||||||
|
seprint(p, e, "\t%s", rp->host->name);
|
||||||
|
break;
|
||||||
|
case Tmg:
|
||||||
|
case Tmr:
|
||||||
|
seprint(p, e, "\t%s", rp->mb->name);
|
||||||
|
break;
|
||||||
|
case Tminfo:
|
||||||
|
seprint(p, e, "\t%s %s", rp->mb->name, rp->rmb->name);
|
||||||
|
break;
|
||||||
|
case Tmx:
|
||||||
|
seprint(p, e, "\t%lud %s", rp->pref, rp->host->name);
|
||||||
|
break;
|
||||||
|
case Ta:
|
||||||
|
case Taaaa:
|
||||||
|
seprint(p, e, "\t%s", rp->ip->name);
|
||||||
|
break;
|
||||||
|
case Tptr:
|
||||||
|
seprint(p, e, "\t%s", rp->ptr->name);
|
||||||
|
break;
|
||||||
|
case Tsoa:
|
||||||
|
seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", rp->host->name,
|
||||||
|
rp->rmb->name, rp->soa->serial, rp->soa->refresh, rp->soa->retry,
|
||||||
|
rp->soa->expire, rp->soa->minttl);
|
||||||
|
break;
|
||||||
|
case Tnull:
|
||||||
|
seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data);
|
||||||
|
break;
|
||||||
|
case Ttxt:
|
||||||
|
p = seprint(p, e, "\t");
|
||||||
|
for(t = rp->txt; t != nil; t = t->next)
|
||||||
|
p = seprint(p, e, "%s", t->p);
|
||||||
|
break;
|
||||||
|
case Trp:
|
||||||
|
seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name);
|
||||||
|
break;
|
||||||
|
case Tkey:
|
||||||
|
seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto,
|
||||||
|
rp->key->alg);
|
||||||
|
break;
|
||||||
|
case Tsig:
|
||||||
|
seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s",
|
||||||
|
rp->sig->type, rp->sig->alg, rp->sig->labels, rp->sig->ttl,
|
||||||
|
rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->sig->signer->name);
|
||||||
|
break;
|
||||||
|
case Tcert:
|
||||||
|
seprint(p, e, "\t%d %d %d",
|
||||||
|
rp->sig->type, rp->sig->tag, rp->sig->alg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return fmtstrcpy(f, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logsection(char *flag, RR *rp)
|
||||||
|
{
|
||||||
|
if(rp == nil)
|
||||||
|
return;
|
||||||
|
print("\t%s%R\n", flag, rp);
|
||||||
|
for(rp = rp->next; rp != nil; rp = rp->next)
|
||||||
|
print("\t %R\n", rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logreply(int id, uchar *addr, DNSmsg *mp)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
char buf[12];
|
||||||
|
char resp[32];
|
||||||
|
|
||||||
|
switch(mp->flags & Rmask){
|
||||||
|
case Rok:
|
||||||
|
strcpy(resp, "OK");
|
||||||
|
break;
|
||||||
|
case Rformat:
|
||||||
|
strcpy(resp, "Format error");
|
||||||
|
break;
|
||||||
|
case Rserver:
|
||||||
|
strcpy(resp, "Server failed");
|
||||||
|
break;
|
||||||
|
case Rname:
|
||||||
|
strcpy(resp, "Nonexistent");
|
||||||
|
break;
|
||||||
|
case Runimplimented:
|
||||||
|
strcpy(resp, "Unimplemented");
|
||||||
|
break;
|
||||||
|
case Rrefused:
|
||||||
|
strcpy(resp, "Refused");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sprint(resp, "%d", mp->flags & Rmask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr,
|
||||||
|
mp->flags & Fauth ? "authoritative" : "",
|
||||||
|
mp->flags & Ftrunc ? " truncated" : "",
|
||||||
|
mp->flags & Frecurse ? " recurse" : "",
|
||||||
|
mp->flags & Fcanrec ? " can_recurse" : "",
|
||||||
|
mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
|
||||||
|
" nx" : "");
|
||||||
|
for(rp = mp->qd; rp != nil; rp = rp->next)
|
||||||
|
print("\tQ: %s %s\n", rp->owner->name, rrname(rp->type, buf, sizeof buf));
|
||||||
|
logsection("Ans: ", mp->an);
|
||||||
|
logsection("Auth: ", mp->ns);
|
||||||
|
logsection("Hint: ", mp->ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
|
||||||
|
{
|
||||||
|
char buf[12];
|
||||||
|
|
||||||
|
print("%d.%d: sending to %I/%s %s %s\n", id, subid,
|
||||||
|
addr, sname, rname, rrname(type, buf, sizeof buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
RR*
|
||||||
|
getdnsservers(int class)
|
||||||
|
{
|
||||||
|
RR *rr;
|
||||||
|
|
||||||
|
if(servername == nil)
|
||||||
|
return dnsservers(class);
|
||||||
|
|
||||||
|
rr = rralloc(Tns);
|
||||||
|
rr->owner = dnlookup("local#dns#servers", class, 1);
|
||||||
|
rr->host = dnlookup(servername, class, 1);
|
||||||
|
|
||||||
|
return rr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
squirrelserveraddrs(void)
|
||||||
|
{
|
||||||
|
RR *rr, *rp, **l;
|
||||||
|
Request req;
|
||||||
|
|
||||||
|
/* look up the resolver address first */
|
||||||
|
resolver = 0;
|
||||||
|
debug = 0;
|
||||||
|
if(serveraddrs)
|
||||||
|
rrfreelist(serveraddrs);
|
||||||
|
serveraddrs = nil;
|
||||||
|
rr = getdnsservers(Cin);
|
||||||
|
l = &serveraddrs;
|
||||||
|
for(rp = rr; rp != nil; rp = rp->next){
|
||||||
|
if(strcmp(ipattr(rp->host->name), "ip") == 0){
|
||||||
|
*l = rralloc(Ta);
|
||||||
|
(*l)->owner = rp->host;
|
||||||
|
(*l)->ip = rp->host;
|
||||||
|
l = &(*l)->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
req.isslave = 1;
|
||||||
|
req.aborttime = now + 60; /* don't spend more than 60 seconds */
|
||||||
|
*l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0);
|
||||||
|
while(*l != nil)
|
||||||
|
l = &(*l)->next;
|
||||||
|
}
|
||||||
|
resolver = 1;
|
||||||
|
debug = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
preloadserveraddrs(void)
|
||||||
|
{
|
||||||
|
RR *rp, **l, *first;
|
||||||
|
|
||||||
|
l = &first;
|
||||||
|
for(rp = serveraddrs; rp != nil; rp = rp->next){
|
||||||
|
rrcopy(rp, l);
|
||||||
|
rrattach(first, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
setserver(char *server)
|
||||||
|
{
|
||||||
|
if(servername != nil){
|
||||||
|
free(servername);
|
||||||
|
servername = nil;
|
||||||
|
resolver = 0;
|
||||||
|
}
|
||||||
|
if(server == nil || *server == 0)
|
||||||
|
return 0;
|
||||||
|
servername = strdup(server);
|
||||||
|
squirrelserveraddrs();
|
||||||
|
if(serveraddrs == nil){
|
||||||
|
print("can't resolve %s\n", servername);
|
||||||
|
resolver = 0;
|
||||||
|
} else {
|
||||||
|
resolver = 1;
|
||||||
|
}
|
||||||
|
return resolver ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
doquery(char *name, char *tstr)
|
||||||
|
{
|
||||||
|
Request req;
|
||||||
|
RR *rr, *rp;
|
||||||
|
int len, type;
|
||||||
|
char *p, *np;
|
||||||
|
int rooted;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if(resolver)
|
||||||
|
preloadserveraddrs();
|
||||||
|
|
||||||
|
/* default to an "ip" request if alpha, "ptr" if numeric */
|
||||||
|
if(tstr == nil || *tstr == 0) {
|
||||||
|
if(strcmp(ipattr(name), "ip") == 0)
|
||||||
|
tstr = "ptr";
|
||||||
|
else
|
||||||
|
tstr = "ip";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if name end in '.', remove it */
|
||||||
|
len = strlen(name);
|
||||||
|
if(len > 0 && name[len-1] == '.'){
|
||||||
|
rooted = 1;
|
||||||
|
name[len-1] = 0;
|
||||||
|
} else
|
||||||
|
rooted = 0;
|
||||||
|
|
||||||
|
/* inverse queries may need to be permuted */
|
||||||
|
strncpy(buf, name, sizeof buf);
|
||||||
|
if(strcmp("ptr", tstr) == 0
|
||||||
|
&& strstr(name, "IN-ADDR") == 0
|
||||||
|
&& strstr(name, "in-addr") == 0){
|
||||||
|
for(p = name; *p; p++)
|
||||||
|
;
|
||||||
|
*p = '.';
|
||||||
|
np = buf;
|
||||||
|
len = 0;
|
||||||
|
while(p >= name){
|
||||||
|
len++;
|
||||||
|
p--;
|
||||||
|
if(*p == '.'){
|
||||||
|
memmove(np, p+1, len);
|
||||||
|
np += len;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memmove(np, p+1, len);
|
||||||
|
np += len;
|
||||||
|
strcpy(np, "in-addr.arpa");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look it up */
|
||||||
|
type = rrtype(tstr);
|
||||||
|
if(type < 0){
|
||||||
|
print("!unknown type %s\n", tstr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getactivity(&req);
|
||||||
|
req.isslave = 1;
|
||||||
|
req.aborttime = now + 60; /* don't spend more than 60 seconds */
|
||||||
|
rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0);
|
||||||
|
if(rr){
|
||||||
|
print("----------------------------\n");
|
||||||
|
for(rp = rr; rp; rp = rp->next)
|
||||||
|
print("answer %R\n", rp);
|
||||||
|
print("----------------------------\n");
|
||||||
|
}
|
||||||
|
rrfreelist(rr);
|
||||||
|
|
||||||
|
putactivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
docmd(int n, char **f)
|
||||||
|
{
|
||||||
|
int tmpsrv;
|
||||||
|
char *name, *type;
|
||||||
|
|
||||||
|
name = nil;
|
||||||
|
type = nil;
|
||||||
|
tmpsrv = 0;
|
||||||
|
|
||||||
|
if(*f[0] == '@') {
|
||||||
|
if(setserver(f[0]+1) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch(n){
|
||||||
|
case 3:
|
||||||
|
type = f[2];
|
||||||
|
/* fall through */
|
||||||
|
case 2:
|
||||||
|
name = f[1];
|
||||||
|
tmpsrv = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(n){
|
||||||
|
case 2:
|
||||||
|
type = f[1];
|
||||||
|
/* fall through */
|
||||||
|
case 1:
|
||||||
|
name = f[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
doquery(name, type);
|
||||||
|
|
||||||
|
if(tmpsrv)
|
||||||
|
setserver("");
|
||||||
|
}
|
||||||
178
src/cmd/ndb/dnserver.c
Executable file
178
src/cmd/ndb/dnserver.c
Executable file
@ -0,0 +1,178 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
static RR* doextquery(DNSmsg*, Request*, int);
|
||||||
|
static void hint(RR**, RR*);
|
||||||
|
|
||||||
|
extern char *logfile;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* answer a dns request
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
|
||||||
|
{
|
||||||
|
RR *tp, *neg;
|
||||||
|
char *cp;
|
||||||
|
DN *nsdp, *dp;
|
||||||
|
Area *myarea;
|
||||||
|
char tname[32];
|
||||||
|
|
||||||
|
dncheck(nil, 1);
|
||||||
|
|
||||||
|
memset(repp, 0, sizeof(*repp));
|
||||||
|
repp->id = reqp->id;
|
||||||
|
repp->flags = Fresp | Fcanrec | Oquery;
|
||||||
|
|
||||||
|
/* move one question from reqp to repp */
|
||||||
|
tp = reqp->qd;
|
||||||
|
reqp->qd = tp->next;
|
||||||
|
tp->next = 0;
|
||||||
|
repp->qd = tp;
|
||||||
|
|
||||||
|
if(!rrsupported(repp->qd->type)){
|
||||||
|
syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
|
||||||
|
repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(repp->qd->owner->class != Cin){
|
||||||
|
syslog(0, logfile, "server: class %d", repp->qd->owner->class);
|
||||||
|
repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
myarea = inmyarea(repp->qd->owner->name);
|
||||||
|
if(myarea != nil && (repp->qd->type == Tixfr || repp->qd->type == Taxfr)){
|
||||||
|
syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
|
||||||
|
repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get the answer if we can
|
||||||
|
*/
|
||||||
|
if(reqp->flags & Frecurse)
|
||||||
|
neg = doextquery(repp, req, Recurse);
|
||||||
|
else
|
||||||
|
neg = doextquery(repp, req, Dontrecurse);
|
||||||
|
|
||||||
|
/* authority is transitive */
|
||||||
|
if(myarea != nil || (repp->an && repp->an->auth))
|
||||||
|
repp->flags |= Fauth;
|
||||||
|
|
||||||
|
/* pass on error codes */
|
||||||
|
if(repp->an == 0){
|
||||||
|
dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
|
||||||
|
if(dp->rr == 0)
|
||||||
|
if(reqp->flags & Frecurse)
|
||||||
|
repp->flags |= dp->nonexistent|Fauth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(myarea == nil){
|
||||||
|
/*
|
||||||
|
* add name server if we know
|
||||||
|
*/
|
||||||
|
for(cp = repp->qd->owner->name; cp; cp = walkup(cp)){
|
||||||
|
nsdp = dnlookup(cp, repp->qd->owner->class, 0);
|
||||||
|
if(nsdp == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
repp->ns = rrlookup(nsdp, Tns, OKneg);
|
||||||
|
if(repp->ns){
|
||||||
|
/* don't pass on anything we know is wrong */
|
||||||
|
if(repp->ns->negative){
|
||||||
|
rrfreelist(repp->ns);
|
||||||
|
repp->ns = nil;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
|
||||||
|
if(repp->ns)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add ip addresses as hints
|
||||||
|
*/
|
||||||
|
if(repp->qd->type != Taxfr && repp->qd->type != Tixfr){
|
||||||
|
for(tp = repp->ns; tp; tp = tp->next)
|
||||||
|
hint(&repp->ar, tp);
|
||||||
|
for(tp = repp->an; tp; tp = tp->next)
|
||||||
|
hint(&repp->ar, tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add an soa to the authority section to help client with negative caching
|
||||||
|
*/
|
||||||
|
if(repp->an == nil){
|
||||||
|
if(myarea != nil){
|
||||||
|
rrcopy(myarea->soarr, &tp);
|
||||||
|
rrcat(&repp->ns, tp);
|
||||||
|
} else if(neg != nil) {
|
||||||
|
if(neg->negsoaowner != nil)
|
||||||
|
rrcat(&repp->ns, rrlookup(neg->negsoaowner, Tsoa, NOneg));
|
||||||
|
repp->flags |= neg->negrcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get rid of duplicates
|
||||||
|
*/
|
||||||
|
unique(repp->an);
|
||||||
|
unique(repp->ns);
|
||||||
|
unique(repp->ar);
|
||||||
|
|
||||||
|
rrfreelist(neg);
|
||||||
|
|
||||||
|
dncheck(nil, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* satisfy a recursive request. dnlookup will handle cnames.
|
||||||
|
*/
|
||||||
|
static RR*
|
||||||
|
doextquery(DNSmsg *mp, Request *req, int recurse)
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
char *name;
|
||||||
|
RR *rp, *neg;
|
||||||
|
|
||||||
|
name = mp->qd->owner->name;
|
||||||
|
type = mp->qd->type;
|
||||||
|
rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
|
||||||
|
|
||||||
|
/* don't return soa hints as answers, it's wrong */
|
||||||
|
if(rp && rp->db && !rp->auth && rp->type == Tsoa)
|
||||||
|
rrfreelist(rp);
|
||||||
|
|
||||||
|
/* don't let negative cached entries escape */
|
||||||
|
neg = rrremneg(&rp);
|
||||||
|
rrcat(&mp->an, rp);
|
||||||
|
return neg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hint(RR **last, RR *rp)
|
||||||
|
{
|
||||||
|
RR *hp;
|
||||||
|
|
||||||
|
switch(rp->type){
|
||||||
|
case Tns:
|
||||||
|
case Tmx:
|
||||||
|
case Tmb:
|
||||||
|
case Tmf:
|
||||||
|
case Tmd:
|
||||||
|
hp = rrlookup(rp->host, Ta, NOneg);
|
||||||
|
if(hp == nil)
|
||||||
|
hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
|
||||||
|
rrcat(last, hp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/cmd/ndb/dnsquery.c
Executable file
113
src/cmd/ndb/dnsquery.c
Executable file
@ -0,0 +1,113 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
#include "ip.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd, n, len, domount;
|
||||||
|
Biobuf in;
|
||||||
|
char line[1024], *lp, *p, *np, *mtpt, *srv, *dns;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
dns = "/net/dns";
|
||||||
|
mtpt = "/net";
|
||||||
|
srv = "/srv/dns";
|
||||||
|
domount = 1;
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'x':
|
||||||
|
dns = "/net.alt/dns";
|
||||||
|
mtpt = "/net.alt";
|
||||||
|
srv = "/srv/dns_net.alt";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprint(2, "usage: %s -x [dns-mount-point]\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
} ARGEND;
|
||||||
|
|
||||||
|
if(argc == 1){
|
||||||
|
domount = 0;
|
||||||
|
mtpt = argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(dns, ORDWR);
|
||||||
|
if(fd < 0){
|
||||||
|
if(domount == 0){
|
||||||
|
fprint(2, "can't open %s: %r\n", mtpt);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
fd = open(srv, ORDWR);
|
||||||
|
if(fd < 0){
|
||||||
|
print("can't open %s: %r\n", srv);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
if(mount(fd, -1, mtpt, MBEFORE, "") < 0){
|
||||||
|
print("can't mount(%s, %s): %r\n", srv, mtpt);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
fd = open(mtpt, ORDWR);
|
||||||
|
if(fd < 0){
|
||||||
|
print("can't open %s: %r\n", mtpt);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Binit(&in, 0, OREAD);
|
||||||
|
for(print("> "); lp = Brdline(&in, '\n'); print("> ")){
|
||||||
|
n = Blinelen(&in)-1;
|
||||||
|
strncpy(line, lp, n);
|
||||||
|
line[n] = 0;
|
||||||
|
if (n<=1)
|
||||||
|
continue;
|
||||||
|
/* default to an "ip" request if alpha, "ptr" if numeric */
|
||||||
|
if (strchr(line, ' ')==0) {
|
||||||
|
if(strcmp(ipattr(line), "ip") == 0) {
|
||||||
|
strcat(line, " ptr");
|
||||||
|
n += 4;
|
||||||
|
} else {
|
||||||
|
strcat(line, " ip");
|
||||||
|
n += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inverse queries may need to be permuted */
|
||||||
|
if(n > 4 && strcmp("ptr", &line[n-3]) == 0
|
||||||
|
&& strstr(line, "IN-ADDR") == 0 && strstr(line, "in-addr") == 0){
|
||||||
|
for(p = line; *p; p++)
|
||||||
|
if(*p == ' '){
|
||||||
|
*p = '.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
np = buf;
|
||||||
|
len = 0;
|
||||||
|
while(p >= line){
|
||||||
|
len++;
|
||||||
|
p--;
|
||||||
|
if(*p == '.'){
|
||||||
|
memmove(np, p+1, len);
|
||||||
|
np += len;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memmove(np, p+1, len);
|
||||||
|
np += len;
|
||||||
|
strcpy(np, "in-addr.arpa ptr");
|
||||||
|
strcpy(line, buf);
|
||||||
|
n = strlen(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
seek(fd, 0, 0);
|
||||||
|
if(write(fd, line, n) < 0) {
|
||||||
|
print("!%r\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seek(fd, 0, 0);
|
||||||
|
while((n = read(fd, buf, sizeof(buf))) > 0){
|
||||||
|
buf[n] = 0;
|
||||||
|
print("%s\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
362
src/cmd/ndb/dnstcp.c
Executable file
362
src/cmd/ndb/dnstcp.c
Executable file
@ -0,0 +1,362 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Maxpath= 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
char *logfile = "dns";
|
||||||
|
char *dbfile;
|
||||||
|
int debug;
|
||||||
|
int cachedb = 1;
|
||||||
|
int testing;
|
||||||
|
int traceactivity;
|
||||||
|
int needrefresh;
|
||||||
|
int resolver;
|
||||||
|
char mntpt[Maxpath];
|
||||||
|
char *caller = "";
|
||||||
|
ulong now;
|
||||||
|
int maxage;
|
||||||
|
uchar ipaddr[IPaddrlen]; /* my ip address */
|
||||||
|
char *LOG;
|
||||||
|
char *zonerefreshprogram;
|
||||||
|
|
||||||
|
static int readmsg(int, uchar*, int);
|
||||||
|
static void reply(int, DNSmsg*, Request*);
|
||||||
|
static void dnzone(DNSmsg*, DNSmsg*, Request*);
|
||||||
|
static void getcaller(char*);
|
||||||
|
static void refreshmain(char*);
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
Request req;
|
||||||
|
DNSmsg reqmsg, repmsg;
|
||||||
|
uchar buf[512];
|
||||||
|
char tname[32];
|
||||||
|
char *err;
|
||||||
|
char *ext = "";
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'd':
|
||||||
|
debug++;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
dbfile = ARGF();
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
resolver = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
ext = ARGF();
|
||||||
|
break;
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
if(debug < 2)
|
||||||
|
debug = 0;
|
||||||
|
|
||||||
|
if(argc > 0)
|
||||||
|
getcaller(argv[0]);
|
||||||
|
|
||||||
|
dninit();
|
||||||
|
|
||||||
|
snprint(mntpt, sizeof(mntpt), "/net%s", ext);
|
||||||
|
if(myipaddr(ipaddr, mntpt) < 0)
|
||||||
|
sysfatal("can't read my ip address");
|
||||||
|
syslog(0, logfile, "dnstcp call from %s to %I", caller, ipaddr);
|
||||||
|
|
||||||
|
db2cache(1);
|
||||||
|
|
||||||
|
setjmp(req.mret);
|
||||||
|
req.isslave = 0;
|
||||||
|
|
||||||
|
/* loop on requests */
|
||||||
|
for(;; putactivity()){
|
||||||
|
now = time(0);
|
||||||
|
memset(&repmsg, 0, sizeof(repmsg));
|
||||||
|
alarm(10*60*1000);
|
||||||
|
len = readmsg(0, buf, sizeof(buf));
|
||||||
|
alarm(0);
|
||||||
|
if(len <= 0)
|
||||||
|
break;
|
||||||
|
getactivity(&req);
|
||||||
|
req.aborttime = now + 15*Min;
|
||||||
|
err = convM2DNS(buf, len, &reqmsg);
|
||||||
|
if(err){
|
||||||
|
syslog(0, logfile, "server: input error: %s from %I", err, buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(reqmsg.qdcount < 1){
|
||||||
|
syslog(0, logfile, "server: no questions from %I", buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(reqmsg.flags & Fresp){
|
||||||
|
syslog(0, logfile, "server: reply not request from %I", buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if((reqmsg.flags & Omask) != Oquery){
|
||||||
|
syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(debug)
|
||||||
|
syslog(0, logfile, "%d: serve (%s) %d %s %s",
|
||||||
|
req.id, caller,
|
||||||
|
reqmsg.id,
|
||||||
|
reqmsg.qd->owner->name,
|
||||||
|
rrname(reqmsg.qd->type, tname, sizeof tname));
|
||||||
|
|
||||||
|
/* loop through each question */
|
||||||
|
while(reqmsg.qd){
|
||||||
|
if(reqmsg.qd->type == Taxfr){
|
||||||
|
dnzone(&reqmsg, &repmsg, &req);
|
||||||
|
} else {
|
||||||
|
dnserver(&reqmsg, &repmsg, &req);
|
||||||
|
reply(1, &repmsg, &req);
|
||||||
|
rrfreelist(repmsg.qd);
|
||||||
|
rrfreelist(repmsg.an);
|
||||||
|
rrfreelist(repmsg.ns);
|
||||||
|
rrfreelist(repmsg.ar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rrfreelist(reqmsg.qd);
|
||||||
|
rrfreelist(reqmsg.an);
|
||||||
|
rrfreelist(reqmsg.ns);
|
||||||
|
rrfreelist(reqmsg.ar);
|
||||||
|
|
||||||
|
if(req.isslave){
|
||||||
|
putactivity();
|
||||||
|
_exits(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refreshmain(mntpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
readmsg(int fd, uchar *buf, int max)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
uchar x[2];
|
||||||
|
|
||||||
|
if(readn(fd, x, 2) != 2)
|
||||||
|
return -1;
|
||||||
|
n = (x[0]<<8) | x[1];
|
||||||
|
if(n > max)
|
||||||
|
return -1;
|
||||||
|
if(readn(fd, buf, n) != n)
|
||||||
|
return -1;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reply(int fd, DNSmsg *rep, Request *req)
|
||||||
|
{
|
||||||
|
int len, rv;
|
||||||
|
char tname[32];
|
||||||
|
uchar buf[4096];
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
if(debug){
|
||||||
|
syslog(0, logfile, "%d: reply (%s) %s %s %ux",
|
||||||
|
req->id, caller,
|
||||||
|
rep->qd->owner->name,
|
||||||
|
rrname(rep->qd->type, tname, sizeof tname),
|
||||||
|
rep->flags);
|
||||||
|
for(rp = rep->an; rp; rp = rp->next)
|
||||||
|
syslog(0, logfile, "an %R", rp);
|
||||||
|
for(rp = rep->ns; rp; rp = rp->next)
|
||||||
|
syslog(0, logfile, "ns %R", rp);
|
||||||
|
for(rp = rep->ar; rp; rp = rp->next)
|
||||||
|
syslog(0, logfile, "ar %R", rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
|
||||||
|
if(len <= 0)
|
||||||
|
abort(); /* "dnserver: converting reply" */;
|
||||||
|
buf[0] = len>>8;
|
||||||
|
buf[1] = len;
|
||||||
|
rv = write(fd, buf, len+2);
|
||||||
|
if(rv != len+2){
|
||||||
|
syslog(0, logfile, "sending reply: %d instead of %d", rv, len+2);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash table for domain names. The hash is based only on the
|
||||||
|
* first element of the domain name.
|
||||||
|
*/
|
||||||
|
extern DN *ht[HTLEN];
|
||||||
|
|
||||||
|
static int
|
||||||
|
numelem(char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
for(; *name; name++)
|
||||||
|
if(*name == '.')
|
||||||
|
i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
inzone(DN *dp, char *name, int namelen, int depth)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(dp->name == 0)
|
||||||
|
return 0;
|
||||||
|
if(numelem(dp->name) != depth)
|
||||||
|
return 0;
|
||||||
|
n = strlen(dp->name);
|
||||||
|
if(n < namelen)
|
||||||
|
return 0;
|
||||||
|
if(strcmp(name, dp->name + n - namelen) != 0)
|
||||||
|
return 0;
|
||||||
|
if(n > namelen && dp->name[n - namelen - 1] != '.')
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
|
||||||
|
{
|
||||||
|
DN *dp, *ndp;
|
||||||
|
RR r, *rp;
|
||||||
|
int h, depth, found, nlen;
|
||||||
|
|
||||||
|
memset(repp, 0, sizeof(*repp));
|
||||||
|
repp->id = reqp->id;
|
||||||
|
repp->flags = Fauth | Fresp | Fcanrec | Oquery;
|
||||||
|
repp->qd = reqp->qd;
|
||||||
|
reqp->qd = reqp->qd->next;
|
||||||
|
repp->qd->next = 0;
|
||||||
|
dp = repp->qd->owner;
|
||||||
|
|
||||||
|
/* send the soa */
|
||||||
|
repp->an = rrlookup(dp, Tsoa, NOneg);
|
||||||
|
reply(1, repp, req);
|
||||||
|
if(repp->an == 0)
|
||||||
|
goto out;
|
||||||
|
rrfreelist(repp->an);
|
||||||
|
|
||||||
|
nlen = strlen(dp->name);
|
||||||
|
|
||||||
|
/* construct a breadth first search of the name space (hard with a hash) */
|
||||||
|
repp->an = &r;
|
||||||
|
for(depth = numelem(dp->name); ; depth++){
|
||||||
|
found = 0;
|
||||||
|
for(h = 0; h < HTLEN; h++)
|
||||||
|
for(ndp = ht[h]; ndp; ndp = ndp->next)
|
||||||
|
if(inzone(ndp, dp->name, nlen, depth)){
|
||||||
|
for(rp = ndp->rr; rp; rp = rp->next){
|
||||||
|
/* there shouldn't be negatives, but just in case */
|
||||||
|
if(rp->negative)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* don't send an soa's, ns's are enough */
|
||||||
|
if(rp->type == Tsoa)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = *rp;
|
||||||
|
r.next = 0;
|
||||||
|
reply(1, repp, req);
|
||||||
|
}
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* resend the soa */
|
||||||
|
repp->an = rrlookup(dp, Tsoa, NOneg);
|
||||||
|
reply(1, repp, req);
|
||||||
|
rrfreelist(repp->an);
|
||||||
|
out:
|
||||||
|
rrfree(repp->qd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getcaller(char *dir)
|
||||||
|
{
|
||||||
|
int fd, n;
|
||||||
|
static char remote[128];
|
||||||
|
|
||||||
|
snprint(remote, sizeof(remote), "%s/remote", dir);
|
||||||
|
fd = open(remote, OREAD);
|
||||||
|
if(fd < 0)
|
||||||
|
return;
|
||||||
|
n = read(fd, remote, sizeof(remote)-1);
|
||||||
|
close(fd);
|
||||||
|
if(n <= 0)
|
||||||
|
return;
|
||||||
|
if(remote[n-1] == '\n')
|
||||||
|
n--;
|
||||||
|
remote[n] = 0;
|
||||||
|
caller = remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
refreshmain(char *net)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char file[128];
|
||||||
|
|
||||||
|
snprint(file, sizeof(file), "%s/dns", net);
|
||||||
|
if(debug)
|
||||||
|
syslog(0, logfile, "refreshing %s", file);
|
||||||
|
fd = open(file, ORDWR);
|
||||||
|
if(fd < 0){
|
||||||
|
syslog(0, logfile, "can't refresh %s", file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fprint(fd, "refresh");
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the following varies between dnsdebug and dns
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
logreply(int id, uchar *addr, DNSmsg *mp)
|
||||||
|
{
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
syslog(0, LOG, "%d: rcvd %I flags:%s%s%s%s%s", id, addr,
|
||||||
|
mp->flags & Fauth ? " auth" : "",
|
||||||
|
mp->flags & Ftrunc ? " trunc" : "",
|
||||||
|
mp->flags & Frecurse ? " rd" : "",
|
||||||
|
mp->flags & Fcanrec ? " ra" : "",
|
||||||
|
mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
|
||||||
|
" nx" : "");
|
||||||
|
for(rp = mp->qd; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I qd %s", id, addr, rp->owner->name);
|
||||||
|
for(rp = mp->an; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I an %R", id, addr, rp);
|
||||||
|
for(rp = mp->ns; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I ns %R", id, addr, rp);
|
||||||
|
for(rp = mp->ar; rp != nil; rp = rp->next)
|
||||||
|
syslog(0, LOG, "%d: rcvd %I ar %R", id, addr, rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
|
||||||
|
{
|
||||||
|
char buf[12];
|
||||||
|
|
||||||
|
syslog(0, LOG, "%d.%d: sending to %I/%s %s %s",
|
||||||
|
id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
RR*
|
||||||
|
getdnsservers(int class)
|
||||||
|
{
|
||||||
|
return dnsservers(class);
|
||||||
|
}
|
||||||
228
src/cmd/ndb/dnudpserver.c
Executable file
228
src/cmd/ndb/dnudpserver.c
Executable file
@ -0,0 +1,228 @@
|
|||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ip.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ndb.h>
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
|
static int udpannounce(char*);
|
||||||
|
static void reply(int, uchar*, DNSmsg*, Request*);
|
||||||
|
|
||||||
|
extern char *logfile;
|
||||||
|
|
||||||
|
static void
|
||||||
|
ding(void *x, char *msg)
|
||||||
|
{
|
||||||
|
USED(x);
|
||||||
|
if(strcmp(msg, "alarm") == 0)
|
||||||
|
noted(NCONT);
|
||||||
|
else
|
||||||
|
noted(NDFLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Inprogress Inprogress;
|
||||||
|
struct Inprogress
|
||||||
|
{
|
||||||
|
int inuse;
|
||||||
|
OUdphdr uh;
|
||||||
|
DN *owner;
|
||||||
|
int type;
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
Inprogress inprog[Maxactive+2];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* record client id and ignore retransmissions.
|
||||||
|
* we're still single thread at this point.
|
||||||
|
*/
|
||||||
|
static Inprogress*
|
||||||
|
clientrxmit(DNSmsg *req, uchar *buf)
|
||||||
|
{
|
||||||
|
Inprogress *p, *empty;
|
||||||
|
OUdphdr *uh;
|
||||||
|
|
||||||
|
uh = (OUdphdr *)buf;
|
||||||
|
empty = 0;
|
||||||
|
for(p = inprog; p < &inprog[Maxactive]; p++){
|
||||||
|
if(p->inuse == 0){
|
||||||
|
if(empty == 0)
|
||||||
|
empty = p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(req->id == p->id)
|
||||||
|
if(req->qd->owner == p->owner)
|
||||||
|
if(req->qd->type == p->type)
|
||||||
|
if(memcmp(uh, &p->uh, OUdphdrsize) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(empty == 0)
|
||||||
|
return 0; /* shouldn't happen - see slave() and definition of Maxactive */
|
||||||
|
|
||||||
|
empty->id = req->id;
|
||||||
|
empty->owner = req->qd->owner;
|
||||||
|
empty->type = req->qd->type;
|
||||||
|
memmove(&empty->uh, uh, OUdphdrsize);
|
||||||
|
empty->inuse = 1;
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a process to act as a dns server for outside reqeusts
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dnudpserver(char *mntpt)
|
||||||
|
{
|
||||||
|
int fd, len, op;
|
||||||
|
Request req;
|
||||||
|
DNSmsg reqmsg, repmsg;
|
||||||
|
uchar buf[OUdphdrsize + Maxudp + 1024];
|
||||||
|
char *err;
|
||||||
|
Inprogress *p;
|
||||||
|
char tname[32];
|
||||||
|
OUdphdr *uh;
|
||||||
|
|
||||||
|
/* fork sharing text, data, and bss with parent */
|
||||||
|
switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
|
||||||
|
case -1:
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = -1;
|
||||||
|
notify(ding);
|
||||||
|
restart:
|
||||||
|
if(fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
while((fd = udpannounce(mntpt)) < 0)
|
||||||
|
sleep(5000);
|
||||||
|
if(setjmp(req.mret))
|
||||||
|
putactivity();
|
||||||
|
req.isslave = 0;
|
||||||
|
|
||||||
|
/* loop on requests */
|
||||||
|
for(;; putactivity()){
|
||||||
|
memset(&repmsg, 0, sizeof(repmsg));
|
||||||
|
memset(&reqmsg, 0, sizeof(reqmsg));
|
||||||
|
alarm(60*1000);
|
||||||
|
len = udpread(fd, (OUdphdr*)buf, buf+OUdphdrsize, sizeof(buf)-OUdphdrsize);
|
||||||
|
alarm(0);
|
||||||
|
if(len <= 0)
|
||||||
|
goto restart;
|
||||||
|
uh = (OUdphdr*)buf;
|
||||||
|
getactivity(&req);
|
||||||
|
req.aborttime = now + 30; /* don't spend more than 30 seconds */
|
||||||
|
err = convM2DNS(&buf[OUdphdrsize], len, &reqmsg);
|
||||||
|
if(err){
|
||||||
|
syslog(0, logfile, "server: input error: %s from %I", err, buf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(reqmsg.qdcount < 1){
|
||||||
|
syslog(0, logfile, "server: no questions from %I", buf);
|
||||||
|
goto freereq;
|
||||||
|
}
|
||||||
|
if(reqmsg.flags & Fresp){
|
||||||
|
syslog(0, logfile, "server: reply not request from %I", buf);
|
||||||
|
goto freereq;
|
||||||
|
}
|
||||||
|
op = reqmsg.flags & Omask;
|
||||||
|
if(op != Oquery && op != Onotify){
|
||||||
|
syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
|
||||||
|
goto freereq;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))){
|
||||||
|
syslog(0, logfile, "%d: serve (%I/%d) %d %s %s",
|
||||||
|
req.id, buf, ((uh->rport[0])<<8)+uh->rport[1],
|
||||||
|
reqmsg.id,
|
||||||
|
reqmsg.qd->owner->name,
|
||||||
|
rrname(reqmsg.qd->type, tname, sizeof tname));
|
||||||
|
}
|
||||||
|
|
||||||
|
p = clientrxmit(&reqmsg, buf);
|
||||||
|
if(p == 0){
|
||||||
|
if(debug)
|
||||||
|
syslog(0, logfile, "%d: duplicate", req.id);
|
||||||
|
goto freereq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loop through each question */
|
||||||
|
while(reqmsg.qd){
|
||||||
|
memset(&repmsg, 0, sizeof(repmsg));
|
||||||
|
switch(op){
|
||||||
|
case Oquery:
|
||||||
|
dnserver(&reqmsg, &repmsg, &req);
|
||||||
|
break;
|
||||||
|
case Onotify:
|
||||||
|
dnnotify(&reqmsg, &repmsg, &req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reply(fd, buf, &repmsg, &req);
|
||||||
|
rrfreelist(repmsg.qd);
|
||||||
|
rrfreelist(repmsg.an);
|
||||||
|
rrfreelist(repmsg.ns);
|
||||||
|
rrfreelist(repmsg.ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->inuse = 0;
|
||||||
|
|
||||||
|
freereq:
|
||||||
|
rrfreelist(reqmsg.qd);
|
||||||
|
rrfreelist(reqmsg.an);
|
||||||
|
rrfreelist(reqmsg.ns);
|
||||||
|
rrfreelist(reqmsg.ar);
|
||||||
|
|
||||||
|
if(req.isslave){
|
||||||
|
putactivity();
|
||||||
|
_exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* announce on udp port
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
udpannounce(char *mntpt)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[40];
|
||||||
|
|
||||||
|
USED(mntpt);
|
||||||
|
|
||||||
|
if((fd=announce("udp!*!nameserver", buf)) < 0)
|
||||||
|
warning("can't announce on dns udp port");
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char tname[32];
|
||||||
|
RR *rp;
|
||||||
|
|
||||||
|
if(debug || (trace && subsume(trace, rep->qd->owner->name)))
|
||||||
|
syslog(0, logfile, "%d: reply (%I/%d) %d %s %s an %R ns %R ar %R",
|
||||||
|
reqp->id, buf, ((buf[4])<<8)+buf[5],
|
||||||
|
rep->id, rep->qd->owner->name,
|
||||||
|
rrname(rep->qd->type, tname, sizeof tname), rep->an, rep->ns, rep->ar);
|
||||||
|
|
||||||
|
len = convDNS2M(rep, &buf[OUdphdrsize], Maxudp);
|
||||||
|
if(len <= 0){
|
||||||
|
syslog(0, logfile, "error converting reply: %s %d", rep->qd->owner->name,
|
||||||
|
rep->qd->type);
|
||||||
|
for(rp = rep->an; rp; rp = rp->next)
|
||||||
|
syslog(0, logfile, "an %R", rp);
|
||||||
|
for(rp = rep->ns; rp; rp = rp->next)
|
||||||
|
syslog(0, logfile, "ns %R", rp);
|
||||||
|
for(rp = rep->ar; rp; rp = rp->next)
|
||||||
|
syslog(0, logfile, "ar %R", rp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(udpwrite(fd, (OUdphdr*)buf, buf+OUdphdrsize, len) != len)
|
||||||
|
syslog(0, logfile, "error sending reply: %r");
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
<$PLAN9/src/mkhdr
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
TARG=\
|
TARG=\
|
||||||
|
# dns\
|
||||||
ndbmkdb\
|
ndbmkdb\
|
||||||
ndbquery\
|
ndbquery\
|
||||||
ndbmkhash\
|
ndbmkhash\
|
||||||
@ -11,3 +12,18 @@ LIB=$PLAN9/lib/libndb.a
|
|||||||
|
|
||||||
<$PLAN9/src/mkmany
|
<$PLAN9/src/mkmany
|
||||||
|
|
||||||
|
DNSOFILES=\
|
||||||
|
convDNS2M.$O\
|
||||||
|
convM2DNS.$O\
|
||||||
|
dblookup.$O\
|
||||||
|
dnarea.$O\
|
||||||
|
dn.$O\
|
||||||
|
dnresolve.$O\
|
||||||
|
dnserver.$O\
|
||||||
|
|
||||||
|
$DNSOFILES dns.$O dnstcp.$O dnsdebug.$O: dns.h
|
||||||
|
|
||||||
|
$O.dns: $DNSOFILES dnnotify.$O dnudpserver.$O
|
||||||
|
$O.dnstcp: $DNSOFILES
|
||||||
|
$O.dnsdebug: $DNSOFILES
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user