X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/cbc2519681f5fceab5c6153110215090663eb3e9..refs/heads/master:/site.c diff --git a/site.c b/site.c index 5146501..d0dd909 100644 --- a/site.c +++ b/site.c @@ -321,7 +321,7 @@ struct site { uint32_t local_capabilities; int32_t setup_retries; /* How many times to send setup packets */ int32_t setup_retry_interval; /* Initial timeout for setup packets */ - int32_t wait_timeout; /* How long to wait if setup unsuccessful */ + int32_t wait_timeout_mean; /* How long to wait if setup unsuccessful */ int32_t mobile_peer_expiry; /* How long to remember 2ary addresses */ int32_t key_lifetime; /* How long a key lasts once set up */ int32_t key_renegotiate_time; /* If we see traffic (or a keepalive) @@ -535,6 +535,16 @@ struct msg { char *sig; }; +static int32_t wait_timeout(struct site *st) { + int32_t t = st->wait_timeout_mean; + int8_t factor; + if (t < INT_MAX/2) { + st->random->generate(st->random->st,sizeof(factor),&factor); + t += (t / 256) * factor; + } + return t; +} + static _Bool set_new_transform(struct site *st, char *pk) { _Bool ok; @@ -757,7 +767,7 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, return False; } if (type==LABEL_MSG2) return True; - if (!consttime_memeq(m->nR,st->remoteN,NONCELEN)!=0) { + if (!consttime_memeq(m->nR,st->remoteN,NONCELEN)) { *error="wrong remotely-generated nonce"; return False; } @@ -1353,7 +1363,7 @@ static void decrement_resolving_count(struct site *st, int by) } 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; + st->key_renegotiate_time=st->now+wait_timeout(st); } else { slog(st,LOG_SETUP_INIT,"resolution failed: " " continuing to use source address of peer's packets"); @@ -1466,7 +1476,8 @@ static void set_link_quality(struct site *st) static void enter_state_run(struct site *st) { - slog(st,LOG_STATE,"entering state RUN"); + slog(st,LOG_STATE,"entering state RUN%s", + current_valid(st) ? " (keyed)" : " (unkeyed)"); st->state=SITE_RUN; st->timeout=0; @@ -1628,7 +1639,7 @@ static bool_t send_msg7(struct site *st, cstring_t reason) static void enter_state_wait(struct site *st) { slog(st,LOG_STATE,"entering state WAIT"); - st->timeout=st->now+st->wait_timeout; + st->timeout=st->now+wait_timeout(st); st->state=SITE_WAIT; set_link_quality(st); BUF_FREE(&st->buffer); /* will have had an outgoing packet in it */ @@ -1770,14 +1781,34 @@ static bool_t named_for_us(struct site *st, const struct buffer_if *buf_in, } static bool_t we_have_priority(struct site *st, const struct msg *m) { - if ((st->local_capabilities & m->remote_capabilities) - && CAPAB_PRIORITY_MOBILE) { + if (st->local_capabilities & m->remote_capabilities & + CAPAB_PRIORITY_MOBILE) { if (st->local_mobile) return True; if (st-> peer_mobile) return False; } return st->our_name_later; } +static bool_t setup_late_msg_ok(struct site *st, + const struct buffer_if *buf_in, + uint32_t msgtype, + const struct comm_addr *source) { + /* For setup packets which seem from their type like they are + * late. Maybe they came via a different path. All we do is make + * a note of the sending address, iff they look like they are part + * of the current key setup attempt. */ + struct msg m; + if (!named_for_us(st,buf_in,msgtype,&m)) + /* named_for_us calls unpick_msg which gets the nonces */ + return False; + if (!consttime_memeq(m.nR,st->remoteN,NONCELEN) || + !consttime_memeq(m.nL,st->localN, NONCELEN)) + /* spoof ? from stale run ? who knows */ + return False; + transport_setup_msgok(st,source); + return True; +} + /* This function is called by the communication device to deliver packets from our peers. It should return True if the packet is recognised as being for @@ -1839,9 +1870,21 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, BUF_FREE(buf); return True; } + } else if (st->state==SITE_SENTMSG2 || + st->state==SITE_SENTMSG4) { + if (consttime_memeq(named_msg.nR,st->remoteN,NONCELEN)) { + /* We are ahead in the protocol, but that msg1 had the + * peer's nonce so presumably it is from this key + * exchange run, via a slower route */ + transport_setup_msgok(st,source); + } else { + slog(st,LOG_UNEXPECTED,"competing incoming message 1"); + } + BUF_FREE(buf); + return True; } /* The message 1 was received at an unexpected stage of the - key setup. XXX POLICY - what do we do? */ + key setup. Well, they lost the race. */ slog(st,LOG_UNEXPECTED,"unexpected incoming message 1"); BUF_FREE(buf); return True; @@ -1886,6 +1929,10 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, case LABEL_MSG2: /* Setup packet: expected only in state SENTMSG1 */ if (st->state!=SITE_SENTMSG1) { + if ((st->state==SITE_SENTMSG3 || + st->state==SITE_SENTMSG5) && + setup_late_msg_ok(st,buf,msgtype,source)) + break; slog(st,LOG_UNEXPECTED,"unexpected MSG2"); } else if (process_msg2(st,buf,source)) { transport_setup_msgok(st,source); @@ -1898,6 +1945,9 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, case LABEL_MSG3BIS: /* Setup packet: expected only in state SENTMSG2 */ if (st->state!=SITE_SENTMSG2) { + if ((st->state==SITE_SENTMSG4) && + setup_late_msg_ok(st,buf,msgtype,source)) + break; slog(st,LOG_UNEXPECTED,"unexpected MSG3"); } else if (process_msg3(st,buf,source,msgtype)) { transport_setup_msgok(st,source); @@ -1909,6 +1959,9 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, case LABEL_MSG4: /* Setup packet: expected only in state SENTMSG3 */ if (st->state!=SITE_SENTMSG3) { + if ((st->state==SITE_SENTMSG5) && + setup_late_msg_ok(st,buf,msgtype,source)) + break; slog(st,LOG_UNEXPECTED,"unexpected MSG4"); } else if (process_msg4(st,buf,source)) { transport_setup_msgok(st,source); @@ -2112,7 +2165,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->key_lifetime= CFG_NUMBER("key-lifetime", KEY_LIFETIME); st->setup_retries= CFG_NUMBER("setup-retries", SETUP_RETRIES); st->setup_retry_interval= CFG_NUMBER("setup-timeout", SETUP_RETRY_INTERVAL); - st->wait_timeout= CFG_NUMBER("wait-time", WAIT_TIME); + st->wait_timeout_mean= CFG_NUMBER("wait-time", WAIT_TIME); st->mtu_target= dict_read_number(dict,"mtu-target",False,"site",loc,0); st->mobile_peer_expiry= dict_read_number(