#include /* for Ref */ typedef struct Ndbtuple Ndbtuple; enum { /* RR types; see: http://www.iana.org/assignments/dns-parameters */ 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, Tafsdb= 18, Tx25= 19, Tisdn= 20, Trt= 21, Tnsap= 22, Tnsapptr= 23, Tsig= 24, Tkey= 25, Tpx= 26, Tgpos= 27, Taaaa= 28, Tloc= 29, Tnxt= 30, Teid= 31, Tnimloc= 32, Tsrv= 33, Tatma= 34, Tnaptr= 35, Tkx= 36, Tcert= 37, Ta6= 38, Tdname= 39, Tsink= 40, Topt= 41, Tapl= 42, Tds= 43, Tsshfp= 44, Tipseckey= 45, Trrsig= 46, Tnsec= 47, Tdnskey= 48, Tspf= 99, Tuinfo= 100, Tuid= 101, Tgid= 102, Tunspec= 103, /* query types (all RR types are also queries) */ Ttkey= 249, /* transaction key */ Ttsig= 250, /* transaction signature */ Tixfr= 251, /* incremental zone transfer */ Taxfr= 252, /* zone transfer */ Tmailb= 253, /* { Tmb, Tmg, Tmr } */ Tmaila= 254, /* obsolete */ 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 (retired) */ Ostatus= 2<<11, /* status request */ Onotify= 4<<11, /* notify slaves of updates */ Oupdate= 5<<11, 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 */ Ryxdomain= 6, /* name exists when it should not */ Ryxrrset= 7, /* rr set exists when it should not */ Rnxrrset= 8, /* rr set that should exist does not */ Rnotauth= 9, /* not authoritative */ Rnotzone= 10, /* name not in zone */ Rbadvers= 16, /* bad opt version */ /* Rbadsig= 16, */ /* also tsig signature failure */ Rbadkey= 17, /* key not recognized */ Rbadtime= 18, /* signature out of time window */ Rbadmode= 19, /* bad tkey mode */ Rbadname= 20, /* duplicate key name */ Rbadalg= 21, /* algorithm not supported */ Rmask= 0x1f, /* mask for response */ Rtimeout= 1<<5, /* 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= 64, /* max domain label length (with NULL) */ Strlen= 256, /* max string 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, Maxpath= 128, /* size of mntpt */ Maxlcks= 10, /* max. query-type locks per domain name */ RRmagic= 0xdeadbabe, DNmagic= 0xa110a110, /* parallelism: tune; was 32; allow lots */ Maxactive= 250, /* tune; was 60; keep it short */ Maxreqtm= 10, /* max. seconds to process a request */ Notauthoritative = 0, Authoritative, }; typedef struct Area Area; typedef struct Block Block; typedef struct Cert Cert; typedef struct DN DN; typedef struct DNSmsg DNSmsg; typedef struct Key Key; typedef struct Null Null; typedef struct RR RR; typedef struct Request Request; typedef struct SOA SOA; typedef struct Server Server; typedef struct Sig Sig; typedef struct Srv Srv; 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; char *from; /* who asked us? */ }; typedef struct Querylck Querylck; struct Querylck { QLock; // Rendez; Ref; }; /* * 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 */ /* refs was `char' but we've seen refs > 120, so go whole hog */ ulong refs; /* for mark and sweep */ ulong ordinal; ushort class; /* RR class */ uchar keep; /* flag: never age this name */ uchar respcode; /* response code */ /* was: char nonexistent; /* true if we get an authoritative nx for this domain */ /* permit only 1 query per (domain name, type) at a time */ Querylck querylck[Maxlcks]; }; /* * security info */ struct Block { int dlen; uchar *data; }; struct Key { int flags; int proto; int alg; Block; }; struct Cert { int type; int tag; int alg; Block; }; struct Sig { Cert; int labels; ulong ttl; ulong exp; ulong incep; DN *signer; }; struct Null { Block; }; /* * 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 */ uintptr pc; /* for tracking memory allocation */ ulong ttl; /* time to live to be passed on */ ulong expire; /* time this entry expires locally */ ulong marker; /* used locally when scanning rrlists */ ushort type; /* RR type */ ushort query; /* query type is in response to */ uchar auth; /* flag: authoritative */ uchar db; /* flag: from database */ uchar cached; /* flag: rr in cache */ uchar negative; /* flag: this is a cached negative response */ union { /* discriminated by negative & type */ DN *negsoaowner; /* soa for cached negative response */ DN *host; /* hostname - soa, cname, mb, md, mf, mx, ns, srv */ DN *cpu; /* cpu type - hinfo */ DN *mb; /* mailbox - mg, minfo */ DN *ip; /* ip address - a, aaaa */ DN *rp; /* rp arg - rp */ uintptr arg0; /* arg[01] are compared to find dups in dn.c */ }; union { /* discriminated by negative & type */ int negrcode; /* response code for cached negative resp. */ 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 */ ushort port; /* - srv */ uintptr arg1; /* arg[01] are compared to find dups in dn.c */ }; union { /* discriminated by type */ SOA *soa; /* soa timers - soa */ Key *key; Cert *cert; Sig *sig; Null *null; Txt *txt; Srv *srv; }; }; /* * list of servers */ struct Server { Server *next; char *name; }; /* * timers for a start-of-authority record. all ulongs are in seconds. */ struct SOA { ulong serial; /* zone serial # */ ulong refresh; /* zone refresh interval */ ulong retry; /* zone retry interval */ ulong expire; /* time to expiration */ ulong minttl; /* min. time to live for any entry */ Server *slaves; /* slave servers */ }; /* * srv (service location) record (rfc2782): * _service._proto.name ttl class(IN) 'SRV' priority weight port target */ struct Srv { ushort pri; ushort weight; }; struct Rrlist { int count; RR *rrs; }; /* * 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; }; typedef struct Cfg Cfg; struct Cfg { int cachedb; int resolver; int justforw; /* flag: pure resolver, just forward queries */ int serve; /* flag: serve udp queries */ int inside; int straddle; }; /* (udp) query stats */ typedef struct { QLock; ulong slavehiwat; /* procs */ ulong qrecvd9p; /* query counts */ ulong qrecvdudp; ulong qsent; ulong qrecvd9prpc; /* packet count */ ulong alarms; /* reply times by count */ ulong under10ths[3*10+2]; /* under n*0.1 seconds, n is index */ ulong tmout; ulong tmoutcname; ulong tmoutv6; ulong answinmem; /* answers in memory */ ulong negans; /* negative answers received */ ulong negserver; /* neg ans with Rserver set */ ulong negbaddeleg; /* neg ans with bad delegations */ ulong negbdnoans; /* ⋯ and no answers */ ulong negnorname; /* neg ans with no Rname set */ ulong negcached; /* neg ans cached */ } Stats; Stats stats; enum { Recurse, Dontrecurse, NOneg, OKneg, }; extern Cfg cfg; extern char *dbfile; extern int debug; extern Area *delegated; extern char *logfile; extern int maxage; /* age of oldest entry in cache (secs) */ extern char mntpt[]; extern int needrefresh; extern int norecursion; extern ulong now; /* time base */ extern vlong nowns; extern Area *owned; extern int sendnotifies; extern ulong target; extern int testing; /* test cache whenever removing a DN */ extern char *trace; extern int traceactivity; extern char *zonerefreshprogram; #pragma varargck type "R" RR* #pragma varargck type "Q" RR* /* dn.c */ extern char *rrtname[]; extern char *rname[]; extern unsigned nrname; extern char *opname[]; void abort(); /* char*, ... */; void addserver(Server**, char*); Server* copyserverlist(Server*); void db2cache(int); void dnage(DN*); void dnageall(int); void dnagedb(void); void dnagenever(void); void dnauthdb(void); void dncheck(void*, int); void dndump(char*); void dnget(void); void dninit(void); DN* dnlookup(char*, int, int); void dnptr(uchar*, uchar*, char*, int, int, int); void dnpurge(void); void dnput(void); void dnslog(char*, ...); void dnstats(char *file); void* emalloc(int); char* estrdup(char*); void freeanswers(DNSmsg *mp); void freeserverlist(Server*); int getactivity(Request*, int); Area* inmyarea(char*); void putactivity(int); RR* randomize(RR*); RR* rralloc(int); void rrattach(RR*, int); int rravfmt(Fmt*); RR* rrcat(RR**, RR*); RR** rrcopy(RR*, RR**); int rrfmt(Fmt*); void rrfree(RR*); void rrfreelist(RR*); RR* rrlookup(DN*, int, int); char* rrname(int, char*, int); RR* rrremneg(RR**); RR* rrremtype(RR**, int); int rrsupported(int); int rrtype(char*); void slave(Request*); int subsume(char*, char*); int tsame(int, int); void unique(RR*); void warning(char*, ...); /* dnarea.c */ void refresh_areas(Area*); void freearea(Area**); void addarea(DN *dp, RR *rp, Ndbtuple *t); /* dblookup.c */ int baddelegation(RR*, RR*, uchar*); RR* dbinaddr(DN*, int); RR* dblookup(char*, int, int, int, int); void dnforceage(void); RR* dnsservers(int); RR* domainlist(int); int insideaddr(char *dom); int insidens(uchar *ip); int myaddr(char *addr); int opendatabase(void); uchar* outsidens(int); /* dns.c */ char* walkup(char*); RR* getdnsservers(int); void logreply(int, uchar*, DNSmsg*); void logsend(int, int, uchar*, char*, char*, int); void procsetname(char *fmt, ...); /* dnresolve.c */ RR* dnresolve(char*, int, int, Request*, RR**, int, int, int, int*); int udpport(char *); int mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno); int seerootns(void); /* dnserver.c */ void dnserver(DNSmsg*, DNSmsg*, Request*, uchar *, int); void dnudpserver(char*); void dntcpserver(char*); /* dnnotify.c */ void dnnotify(DNSmsg*, DNSmsg*, Request*); void notifyproc(void); /* convDNS2M.c */ int convDNS2M(DNSmsg*, uchar*, int); /* convM2DNS.c */ char* convM2DNS(uchar*, int, DNSmsg*, int*); #pragma varargck argpos dnslog 1