X-Git-Url: https://git.distorted.org.uk/~mdw/adns/blobdiff_plain/705b9b159806e6e96839c81668f685a6576ea961..6480e2dfab3ff911cac1d1e922666fcea65e511e:/src/internal.h diff --git a/src/internal.h b/src/internal.h index 2c5a073..98f492f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -42,6 +42,7 @@ typedef unsigned char byte; #include +#define ADNS_FEATURE_MANYAF #include "adns.h" #include "dlist.h" @@ -71,6 +72,8 @@ typedef unsigned char byte; #define DNS_INADDR_ARPA "in-addr", "arpa" #define DNS_IP6_ARPA "ip6", "arpa" +#define MAX_ADDRSTRLEN 64 + #define STRINGIFY(x) REALLY_STRINGIFY(x) #define REALLY_STRINGIFY(x) #x @@ -91,6 +94,11 @@ typedef enum { rcode_refused } dns_rcode; +enum { + adns__qf_addr_answer= 0x01000000,/* addr query received an answer */ + adns__qf_addr_cname = 0x02000000 /* addr subquery performed on cname */ +}; + /* Shared data structures */ typedef union { @@ -121,26 +129,38 @@ union gen_addr { struct in6_addr v6; }; +#define NREVDOMAINS 2 /* keep in sync with addrfam! */ +struct revparse_state { + unsigned map; /* which domains are still live */ + byte ipv[NREVDOMAINS][32]; /* address components so far */ +}; + +union checklabel_state { + struct revparse_state ptr; +}; + +struct af_addr { int af; union gen_addr addr; }; + typedef struct { - int af; - int width; - int delim; - int nrevcomp; - int revcompwd; - adns_rrtype rrtype; - void *(*sockaddr_to_inaddr)(struct sockaddr *sa); - int (*sockaddr_equalp)(const struct sockaddr *sa, - const struct sockaddr *sb); - void (*prefix_mask)(int len, union gen_addr *a); - int (*guess_len)(const union gen_addr *a); - int (*matchp)(const union gen_addr *addr, - const union gen_addr *base, const union gen_addr *mask); - int (*rev_parsecomp)(const char *p, size_t n); - void (*rev_mkaddr)(union gen_addr *addr, const byte *ipv); - char *(*rev_mkname)(const struct sockaddr *sa, char *buf); -} afinfo; - -struct afinfo_addr { const afinfo *ai; union gen_addr addr; }; + void *ext; + void (*callback)(adns_query parent, adns_query child); + + union { + adns_rr_hostaddr *hostaddr; + } pinfo; /* state for use by parent's callback function */ + + union { + struct { + adns_rrtype rev_rrtype; + struct af_addr addr; + } ptr; + struct { + unsigned want, have; + } addr; + } tinfo; /* type-specific state for the query itself: zero-init if you + * don't know better. */ + +} qcontext; typedef struct typeinfo { adns_rrtype typekey; @@ -177,16 +197,17 @@ typedef struct typeinfo { * 0 otherwise. Must not fail. */ - adns_status (*qdparselabel)(adns_state ads, - const char **p_io, const char *pe, int labelnum, - char label_r[DNS_MAXDOMAIN], int *ll_io, - adns_queryflags flags, - const struct typeinfo *typei); - /* Parses one label from the query domain string. On entry, *p_io - * points to the next character to parse and *ll_io is the size of - * the buffer. pe points just after the end of the query domain - * string. On successful return, label_r[] and *ll_io are filled in - * and *p_io points to *pe or just after the label-ending `.'. */ + adns_status (*checklabel)(adns_state ads, adns_queryflags flags, + union checklabel_state *css, qcontext *ctx, + int labnum, const char *label, int lablen); + /* Check a label from the query domain string. The label is not + * necessarily null-terminated. The query has not yet been constructed, + * and this hook can refuse its submission by returning a nonzero status. + * State can be stored in *css between calls, and useful information can be + * stashed in ctx->tinfo, to be stored with the query (e.g., it will be + * available to the parse hook). This hook can detect a first call because + * labnum is zero, and a final call because lablen is zero. + */ void (*postsort)(adns_state ads, void *array, int nrrs, const struct typeinfo *typei); @@ -194,18 +215,29 @@ typedef struct typeinfo { * them. (This is really for the benefit of SRV's bizarre weighting * stuff.) May be 0 to mean nothing needs to be done. */ + + int (*getrrsz)(adns_rrtype type); + /* Return the output resource-record element size; if this is null, then + * the rrsz member can be used. + */ + + void (*query_send)(adns_query qu, struct timeval now); + /* Send the query to nameservers, and hook it into the appropriate queue. + * Normal behaviour is to call adns__query_send, but this can be overridden + * for special effects. + */ } typeinfo; -adns_status adns__qdpl_normal(adns_state ads, - const char **p_io, const char *pe, int labelnum, - char label_r[], int *ll_io, - adns_queryflags flags, - const typeinfo *typei); - /* implemented in transmit.c, used by types.c as default - * and as part of implementation for some fancier types */ +adns_status adns__ckl_hostname(adns_state ads, adns_queryflags flags, + union checklabel_state *css, + qcontext *ctx, int labnum, + const char *label, int lablen); +/* implemented in query.c, used by types.c as default + * and as part of implementation for some fancier types */ typedef struct allocnode { struct allocnode *next, *back; + size_t sz; } allocnode; union maxalign { @@ -217,15 +249,6 @@ union maxalign { union maxalign *up; } data; -typedef struct { - void *ext; - void (*callback)(adns_query parent, adns_query child); - union { - struct afinfo_addr ptr_parent_addr; - adns_rr_hostaddr *hostaddr; - } info; -} qcontext; - struct adns__query { adns_state ads; enum { query_tosend, query_tcpw, query_childw, query_done } state; @@ -346,7 +369,7 @@ struct adns__state { struct query_queue udpw, tcpw, childw, output; adns_query forallnext; int nextid, tcpsocket; - struct udpsocket { const afinfo *ai; int fd; } udpsocket[MAXUDP]; + struct udpsocket { int af; int fd; } udpsocket[MAXUDP]; int nudp; vbuf tcpsend, tcprecv; int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip; @@ -365,7 +388,7 @@ struct adns__state { struct pollfd pollfds_buf[MAX_POLLFDS]; adns_rr_addr servers[MAXSERVERS]; struct sortlist { - const afinfo *ai; + int af; union gen_addr base, mask; } sortlist[MAXSORTLIST]; char **searchlist; @@ -374,7 +397,87 @@ struct adns__state { /* From addrfam.c: */ -extern const afinfo adns__inet_afinfo, adns__inet6_afinfo; +extern int adns__af_supported_p(int af); +/* Return nonzero if the address family af known to the library and supported + * by the other addrfam operations. Note that the other operations will + * abort on an unrecognized address family rather than returning an error + * code. + */ + +extern int adns__sockaddr_equal_p(const struct sockaddr *sa, + const struct sockaddr *sb); +/* Return nonzero if the two socket addresses are equal (in all significant + * respects). + */ + +extern int adns__gen_pton(const char *p, int *af_r, union gen_addr *addr_r); +/* Parse an address at p, deciding which address family it belongs to. On + * success, returns 1 (like inet_aton) having stashed the address family in + * *af_r and the parsed address in *addr_r. If the address string is + * invalid, returns 0. + */ + +extern int adns__addr_width(int af); +/* Return the width of addresses of family af, in bits. */ + +extern void adns__prefix_mask(int af, int len, union gen_addr *mask_r); +/* Store in mask_r an address mask for address family af, whose first len + * bits are set and the remainder are clear. This is what you want for + * converting a prefix length into a netmask. + */ + +extern int adns__guess_prefix_length(int af, const union gen_addr *addr); +/* Given a network base address, guess the appropriate prefix length based on + * the appropriate rules for the address family (e.g., for IPv4, this uses + * the old address classes). + */ + +extern int adns__addr_match_p(int addraf, const union gen_addr *addr, + int netaf, const union gen_addr *base, + const union gen_addr *mask); +/* Given an address af (with family addraf) and a network (with family netaf, + * base address base, and netmask mask), return nonzero if the address lies + * within the network. + */ + +const void *adns__sockaddr_to_inaddr(const struct sockaddr *sa); +/* Given a socket address, return a pointer to the actual network address + * within it. + */ + +extern int adns__make_reverse_domain(const struct sockaddr *sa, + const char *zone, + char **buf_io, size_t bufsz, + char **buf_free_r); +/* Construct a reverse domain string, given a socket address and a parent + * zone. If zone is null, then use the standard reverse-lookup zone for the + * address family. If the length of the resulting string is no larger than + * bufsz, then the result is stored starting at *buf_io; otherwise a new + * buffer is allocated is used, and a pointer to it is stored in both *buf_io + * and *buf_free_r (the latter of which should be null on entry). If + * something goes wrong, then an errno value is returned: ENOSYS if the + * address family of sa isn't recognized, or ENOMEM if the attempt to + * allocate an output buffer failed. + */ + +extern int adns__revparse_label(struct revparse_state *rps, int labnum, + const char *label, int lablen); +/* Parse a label in a reverse-domain name, given its index labnum (starting + * from zero), a pointer to its contents (which need not be null-terminated), + * and its length. The state in *rps is initialized implicitly when labnum + * is zero. + * + * Returns zero if the parse was successful, nonzero if the domain name is + * definitely invalid and the parse must be abandoned. + */ + +extern int adns__revparse_done(struct revparse_state *rps, int nlabels, + adns_rrtype *rrtype_r, struct af_addr *addr_r); +/* Finishes parsing a reverse-domain name, given the total number of labels + * in the name. On success, fills in the address in *addr_r, and the forward + * query type in *rrtype_r (because that turns out to be useful). Returns + * nonzero if the parse must be abandoned. + */ /* From setup.c: */ @@ -382,7 +485,9 @@ int adns__setnonblock(adns_state ads, int fd); /* => errno value */ /* From general.c: */ -const char *adns__sockaddr_ntoa(struct sockaddr *sa, size_t n); +const char *adns__sockaddr_ntoa(struct sockaddr *sa, size_t n, char *buf); +/* Buffer must be at least MAX_ADDRSTRLEN bytes long. */ + void adns__vlprintf(adns_state ads, const char *fmt, va_list al); void adns__lprintf(adns_state ads, const char *fmt, ...) PRINTFFORMAT(2,3); @@ -460,6 +565,15 @@ void adns__querysend_tcp(adns_query qu, struct timeval now); * might be broken, but no reconnect will be attempted. */ +struct udpsocket *adns__udpsocket_by_af(adns_state ads, int af); +/* Find the UDP socket structure in ads which has the given address family. + * Return null if there isn't one. + * + * This is used during initialization, so ads is only partially filled in. + * The requirements are that nudp is set, and that udpsocket[i].af are + * defined for 0<=ivb). * + * If adns__qf_nosend is set in flags, then the query is not sent: doing + * whatever is necessary to send the query and link it onto the appropriate + * queue is left as the caller's responsibility. + * * *ctx is copied byte-for-byte into the query. * * When the child query is done, ctx->callback will be called. The @@ -535,8 +653,7 @@ void *adns__alloc_preserved(adns_query qu, size_t sz); * answer->cname and answer->owner are _preserved. */ -void adns__transfer_interim(adns_query from, adns_query to, - void *block, size_t sz); +void adns__transfer_interim(adns_query from, adns_query to, void *block); /* Transfers an interim allocation from one query to another, so that * the `to' query will have room for the data when we get to makefinal * and so that the free will happen when the `to' query is freed @@ -550,6 +667,10 @@ void adns__transfer_interim(adns_query from, adns_query to, * TTLs get inherited by their parents. */ +void adns__free_interim(adns_query qu, void *p); +/* Forget about a block allocated by adns__alloc_interim. + */ + void *adns__alloc_mine(adns_query qu, size_t sz); /* Like _interim, but does not record the length for later * copying into the answer. This just ensures that the memory @@ -573,6 +694,7 @@ void adns__reset_preserved(adns_query qu); void adns__query_done(adns_query qu); void adns__query_fail(adns_query qu, adns_status stat); +void adns__cancel_children(adns_query qu); /* From reply.c: */