X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=site.c;h=f9c2f087823d191f2b056032ff4c5a28b3c90eef;hb=5c19b79c7c817a28a1582970b2685c98e05b2de5;hp=e8dba8734861280a200b71c0aeb5653ecc01dc96;hpb=e5d8c16e9249b2f96931c74f3fddd2cbbcc04a2c;p=secnet.git diff --git a/site.c b/site.c index e8dba87..f9c2f08 100644 --- a/site.c +++ b/site.c @@ -267,6 +267,7 @@ struct site { uint32_t state; uint64_t now; /* Most recently seen time */ bool_t allow_send_prod; + bool_t resolving; /* The currently established session */ struct data_key current; @@ -319,23 +320,58 @@ static uint32_t event_log_priority(struct site *st, uint32_t event) } } -static void slog(struct site *st, uint32_t event, cstring_t msg, ...) -FORMAT(printf,3,4); -static void slog(struct site *st, uint32_t event, cstring_t msg, ...) +static void vslog(struct site *st, uint32_t event, cstring_t msg, va_list ap) +FORMAT(printf,3,0); +static void vslog(struct site *st, uint32_t event, cstring_t msg, va_list ap) { - va_list ap; uint32_t class; class=event_log_priority(st, event); if (class) { - va_start(ap,msg); slilog_part(st->log,class,"%s: ",st->tunname); vslilog_part(st->log,class,msg,ap); slilog_part(st->log,class,"\n"); - va_end(ap); } } +static void slog(struct site *st, uint32_t event, cstring_t msg, ...) +FORMAT(printf,3,4); +static void slog(struct site *st, uint32_t event, cstring_t msg, ...) +{ + va_list ap; + va_start(ap,msg); + vslog(st,event,msg,ap); + va_end(ap); +} + +static void logtimeout(struct site *st, const char *fmt, ...) +FORMAT(printf,2,3); +static void logtimeout(struct site *st, const char *fmt, ...) +{ + uint32_t class=event_log_priority(st,LOG_SETUP_TIMEOUT); + if (!class) + return; + + va_list ap; + va_start(ap,fmt); + + slilog_part(st->log,class,"%s: ",st->tunname); + vslilog_part(st->log,class,fmt,ap); + + const char *delim; + int i; + for (i=0, delim=" (tried "; + isetup_peers.npeers; + i++, delim=", ") { + transport_peer *peer=&st->setup_peers.peers[i]; + const char *s=comm_addr_to_string(&peer->addr); + slilog_part(st->log,class,"%s%s",delim,s); + } + + slilog_part(st->log,class,")\n"); + va_end(ap); +} + static void set_link_quality(struct site *st); static void delete_keys(struct site *st, cstring_t reason, uint32_t loglevel); static void delete_one_key(struct site *st, struct data_key *key, @@ -1082,7 +1118,7 @@ static bool_t send_msg(struct site *st) st->retries--; return True; } else if (st->state==SITE_SENTMSG5) { - slog(st,LOG_SETUP_TIMEOUT,"timed out sending MSG5, stashing new key"); + logtimeout(st,"timed out sending MSG5, stashing new key"); /* We stash the key we have produced, in case it turns out that * our peer did see our MSG5 after all and starts using it. */ /* This is a bit like some of activate_new_key */ @@ -1100,7 +1136,7 @@ static bool_t send_msg(struct site *st) enter_state_wait(st); return False; } else { - slog(st,LOG_SETUP_TIMEOUT,"timed out sending key setup packet " + logtimeout(st,"timed out sending key setup packet " "(in state %s)",state_name(st->state)); enter_state_wait(st); return False; @@ -1112,6 +1148,8 @@ static void site_resolve_callback(void *sst, struct in_addr *address) struct site *st=sst; struct comm_addr ca_buf, *ca_use; + st->resolving=False; + if (st->state!=SITE_RESOLVE) { slog(st,LOG_UNEXPECTED,"site_resolve_callback called unexpectedly"); return; @@ -1139,6 +1177,7 @@ static void site_resolve_callback(void *sst, struct in_addr *address) static bool_t initiate_key_setup(struct site *st, cstring_t reason, const struct comm_addr *prod_hint) { + /* Reentrancy hazard: can call enter_new_state/enter_state_* */ if (st->state!=SITE_RUN) return False; slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason); if (st->address) { @@ -1249,14 +1288,33 @@ static void enter_state_run(struct site *st) set_link_quality(st); } +static bool_t ensure_resolving(struct site *st) +{ + /* Reentrancy hazard: may call site_resolve_callback and hence + * enter_new_state, enter_state_* and generate_msg*. */ + if (st->resolving) + return True; + + /* 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 + * case we have to clear ->resolving again. */ + st->resolving=True; + bool_t ok = st->resolver->request(st->resolver->st,st->address, + site_resolve_callback,st); + if (!ok) + st->resolving=False; + + return ok; +} + static bool_t enter_state_resolve(struct site *st) { + /* Reentrancy hazard! See ensure_resolving. */ 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); - return True; + return ensure_resolving(st); } static bool_t enter_new_state(struct site *st, uint32_t next) @@ -1826,6 +1884,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->log_events=string_list_to_word(dict_lookup(dict,"log-events"), log_event_table,"site"); + st->resolving=False; st->allow_send_prod=0; st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5, @@ -1916,14 +1975,14 @@ static void transport_peers_debug(struct site *st, transport_peers *dst, i++, (argp+=stride?stride:sizeof(*args))) { const struct comm_addr *ca=(void*)argp; slog(st, LOG_PEER_ADDRS, " args: addrs[%d]=%s", - i, ca->comm->addr_to_string(ca->comm->st,ca)); + i, comm_addr_to_string(ca)); } for (i=0; inpeers; i++) { struct timeval diff; timersub(tv_now,&dst->peers[i].last,&diff); const struct comm_addr *ca=&dst->peers[i].addr; slog(st, LOG_PEER_ADDRS, " peers: addrs[%d]=%s T-%ld.%06ld", - i, ca->comm->addr_to_string(ca->comm->st,ca), + i, comm_addr_to_string(ca), (unsigned long)diff.tv_sec, (unsigned long)diff.tv_usec); } }