From 51ed1f1e9fbba07ada8fcda115ba4530b692c3e1 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Thu, 21 Jul 2011 17:21:40 +0100 Subject: [PATCH] comm,site: Make peer address configuration the responsibility of comm (udp) We want to be able to introduce new kinds of comm. These may need to be configured differently to the current udp comm, which expects to be given a sockaddr_in. So move the knowledge of how to configure a peer address (ie, which keys to look up in the site dictionary) to udp. udp gets passed site's dictionary during configuration setup, and extracts the relevant information. site can then later ask udp to (try to) find the peer address. As a side-effect, the resolver key now belongs to comm (ie, udp), not to the site. This is a backwards-incompatible change because it means that (in the usual kind of situation) the resolver must be defined before the udp comm in the config file. I don't know what proportion of existing config files need adjusting but certainly test-example did. We could avoid the backward-compatibility problem by having udp look up the "resolver" key in the supplied site dictionary, and stash the result away, but this would result in a more-convoluted configuration setup. Signed-off-by: Ian Jackson --- README | 14 +++++--- secnet.h | 21 ++++++++---- site.c | 37 ++++++-------------- test-example/common.conf | 2 -- test-example/inside.conf | 1 + test-example/outside.conf | 1 + test-example/top.conf | 2 ++ udp.c | 72 +++++++++++++++++++++++++++++++++++---- 8 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 test-example/top.conf diff --git a/README b/README index 1901223..12a8469 100644 --- a/README +++ b/README @@ -201,9 +201,18 @@ Defines: udp: dict argument address (string): IP address to listen and send on port (integer): UDP port to listen and send on + resolver (resolver closure) buffer (buffer closure): buffer for incoming packets authbind (string): optional, path to authbind-helper program + udp looks up the following keys in its calling closure (usually, this + is a site closure) when a peer needs to be found: + + address (string): optional, DNS name used to find our peer + port (integer): mandatory if 'address' is specified: the port used + to contact our peer + + ** log Defines: @@ -274,12 +283,8 @@ site: dict argument first one will be used for any key setups initiated by us using the configured address. Others are only used if our peer talks to them. - resolver (resolver closure) random (randomsrc closure) local-key (rsaprivkey closure) - address (string): optional, DNS name used to find our peer - port (integer): mandatory if 'address' is specified: the port used - to contact our peer key (rsapubkey closure): our peer's public key transform (transform closure): how to mangle packets sent between sites dh (dh closure) @@ -334,6 +339,7 @@ site: dict argument check that there are no links both ends of which are allegedly mobile (which is not supported, so those links are ignored) and to change some of the tuning parameter defaults. [false] + Plus further keys depending on the first comm. Links involving mobile peers have some different tuning parameter default values, which are generally more aggressive about retrying key diff --git a/secnet.h b/secnet.h index d330f64..9d0b09e 100644 --- a/secnet.h +++ b/secnet.h @@ -325,12 +325,18 @@ typedef void comm_release_notify_fn(void *commst, void *nst, comm_notify_fn *fn); typedef bool_t comm_sendmsg_fn(void *commst, struct buffer_if *buf, const struct comm_addr *dest); -typedef bool_t comm_addr_construct_fn(void *commst, struct comm_addr *ca, - const struct sockaddr_in *sin); - /* Fills in ca->comm an ca->priv. *sin must have no nonzero padding, - so must have been FILLZERO'd before its useful fields were filled in. - The resulting ca->comm has been constructed likewise, as required - above. On failure, logs error, returns false on failure.*/ +typedef void *comm_peer_addr_config_fn(void *commst, dict_t*, struct cloc, + cstring_t desc); + /* Checks the config for the peer as specified in dict, + * and either returns NULL to mean the relevant parameters + * weren't specified, or a non-NULL void* which can be + * passed to comm_peer_addr_fn */ +typedef void comm_peer_addr_answer_fn(void *st, const struct comm_addr *ca); +typedef bool_t comm_peer_addr_request_fn(void *commst, void *from_peer_config, + comm_peer_addr_answer_fn *cb, void *cst); + /* Calls comm_peer_addr_answer_fn, either immediately or later, + * with a suitable comm_addr. The caller's cb should + * memcpy ca. On failure, logs error and calls cb with ca=NULL */ typedef const char *comm_addr_to_string_fn(void *commst, const struct comm_addr *ca); /* Returned string is in a static buffer. */ @@ -341,7 +347,8 @@ struct comm_if { comm_request_notify_fn *request_notify; comm_release_notify_fn *release_notify; comm_sendmsg_fn *sendmsg; - comm_addr_construct_fn *addr_construct; + comm_peer_addr_config_fn *peer_addr_config; + comm_peer_addr_request_fn *peer_addr_request; comm_addr_to_string_fn *addr_to_string; }; diff --git a/site.c b/site.c index 40819a4..8892400 100644 --- a/site.c +++ b/site.c @@ -223,12 +223,10 @@ struct site { bool_t peer_mobile; /* Mobile client support */ int32_t transport_peers_max; string_t tunname; /* localname<->remotename by default, used in logs */ - string_t address; /* DNS name for bootstrapping, optional */ - int remoteport; /* Port for bootstrapping, optional */ + void *remote_addr_config; /* created and used by comm */ struct netlink_if *netlink; struct comm_if **comms; int ncomms; - struct resolver_if *resolver; struct log_if *log; struct random_if *random; struct rsaprivkey_if *privkey; @@ -793,28 +791,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 *address) { struct site *st=sst; - struct comm_addr ca_buf, *ca_use=0; if (st->state!=SITE_RESOLVE) { slog(st,LOG_UNEXPECTED,"site_resolve_callback called unexpectedly"); return; } - if (address) { - struct sockaddr_in sin; - FILLZERO(sin); - sin.sin_family=AF_INET; - sin.sin_port=htons(st->remoteport); - sin.sin_addr=*address; - if (st->comms[0]->addr_construct(st->comms[0]->st, &ca_buf, &sin)) { - ca_use=&ca_buf; - } - } else { - slog(st,LOG_ERROR,"resolution of %s failed",st->address); + if (!address) { + slog(st,LOG_ERROR,"resolution of peer address failed"); } - if (transport_compute_setupinit_peers(st,ca_use)) { + if (transport_compute_setupinit_peers(st,address)) { enter_new_state(st,SITE_SENTMSG1); } else { /* Can't figure out who to try to to talk to */ @@ -827,7 +815,7 @@ static bool_t initiate_key_setup(struct site *st, cstring_t reason) { if (st->state!=SITE_RUN) return False; slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason); - if (st->address) { + if (st->remote_addr_config) { slog(st,LOG_SETUP_INIT,"resolving peer address"); return enter_state_resolve(st); } else if (transport_compute_setupinit_peers(st,0)) { @@ -891,7 +879,7 @@ static void set_link_quality(struct site *st) quality=LINK_QUALITY_UP; else if (st->state==SITE_WAIT || st->state==SITE_STOP) quality=LINK_QUALITY_DOWN; - else if (st->address) + else if (st->remote_addr_config) quality=LINK_QUALITY_DOWN_CURRENT_ADDRESS; else if (transport_peers_valid(&st->peers)) quality=LINK_QUALITY_DOWN_STALE_ADDRESS; @@ -922,8 +910,8 @@ static bool_t enter_state_resolve(struct site *st) state_assert(st,st->state==SITE_RUN); slog(st,LOG_STATE,"entering state RESOLVE"); st->state=SITE_RESOLVE; - st->resolver->request(st->resolver->st,st->address, - site_resolve_callback,st); + st->comms[0]->peer_addr_request(st->comms[0]->st,st->remote_addr_config, + site_resolve_callback,st); return True; } @@ -1352,15 +1340,12 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->comms[i]=cl->interface; } - st->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc); st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc); st->random=find_cl_if(dict,"random",CL_RANDOMSRC,True,"site",loc); + st->remote_addr_config=st->comms[0]->peer_addr_config( + st->comms[0]->st,dict,loc,"site"); st->privkey=find_cl_if(dict,"local-key",CL_RSAPRIVKEY,True,"site",loc); - st->address=dict_read_string(dict, "address", False, "site", loc); - if (st->address) - st->remoteport=dict_read_number(dict,"port",True,"site",loc,0); - else st->remoteport=0; st->pubkey=find_cl_if(dict,"key",CL_RSAPUBKEY,True,"site",loc); st->transform= diff --git a/test-example/common.conf b/test-example/common.conf index 64bfc81..47b3430 100644 --- a/test-example/common.conf +++ b/test-example/common.conf @@ -4,8 +4,6 @@ log logfile { }; system { }; -resolver adns { -}; log-events "all"; random randomfile("/dev/urandom",no); transform serpent256-cbc { diff --git a/test-example/inside.conf b/test-example/inside.conf index a64f125..4d5913d 100644 --- a/test-example/inside.conf +++ b/test-example/inside.conf @@ -1,3 +1,4 @@ +include test-example/top.conf netlink tun { name "netlink-tun"; # Printed in log messages from this netlink local-address "172.18.232.9"; diff --git a/test-example/outside.conf b/test-example/outside.conf index db78b7b..df4aba9 100644 --- a/test-example/outside.conf +++ b/test-example/outside.conf @@ -1,3 +1,4 @@ +include test-example/top.conf netlink tun { name "netlink-tun"; # Printed in log messages from this netlink local-address "172.18.232.1"; diff --git a/test-example/top.conf b/test-example/top.conf new file mode 100644 index 0000000..a9ccc81 --- /dev/null +++ b/test-example/top.conf @@ -0,0 +1,2 @@ +resolver adns { +}; diff --git a/udp.c b/udp.c index a1d3b74..1431135 100644 --- a/udp.c +++ b/udp.c @@ -34,6 +34,11 @@ struct notify_list { struct notify_list *next; }; +struct peer_config { + string_t address; /* DNS name for bootstrapping, optional */ + int remoteport; /* Port for bootstrapping, optional */ +}; + struct udp { closure_t cl; struct comm_if ops; @@ -44,6 +49,7 @@ struct udp { string_t authbind; struct buffer_if *rbuf; struct notify_list *notify; + struct resolver_if *resolver; bool_t use_proxy; struct sockaddr_in proxy; }; @@ -72,13 +78,63 @@ static const char *addr_to_string(void *commst, const struct comm_addr *ca) { return sbuf; } -static bool_t addr_construct(void *commst, struct comm_addr *ca, - const struct sockaddr_in *sin) { +struct peer_addr_cst { + struct udp *udp; + struct peer_config *cfg; + comm_peer_addr_answer_fn *cb; + void *cst; +}; + +static void *peer_addr_config(void *commst, dict_t *dict, struct cloc loc, + cstring_t desc) +{ + struct peer_config *cfg; + cfg=safe_malloc(sizeof(*cfg),"peer addr config"); + cfg->address=dict_read_string(dict, "address",False,desc,loc); + if (cfg->address) + cfg->remoteport=dict_read_number(dict,"port",True,desc,loc,0); + else cfg->remoteport=0; + if (cfg->address) + return cfg; + free(cfg); + return NULL; +} + +static void peer_resolve_callback(void *sst, struct in_addr *address) +{ + struct peer_addr_cst *pacst=sst; + struct udp *st=pacst->udp; + struct peer_config *cfg=pacst->cfg; + struct comm_addr ca; + if (address) { + FILLZERO(ca); + ca.comm=&st->ops; + ca.priv.sin.sin_family=AF_INET; + ca.priv.sin.sin_port=htons(cfg->remoteport); + ca.priv.sin.sin_addr=*address; + pacst->cb(pacst->cst,&ca); + } else { + pacst->cb(pacst->cst,0); + } + free(pacst); +} + +static bool_t peer_addr_request(void *commst, void *from_peer_config, + comm_peer_addr_answer_fn *cb, void *cst) +{ struct udp *st=commst; - FILLZERO(*ca); - ca->comm=&st->ops; - ca->priv.sin=*sin; - return True; + struct peer_config *cfg=from_peer_config; + struct peer_addr_cst *pacst; + pacst=safe_malloc(sizeof(*pacst),"udp peer addr request cst"); + pacst->udp=st; + pacst->cfg=cfg; + pacst->cb=cb; + pacst->cst=cst; + bool_t ok=st->resolver->request(st->resolver->st,cfg->address, + peer_resolve_callback,pacst); + if (!ok) + free(pacst); + return ok; } static int udp_beforepoll(void *state, struct pollfd *fds, int *nfds_io, @@ -302,7 +358,8 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, st->ops.request_notify=request_notify; st->ops.release_notify=release_notify; st->ops.sendmsg=udp_sendmsg; - st->ops.addr_construct=addr_construct; + st->ops.peer_addr_config=peer_addr_config; + st->ops.peer_addr_request=peer_addr_request; st->ops.addr_to_string=addr_to_string; st->port=0; st->use_proxy=False; @@ -336,6 +393,7 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context, st->proxy.sin_port=htons(i->data.number); st->ops.min_start_pad=8; } + st->resolver=find_cl_if(d,"resolver",CL_RESOLVER,True,"comm",loc); add_hook(PHASE_GETRESOURCES,udp_phase_hook,st); -- 2.30.2