📄 domain.c
字号:
register struct rr *rrlp;
{
register struct rr **rrpp;
struct rr *result_rrlp;
rrpp = &result_rrlp;
while(rrlp != NULL){
*rrpp = copy_rr(rrlp);
rrpp = &(*rrpp)->next;
rrlp = rrlp->next;
}
*rrpp = NULL;
return result_rrlp;
}
/* Free (list of) resource records */
void
free_rr(rrlp)
register struct rr *rrlp;
{
register struct rr *rrp;
while((rrp = rrlp) != NULL){
rrlp = rrlp->next;
free(rrp->comment);
free(rrp->name);
if(rrp->rdlength > 0){
switch(rrp->type){
case TYPE_A:
break; /* Nothing allocated in rdata section */
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
case TYPE_TXT:
free(rrp->rdata.name);
break;
case TYPE_HINFO:
free(rrp->rdata.hinfo.cpu);
free(rrp->rdata.hinfo.os);
break;
case TYPE_MX:
free(rrp->rdata.mx.exch);
break;
case TYPE_SOA:
free(rrp->rdata.soa.mname);
free(rrp->rdata.soa.rname);
break;
}
}
free(rrp);
}
}
static struct rr *
make_rr(source,dname,dclass,dtype,ttl,rdl,data)
int source;
char *dname;
uint16 dclass;
uint16 dtype;
int32 ttl;
uint16 rdl;
void *data;
{
register struct rr *newrr;
newrr = (struct rr *)callocw(1,sizeof(struct rr));
newrr->source = source;
newrr->name = strdup(dname);
newrr->class = dclass;
newrr->type = dtype;
newrr->ttl = ttl;
if((newrr->rdlength = rdl) == 0)
return newrr;
switch(dtype){
case TYPE_A:
{
register int32 *ap = (int32 *)data;
newrr->rdata.addr = *ap;
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((char *)data);
break;
}
case TYPE_HINFO:
{
register struct hinfo *hinfop = (struct hinfo *)data;
newrr->rdata.hinfo.cpu = strdup(hinfop->cpu);
newrr->rdata.hinfo.os = strdup(hinfop->os);
break;
}
case TYPE_MX:
{
register struct mx *mxp = (struct mx *)data;
newrr->rdata.mx.pref = mxp->pref;
newrr->rdata.mx.exch = strdup(mxp->exch);
break;
}
case TYPE_SOA:
{
register struct soa *soap = (struct soa *)data;
newrr->rdata.soa.mname = strdup(soap->mname);
newrr->rdata.soa.rname = strdup(soap->rname);
newrr->rdata.soa.serial = soap->serial;
newrr->rdata.soa.refresh = soap->refresh;
newrr->rdata.soa.retry = soap->retry;
newrr->rdata.soa.expire = soap->expire;
newrr->rdata.soa.minimum = soap->minimum;
break;
}
}
return newrr;
}
/**
** Domain Cache Utilities
**/
static void
dcache_add(rrlp)
register struct rr *rrlp;
{
register struct rr *last_rrp;
struct rr *save_rrp;
if(rrlp == NULL)
return;
save_rrp = rrlp;
last_rrp = NULL;
while(rrlp != NULL){
rrlp->last = last_rrp;
last_rrp = rrlp;
rrlp = rrlp->next;
}
last_rrp->next = Dcache;
if(Dcache != NULL)
Dcache->last = last_rrp;
Dcache = save_rrp;
}
static void
dcache_drop(rrp)
register struct rr *rrp;
{
if(rrp->last != NULL)
rrp->last->next = rrp->next;
else
Dcache = rrp->next;
if(rrp->next != NULL)
rrp->next->last = rrp->last;
rrp->last =
rrp->next = NULL;
}
/* Search cache for resource records, removing them from the cache.
* Also, timeout cache entries, and trim cache to size.
* (Calling with NULL is legal -- will timeout & trim only.)
* Note that an answer from the cache cannot be authoritative, because
* we cannot guarantee that all the entries remain from a previous request.
* Returns RR list, or NULL if no record found.
*/
static struct rr *
dcache_search(rrlp)
struct rr *rrlp;
{
register struct rr *rrp, *test_rrp;
struct rr **rrpp, *result_rrlp;
int32 elapsed;
time_t now;
int count = 0;
#ifdef DEBUG
if(Dtrace && rrlp != NULL){
printf("dcache_search: searching for %s\n",rrlp->name);
}
#endif
elapsed = (int32)(time(&now) - Dcache_time);
Dcache_time = now;
rrpp = &result_rrlp;
for(rrp = Dcache; (test_rrp = rrp) != NULL;){
rrp = rrp->next;
/* timeout entries */
if(test_rrp->ttl > 0L
&& (test_rrp->ttl -= elapsed) <= 0L)
test_rrp->ttl = 0L;
if(compare_rr_list(rrlp,test_rrp) == 0){
dcache_drop( *rrpp = test_rrp );
rrpp = &(*rrpp)->next;
} else if(test_rrp->source == RR_FILE && ++count > Dcache_size){
dcache_drop(test_rrp);
free_rr(test_rrp);
}
}
*rrpp = NULL;
return result_rrlp;
}
/* Move a list of resource records to the cache, removing duplicates. */
static void
dcache_update(rrlp)
register struct rr *rrlp;
{
if(rrlp == NULL)
return;
free_rr(dcache_search(rrlp)); /* remove duplicates, first */
dcache_add(rrlp);
}
/**
** File Utilities
**/
static struct rr *
get_rr(fp,lastrrp)
FILE *fp;
struct rr *lastrrp;
{
char *line,*lp,*strtok();
struct rr *rrp;
char *name,*ttl,*class,*type,*data;
int i;
line = mallocw(256);
if(fgets(line,256,fp) == NULL){
free(line);
return NULL;
}
rrp = (struct rr *)callocw(1,sizeof(struct rr));
rrp->source = RR_FILE;
if(line[0] == '\0' || line[0] == '#' || line[0] == ';'){
rrp->comment = line;
return rrp;
}
if(!isspace(line[0]) || lastrrp == NULL){
name = strtok(line,delim);
lp = NULL;
} else { /* Name field is missing */
name = lastrrp->name;
lp = line;
}
if(name == NULL || (i = strlen(name)) == 0){
rrp->comment = strdup("\n");
free(line);
return rrp;
}
if(name[i-1] != '.'){
/* Tack on a trailing period if it's not there */
/* !!! need to implement $ORIGIN suffix here */
rrp->name = mallocw(i+2);
strcpy(rrp->name,name);
strcat(rrp->name,".");
} else
rrp->name = strdup(name);
ttl = strtok(lp,delim);
if(ttl == NULL || (!isdigit(ttl[0]) && ttl[0] != '-')){
/* Optional ttl field is missing */
rrp->ttl = TTL_MISSING;
class = ttl;
} else {
rrp->ttl = atol(ttl);
class = strtok(NULL,delim);
}
if(class == NULL){
/* we're in trouble, but keep processing */
rrp->class = CLASS_MISSING;
type = class;
} else if(class[0] == '<'){
rrp->class = atoi(&class[1]);
type = strtok(NULL,delim);
} else if(stricmp(class,"IN") == 0){
rrp->class = CLASS_IN;
type = strtok(NULL,delim);
} else {
/* Optional class field is missing; assume IN */
rrp->class = CLASS_IN;
type = class;
}
if(type == NULL){
/* we're in trouble, but keep processing */
rrp->type = TYPE_MISSING;
data = type;
} else if(type[0] == '{'){
rrp->type = atoi(&class[1]);
data = strtok(NULL,delim);
} else {
rrp->type = TYPE_MISSING;
for(i=1;i<Ndtypes;i++){
if(stricmp(type,Dtypes[i]) == 0){
rrp->type = i;
data = strtok(NULL,delim);
break;
}
}
}
if(rrp->type == TYPE_MISSING){
data = NULL;
}
if(data == NULL){
/* Empty record, just return */
free(line);
return rrp;
}
switch(rrp->type){
case TYPE_A:
rrp->rdlength = 4;
rrp->rdata.addr = aton(data);
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
case TYPE_TXT:
rrp->rdlength = strlen(data);
rrp->rdata.name = strdup(data);
break;
case TYPE_HINFO:
rrp->rdlength = strlen(data);
rrp->rdata.hinfo.cpu = strdup(data);
if((data = strtok(NULL,delim)) != NULL){
rrp->rdlength += strlen(data);
rrp->rdata.hinfo.os = strdup(data);
}
break;
case TYPE_MX:
rrp->rdata.mx.pref = atoi(data);
rrp->rdlength = 2;
/* Get domain name of exchanger */
if((data = strtok(NULL,delim)) != NULL){
rrp->rdlength += strlen(data);
rrp->rdata.mx.exch = strdup(data);
}
break;
case TYPE_SOA:
/* Get domain name of master name server */
rrp->rdlength = strlen(data);
rrp->rdata.soa.mname = strdup(data);
/* Get domain name of irresponsible person */
if((data = strtok(NULL,delim)) != NULL){
rrp->rdata.soa.rname = strdup(data);
rrp->rdlength += strlen(data);
}
data = strtok(NULL,delim);
rrp->rdata.soa.serial = atol(data);
data = strtok(NULL,delim);
rrp->rdata.soa.refresh = atol(data);
data = strtok(NULL,delim);
rrp->rdata.soa.retry = atol(data);
data = strtok(NULL,delim);
rrp->rdata.soa.expire = atol(data);
data = strtok(NULL,delim);
rrp->rdata.soa.minimum = atol(data);
rrp->rdlength += 20;
break;
}
/* !!! need to handle trailing comments */
free(line);
return rrp;
}
/* Print a resource record */
static void
put_rr(fp,rrp)
FILE *fp;
struct rr *rrp;
{
char * stuff;
if(fp == NULL || rrp == NULL)
return;
if(rrp->name == NULL && rrp->comment != NULL){
fprintf(fp,"%s",rrp->comment);
return;
}
fprintf(fp,"%s",rrp->name);
if(rrp->ttl != TTL_MISSING)
fprintf(fp,"\t%ld",rrp->ttl);
if(rrp->class == CLASS_IN)
fprintf(fp,"\tIN");
else
fprintf(fp,"\t<%u>",rrp->class);
stuff = dtype(rrp->type);
fprintf(fp,"\t%s",stuff);
if(rrp->rdlength == 0){
/* Null data portion, indicates nonexistent record */
/* or unsupported type. Hopefully, these will filter */
/* as time goes by. */
fprintf(fp,"\n");
return;
}
switch(rrp->type){
case TYPE_A:
fprintf(fp,"\t%s\n",inet_ntoa(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:
/* These are all printable text strings */
fprintf(fp,"\t%s\n",rrp->rdata.data);
break;
case TYPE_HINFO:
fprintf(fp,"\t%s\t%s\n",
rrp->rdata.hinfo.cpu,
rrp->rdata.hinfo.os);
break;
case TYPE_MX:
fprintf(fp,"\t%u\t%s\n",
rrp->rdata.mx.pref,
rrp->rdata.mx.exch);
break;
case TYPE_SOA:
fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
rrp->rdata.soa.mname,rrp->rdata.soa.rname,
rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
rrp->rdata.soa.retry,rrp->rdata.soa.expire,
rrp->rdata.soa.minimum);
break;
default:
fprintf(fp,"\n");
break;
}
}
/* Search local database for resource records.
* Returns RR list, or NULL if no record found.
*/
static struct rr *
dfile_search(rrlp)
struct rr *rrlp;
{
register struct rr *frrp;
struct rr **rrpp, *result_rrlp, *oldrrp;
int32 elapsed;
FILE *dbase;
struct stat dstat;
#ifdef DEBUG
if(Dtrace){
printf("dfile_search: searching for %s\n",rrlp->name);
}
#endif
while(Dfile_writing > 0)
kwait(&Dfile_reading);
Dfile_reading++;
if((dbase = fopen(Dfile,READ_TEXT)) == NULL){
Dfile_reading--;
return NULL;
}
if(fstat(fileno(dbase),&dstat) != 0){
printf("dfile_search: can't get file status\n");
fclose(dbase);
Dfile_reading--;
return NULL;
}
if((elapsed = (int32)(Dcache_time - (time_t)dstat.st_ctime)) < 0L)
elapsed = -elapsed; /* arbitrary time mismatch */
result_rrlp = NULL; /* for contiguous test below */
oldrrp = NULL;
rrpp = &result_rrlp;
while((frrp = get_rr(dbase,oldrrp)) != NULL){
free_rr(oldrrp);
if(frrp->type != TYPE_MISSING
&& frrp->rdlength > 0
&& compare_rr_list(rrlp,frrp) == 0){
if(frrp->ttl > 0L
&& (frrp->ttl -= elapsed) <= 0L)
frrp->ttl = 0L;
*rrpp = frrp;
rrpp = &(*rrpp)->next;
oldrrp = copy_rr(frrp);
} else {
oldrrp = frrp;
/*
All records of the same name and the same type
are contiguous. Therefore, for a single query,
we can stop searching. Multiple queries must
read the whole file.
*/
if(rrlp->type != TYPE_ANY
&& rrlp->next == NULL
&& result_rrlp != NULL)
break;
}
if(!main_exit)
kwait(NULL); /* run multiple sessions */
}
free_rr(oldrrp);
*rrpp = NULL;
fclose(dbase);
if(--Dfile_reading <= 0){
Dfile_reading = 0;
ksignal(&Dfile_writing,0);
}
return result_rrlp;
}
/* Process which will add new resource records from the cache
* to the local file, eliminating duplicates while it goes.
*/
static void
dfile_update(s,unused,p)
int s;
void *unused;
void *p;
{
struct rr **rrpp, *rrlp, *oldrrp;
char *newname;
FILE *old_fp, *new_fp;
struct stat old_stat, new_stat;
logmsg(-1,"update Domain.txt initiated");
/* Produce output on command session rather than the one
* that invoked us
*/
fclose(stdin);
stdin = fdup(Cmdpp->input);
fclose(stdout);
stdout = fdup(Cmdpp->output);
newname = strdup(Dfile);
strcpy(&newname[strlen(newname)-3],"tmp");
while(Dfile_wait_absolute != 0L && !main_exit){
register struct rr *frrp;
int32 elapsed;
while(Dfile_wait_absolute != 0L){
elapsed = Dfile_wait_absolute - secclock();
Dfile_wait_absolute = 0L;
if(elapsed > 0L && !main_exit){
kalarm(elapsed*1000L);
kwait(&Dfile_wait_absolute);
kalarm(0L);
}
}
logmsg(-1,"update Domain.txt");
/* create new file for copy */
if((new_fp = fopen(newname,WRITE_TEXT)) == NULL){
printf("dfile_update: can't create %s!\n",newname);
break;
}
if(fstat(fileno(new_fp),&new_stat) != 0){
printf("dfile_update: can't get new_file status!\n");
fclose(new_fp);
break;
}
kwait(NULL); /* file operations can be slow */
/* timeout the cache one last time before writing */
(void)dcache_search(NULL);
/* copy new RRs out to the new file */
/* (can't wait here, the cache might change) */
rrpp = &rrlp;
for(frrp = Dcache; frrp != NULL; frrp = frrp->next ){
switch(frrp->source){
case RR_QUESTION:
case RR_ANSWER:
case RR_AUTHORITY:
case RR_ADDITIONAL:
*rrpp = copy_rr(frrp);
if(frrp->type != TYPE_MISSING
&& frrp->rdlength > 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -