X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=blobdiff_plain;f=src%2Finternal.h;h=a7f868d26aef40e5017050e486197303da2d0a21;hp=9a555195f653c2a1272337f7ab1997d9b1c8fee0;hb=e128c3551e8c178c181b212b990aaad613e489b9;hpb=07554ccd8286775b4f88a608ba3b94ff7b9efaf9 diff --git a/src/internal.h b/src/internal.h index 9a55519..a7f868d 100644 --- a/src/internal.h +++ b/src/internal.h @@ -39,9 +39,11 @@ typedef unsigned char byte; #include #include #include +#include #include +#define ADNS_FEATURE_MANYAF #include "adns.h" #include "dlist.h" @@ -68,8 +70,6 @@ typedef unsigned char byte; #define DNS_IDOFFSET 0 #define DNS_CLASS_IN 1 -#define DNS_INADDR_ARPA "in-addr", "arpa" - #define MAX_POLLFDS ADNS_POLLFDS_RECOMMENDED /* Some preprocessor hackery */ @@ -108,6 +108,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 struct { @@ -124,15 +129,14 @@ typedef struct { struct timeval now; } parseinfo; -union gen_addr { - struct in_addr v4; - struct in6_addr v6; +#define MAXREVLABELS 34 /* keep in sync with addrfam! */ +struct revparse_state { + uint16_t labstart[MAXREVLABELS]; + uint8_t lablen[MAXREVLABELS]; }; -struct af_addr { int af; union gen_addr addr; }; - union checklabel_state { - struct { byte ipv[4]; } ptr; + struct revparse_state ptr; }; typedef struct { @@ -141,8 +145,12 @@ typedef struct { union { struct { - struct af_addr addr; + adns_rrtype rev_rrtype; + adns_sockaddr addr; } ptr; + struct { + unsigned want, have; + } addr; } tinfo; /* type-specific state for the query itself: zero-init if you * don't know better. */ @@ -188,7 +196,8 @@ typedef struct typeinfo { adns_status (*checklabel)(adns_state ads, adns_queryflags flags, union checklabel_state *cls, qcontext *ctx, - int labnum, const char *label, int lablen); + int labnum, const char *dgram, + int labstart, int lablen); /* Check a label from the query domain string. The label is not * necessarily null-terminated. The hook can refuse the query's submission * by returning a nonzero status. State can be stored in *cls between @@ -198,7 +207,7 @@ typedef struct typeinfo { * because lablen is zero. */ - void (*postsort)(adns_state ads, void *array, int nrrs,int rrsz, + void (*postsort)(adns_state ads, void *array, int nrrs, int rrsz, const struct typeinfo *typei); /* Called immediately after the RRs have been sorted, and may rearrange * them. (This is really for the benefit of SRV's bizarre weighting @@ -209,18 +218,25 @@ typedef struct typeinfo { /* 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__ckl_hostname(adns_state ads, adns_queryflags flags, union checklabel_state *cls, qcontext *ctx, int labnum, - const char *label, int lablen); + const char *dgram, int labstart, int lablen); /* implemented in query.c, used by types.c as default * and as part of implementation for some fancier types * doesn't require any state */ typedef struct allocnode { struct allocnode *next, *back; + size_t sz; } allocnode; union maxalign { @@ -304,6 +320,10 @@ struct adns__query { * Queries in state tcpw/tcpw have been sent (or are in the to-send buffer) * iff the tcp connection is in state server_ok. * + * Internal queries (from adns__submit_internal) end up on intdone + * instead of output, and the callbacks are made on the way out of + * adns, to avoid reentrancy hazards. + * * +------------------------+ * START -----> | tosend/NONE | * +------------------------+ @@ -342,14 +362,18 @@ struct adns__query { struct query_queue { adns_query head, tail; }; +#define MAXUDP 2 + struct adns__state { adns_initflags iflags; adns_logcallbackfn *logfn; void *logfndata; int configerrno; - struct query_queue udpw, tcpw, childw, output; + struct query_queue udpw, tcpw, childw, output, intdone; adns_query forallnext; - int nextid, udpsocket, tcpsocket; + int nextid, tcpsocket; + struct udpsocket { int af; int fd; } udpsocket[MAXUDP]; + int nudp; vbuf tcpsend, tcprecv; int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip; enum adns__tcpstate { @@ -367,8 +391,7 @@ struct adns__state { struct pollfd pollfds_buf[MAX_POLLFDS]; adns_rr_addr servers[MAXSERVERS]; struct sortlist { - int af; - union gen_addr base, mask; + adns_sockaddr base, mask; } sortlist[MAXSORTLIST]; char **searchlist; unsigned short rand48xsubi[3]; @@ -376,21 +399,20 @@ struct adns__state { /* From addrfam.c: */ -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__addrs_equal_raw(const struct sockaddr *a, + int bf, const void *b); +/* Returns nonzero a's family is bf and a's protocol address field + * refers to the same protocol address as that stored at ba. */ -extern int adns__genaddr_equal_p(int af, const union gen_addr *a, - int bf, const void *b); -/* b should point to a `struct in_addr' or equivalent for the address family - * bf. Returns nonzero if the two addresses are equal. +extern int adns__addrs_equal(const adns_sockaddr *a, + const adns_sockaddr *b); +/* Returns nonzero if the two refer to the same protocol address + * (disregarding port, IPv6 scope, etc). */ -extern int adns__sockaddr_equal_p(const struct sockaddr *sa, - const struct sockaddr *sb); +extern int adns__sockaddrs_equal(const struct sockaddr *sa, + const struct sockaddr *sb); /* Return nonzero if the two socket addresses are equal (in all significant * respects). */ @@ -398,39 +420,75 @@ extern int adns__sockaddr_equal_p(const struct sockaddr *sa, 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 void adns__prefix_mask(adns_sockaddr *sa, int len); +/* Stores in sa's protocol address field an address mask for address + * family af, whose first len bits are set and the remainder are + * clear. On entry, sa's af field must be set. 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); +extern int adns__guess_prefix_length(const adns_sockaddr *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. +extern int adns__addr_matches(int af, const void *addr, + const adns_sockaddr *base, + const adns_sockaddr *mask); +/* Return nonzero if the protocol address specified by af and addr + * lies within the network specified by base and mask. + */ + +extern void adns__addr_inject(const void *a, adns_sockaddr *sa); +/* Injects the protocol address *a into the socket adress sa. Assumes + * that sa->sa_family is already set correctly. + */ + +extern const void *adns__sockaddr_addr(const struct sockaddr *sa); +/* Returns the address of the protocol address field in sa. */ -extern void adns__sockaddr_extract(const struct sockaddr *sa, - union gen_addr *a_r, int *port_r); -/* Extract fields from the socket address, filling in *a_r and *port_r with - * the address and (integer, host byte-order) port number, respectively. - * Either (or, pointlessly, both) of a_r and port_r may be null to mean - * `don't care'. +char *adns__sockaddr_ntoa(const struct sockaddr *sa, char *buf); +/* Convert sa to a string, and write it to buf, which must be at least + * ADNS_ADDR2TEXT_BUFLEN bytes long (unchecked). Return buf; can't fail. */ -extern void adns__sockaddr_inject(const union gen_addr *a, int port, - struct sockaddr *sa); -/* Inject fields into the socket adress sa. If a is not null, copy the - * address in; if port is not -1, then copy the port (converting from host - * byte-order). Assumes that sa->sa_family is already set correctly. +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 bool adns__revparse_label(struct revparse_state *rps, int labnum, + const char *dgram, + int labstart, 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 1 if the parse is proceeding successfully, 0 if the domain + * name is definitely invalid and the parse must be abandoned. + */ + +extern bool adns__revparse_done(struct revparse_state *rps, + const char *dgram, int nlabels, + adns_rrtype *rrtype_r, adns_sockaddr *addr_r); +/* Finishes parsing a reverse-domain name, given the total number of + * labels in the name. On success, fills in the af and protocol + * address in *addr_r, and the forward query type in *rrtype_r + * (because that turns out to be useful). Returns 1 if the parse + * was successful. */ /* From setup.c: */ @@ -521,6 +579,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<=icname 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 @@ -612,6 +679,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 @@ -633,8 +704,18 @@ void adns__reset_preserved(adns_query qu); * in a datagram and discover that we need to retry the query. */ +void adns__cancel(adns_query qu); void adns__query_done(adns_query qu); -void adns__query_fail(adns_query qu, adns_status stat); +void adns__query_fail(adns_query qu, adns_status st); +void adns__cancel_children(adns_query qu); + +void adns__returning(adns_state ads, adns_query qu); +/* Must be called before returning from adns any time that we have + * progressed (including made, finished or destroyed) queries. + * + * Might reenter adns via internal query callbacks, so + * external-faciing functions which call adns__returning should + * normally be avoided in internal code. */ /* From reply.c: */ @@ -785,6 +866,8 @@ void adns__update_expires(adns_query qu, unsigned long ttl, int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len); +bool adns__labels_equal(const byte *a, int al, const byte *b, int bl); + /* From event.c: */ void adns__tcp_broken(adns_state ads, const char *what, const char *why); @@ -800,6 +883,7 @@ void adns__autosys(adns_state ads, struct timeval now); void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io, struct timeval *tv_buf); +/* Call with care - might reentrantly cause queries to be completed! */ int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]); void adns__fdevents(adns_state ads, @@ -832,6 +916,9 @@ static inline int ctype_digit(int c) { return c>='0' && c<='9'; } static inline int ctype_alpha(int c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } +static inline int ctype_toupper(int c) { + return ctype_alpha(c) ? (c & ~32) : c; +} static inline int ctype_822special(int c) { return strchr("()<>@,;:\\\".[]",c) != 0; }