?? domain.c
字號:
/*
* DOMAIN.C -- domain name system stub resolver
*/
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "ip.h"
#include "netuser.h"
#include "session.h"
#include "socket.h"
#include "cmdparse.h"
#include "commands.h"
#include "files.h"
#include "main.h"
#include "domain.h"
#undef DEBUG /* for certain trace messages */
#undef DEBUG_PAIN /* for painful debugging */
static struct rr *Dcache = NULL; /* Cache of resource records */
static int Dcache_size = 20; /* size limit */
static time_t Dcache_time = 0L; /* timestamp */
static int Dfile_clean = FALSE; /* discard expired records (flag) */
static int Dfile_reading = 0; /* read interlock (count) */
static int Dfile_writing = 0; /* write interlock (count) */
struct proc *Dfile_updater = NULL;
static int32 Dfile_wait_absolute = 0L; /* timeout Clock time */
static int Dfile_wait_relative = 300; /* timeout file activity (seconds) */
static struct dserver *Dservers = NULL; /* List of potential servers */
static int Dserver_retries = 2; /* Attempts to reach servers */
static char *Dsuffix = NULL; /* Default suffix for names without periods */
static int Dtrace = FALSE;
static char *Dtypes[] = {
"",
"A",
"NS",
"MD",
"MF",
"CNAME",
"SOA",
"MB",
"MG",
"MR",
"NULL",
"WKS",
"PTR",
"HINFO",
"MINFO",
"MX",
"TXT"
};
static int Ndtypes = 17;
static char delim[] = " \t\r\n";
static int docache(int argc,char *argv[],void *p);
static int dosuffix(int argc,char *argv[],void *p);
static int docacheclean(int argc,char *argv[],void *p);
static int docachelist(int argc,char *argv[],void *p);
static int docachesize(int argc,char *argv[],void *p);
static int docachewait(int argc,char *argv[],void *p);
static void dlist_add(struct dserver *dp);
static void dlist_drop(struct dserver *dp);
static int dodnsadd(int argc,char *argv[],void *p);
static int dodnsdrop(int argc,char *argv[],void *p);
static int dodnslist(int argc,char *argv[],void *p);
static int dodnsquery(int argc,char *argv[],void *p);
static int dodnsretry(int argc,char *argv[],void *p);
static int dodnstrace(int argc,char *argv[],void *p);
static char * dtype(int value);
static int check_ttl(struct rr *rrlp);
static int compare_rr(struct rr *search_rrp,struct rr *target_rrp);
static int compare_rr_list(struct rr *rrlp,struct rr *target_rrp);
static struct rr *copy_rr(struct rr *rrp);
static struct rr *copy_rr_list(struct rr *rrlp);
static struct rr *make_rr(int source,
char *dname,uint16 class,uint16 type,int32 ttl,uint16 rdl,void *data);
static void dcache_add(struct rr *rrlp);
static void dcache_drop(struct rr *rrp);
static struct rr *dcache_search(struct rr *rrlp);
static void dcache_update(struct rr *rrlp);
static struct rr *get_rr(FILE *fp, struct rr *lastrrp);
static void put_rr(FILE *fp,struct rr *rrp);
static struct rr *dfile_search(struct rr *rrlp);
static void dfile_update(int s,void *unused,void *p);
static void dumpdomain(struct dhdr *dhp,int32 rtt);
static int dns_makequery(uint16 op,struct rr *rrp,
uint8 *buffer,uint16 buflen);
static int dns_query(struct rr *rrlp);
static int isaddr(char *s);
static char *checksuffix(char *dname);
static struct rr *resolver(struct rr *rrlp);
/**
** Domain Resolver Commands
**/
static struct cmds Dcmds[] = {
"addserver", dodnsadd, 0, 2, "add <hostid>",
"dropserver", dodnsdrop, 0, 2, "drop <hostid>",
"list", dodnslist, 0, 0, NULL,
"query", dodnsquery, 512, 2, "query <hostid>",
"retry", dodnsretry, 0, 0, NULL,
"suffix", dosuffix, 0, 0, NULL,
"trace", dodnstrace, 0, 0, NULL,
"cache", docache, 0, 0, NULL,
NULL,
};
static struct cmds Dcachecmds[] = {
"clean", docacheclean, 0, 0, NULL,
"list", docachelist, 512, 0, NULL,
"size", docachesize, 0, 0, NULL,
"wait", docachewait, 0, 0, NULL,
NULL,
};
int
dodomain(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Dcmds,argc,argv,p);
}
static int
docache(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Dcachecmds,argc,argv,p);
}
static int
dosuffix(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
if(Dsuffix != NULL)
printf("%s\n",Dsuffix);
return 0;
}
free(Dsuffix);
Dsuffix = strdup(argv[1]);
return 0;
}
static int
docacheclean(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool( &Dfile_clean, "discard expired records", argc,argv );
}
static int
docachelist(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct rr *rrp;
struct session *sp;
int row = 25;
if((sp = newsession(Cmdline,DCLIST,1)) == NULL){
return -1;
}
(void)dcache_search(NULL); /* update ttl */
/* Put tty into raw mode so single-char responses will work */
sp->ttystate.echo = sp->ttystate.edit = 0;
for(rrp=Dcache;rrp!=NULL;rrp=rrp->next)
{
put_rr(stdout,rrp);
if(--row == 0){
row = keywait("--More--",0);
switch(row){
case -1:
case 'q':
case 'Q':
rrp = NULL;
break;
case '\n':
case '\r':
row = 1;
break;
case ' ':
default:
row = 25;
};
}
}
fflush(stdout);
keywait(NULL,1);
freesession(sp);
return 0;
}
static int
docachesize(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int newsize;
int oldsize;
int result;
newsize = oldsize = Dcache_size;
result = setint( &newsize, "memory cache size", argc,argv );
if(newsize > 0){
Dcache_size = newsize;
if(newsize < oldsize){
(void)dcache_search(NULL); /* update size */
}
}
return result;
}
static int
docachewait(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setint( &Dfile_wait_relative, "time before file update (seconds)", argc,argv );
}
static void
dlist_add(dp)
register struct dserver *dp;
{
dp->prev = NULL;
dp->next = Dservers;
if(Dservers != NULL)
Dservers->prev = dp;
Dservers = dp;
}
static void
dlist_drop(dp)
register struct dserver *dp;
{
if(dp->prev != NULL)
dp->prev->next = dp->next;
else
Dservers = dp->next;
if(dp->next != NULL)
dp->next->prev = dp->prev;
}
static int
dodnsadd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int32 address;
if((address = resolve(argv[1])) == 0L){
printf("Resolver %s unknown\n",argv[1]);
return 1;
}
return add_nameserver(address);
}
int
add_nameserver(address)
int32 address;
{
struct dserver *dp;
dp = (struct dserver *)callocw(1,sizeof(struct dserver));
dp->address = address;
dp->srtt = INITRTT;
dp->mdev = 0;
dp->timeout = 2 * dp->mdev + dp->srtt + 3;
dlist_add(dp);
return 0;
}
static int
dodnsdrop(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct dserver *dp;
int32 addr;
addr = resolve(argv[1]);
for(dp = Dservers;dp != NULL;dp = dp->next)
if(addr == dp->address)
break;
if(dp == NULL){
printf("Not found\n");
return 1;
}
dlist_drop(dp);
free(dp);
return 0;
}
static int
dodnslist(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct dserver *dp;
printf("Server address srtt mdev timeout queries responses\n");
for(dp = Dservers;dp != NULL;dp = dp->next){
printf("%-20s%8lu%8lu%10lu%10lu%10lu\n",
inet_ntoa(dp->address),
dp->srtt,dp->mdev,dp->timeout,
dp->queries,dp->responses);
}
return 0;
}
static int
dodnsquery(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct rr *rrp;
struct rr *result_rrlp;
char *sname;
struct session *sp;
int row = 25;
if((sp = newsession(Cmdline,DQUERY,1)) == NULL){
return -1;
}
if ( isaddr( argv[1] ) ) {
result_rrlp = inverse_a( aton( argv[1] ) );
} else {
sname = checksuffix( argv[1] );
rrp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_ANY,0,0,NULL);
FREE(sname);
dns_query(rrp);
result_rrlp = dcache_search(rrp);
free_rr(rrp);
}
/* Put tty into raw mode so single-char responses will work */
sp->ttystate.echo = sp->ttystate.edit = 0;
for( rrp=result_rrlp; rrp!=NULL; rrp=rrp->next)
{
put_rr(stdout,rrp);
if(--row == 0){
row = keywait("--More--",0);
switch(row){
case -1:
case 'q':
case 'Q':
rrp = NULL;
break;
case '\n':
case '\r':
row = 1;
break;
case ' ':
default:
row = 25;
};
}
}
fflush(stdout);
free_rr(result_rrlp);
keywait(NULL,1);
freesession(sp);
return 0;
}
static int
dodnsretry(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setint( &Dserver_retries, "server retries", argc,argv );
}
static int
dodnstrace(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Dtrace,"server trace",argc,argv);
}
/**
** Domain Resource Record Utilities
**/
static char *
dtype(value)
int value;
{
static char buf[10];
if (value < Ndtypes)
return Dtypes[value];
sprintf( buf, "{%d}", value);
return buf;
}
/* check list of resource records for any expired ones.
* returns number of expired records.
*/
static int
check_ttl(rrlp)
register struct rr *rrlp;
{
int count = 0;
while(rrlp != NULL){
if(rrlp->ttl == 0L)
count++;
rrlp = rrlp->next;
}
return count;
}
/* Compare two resource records.
* returns 0 if match, nonzero otherwise.
*/
static int
compare_rr(search_rrp,target_rrp)
register struct rr *search_rrp,*target_rrp;
{
int i;
if(search_rrp == NULL || target_rrp == NULL)
return -32765;
if(search_rrp->class != target_rrp->class)
return -32763;
if(search_rrp->type != TYPE_ANY
&& search_rrp->type != target_rrp->type
&& (search_rrp->source != RR_QUERY
|| (target_rrp->type != TYPE_CNAME
&& target_rrp->type != TYPE_PTR)))
return -32761;
if(search_rrp->source != RR_INQUERY){
if((i = strlen(search_rrp->name)) != strlen(target_rrp->name))
return -32759;
if((i = strnicmp(search_rrp->name,target_rrp->name,i)) != 0)
return i;
/* match negative records so that they are replaced */
if(target_rrp->rdlength == 0)
return 0;
}
/* if a query has gotten this far, match it */
if(search_rrp->source == RR_QUERY)
return 0;
/* ensure negative records don't replace older records */
if(search_rrp->rdlength == 0)
return -32757;
/* match expired records so that they are replaced */
if(search_rrp->source != RR_INQUERY){
if(target_rrp->ttl == 0L)
return 0;
}
/* Note: rdlengths are not compared because they vary depending
* on the representation (ASCII or encoded) this record was
* generated from.
*/
switch(search_rrp->type){
case TYPE_A:
i = search_rrp->rdata.addr != target_rrp->rdata.addr;
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
case TYPE_TXT:
i = stricmp(search_rrp->rdata.data,target_rrp->rdata.data);
break;
case TYPE_HINFO:
i = strcmp(search_rrp->rdata.hinfo.cpu,target_rrp->rdata.hinfo.cpu) ||
strcmp(search_rrp->rdata.hinfo.os,target_rrp->rdata.hinfo.os);
break;
case TYPE_MX:
i = stricmp(search_rrp->rdata.mx.exch,target_rrp->rdata.mx.exch);
break;
case TYPE_SOA:
i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
break;
default:
i = -32755; /* unsupported */
}
return i;
}
static int
compare_rr_list(rrlp,target_rrp)
register struct rr *rrlp,*target_rrp;
{
while(rrlp != NULL){
if(compare_rr(rrlp,target_rrp) == 0)
return 0;
#ifdef DEBUG_PAIN
if(Dtrace)
printf("%15d %s\n",
compare_rr(rrlp,target_rrp),
target_rrp->name);
#endif
rrlp = rrlp->next;
}
return -32767;
}
/* Make a new copy of a resource record */
static struct rr *
copy_rr(rrp)
register struct rr *rrp;
{
register struct rr *newrr;
if(rrp == NULL)
return NULL;
newrr = (struct rr *)callocw(1,sizeof(struct rr));
newrr->source = rrp->source;
newrr->name = strdup(rrp->name);
newrr->type = rrp->type;
newrr->class = rrp->class;
newrr->ttl = rrp->ttl;
if((newrr->rdlength = rrp->rdlength) == 0)
return newrr;
switch(rrp->type){
case TYPE_A:
newrr->rdata.addr = rrp->rdata.addr;
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
case TYPE_TXT:
newrr->rdata.name = strdup(rrp->rdata.name);
break;
case TYPE_HINFO:
newrr->rdata.hinfo.cpu = strdup(rrp->rdata.hinfo.cpu);
newrr->rdata.hinfo.os = strdup(rrp->rdata.hinfo.os);
break;
case TYPE_MX:
newrr->rdata.mx.pref = rrp->rdata.mx.pref;
newrr->rdata.mx.exch = strdup(rrp->rdata.mx.exch);
break;
case TYPE_SOA:
newrr->rdata.soa.mname = strdup(rrp->rdata.soa.mname);
newrr->rdata.soa.rname = strdup(rrp->rdata.soa.rname);
newrr->rdata.soa.serial = rrp->rdata.soa.serial;
newrr->rdata.soa.refresh = rrp->rdata.soa.refresh;
newrr->rdata.soa.retry = rrp->rdata.soa.retry;
newrr->rdata.soa.expire = rrp->rdata.soa.expire;
newrr->rdata.soa.minimum = rrp->rdata.soa.minimum;
break;
}
return newrr;
}
static struct rr *
copy_rr_list(rrlp)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -