📄 nsdb.c
字号:
/* @(#)nsdb.c 1.1 92/07/30 SMI *//* Copyright (c) 1984 AT&T *//* All Rights Reserved *//* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T *//* The copyright notice above does not evidence any *//* actual or intended publication of such source code. */#ident "@(#)nserve:nsdb.c 1.10"#include <stdio.h>#include <string.h>#include <ctype.h>#include "nslog.h"#include "nsdb.h"#include "stdns.h"#include <rfs/nserve.h>#include "nsrec.h"#include <tiuser.h>#include <rfs/nsaddr.h>/* * * This file contains the core of the Name Server * database. From the outside, the database is a * group of resource records that may be accessed * through a set of access functions defined here. * * The header file nsdb.h should be included by any * program that uses these access functions. It * defines the functions and structures that are * used by the database. * * */#define ISIZE 4 /* distance to indent when dumping database *//* static variables */static struct domain Dstruct; /* root of database */static struct domain *Domain = &Dstruct;static struct { char *name; int type;} *Tptr, Table[] = { "P", SOA, "SOA", SOA, "S", NS, "NS", NS, "DOM", DOM, "RN", RN, "A", A, "NSTYPE", NSTYPE, "ANYTYPE", ANYTYPE, "ANY", ANYTYPE, "*", ANYTYPE, NULL,0};static int Indent; /* for dumping domains *//* static functions */static struct res_rec **findrec();static int addrec();static struct domain *finddom();static struct domain *newdom();static struct res_rec **findns();static int freedom();struct res_rec **duplist();struct question **dupqd();struct res_rec *duprec();int writedb();int readfile();char *prec();char *getctype();char *dompart();char *namepart();/* * Find resource records that match name and type. * Return pointer to list or NULL. */struct res_rec **findrr(name, type)char *name;int type;{ struct res_rec **list; char *r; struct domain *d; struct domain *d1 = NULL; LOG4(L_DB,"(%5d) findrr: name=%s, type=%s\n", Logstamp,name,getctype(type)); d = Domain; r = dompart(name); if ((d1=finddom(r,d)) == NULL) { LOG3(L_DB,"(%5d) findrr: can't find domain '%s'\n",Logstamp,r); return(NULL); } if ((list = findrec(namepart(name),type,d1)) == NULL) LOG4(L_DB,"(%5d) findrr: search failed, name = '%s', type =%d\n", Logstamp,name,type); return(duplist(list));}/* * Add a record in the database using name as key. * Return R_NOERR if the operation is successful, * otherwise return an appropriate rcode value (see stdns.h) * Addrr copies the record before adding it to the database. */intaddrr(name,res)char *name;struct res_rec *res;{ int ret; if ((ret = addraw(name,duprec(res))) == R_NOERR) return(R_NOERR); return(ret);}/* * addraw adds a record to the database without first copying it */static intaddraw(name,res)char *name;struct res_rec *res;{ struct domain *d; struct domain *d1; char *r; LOG4(L_DB,"(%5d) addrr: name=%s, res=%s\n", Logstamp,name,prec(res)); d = Domain; r = dompart(name); if (*r == WILDCARD) { LOG2(L_DB,"(%5d) addrr: can't add wildcard\n",Logstamp); return(R_FORMAT); } if ((d1=finddom(r,d)) == NULL) { LOG3(L_DB,"(%5d) addrr: can't find domain '%s'\n", Logstamp,r); return(R_NONAME); } return(addrec(namepart(name),res,d1));}/* * put record res in domain dom under name name. */static intaddrec(name,res,dom)char *name;struct res_rec *res;struct domain *dom;{ int type; int i; type = res->rr_type; LOG4(L_DB,"(%5d) addrec: name=%s, res=%s\n", Logstamp,name,prec(res)); if (findrec(namepart(name),type,dom) != NULL) { LOG4(L_DB,"(%5d) addrec: DUPLICATE NAME='%s', TYPE='%s'\n", Logstamp, name, getctype(type)); return(R_DUP); } for(i=0;1;i++) { if (i+1 >= dom->d_size) { dom->d_size += NREC; if (dom->d_rec) { free(dom->d_rec); if ((dom->d_rec=(struct res_rec **)realloc(dom->d_rec, sizeof(struct res_rec *) * dom->d_size)) == NULL) { PLOG4( "(%5d) addrec: can't realloc(%s,%d)\n", Logstamp,"dom->rec", sizeof(struct res_rec *)*dom->d_size); return(R_NSFAIL); } } else { if ((dom->d_rec=(struct res_rec **) calloc(dom->d_size,sizeof(struct res_rec *))) == NULL) { PLOG4( "(%5d) addrec: can't calloc(%d,%d)\n", Logstamp,dom->d_size, sizeof(struct res_rec *)); return(R_NSFAIL); } } } if (dom->d_rec[i] == NULL) break; /* found */ } dom->d_rec[i] = res; dom->d_rec[i+1] = NULL; LOG2(L_DB,"(%5d) addrec: returns R_NOERR\n",Logstamp); return(R_NOERR);}/* * findrec takes a domain ptr, a name, and a type and * returns all records in domain that match name and type. * Name is an unqualified (i.e., no dots) domain or resource name. * * if name is "*", all names are matched. * if type is ANYTYPE, all types are matched. * if type is NSTYPE, all name server types are matched. * * findrec returns a NULL terminated list of pointers * to struct res_rec if any records are found. If none * are found, it returns NULL. * * findrec puts the list that points to its result in static storage, * therefore, subsequent calls will destroy previous results. */static struct res_rec **findrec(name,type,d)char *name;int type;struct domain *d;{ static int rrsize = 0; static struct res_rec **rrlist = NULL; int trrec = 0; int i; int nstype; struct res_rec *rp; LOG5(L_DB,"(%5d) findrec: name=%s, type=%s, domain=%d\n", Logstamp,name,getctype(type),d); nstype = (type == NSTYPE)?NSTYPE:0; if (d->d_rec == NULL) return(NULL); if (rrsize < d->d_size) /* expand rrlist */ if (!(rrlist = (rrlist == NULL) ? (struct res_rec **)malloc((rrsize = d->d_size) * sizeof(struct res_rec *)) : (struct res_rec **)realloc(rrlist, (rrsize = d->d_size) * sizeof(struct res_rec *)))) return NULL; for (i=0, rp=d->d_rec[0]; i < d->d_size && rp != NULL; rp=d->d_rec[++i]) if ((type == ANYTYPE || type == rp->rr_type || nstype & rp->rr_type) && (*name == WILDCARD || strcmp(name,rp->rr_name) == NULL)) rrlist[trrec++] = rp; LOG3(L_DB,"(%5d) findrec: returns %d records\n", Logstamp,trrec); if (trrec > 0) { rrlist[trrec] = NULL; return(rrlist); } return(NULL);}/* * * finddom searches the database from the given * root and returns a pointer to the domain structure * that represents the argument "name." * * finddom returns NULL if there is an error. * errors include: * given name is not a domain. * can't find name. * */static struct domain *finddom(name,domain)char *name;struct domain *domain;{ char *r; char sname[BUFSIZ]; struct domain *d; struct res_rec **rec; char *rtoken(); LOG4(L_DB,"(%5d) finddom: name=%s, domain=%d\n", Logstamp, (name)?name:"NULL",domain); if (name == NULL) return(NULL); /* null name means this is the correct domain already */ if (*name == '\0') return(domain); strcpy(sname,name); for (r=rtoken(sname), d=domain; r != NULL; r=rtoken(NULL)) if ((rec=findrec(r,DOM,d)) != NULL) d = rec[0]->rr_dom; else return(NULL); return(d);}/* * find list of name servers that should know about this * name. Uses findns, starting from the root of the database. */struct res_rec **findind(name)char *name;{ return(duplist(findns(name,Domain)));}/* * * findns searches the database for a reference to a * remote name servers anywhere in the given name. * It returns a list of pointers to the MOST qualified * name servers found. (i.e., if SOA or NS records are found * for b.c.e and b.c, the reference to b.c.e will be returned). * * findns returns NULL if there is an error or if * no name server records are found. * */static struct res_rec **findns(name,domain)char *name;struct domain *domain;{ static int reclen = 0; int i, tot; char *r; char sname[BUFSIZ]; struct domain *d; struct res_rec **trec=NULL; struct res_rec **recptr=NULL; static struct res_rec **rec=NULL; char *rtoken(); LOG4(L_DB,"(%5d) findns: name=%s, domain=%d\n", Logstamp,(name)?name:"NULL",domain); if (name == NULL || domain == NULL) return(NULL); strcpy(sname,name); for (r=rtoken(sname), d=domain; r != NULL; r=rtoken(NULL)) { if ((trec=findrec(r,NSTYPE,d)) != NULL) { for (i=0; trec[i] != NULL; i++); if (i >= reclen) { reclen = i + 1; rec = (rec == NULL) ? (struct res_rec **)malloc((i + 1) * sizeof(struct res_rec *)) : (struct res_rec **)realloc(rec, (i + 1) * sizeof(struct res_rec *)); } tot = i; for (;i >= 0; --i) rec[i] = trec[i]; recptr = rec; } if ((trec=findrec(r,DOM,d)) != NULL) d = trec[0]->rr_dom; else break; } LOG3(L_DB,"(%5d) findns: returns %d records\n", Logstamp,(recptr)?tot:0); return(recptr);}/* * dump entire database to stdout. */intdumpdb(){ struct domain *d; Indent = 0; d = Domain; dumpdom(d,""); return;}/* * dump the contents of a domain and all of its * subdomains to stdout. */intdumpdom(d,name)struct domain *d;char *name; /* name so far */{ struct res_rec **list; struct res_rec *rec; char dname[MAXDNAME]; if (d == NULL || d->d_rec == NULL) return; for (list=d->d_rec; *list != NULL; list++) { rec = *list;#ifdef RIGHT_TO_LEFT sprintf(dname,"%s.%s",rec->rr_name,name);#else sprintf(dname,"%s.%s",name,rec->rr_name);#endif if (*name == '\0') dname[strlen(dname)-1] = '\0'; printf("%*s%s\t%s",Indent,"",dname,getctype(rec->rr_type)); switch (rec->rr_type) { case RN: printf("\t%s\n",rec->rr_owner); break; case DOM: printf(", auth=%d, size=%d\n",rec->rr_dauth,rec->rr_dsize); Indent += ISIZE; dumpdom(rec->rr_dom,dname); Indent -= ISIZE; break; default: printf("\t%s\n",rec->rr_data); break; } } return;}/* * remrr removes the resource record that matches * the name and type passed in. WILDCARDS are illegal. * * It returns R_NOERR if the operation is successful, * otherwise, it returns an rcode (see stdns.h). */intremrr(name,res)char *name;struct res_rec *res;{ char *r; struct domain *d; struct domain *d1; int i,j; struct res_rec *rptr; LOG4(L_DB,"(%5d) remrr: name=%s, res=%s\n", Logstamp,name,prec(res)); d1 = Domain; r = dompart(name); if ((d=finddom(r,d1)) == NULL) { LOG3(L_DB,"(%5d) remrr: can't find domain '%s'\n", Logstamp,r); return(R_NONAME); } r = namepart(name); for (i=0, rptr=d->d_rec[0]; i < d->d_size && rptr != NULL; rptr = d->d_rec[++i]) if ((strcmp(r,rptr->rr_name) == NULL) && (res->rr_type == rptr->rr_type)) { for (j=i; j+1 < d->d_size && d->d_rec[j] != NULL; j++) d->d_rec[j] = d->d_rec[j+1]; d->d_rec[j] = NULL; freerec(rptr); return(R_NOERR); } return(R_NONAME);}/* * Inverse query. Search for resource(s) given domain, rdata, and type. * The argument name is matched as a character string with the data portion * of records of all types except RN, where name is matched with rr_owner. * Since DOM records are internal, an inverse query for DOM records will * return NULL. */struct res_rec **iquery(domain, type, name) /* find rrs where rdata matches name */char *domain;int type;char *name;{ static int reclen = 0; struct res_rec **list; int i,j; char *str; static struct res_rec **rlist; char *dompart(); char *namepart(); char qname[2]; struct domain *d; struct domain *d1 = NULL; LOG5(L_DB,"(%5d) iquery: domain=%s, type=%s, name=%s\n", Logstamp,domain,getctype(type),name); d = Domain; if ((d1=finddom(domain,d)) == NULL) { if ((list=findns(domain,d)) == NULL) LOG3(L_DB,"(%5d) iquery: can't find domain '%s'\n", Logstamp,domain); return(duplist(list)); } /* get all records with the right type regardless of name. */ qname[0] = WILDCARD; qname[1] = '\0'; if ((list = findrec(qname,type,d1)) == NULL) { LOG4(L_DB,"(%5d) iquery: search failed, name = '%s', type =%d\n", Logstamp,qname,type); return(NULL); } for (i=0, j=0; list[i] != NULL; i++) { LOG3(L_DB,"(%5d) iquery: checks record %s\n", Logstamp,prec(list[i])); switch (type) { case DOM: return(NULL); case RN: str = list[i]->rr_owner; break; default: str = list[i]->rr_data; break; } if ((str == NULL) || (strcmp(str,name) != NULL)) continue; LOG2(L_DB,"(%5d) iquery: record matches\n",Logstamp); if (j >= reclen) rlist = (rlist == NULL) ? (struct res_rec **)malloc((1+ ++reclen) * sizeof(struct res_rec *)) : (struct res_rec **)realloc(rlist, (1+ ++reclen) * sizeof(struct res_rec *)); rlist[j++] = list[i]; } LOG3(L_DB,"(%5d) iquery: returns %d records\n",Logstamp,j); if (j > 0) { rlist[j] = 0; return(duplist(rlist)); } return(NULL);}char *prec(rec)struct res_rec *rec;{ static char buf[BUFSIZ]; char *ptr; sprintf(buf,"%s %s",rec->rr_name,getctype(rec->rr_type)); ptr = &(buf[strlen(buf)]); switch (rec->rr_type) { default: sprintf(ptr," %s",rec->rr_data); break; case DOM: sprintf(ptr," auth=%d size=%d",rec->rr_dauth,rec->rr_dsize); break; case RN: sprintf(ptr," %s",rec->rr_owner); break; } return(buf);}/* * convert string representation of a record type into * its internal numeric value. */intgettype(nm)char *nm;{ char type[10]; int i; for (i=0; i < 10 && *nm != NULL; i++, nm++) type[i] = toupper(*nm); type[i] = '\0'; for (Tptr = Table; Tptr->name != NULL; Tptr++) if (strcmp(Tptr->name,type) == NULL) { LOG4(L_DB,"(%5d) gettype: nm='%s', returns %d\n", Logstamp,type,Tptr->type); return(Tptr->type); } LOG4(L_DB,"(%5d) gettype: nm='%s', NOT FOUND returns %d\n", Logstamp,type,NULL); return(NULL);}/* * convert numeric record type into character string * NOTE: all NSTYPES are forced to fold into either SOA or NS. */char *getctype(num)int num;{ if (((num & MASKNS) == NSTYPE) && num != SOA) num = NS; for (Tptr = Table; Tptr->name != NULL; Tptr++) if (Tptr->type == num) return((Tptr->name)?Tptr->name:"NULL"); return(" NULL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -