From: Ian Jackson Date: Sat, 28 Jun 2014 16:32:34 +0000 (+0100) Subject: resolver: construct comm_addr; honour multiple addresses from the resolver X-Git-Tag: base.polypath.v1~26 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=commitdiff_plain;h=ee226369193a35e6883d1031261205d2db4693b9 resolver: construct comm_addr; honour multiple addresses from the resolver We move construction of the comm_addr into the resolver. The comm_if and port are supplied to it by site and filled in by the resolver. This allows the resolver to return a complete comm_addr array. While we're here, we make an adns_r_addr query instead of an adns_r_a query. Signed-off-by: Ian Jackson --- diff --git a/resolver.c b/resolver.c index 15b8e76..5360966 100644 --- a/resolver.c +++ b/resolver.c @@ -2,6 +2,7 @@ #include #include "secnet.h" +#include "util.h" #ifndef HAVE_LIBADNS #error secnet requires ADNS version 1.0 or above #endif @@ -19,12 +20,15 @@ struct adns { struct query { void *cst; + int port; + struct comm_if *comm; resolve_answer_fn *answer; adns_query query; }; 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; @@ -37,19 +41,25 @@ static bool_t resolve_request(void *sst, cstring_t name, char trimmed[maxlitlen+1]; memcpy(trimmed,name+1,l-2); trimmed[l-2]=0; - struct in_addr ia; - if (inet_aton(trimmed,&ia)) - cb(cst,&ia); + struct comm_addr ca; + FILLZERO(ca); + ca.comm=comm; + ca.sin.sin_family=AF_INET; + ca.sin.sin_port=htons(port); + if (inet_aton(trimmed,&ca.sin.sin_addr)) + cb(cst,&ca,1); else - cb(cst,0); + cb(cst,0,0); return True; } q=safe_malloc(sizeof *q,"resolve_request"); q->cst=cst; + q->comm=comm; + q->port=port; 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, @@ -85,11 +95,34 @@ 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); /* Failure */ free(q); free(ans); } else { - q->answer(q->cst,ans->rrs.inaddr); + int rslot, wslot; + int ca_len=MIN(ans->nrrs,MAX_PEER_ADDRS); + struct comm_addr ca_buf[ca_len]; + FILLZERO(ca_buf); + for (rslot=0, wslot=0; + rslotnrrs && wslotrrs.addr[rslot]; + struct comm_addr *ca=&ca_buf[wslot]; + ca->comm=q->comm; + /* copy fields individually so we leave holes zeroed: */ + switch (ra->addr.sa.sa_family) { + case AF_INET: + assert(ra->len == sizeof(ca->sin)); + ca->sin.sin_family=ra->addr.inet.sin_family; + ca->sin.sin_addr= ra->addr.inet.sin_addr; + ca->sin.sin_port= htons(q->port); + wslot++; + break; + default: + break; + } + } + q->answer(q->cst,ca_buf,wslot); free(q); free(ans); } diff --git a/secnet.h b/secnet.h index b01c485..2efd11d 100644 --- a/secnet.h +++ b/secnet.h @@ -15,6 +15,13 @@ #include #include #include +#include + +#define MAX_PEER_ADDRS 5 +/* send at most this many copies; honour at most that many addresses */ + +struct comm_if; +struct comm_addr; typedef char *string_t; typedef const char *cstring_t; @@ -277,9 +284,10 @@ struct buffer_if; type. 'address' will be NULL if there was a problem with the query. It will be freed once resolve_answer_fn returns. It is in network byte order. */ -/* XXX extend to be able to provide multiple answers */ -typedef void resolve_answer_fn(void *st, struct in_addr *addr); +typedef void resolve_answer_fn(void *st, const struct comm_addr *addrs, + int naddrs); typedef bool_t resolve_request_fn(void *st, cstring_t name, + int remoteport, struct comm_if *comm, resolve_answer_fn *cb, void *cst); struct resolver_if { void *st; diff --git a/site.c b/site.c index 9a43825..73a0c4d 100644 --- a/site.c +++ b/site.c @@ -220,7 +220,7 @@ static struct flagstr log_event_table[]={ */ -#define MAX_MOBILE_PEERS_MAX 5 /* send at most this many copies, compiled max */ +#define MAX_MOBILE_PEERS_MAX MAX_PEER_ADDRS /* send at most this many copies */ typedef struct { struct timeval last; @@ -1196,29 +1196,18 @@ static bool_t send_msg(struct site *st) } } -static void site_resolve_callback(void *sst, struct in_addr *address) +static void site_resolve_callback(void *sst, const struct comm_addr *addrs, + int naddrs) { struct site *st=sst; - struct comm_addr ca_buf; - const struct comm_addr *addrs; - int naddrs; st->resolving=False; - if (address) { - FILLZERO(ca_buf); - ca_buf.comm=st->comms[0]; - ca_buf.sin.sin_family=AF_INET; - ca_buf.sin.sin_port=htons(st->remoteport); - ca_buf.sin.sin_addr=*address; - addrs=&ca_buf; - naddrs=1; - slog(st,LOG_STATE,"resolution of %s completed: %s", - st->address, comm_addr_to_string(&addrs[0]));; + if (naddrs) { + slog(st,LOG_STATE,"resolution of %s completed, %d addrs, eg: %s", + st->address, naddrs, comm_addr_to_string(&addrs[0]));; } else { slog(st,LOG_ERROR,"resolution of %s failed",st->address); - addrs=0; - naddrs=0; } switch (st->state) { @@ -1405,6 +1394,7 @@ static bool_t ensure_resolving(struct site *st) * case we have to clear ->resolving again. */ st->resolving=True; bool_t ok = st->resolver->request(st->resolver->st,st->address, + st->remoteport,st->comms[0], site_resolve_callback,st); if (!ok) st->resolving=False;