X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=blobdiff_plain;f=src%2Finternal.h;h=24e69a8d4cfb1428aa9112a07ab80ac2c46eb574;hp=bf6d3ac3aa44fa5518238fc5d67bae46e20be097;hb=3955725ceceb330041f8e7a27e6629a2e8a9b5ba;hpb=b9de380c1e587b6c5828cb9de796746024946880 diff --git a/src/internal.h b/src/internal.h index bf6d3ac..24e69a8 100644 --- a/src/internal.h +++ b/src/internal.h @@ -1,4 +1,26 @@ -/**/ +/* + * internal.h + * - declarations of private objects with external linkage (adns__*) + * - definitons of internal macros + * - comments regarding library data structures + */ +/* + * This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ #ifndef ADNS_INTERNAL_H_INCLUDED #define ADNS_INTERNAL_H_INCLUDED @@ -22,12 +44,21 @@ typedef unsigned char byte; #define TCPMS 30000 #define LOCALRESOURCEMS 20 -#define DNS_UDPPORT 53 +#define DNS_PORT 53 #define DNS_MAXUDP 512 #define DNS_MAXDOMAIN 255 #define DNS_HDRSIZE 12 #define DNS_CLASS_IN 1 +typedef enum { + rcode_noerror, + rcode_formaterror, + rcode_servfail, + rcode_nxdomain, + rcode_notimp, + rcode_refused +} dns_rcode; + /* Shared data structures */ typedef union { @@ -49,37 +80,94 @@ typedef union { int dmaddr_index; } qcontext; +typedef struct { + adns_rrtype type; + const char *name; + int rrsz; + + adns_status (*parse)(adns_query qu, int serv, + const byte *dgram, int dglen, int cbyte, int max, + void *store_r); + /* Parse one RR, in dgram of length dglen, starting at cbyte and + * extending until at most max. + * + * The RR should be stored at *store_r, of length qu->typei->rrsz. + * + * If there is an overrun which might indicate truncation, it should set + * *rdstart to -1; otherwise it may set it to anything else positive. + */ + + void (*makefinal)(adns_query qu, void *data); + /* Change memory management of *data. + * Previously, used alloc_interim, now use alloc_final. + */ +} typeinfo; + +typedef struct allocnode { + struct allocnode *next; +} allocnode; + +union maxalign { + byte d[1]; + struct in_addr ia; + long l; + void *p; + void (*fp)(void); + union maxalign *up; +} data; + struct adns__query { - /* FIXME: make sure this is all init'd properly */ + adns_state ads; enum { query_udp, query_tcpwait, query_tcpsent, query_child, query_done } state; adns_query back, next, parent; struct { adns_query head, tail; } children; struct { adns_query back, next; } siblings; - adns_rrtype type; - vbuf ans; + struct allocnode *allocations; + int interim_allocd; + void *final_allocspace; + + const typeinfo *typei; + char *query_dgram; + int query_dglen; + + vbuf vb; + /* General-purpose messing-about buffer. + * Wherever a `big' interface is crossed, this may be corrupted/changed + * unless otherwise specified. + */ + + adns_answer *answer; + /* This is allocated when a query is submitted, to avoid being unable + * to relate errors to queries if we run out of memory. During + * query processing status, rrs is 0. cname is set if + * we found a cname (this corresponds to cname_dgram in the query + * structure). type is set from the word go. nrrs and rrs + * are set together, when we find how many rrs there are. + */ + + byte *cname_dgram; + int cname_dglen, cname_begin; + /* If non-0, has been allocated using . */ + int id, flags, udpretries; int udpnextserver; unsigned long udpsent, tcpfailed; /* bitmap indexed by server */ struct timeval timeout; - byte *querymsg; - int querylen; qcontext context; - char owner[1]; - /* After the owner name and nul comes the query message, pointed to by querymsg */ /* Possible states: * - * state Queue child id answer nextudpserver sentudp failedtcp - * - * udp NONE null >=0 null 0 zero zero - * udp timew null >=0 null any nonzero zero - * udp NONE null >=0 null any nonzero zero - * - * tcpwait timew null >=0 null irrelevant zero any - * tcpsent timew null >=0 null irrelevant zero any - * - * child childw set >=0 partial irrelevant irrelevant irrelevant - * done output null -1 set/null irrelevant irrelevant irrelevant + * state Queue child id nextudpserver sentudp failedtcp + * + * udp NONE null >=0 0 zero zero + * udp timew null >=0 any nonzero zero + * udp NONE null >=0 any nonzero zero + * + * tcpwait timew null >=0 irrelevant zero any + * tcpsent timew null >=0 irrelevant zero any + * + * child childw set >=0 irrelevant irrelevant irrelevant + * done output null -1 irrelevant irrelevant irrelevant * * +------------------------+ * START -----> | udp/NONE | @@ -125,7 +213,7 @@ struct adns__state { FILE *diagfile; struct { adns_query head, tail; } timew, childw, output; int nextid, udpsocket, tcpsocket; - vbuf rqbuf, tcpsend, tcprecv; + vbuf tcpsend, tcprecv; int nservers, tcpserver; enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate; struct timeval tcptimeout; @@ -136,41 +224,229 @@ struct adns__state { /* From setup.c: */ +int adns__setnonblock(adns_state ads, int fd); /* => errno value */ + +/* From general.c: */ + void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent, - int serv, const char *fmt, va_list al); -void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4); -void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4); -void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4); + int serv, adns_query qu, const char *fmt, va_list al); + +void adns__debug(adns_state ads, int serv, adns_query qu, + const char *fmt, ...) PRINTFFORMAT(4,5); +void adns__warn(adns_state ads, int serv, adns_query qu, + const char *fmt, ...) PRINTFFORMAT(4,5); +void adns__diag(adns_state ads, int serv, adns_query qu, + const char *fmt, ...) PRINTFFORMAT(4,5); int adns__vbuf_ensure(vbuf *vb, int want); +int adns__vbuf_appendstr(vbuf *vb, const char *data); int adns__vbuf_append(vbuf *vb, const byte *data, int len); /* 1=>success, 0=>realloc failed */ void adns__vbuf_appendq(vbuf *vb, const byte *data, int len); void adns__vbuf_init(vbuf *vb); +void adns__vbuf_free(vbuf *vb); + +const char *adns__diag_domain(adns_state ads, int serv, adns_query qu, vbuf *vb, + int flags, const byte *dgram, int dglen, int cbyte); +/* Unpicks a domain in a datagram and returns a string suitable for + * printing it as. Never fails - if an error occurs, it will + * return some kind of string describing the error. + * + * serv may be -1 and qu may be 0. vb must have been initialised, + * and will be left in an arbitrary consistent state. + * + * Returns either vb->buf, or a pointer to a string literal. Do not modify + * vb before using the return value. + */ + +/* From transmit.c: */ + +adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r, + const char *owner, int ol, + const typeinfo *typei, adns_queryflags flags); +/* Assembles a query packet in vb, and returns id at *id_r. */ + +void adns__query_tcp(adns_query qu, struct timeval now); +/* Query must be in state tcpwait/timew; it will be moved to a new state + * if possible and no further processing can be done on it for now. + * (Resulting state is one of tcpwait/timew (if server not connected), + * tcpsent/timew, child/childw or done/output.) + * + * adns__tcp_tryconnect should already have been called - _tcp + * will only use an existing connection (if there is one), which it + * may break. If the conn list lost then the caller is responsible for any + * reestablishment and retry. + */ + +void adns__query_udp(adns_query qu, struct timeval now); +/* Query must be in state udp/NONE; it will be moved to a new state, + * and no further processing can be done on it for now. + * (Resulting state is one of udp/timew, tcpwait/timew (if server not connected), + * tcpsent/timew, child/childw or done/output.) + */ -int adns__setnonblock(adns_state ads, int fd); /* => errno value */ +/* From query.c: */ -/* From submit.c: */ +int adns__internal_submit(adns_state ads, adns_query *query_r, + const typeinfo *typei, vbuf *qumsg_vb, int id, + adns_queryflags flags, struct timeval now, + adns_status failstat, const qcontext *ctx); +/* Submits a query (for internal use, called during external submits). + * + * The new query is returned in *query_r, or we return adns_s_nomemory. + * + * The query datagram should already have been assembled in qumsg_vb; + * the memory for it is _taken over_ by this routine whether it + * succeeds or fails (if it succeeds, the vbuf is reused for qu->vb). + * + * If failstat is nonzero then if we are successful in creating the query + * it is immediately failed with code failstat (but _submit still succeds). + * + * ctx is copied byte-for-byte into the query. + */ + +void *adns__alloc_interim(adns_query qu, size_t sz); +/* Allocates some memory, and records which query it came from + * and how much there was. + * + * If an error occurs in the query, all its memory is simply freed. + * + * If the query succeeds, one large buffer will be made which is + * big enough for all these allocations, and then adns__alloc_final + * will get memory from this buffer. + * + * _alloc_interim can fail, in which case it will fail the query too, + * so nothing more need be done with it. + */ + +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 + * will be freed when we're done with the query. + */ + +void *adns__alloc_final(adns_query qu, size_t sz); +/* Cannot fail. + */ + +void adns__makefinal_block(adns_query qu, void **blpp, size_t sz); +void adns__makefinal_str(adns_query qu, char **strp); + +void adns__reset_cnameonly(adns_query qu); +/* Resets all of the memory management stuff etc. to + * take account of only the CNAME. Used when we find an error somewhere + * and want to just report the error (with perhaps CNAME info), and also + * when we're halfway through RRs in a datagram and discover that we + * need to retry the query. + */ + +void adns__query_done(adns_query qu); +void adns__query_fail(adns_query qu, adns_status stat); + +/* From reply.c: */ -void adns__query_nomem(adns_state ads, adns_query qu); -void adns__query_fail(adns_state ads, adns_query qu, adns_status stat); +void adns__procdgram(adns_state ads, const byte *dgram, int len, + int serv, struct timeval now); -/* From query.c: */ +/* From types.c: */ -void adns__query_udp(adns_state ads, adns_query qu, struct timeval now); -void adns__query_tcp(adns_state ads, adns_query qu, struct timeval now); -adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, - adns_rrtype type, adns_queryflags flags); +const typeinfo *adns__findtype(adns_rrtype type); -/* From reply.c: */ +/* From parse.c: */ + +typedef struct { + adns_state ads; + adns_query qu; + int serv; + const byte *dgram; + int dglen, max, cbyte, namelen; + int *dmend_r; +} findlabel_state; + +void adns__findlabel_start(findlabel_state *fls, adns_state ads, + int serv, adns_query qu, + const byte *dgram, int dglen, int max, + int dmbegin, int *dmend_rlater); +/* Finds labels in a domain in a datagram. + * + * Call this routine first. + * dmend_rlater may be null. ads (and of course fls) may not be. + * serv may be -1, qu may be null - they are for error reporting. + */ + +adns_status adns__findlabel_next(findlabel_state *fls, int *lablen_r, int *labstart_r); +/* Then, call this one repeatedly. + * + * It will return adns_s_ok if all is well, and tell you the length + * and start of successive labels. labstart_r may be null, but + * lablen_r must not be. + * + * After the last label, it will return with *lablen_r zero. + * Do not then call it again; instead, just throw away the findlabel_state. + * + * *dmend_rlater will have been set to point to the next part of + * the datagram after the label (or after the uncompressed part, + * if compression was used). *namelen_rlater will have been set + * to the length of the domain name (total length of labels plus + * 1 for each intervening dot). + * + * If the datagram appears to be truncated, *lablen_r will be -1. + * *dmend_rlater, *labstart_r and *namelen_r may contain garbage. + * Do not call _next again. + * + * There may also be errors, in which case *dmend_rlater, + * *namelen_rlater, *lablen_r and *labstart_r may contain garbage. + * Do not then call findlabel_next again. + */ + +adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu, + vbuf *vb, int flags, + const byte *dgram, int dglen, int *cbyte_io, int max); +/* vb must already have been initialised; it will be reset if necessary. + * If there is truncation, vb->used will be set to 0; otherwise + * (if there is no error) vb will be null-terminated. + * If there is an error vb and *cbyte_io may be left indeterminate. + * + * serv may be -1 and qu may be 0 - they are used for error reporting only. + */ + +adns_status adns__findrr(adns_query qu, int serv, + const byte *dgram, int dglen, int *cbyte_io, + int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, + int *ownermatchedquery_r); + /* Finds the extent and some of the contents of an RR in a datagram + * and does some checks. The datagram is *dgram, length dglen, and + * the RR starts at *cbyte_io (which is updated afterwards to point + * to the end of the RR). + * + * The type, class and RRdata length and start are returned iff + * the corresponding pointer variables are not null. type_r and + * class_r may not be null. + * + * If ownermatchedquery_r != 0 then the owner domain of this + * RR will be compared with that in the query (or, if the query + * has gone to a CNAME lookup, with the canonical name). + * In this case, *ownermatchedquery_r will be set to 0 or 1. + * The query datagram (or CNAME datagram) MUST be valid and not truncated. + * + * If there is truncation then *type_r will be set to -1 and + * *cbyte_io, *class_r, *rdlen_r, *rdstart_r and *eo_matched_r will be + * undefined. + * + * qu must obviously be non-null. + * + * If an error is returned then *type_r will be undefined too. + */ -void adns__procdgram(adns_state ads, const byte *dgram, int len, int serv); +int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len); /* From event.c: */ void adns__tcp_broken(adns_state ads, const char *what, const char *why); void adns__tcp_tryconnect(adns_state ads, struct timeval now); + void adns__autosys(adns_state ads, struct timeval now); +/* Make all the system calls we want to if the application wants us to. */ /* Useful static inline functions: */ @@ -186,9 +462,16 @@ static inline void timevaladd(struct timeval *tv_io, long ms) { static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; } 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'); +} /* Useful macros */ +#define MEM_ROUND(sz) \ + (( ((sz)+sizeof(union maxalign)-1) / sizeof(union maxalign) ) \ + * sizeof(union maxalign) ) + #define LIST_INIT(list) ((list).head= (list).tail= 0) #define LIST_UNLINK_PART(list,node,part) \ @@ -210,4 +493,8 @@ static inline int ctype_digit(int c) { return c>='0' && c<='9'; } #define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,) #define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,) +#define GETIL_B(cb) (dgram[(cb)++]) +#define GET_B(cb,tv) ((tv)= GETIL_B((cb))) +#define GET_W(cb,tv) ((tv)=0, (tv)|=(GETIL_B((cb))<<8), (tv)|=GETIL_B(cb), (tv)) + #endif