X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=site.c;h=a91c1be963567c2d732e22f8fa7e4e09a144e810;hb=1d38856958136dc28a9d16f58a55f75867cdc57d;hp=9f3ee856b8adb2cb015b477b2ba5e64afc852eef;hpb=c90cc2a73eabbda9887e67898389acbd759d7270;p=secnet.git diff --git a/site.c b/site.c index 9f3ee85..a91c1be 100644 --- a/site.c +++ b/site.c @@ -214,6 +214,12 @@ static void transport_xmit(struct site *st, transport_peers *peers, /***** END of transport peers declarations *****/ +struct data_key { + struct transform_inst_if *transform; + uint64_t key_timeout; /* End of life of current key */ + uint32_t remote_session_id; +}; + struct site { closure_t cl; struct site_if ops; @@ -259,10 +265,7 @@ struct site { uint64_t now; /* Most recently seen time */ /* The currently established session */ - uint32_t remote_session_id; - struct transform_inst_if *current_transform; - bool_t current_valid; - uint64_t current_key_timeout; /* End of life of current key */ + struct data_key current; uint64_t renegotiate_key_time; /* When we can negotiate a new key */ transport_peers peers; /* Current address(es) of peer for data traffic */ @@ -316,7 +319,11 @@ static void slog(struct site *st, uint32_t event, cstring_t msg, ...) } static void set_link_quality(struct site *st); -static void delete_key(struct site *st, cstring_t reason, uint32_t loglevel); +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, + const char *reason /* may be 0 meaning don't log*/, + const char *which /* ignored if !reasonn */, + uint32_t loglevel /* ignored if !reasonn */); static bool_t initiate_key_setup(struct site *st, cstring_t reason); static void enter_state_run(struct site *st); static bool_t enter_state_resolve(struct site *st); @@ -324,6 +331,11 @@ static bool_t enter_new_state(struct site *st,uint32_t next); static void enter_state_wait(struct site *st); static void activate_new_key(struct site *st); +static bool_t current_valid(struct site *st) +{ + return st->current.transform->valid(st->current.transform->st); +} + #define CHECK_AVAIL(b,l) do { if ((b)->size<(l)) return False; } while(0) #define CHECK_EMPTY(b) do { if ((b)->size!=0) return False; } while(0) #define CHECK_TYPE(b,t) do { uint32_t type; \ @@ -726,7 +738,7 @@ static bool_t decrypt_msg0(struct site *st, struct buffer_if *msg0) /* Keep a copy so we can try decrypting it with multiple keys */ buffer_copy(&st->scratch, msg0); - problem = st->current_transform->reverse(st->current_transform->st, + problem = st->current.transform->reverse(st->current.transform->st, msg0,&transform_err); if (!problem) return True; @@ -767,7 +779,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, switch(type) { case LABEL_MSG7: /* We must forget about the current session. */ - delete_key(st,"request from peer",LOG_SEC); + delete_keys(st,"request from peer",LOG_SEC); return True; case LABEL_MSG9: /* Deliver to netlink layer */ @@ -867,30 +879,36 @@ static void activate_new_key(struct site *st) /* We have two transform instances, which we swap between active and setup */ - t=st->current_transform; - st->current_transform=st->new_transform; + t=st->current.transform; + st->current.transform=st->new_transform; st->new_transform=t; t->delkey(t->st); st->timeout=0; - st->current_valid=True; - st->current_key_timeout=st->now+st->key_lifetime; + st->current.key_timeout=st->now+st->key_lifetime; st->renegotiate_key_time=st->now+st->key_renegotiate_time; transport_peers_copy(st,&st->peers,&st->setup_peers); - st->remote_session_id=st->setup_session_id; + st->current.remote_session_id=st->setup_session_id; slog(st,LOG_ACTIVATE_KEY,"new key activated"); enter_state_run(st); } -static void delete_key(struct site *st, cstring_t reason, uint32_t loglevel) +static void delete_one_key(struct site *st, struct data_key *key, + cstring_t reason, cstring_t which, uint32_t loglevel) { - if (st->current_valid) { + if (!key->transform->valid(key->transform->st)) return; + if (reason) slog(st,loglevel,"%s deleted (%s)",which,reason); + key->transform->delkey(key->transform->st); + key->key_timeout=0; +} + +static void delete_keys(struct site *st, cstring_t reason, uint32_t loglevel) +{ + if (current_valid(st)) { slog(st,loglevel,"session closed (%s)",reason); - st->current_valid=False; - st->current_transform->delkey(st->current_transform->st); - st->current_key_timeout=0; + delete_one_key(st,&st->current,0,0,0); set_link_quality(st); } } @@ -904,14 +922,14 @@ static void enter_state_stop(struct site *st) { st->state=SITE_STOP; st->timeout=0; - delete_key(st,"entering state STOP",LOG_TIMEOUT_KEY); + delete_keys(st,"entering state STOP",LOG_TIMEOUT_KEY); st->new_transform->delkey(st->new_transform->st); } static void set_link_quality(struct site *st) { uint32_t quality; - if (st->current_valid) + if (current_valid(st)) quality=LINK_QUALITY_UP; else if (st->state==SITE_WAIT || st->state==SITE_STOP) quality=LINK_QUALITY_DOWN; @@ -1023,17 +1041,17 @@ static bool_t send_msg7(struct site *st, cstring_t reason) { cstring_t transform_err; - if (st->current_valid && st->buffer.free + if (current_valid(st) && st->buffer.free && transport_peers_valid(&st->peers)) { BUF_ALLOC(&st->buffer,"site:MSG7"); buffer_init(&st->buffer,st->transform->max_start_pad+(4*3)); buf_append_uint32(&st->buffer,LABEL_MSG7); buf_append_string(&st->buffer,reason); - st->current_transform->forwards(st->current_transform->st, + st->current.transform->forwards(st->current.transform->st, &st->buffer, &transform_err); buf_prepend_uint32(&st->buffer,LABEL_MSG0); buf_prepend_uint32(&st->buffer,st->index); - buf_prepend_uint32(&st->buffer,st->remote_session_id); + buf_prepend_uint32(&st->buffer,st->current.remote_session_id); transport_xmit(st,&st->peers,&st->buffer,True); BUF_FREE(&st->buffer); return True; @@ -1074,14 +1092,22 @@ static int site_beforepoll(void *sst, struct pollfd *fds, int *nfds_io, st->now=*now; /* Work out when our next timeout is. The earlier of 'timeout' or - 'current_key_timeout'. A stored value of '0' indicates no timeout + 'current.key_timeout'. A stored value of '0' indicates no timeout active. */ site_settimeout(st->timeout, timeout_io); - site_settimeout(st->current_key_timeout, timeout_io); + site_settimeout(st->current.key_timeout, timeout_io); return 0; /* success */ } +static void check_expiry(struct site *st, struct data_key *key, + const char *which) +{ + if (key->key_timeout && *now>key->key_timeout) { + delete_one_key(st,key,"maximum life exceeded",which,LOG_TIMEOUT_KEY); + } +} + /* NB site_afterpoll will be called before site_beforepoll is ever called */ static void site_afterpoll(void *sst, struct pollfd *fds, int nfds) { @@ -1100,9 +1126,7 @@ static void site_afterpoll(void *sst, struct pollfd *fds, int nfds) st->state); } } - if (st->current_key_timeout && *now>st->current_key_timeout) { - delete_key(st,"maximum key life exceeded",LOG_TIMEOUT_KEY); - } + check_expiry(st,&st->current,"current key"); } /* This function is called by the netlink device to deliver packets @@ -1120,15 +1144,15 @@ static void site_outgoing(void *sst, struct buffer_if *buf) /* In all other states we consider delivering the packet if we have a valid key and a valid address to send it to. */ - if (st->current_valid && transport_peers_valid(&st->peers)) { + if (current_valid(st) && transport_peers_valid(&st->peers)) { /* Transform it and send it */ if (buf->size>0) { buf_prepend_uint32(buf,LABEL_MSG9); - st->current_transform->forwards(st->current_transform->st, + st->current.transform->forwards(st->current.transform->st, buf, &transform_err); buf_prepend_uint32(buf,LABEL_MSG0); buf_prepend_uint32(buf,st->index); - buf_prepend_uint32(buf,st->remote_session_id); + buf_prepend_uint32(buf,st->current.remote_session_id); transport_xmit(st,&st->peers,buf,False); } BUF_FREE(buf); @@ -1208,7 +1232,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, case 0: /* NAK */ /* If the source is our current peer then initiate a key setup, because our peer's forgotten the key */ - if (get_uint32(buf->start+4)==st->remote_session_id) { + if (get_uint32(buf->start+4)==st->current.remote_session_id) { initiate_key_setup(st,"received a NAK"); } else { slog(st,LOG_SEC,"bad incoming NAK"); @@ -1270,10 +1294,11 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, slog(st,LOG_SEC,"invalid MSG5"); } } else if (st->state==SITE_RUN) { - if (process_msg5(st,buf,source,st->current_transform)) { + if (process_msg5(st,buf,source,st->current.transform)) { slog(st,LOG_DROP,"got MSG5, retransmitting MSG6"); transport_setup_msgok(st,source); - create_msg6(st,st->current_transform,st->remote_session_id); + create_msg6(st,st->current.transform, + st->current.remote_session_id); transport_xmit(st,&st->peers,&st->buffer,True); BUF_FREE(&st->buffer); } else { @@ -1470,8 +1495,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, register_for_poll(st, site_beforepoll, site_afterpoll, 0, "site"); st->timeout=0; - st->current_valid=False; - st->current_key_timeout=0; + st->current.key_timeout=0; transport_peers_clear(st,&st->peers); transport_peers_clear(st,&st->setup_peers); /* XXX mlock these */ @@ -1498,7 +1522,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, for (i=0; incomms; i++) st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming); - st->current_transform=st->transform->create(st->transform->st); + st->current.transform=st->transform->create(st->transform->st); st->new_transform=st->transform->create(st->transform->st); enter_state_stop(st);