X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=secnet.git;a=blobdiff_plain;f=resolver.c;h=06aa7c3db6da43616a2a47a5ef6c4bc2e535798b;hp=8ffdc28f96b1fb8daeabb351ff056f4174ba67d3;hb=ce53e0ea9aad729511e8b315dcbed7122272c2a1;hpb=4f5e39ecfaa49376b0a5c3a4c384e91a828c1105 diff --git a/resolver.c b/resolver.c index 8ffdc28..06aa7c3 100644 --- a/resolver.c +++ b/resolver.c @@ -1,11 +1,32 @@ +/* + * This file is part of secnet. + * See README for full list of copyright holders. + * + * secnet 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 d of the License, or + * (at your option) any later version. + * + * secnet 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 + * version 3 along with secnet; if not, see + * https://www.gnu.org/licenses/gpl.html. + */ /* Name resolution using adns */ #include #include "secnet.h" +#include "util.h" #ifndef HAVE_LIBADNS #error secnet requires ADNS version 1.0 or above #endif #include +#include +#include struct adns { @@ -17,36 +38,88 @@ struct adns { struct query { void *cst; + const char *name; + int port; + struct comm_if *comm; resolve_answer_fn *answer; adns_query query; }; -static bool_t resolve_request(void *sst, string_t name, +static resolve_request_fn resolve_request; +static bool_t resolve_request(void *sst, cstring_t name, + int port, struct comm_if *comm, resolve_answer_fn *cb, void *cst) { struct adns *st=sst; struct query *q; int rv; + const int maxlitlen= +#ifdef CONFIG_IPV6 + ADNS_ADDR2TEXT_BUFLEN*2 +#else + 50 +#endif + ; + ssize_t l=strlen(name); + if (name[0]=='[' && l2 && name[l-1]==']') { + char trimmed[maxlitlen+1]; + memcpy(trimmed,name+1,l-2); + trimmed[l-2]=0; + struct comm_addr ca; + ca.comm=comm; + ca.ix=-1; +#ifdef CONFIG_IPV6 + socklen_t salen=sizeof(ca.ia); + rv=adns_text2addr(trimmed, port, adns_qf_addrlit_ipv4_quadonly, + &ca.ia.sa, &salen); + assert(rv!=ENOSPC); + if (rv) { + char msg[250]; + snprintf(msg,sizeof(msg),"invalid address literal: %s", + strerror(rv)); + msg[sizeof(msg)-1]=0; + cb(cst,0,0,0,name,msg); + } else { + cb(cst,&ca,1,1,name,0); + } +#else + ca.ia.sin.sin_family=AF_INET; + ca.ia.sin.sin_port=htons(port); + if (inet_aton(trimmed,&ca.ia.sin.sin_addr)) + cb(cst,&ca,1,1,name,0); + else + cb(cst,0,0,0,name,"invalid IP address"); +#endif + return True; + } - q=safe_malloc(sizeof *q,"resolve_request"); + NEW(q); q->cst=cst; + q->comm=comm; + q->port=port; + q->name=name; q->answer=cb; - rv=adns_submit(st->ast, name, adns_r_a, 0, q, &q->query); + rv=adns_submit(st->ast, name, adns_r_addr, 0, q, &q->query); + if (rv) { + Message(M_WARNING, + "resolver: failed to submit lookup for %s: %s",name, + adns_strerror(rv)); + free(q); + return False; + } - return rv==0; + return True; } static int resolver_beforepoll(void *sst, struct pollfd *fds, int *nfds_io, - int *timeout_io, const struct timeval *tv_now, - uint64_t *now) + int *timeout_io) { struct adns *st=sst; return adns_beforepoll(st->ast, fds, nfds_io, timeout_io, tv_now); } -static void resolver_afterpoll(void *sst, struct pollfd *fds, int nfds, - const struct timeval *tv_now, uint64_t *now) +static void resolver_afterpoll(void *sst, struct pollfd *fds, int nfds) { struct adns *st=sst; adns_query aq; @@ -63,11 +136,42 @@ static void resolver_afterpoll(void *sst, struct pollfd *fds, int nfds, if (rv==0) { q=qp; if (ans->status!=adns_s_ok) { - q->answer(q->cst,NULL); /* Failure */ + q->answer(q->cst,NULL,0,0,q->name,adns_strerror(ans->status)); free(q); free(ans); } else { - q->answer(q->cst,ans->rrs.inaddr); + int rslot, wslot, total; + int ca_len=MIN(ans->nrrs,MAX_PEER_ADDRS); + struct comm_addr ca_buf[ca_len]; + for (rslot=0, wslot=0, total=0; + rslotnrrs; + rslot++) { + total++; + if (!(wslotrrs.addr[rslot]; + struct comm_addr *ca=&ca_buf[wslot]; + ca->comm=q->comm; + ca->ix=-1; + assert(ra->len <= (int)sizeof(ca->ia)); + memcpy(&ca->ia,&ra->addr,ra->len); + switch (ra->addr.sa.sa_family) { + case AF_INET: + assert(ra->len == sizeof(ca->ia.sin)); + ca->ia.sin.sin_port=htons(q->port); + break; +#ifdef CONFIG_IPV6 + case AF_INET6: + assert(ra->len == sizeof(ca->ia.sin6)); + ca->ia.sin6.sin6_port=htons(q->port); + break; +#endif /*CONFIG_IPV6*/ + default: + /* silently skip unexpected AFs from adns */ + continue; + } + wslot++; + } + q->answer(q->cst,ca_buf,wslot,total,q->name,0); free(q); free(ans); } @@ -90,7 +194,7 @@ static list_t *adnsresolver_apply(closure_t *self, struct cloc loc, item_t *i; string_t conf; - st=safe_malloc(sizeof(*st),"adnsresolver_apply"); + NEW(st); st->cl.description="adns"; st->cl.type=CL_RESOLVER; st->cl.apply=NULL; @@ -117,12 +221,11 @@ static list_t *adnsresolver_apply(closure_t *self, struct cloc loc, } register_for_poll(st, resolver_beforepoll, resolver_afterpoll, - ADNS_POLLFDS_RECOMMENDED+5,"resolver"); + "resolver"); return new_closure(&st->cl); } -init_module resolver_module; void resolver_module(dict_t *dict) { add_closure(dict,"adns",adnsresolver_apply);