From a17d3a1d960ca40434205a80aa106ca4c7224ec9 Mon Sep 17 00:00:00 2001 From: ian Date: Sun, 27 Sep 1998 15:31:35 +0000 Subject: [PATCH] Found on chiark. --- src/adns-internal.h | 38 +++++++++++ src/adns.c | 127 +++++++++++++++++++++++++++++++++++ src/adns.h | 160 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 src/adns-internal.h create mode 100644 src/adns.c create mode 100644 src/adns.h diff --git a/src/adns-internal.h b/src/adns-internal.h new file mode 100644 index 0000000..cabb271 --- /dev/null +++ b/src/adns-internal.h @@ -0,0 +1,38 @@ +/**/ + +#ifndef ADNS_INTERNAL_H_INCLUDED +#define ADNS_INTERNAL_H_INCLUDED + +#include "adns.h" + +#define MAXSERVERS 5 +#define MAXUDPRETRIES 10 +#define UDPRETRYMS 2000 +#define TCPMS 20000 + +struct adns__query { + adns_query next, back; + adns_query parent, child; + adns_rrtype type; + stuct adns_answer *answer; + int flags, udpretries, server; + struct timeval timeout; + void *context; + char owner[1]; +}; + +struct adns__state { + struct { adns_query head, tail } input, timew, childw, output; + int udpsocket; + int qbufavail, tcpbufavail, tcpbufused, tcpbufdone; + char *qbuf, *tcpbuf; + int nservers; + struct { + struct in_addr addr; + int tcpsocket; + struct timeval timeout; + struct { adns_query head, tail } connw; + } servers[MAXSERVERS]; +}; + +#endif diff --git a/src/adns.c b/src/adns.c new file mode 100644 index 0000000..381105d --- /dev/null +++ b/src/adns.c @@ -0,0 +1,127 @@ +/**/ + +#include + +#include "adns-internal.h" + +#define LIST_UNLINK(list,node) \ + do { \ + if ((node)->back) (node)->back->next= (node)->next; \ + else (list).head= (node)->next; \ + if ((node)->next) (node)->next->back= (node)->back; \ + else (list).tail= (node)->back; \ + } while(0) + +#define LIST_LINK_TAIL(list,node) \ + do { \ + (node)->back= 0; \ + (node)->next= (list).tail; \ + if (list).tail (list).tail->back= (node); else (list).head= (node); \ + (list).tail= (node); \ + } while(0) + +void addserver(adns_state ads, struct in_addr addr) { + if (ads->nservers>=MAXSERVERS) { + if (ads->flags & adns_if_debug) + fprintf(stderr,"adns: too many nameservers, ignoring %s", + inet_ntoa(addr)); + } else { + ads->servers[ads->nservers].addr= addr; + ads->servers[ads->nservers].tcpsocket= -1; + ads->nservers++; + } +} + +void readconfig(adns_state ads, const char *filename) { +} + +void readconfigenv(adns_state ads, const char *envvar) { + const char *filename; + + if (flags & adns_if_noenv) return; + filename= getenv(envvar); if (!filename) return; + readconfig(ads,filename); +} + +int adns_init(adns_state *ads_r, int flags) { + adns_state ads; + const char *cfile; + + ads= malloc(sizeof(*ads)); if (!ads) return errno; + ads->queue.head= ads->queue.tail= 0; + ads->timew.head= ads->timew.tail= 0; + ads->child.head= ads->child.tail= 0; + ads->ready.head= ads->ready.tail= 0; + ads->udpsocket= -1; + ads->qbufavail= 0; + ads->qbuf= 0; + ads->tcpbufavail= ads->tcpbufused= ads->tcpbufdone= 0; + ads->tcpbuf= 0; + ads->flags= flags; + ads->nservers= 0; + + readconfig(ads,"/etc/resolv.conf"); + readconfigenv(ads,"RES_CONF"); + readconfigenv(ads,"ADNS_RES_CONF"); + if (!ads->nservers) { + if (ads->flags & adns_if_debug) + fprintf(stderr,"adns: no nameservers, using localhost\n"); + addserver(ads,INADDR_LOOPBACK); + } + + *ads_r= ads; + return 0; +} + +void query_fail(adns_state ads, adns_query qu, ands_status stat) { + struct adns_answer ans; + + ans= qu->answer; + if (!ans) ans= malloc(sizeof(*qu->answer)); + if (ans) { + ans->status= stat; + ans->cname= 0; + ans->type= qu->type; + ans->nrrs= 0; + } + qu->answer= ans; + LIST_LINK_TAIL(ads.ready,qu); +} + +void adns_event(adns_state ads, + fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + int *maxfd, struct timeval *tv) { + for ( +} + +int adns_submit(adns_state ads, + const char *owner, + adns_rrtype type, + int flags, + void *context, + adns_query *query_r) { + adns_query qu; + adns_status stat; + int ol, r; + + stat= 0; + ol= strlen(owner); + if (ol>MAXDNAME+1) { stat= ands_s_invaliddomain; ol= 0; } + if (ol>0 && owner[ol-1]=='.') { flags &= ~adns_f_search; ol--; } + qu= malloc(sizeof(*qu)+ol+1); if (!qu) return errno; + qu->next= qu->back= qu->parent= qu->child= 0; + qu->type= type; + qu->answer= 0; + qu->flags= flags; + qu->context= context; + qu->retries= 0; + qu->server= 0; + memcpy(qu->owner,owner,ol); qu->owner[ol]= 0; + if (stat) { + query_fail(ads,qu,stat); + } else { + LIST_LINK_TAIL(ads->input,qu); + adns_event(ads,0,0,0,0,0); + } + *query_r= qu; +} diff --git a/src/adns.h b/src/adns.h new file mode 100644 index 0000000..61b3fc8 --- /dev/null +++ b/src/adns.h @@ -0,0 +1,160 @@ +/**/ + +#ifndef ADNS_H_INCLUDED +#define ADNS_H_INCLUDED + +typedef struct adns__state adns_state; +typedef struct adns__query adns_query; + +typedef enum { + adns_if_noenv= 0x0001, /* do not look at environment */ + adns_if_noerrprint= 0x0002, /* never print output to stderr */ + adns_if_debug= 0x0004, /* print debugging output to stderr */ +} adns_initflags; + +typedef enum { + adns_f_search= 0x0001, /* use the searchlist */ + adns_f_usevc= 0x0002, /* use a virtual circuit (TCP connection) */ +} adns_queryflags; + +typedef enum { + adns_rrttype_mask= 0x0fff, + adns_qtf_deref= 0x1000, + adns_qtf_mailconv= 0x2000, + adns_r_none= 0, + adns_r_a= 1, + adns_r_ns_raw= 2, + adns_r_ns= adns_r_ns_raw|adns_qtf_deref, + adns_r_cname= 5, + adns_r_soa_raw= 6, + adns_r_soa= adns_r_soa_raw|adns_qtf_mailconv, + adns_r_null= 10, + adns_r_ptr_raw= 12, + adns_r_ptr= adns_r_ptr_raw|adns_rf_deref, + adns_r_hinfo= 13, + adns_r_mx_raw= 15, + adns_r_mx= adns_r_mx_raw|adns_qtf_deref, + adns_r_txt= 16, + adns_r_rp_raw 17, + adns_r_rp= adns_r_rp_raw|adns_qtf_mailconv +} adns_rrtype; + +typedef enum { + adns_s_ok, + adns_s_notresponding, + adns_s_serverfailure, + adns_s_unknownqtype, + adns_s_remoteerror, + adns_s_max_tempfail= 99, + adns_s_nxdomain, + adns_s_norecord, + adns_s_invaliddomain +} adns_status; + +/* In dereferenced answers, multiple addresses show up as multiple + * answers with all the dm pointers being the same. If no + * address is available (permanent failure) then INADDR_NONE is + * used. */ + +struct adns_answer { + adns_status status; + char *cname; /* always NULL if query was for CNAME records */ + adns_rrtype type; + int nrrs; + union { + struct in_addr inaddr[1]; /* a */ + char (*str)[1]; /* ns_raw, cname, ptr, ptr_raw, txt */ + struct { char *dm; struct in_addr addr; } dmaddr; /* ns */ + struct { char *a, *b; } strpair[1]; /* hinfo, rp, rp_raw */ + struct { int pref; char *dm; struct in_addr addr; } intdmaddr[1]; /* mx */ + struct { int pref; char *str; } intstr[1]; /* mx_raw */ + struct { + char *ns0, *rp; + unsigned long serial, refresh, retry, expire, minimum; + } soa[1]; /* soa, soa_raw */ + /* NULL is empty */ + } rrs; +}; + +/* Memory management: + * adns_state and adns_query are actually pointers to malloc'd state; + * On submission questions are copied, including the owner domain; + * Answers are malloc'd as a single piece of memory. + * query_io: + * Must always be non-null pointer; + * If *query_io is 0 to start with then any query may be returned; + * If *query_io is !0 adns_query then only that query may be returned. + * Errors: + * Return values are 0 or an errno value; + * Seriously fatal system errors (eg, failure to create sockets, + * malloc failure, etc.) return errno values; + * Other errors (nameserver failure, timed out connections, &c) + * are returned in the status field of the answer. If status is + * nonzero then nrrs will be 0, otherwise it will be >0. + * type will always be the type requested; + * If no (appropriate) requests are done adns_query returns EWOULDBLOCK; + * If no requests are outstanding adns_query and adns_wait return ESRCH; + * If malloc failure occurs during internal allocation or processing + * ands_query, _wait and _answer set *answer to 0. + */ + +int adns_init(adns_state *newstate_r); + +int adns_synchronous(adns_state ads, + const char *owner, + adns_rrtype type, + int flags, + struct adns_answer *answer); + +int adns_submit(adns_state ads, + const char *owner, + adns_rrtype type, + int flags, + void *context, + const struct adns_query *query_r); + +int adns_query(adns_state ads, + adns_query *query_io, + struct adns_answer *answer, + void *context_r); + +int adns_wait(adns_state ads, + adns_query *query_io, + struct adns_answer *answer, + void *context_r); + +int adns_cancel(adns_state ads, adns_query query); + +int adns_finish(adns_state); + +void adns_event(adns_state, fd_set *readfds_mod, + fd_set *writefds_mod, fd_set *exceptfds_mod, + int *maxfd_mod, struct timeval *tv_mod); +/* You may call this with *_mod=0 to have a simple callback, + or with *fds_mod=*maxfd_mod=0 but tv_mod!=0 if you are + not going to sleep, or with all !=0 if you are going to sleep. */ + +/* Example expected/legal calling sequences: + * adns_init + * adns_submit 1 + * adns_submit 2 + * adns_submit 3 + * adns_wait 1 + * adns_query 3 -> EWOULDBLOCK + * adns_wait 2 + * adns_wait 3 + * .... + * adns_finish + * + * adns_init + * adns_submit ... + * loop { + * adns_query + * adns_interest + * select + * adns_callback + * other things + * } + */ + +#endif -- 2.30.2