#include <thread.h> /* for Ref */
#define NS2MS(ns) ((ns) / 1000000L)
#define S2MS(s) ((s) * 1000LL)
#define timems() NS2MS(nsec())
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 */
Tany= 255, /* some or all records, see rfc8482 */
Tcaa= 257, /* Certificate Authority Authorization, see RFC 8659 */
Tall= 260, /* all records */
Tipall= 48000, /* local invention: either ip vers */
/* classes */
Csym= 0, /* internal symbols */
Cin= 1, /* internet */
Ccs, /* CSNET (obsolete) */
Cch, /* Chaos net (obsolete MIT & Lisp machines) */
Chs, /* Hesiod (obsolete MIT Athena) */
/* 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,
/* tcp & udp port number */
Dnsport= 53,
/*
* payload size. originally, 512 bytes was the upper bound, to
* eliminate fragmentation when using udp transport.
* with edns (rfc 6891), that has been raised to 4096.
* we don't currently generate edns, but we might be sent edns packets.
*/
Maxdnspayload= 512,
Maxpayload= 4096,
/* 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*1000; keep them short */
Maxreqtm= 8*1000, /* max. ms. to process a request */
Minreqtm= 3*1000, /* give each outgoing query this many ms. */
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;
typedef struct Caa Caa;
/*
* a structure to track a request and any slave process handling it
*/
struct Request
{
int isslave; /* pid of slave */
uvlong aborttime; /* time in ms 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;
};
/*
* caa (certification authority authorization) record (rfc8659)
* Utilize RR host->name bytes for value storage.
*/
struct Caa
{
int flag;
char *tag;
};
/*
* 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;
Caa *caa;
};
};
/*
* 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;
};
typedef struct Rrlist Rrlist;
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[];
extern Lock dnlock;
void abort(); /* char*, ... */;
void addserver(Server**, char*);
Server* copyserverlist(Server*);
void db2cache(int);
void dnage(DN*);
void dnageall(int);
void dnagedb(void);
void dnageallnever(void);
void dnagenever(DN *, int);
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);
void initdnsmsg(DNSmsg *mp, RR *rp, int flags, ushort reqno);
DNSmsg* newdnsmsg(RR *rp, int flags, ushort reqno);
/* 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);
/* dnrev.c */
char* revv4(char *dom);
char* revv6(char *dom);
/* convDNS2M.c */
int convDNS2M(DNSmsg*, uchar*, int);
/* convM2DNS.c */
char* convM2DNS(uchar*, int, DNSmsg*, int*);
#pragma varargck argpos dnslog 1
|