X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;ds=sidebyside;f=site.c;h=b14b8e8f60ee1987f07aa1822db693fd9d65af68;hb=a96fda35655e11388dda789f83d4c04c751eb946;hp=f9c2f087823d191f2b056032ff4c5a28b3c90eef;hpb=5c19b79c7c817a28a1582970b2685c98e05b2de5;p=secnet.git diff --git a/site.c b/site.c index f9c2f08..b14b8e8 100644 --- a/site.c +++ b/site.c @@ -207,7 +207,11 @@ static void transport_setup_msgok(struct site *st, const struct comm_addr *a); static void transport_data_msgok(struct site *st, const struct comm_addr *a); static bool_t transport_compute_setupinit_peers(struct site *st, const struct comm_addr *configured_addr /* 0 if none or not found */, - const struct comm_addr *prod_hint_addr /* 0 if none */); + const struct comm_addr *incoming_packet_addr /* 0 if none */); +static void transport_resolve_complete(struct site *st, + const struct comm_addr *a); +static void transport_resolve_complete_tardy(struct site *st, + const struct comm_addr *ca_use); static void transport_record_peer(struct site *st, transport_peers *peers, const struct comm_addr *addr, const char *m); @@ -229,7 +233,7 @@ struct site { /* configuration information */ string_t localname; string_t remotename; - bool_t peer_mobile; /* Mobile client support */ + bool_t local_mobile, 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 */ @@ -699,7 +703,6 @@ static bool_t process_msg1(struct site *st, struct buffer_if *msg1, process an incoming MSG1, and that the MSG1 has correct values of A and B. */ - transport_record_peer(st,&st->setup_peers,src,"msg1"); st->setup_session_id=m->source; st->remote_capabilities=m->remote_capabilities; memcpy(st->remoteN,m->nR,NONCELEN); @@ -1150,10 +1153,6 @@ static void site_resolve_callback(void *sst, struct in_addr *address) st->resolving=False; - if (st->state!=SITE_RESOLVE) { - slog(st,LOG_UNEXPECTED,"site_resolve_callback called unexpectedly"); - return; - } if (address) { FILLZERO(ca_buf); ca_buf.comm=st->comms[0]; @@ -1161,16 +1160,65 @@ static void site_resolve_callback(void *sst, struct in_addr *address) ca_buf.sin.sin_port=htons(st->remoteport); ca_buf.sin.sin_addr=*address; ca_use=&ca_buf; + slog(st,LOG_STATE,"resolution of %s completed: %s", + st->address, comm_addr_to_string(ca_use));; } else { slog(st,LOG_ERROR,"resolution of %s failed",st->address); ca_use=0; } - if (transport_compute_setupinit_peers(st,ca_use,0)) { - enter_new_state(st,SITE_SENTMSG1); - } else { - /* Can't figure out who to try to to talk to */ - slog(st,LOG_SETUP_INIT,"key exchange failed: cannot find peer address"); - enter_state_run(st); + + switch (st->state) { + case SITE_RESOLVE: + if (transport_compute_setupinit_peers(st,ca_use,0)) { + enter_new_state(st,SITE_SENTMSG1); + } else { + /* Can't figure out who to try to to talk to */ + slog(st,LOG_SETUP_INIT, + "key exchange failed: cannot find peer address"); + enter_state_run(st); + } + break; + case SITE_SENTMSG1: case SITE_SENTMSG2: + case SITE_SENTMSG3: case SITE_SENTMSG4: + case SITE_SENTMSG5: + if (ca_use) { + /* We start using the address immediately for data too. + * It's best to store it in st->peers now because we might + * go via SENTMSG5, WAIT, and a MSG0, straight into using + * the new key (without updating the data peer addrs). */ + transport_resolve_complete(st,ca_use); + } else if (st->local_mobile) { + /* We can't let this rest because we may have a peer + * address which will break in the future. */ + slog(st,LOG_SETUP_INIT,"resolution of %s failed: " + "abandoning key exchange",st->address); + enter_state_wait(st); + } else { + slog(st,LOG_SETUP_INIT,"resolution of %s failed: " + " continuing to use source address of peer's packets" + " for key exchange and ultimately data", + st->address); + } + break; + case SITE_RUN: + if (ca_use) { + slog(st,LOG_SETUP_INIT,"resolution of %s completed tardily," + " updating peer address(es)",st->address); + transport_resolve_complete_tardy(st,ca_use); + } else if (st->local_mobile) { + /* Not very good. We should queue (another) renegotiation + * so that we can update the peer address. */ + st->key_renegotiate_time=st->now+st->wait_timeout; + } else { + slog(st,LOG_SETUP_INIT,"resolution of %s failed: " + " continuing to use source address of peer's packets", + st->address); + } + break; + case SITE_WAIT: + case SITE_STOP: + /* oh well */ + break; } } @@ -1295,6 +1343,8 @@ static bool_t ensure_resolving(struct site *st) if (st->resolving) return True; + assert(st->address); + /* resolver->request might reentrantly call site_resolve_callback * which will clear st->resolving, so we need to set it beforehand * rather than afterwards; also, it might return False, in which @@ -1580,9 +1630,14 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, if (st->state==SITE_RUN || st->state==SITE_RESOLVE || st->state==SITE_WAIT) { /* We should definitely process it */ + transport_record_peer(st,&st->setup_peers,source,"msg1"); if (process_msg1(st,buf,source,&named_msg)) { slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); - enter_new_state(st,SITE_SENTMSG2); + bool_t entered=enter_new_state(st,SITE_SENTMSG2); + if (entered && st->address && st->local_mobile) + /* We must do this as the very last thing, because + the resolver callback might reenter us. */ + ensure_resolving(st); } else { slog(st,LOG_ERROR,"failed to process incoming msg1"); } @@ -1602,6 +1657,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, "priority => use incoming msg1"); if (process_msg1(st,buf,source,&named_msg)) { BUF_FREE(&st->buffer); /* Free our old message 1 */ + transport_setup_msgok(st,source); enter_new_state(st,SITE_SENTMSG2); } else { slog(st,LOG_ERROR,"failed to process an incoming " @@ -1785,7 +1841,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->remotename=dict_read_string(dict, "name", True, "site", loc); st->peer_mobile=dict_read_bool(dict,"mobile",False,"site",loc,False); - bool_t local_mobile= + st->local_mobile= dict_read_bool(dict,"local-mobile",False,"site",loc,False); /* Sanity check (which also allows the 'sites' file to include @@ -1794,14 +1850,14 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, if (strcmp(st->localname,st->remotename)==0) { Message(M_DEBUG,"site %s: local-name==name -> ignoring this site\n", st->localname); - if (st->peer_mobile != local_mobile) + if (st->peer_mobile != st->local_mobile) cfgfatal(loc,"site","site %s's peer-mobile=%d" " but our local-mobile=%d\n", - st->localname, st->peer_mobile, local_mobile); + st->localname, st->peer_mobile, st->local_mobile); free(st); return NULL; } - if (st->peer_mobile && local_mobile) { + if (st->peer_mobile && st->local_mobile) { Message(M_WARNING,"site %s: site is mobile but so are we" " -> ignoring this site\n", st->remotename); free(st); @@ -1849,7 +1905,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->dh=find_cl_if(dict,"dh",CL_DH,True,"site",loc); st->hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc); -#define DEFAULT(D) (st->peer_mobile || local_mobile \ +#define DEFAULT(D) (st->peer_mobile || st->local_mobile \ ? DEFAULT_MOBILE_##D : DEFAULT_##D) #define CFG_NUMBER(k,D) dict_read_number(dict,(k),False,"site",loc,DEFAULT(D)); @@ -2038,19 +2094,19 @@ static void transport_record_peer(struct site *st, transport_peers *peers, static bool_t transport_compute_setupinit_peers(struct site *st, const struct comm_addr *configured_addr /* 0 if none or not found */, - const struct comm_addr *prod_hint_addr /* 0 if none */) { + const struct comm_addr *incoming_packet_addr /* 0 if none */) { - if (!configured_addr && !prod_hint_addr && + if (!configured_addr && !incoming_packet_addr && !transport_peers_valid(&st->peers)) return False; slog(st,LOG_SETUP_INIT, "using:%s%s %d old peer address(es)", configured_addr ? " configured address;" : "", - prod_hint_addr ? " PROD hint address;" : "", + incoming_packet_addr ? " incoming packet address;" : "", st->peers.npeers); - /* Non-mobile peers havve st->peers.npeers==0 or ==1, since they + /* Non-mobile peers have st->peers.npeers==0 or ==1, since they * have transport_peers_max==1. The effect is that this code * always uses the configured address if supplied, or otherwise * the address of the incoming PROD, or the existing data peer if @@ -2058,8 +2114,9 @@ static bool_t transport_compute_setupinit_peers(struct site *st, transport_peers_copy(st,&st->setup_peers,&st->peers); - if (prod_hint_addr) - transport_record_peer(st,&st->setup_peers,prod_hint_addr,"prod"); + if (incoming_packet_addr) + transport_record_peer(st,&st->setup_peers,incoming_packet_addr, + "incoming"); if (configured_addr) transport_record_peer(st,&st->setup_peers,configured_addr,"setupinit"); @@ -2092,6 +2149,17 @@ static void transport_peers_copy(struct site *st, transport_peers *dst, src->npeers, &src->peers->addr, sizeof(*src->peers)); } +static void transport_resolve_complete(struct site *st, + const struct comm_addr *ca_use) { + transport_record_peer(st,&st->peers,ca_use,"resolved data"); + transport_record_peer(st,&st->setup_peers,ca_use,"resolved setup"); +} + +static void transport_resolve_complete_tardy(struct site *st, + const struct comm_addr *ca_use) { + transport_record_peer(st,&st->peers,ca_use,"resolved tardily"); +} + void transport_xmit(struct site *st, transport_peers *peers, struct buffer_if *buf, bool_t candebug) { int slot;