X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=site.c;h=f035e79e08ea1c11890a4776e5deebd210884fdb;hp=b14b8e8f60ee1987f07aa1822db693fd9d65af68;hb=ac570433618f9324d99d0fbb400cd6b3cc95aecc;hpb=a96fda35655e11388dda789f83d4c04c751eb946 diff --git a/site.c b/site.c index b14b8e8..f035e79 100644 --- a/site.c +++ b/site.c @@ -143,44 +143,80 @@ static struct flagstr log_event_table[]={ /***** TRANSPORT PEERS declarations *****/ /* Details of "mobile peer" semantics: + + | Note: this comment is wishful thinking right now. It will be + | implemented in subsequent commits. + + - We use the same data structure for the different configurations, + but manage it with different algorithms. - - We record mobile_peers_max peer address/port numbers ("peers") - for key setup, and separately mobile_peers_max for data - transfer. If these lists fill up, we retain the newest peers. - (For non-mobile peers we only record one of each.) + - We record up to mobile_peers_max peer address/port numbers + ("peers") for key setup, and separately up to mobile_peers_max + for data transfer. + + - In general, we make a new set of addrs (see below) when we start + a new key exchange; the key setup addrs become the data transport + addrs when key setup complets. + + If our peer is mobile: + + - We send to all recent addresses of incoming packets, plus + initially all configured addresses (which we also expire). + + - So, we record addrs of good incoming packets, as follows: + 1. expire any peers last seen >120s ("mobile-peer-expiry") ago + 2. add the peer of the just received packet to the applicable list + (possibly evicting the oldest entries to make room) + NB that we do not expire peers until an incoming packet arrives. + + - If the peer has a configured address or name, we record them the + same way, but only as a result of our own initiation of key + setup. (We might evict some incoming packet addrs to make room.) + + - The default number of addrs to keep is 3, or 4 if we have a + configured name or address. That's space for two configured + addresses (one IPv6 and one IPv4), plus two received addresses. - - Outgoing packets are sent to every recorded peer in the - applicable list. + - Outgoing packets are sent to every recorded address in the + applicable list. Any unsupported[1] addresses are deleted from + the list right away. (This should only happen to configured + addresses, of course, but there is no need to check that.) - - Data transfer peers are straightforward: whenever we successfully - process a data packet, we record the peer. Also, whenever we - successfully complete a key setup, we merge the key setup + - When we successfully complete a key setup, we merge the key setup peers into the data transfer peers. - (For "non-mobile" peers we simply copy the peer used for - successful key setup, and don't change the peer otherwise.) + [1] An unsupported address is one for whose AF we don't have a + socket (perhaps because we got EAFNOSUPPORT or some such) or for + which sendto gives ENETUNREACH. - - Key setup peers are slightly more complicated. + If neither end is mobile: - Whenever we receive and successfully process a key exchange - packet, we record the peer. + - When peer initiated the key exchange, we use the incoming packet + address. - Whenever we try to initiate a key setup, we copy the list of data - transfer peers and use it for key setup. But we also look to see - if the config supplies an address and port number and if so we - add that as a key setup peer (possibly evicting one of the data - transfer peers we just copied). + - When we initiate the key exchange, we try configured addresses + until we get one which isn't unsupported then fixate on that. - (For "non-mobile" peers, if we if we have a configured peer - address and port, we always use that; otherwise if we have a - current data peer address we use that; otherwise we do not - attempt to initiate a key setup for lack of a peer address.) + - When we complete a key setup, we replace the data transport peers + with those from the key setup. - "Record the peer" means - 1. expire any peers last seen >120s ("mobile-peer-expiry") ago - 2. add the peer of the just received packet to the applicable list - (possibly evicting older entries) - NB that we do not expire peers until an incoming packet arrives. + If we are mobile: + + - We can't tell when local network setup changes so we can't cache + the unsupported addrs and completely remove the spurious calls to + sendto, but we can optimise things a bit by deprioritising addrs + which seem to be unsupported. + + - Use only configured addresses. (Except, that if our peer + initiated a key exchange we use the incoming packet address until + our name resolution completes.) + + - When we send a packet, try each address in turn; if addr + supported, put that address to the end of the list for future + packets, and go onto the next address. + + - When we complete a key setup, we replace the data transport peers + with those from the key setup. */ @@ -198,22 +234,35 @@ typedef struct { transport_peer peers[MAX_MOBILE_PEERS_MAX]; } transport_peers; +/* Basic operations on transport peer address sets */ static void transport_peers_clear(struct site *st, transport_peers *peers); static int transport_peers_valid(transport_peers *peers); static void transport_peers_copy(struct site *st, transport_peers *dst, const transport_peers *src); +/* Record address of incoming setup packet; resp. data packet. */ 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); + +/* Initialise the setup addresses. Called before we send the first + * packet in a key exchange. If we are the initiator, as a result of + * resolve completing (or being determined not to be relevant) or an + * incoming PROD; if we are the responder, as a result of the MSG1. */ 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 *incoming_packet_addr /* 0 if none */); + +/* Called if we are the responder in a key setup, when the resolve + * completes. transport_compute_setupinit_peers will hvae been called + * earlier. If _complete is called, we are still doing the key setup + * (and we should use the new values for both the rest of the key + * setup and the ongoing data exchange); if _tardy is called, the key + * setup is done (either completed or not) and only the data peers are + * relevant */ 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); static void transport_xmit(struct site *st, transport_peers *peers, struct buffer_if *buf, bool_t candebug); @@ -549,9 +598,9 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) append_string_xinfo_done(&st->buffer,&xia); buf_append_string(&st->buffer,st->remotename); - memcpy(buf_append(&st->buffer,NONCELEN),st->localN,NONCELEN); + BUF_ADD_OBJ(append,&st->buffer,st->localN); if (type==LABEL_MSG1) return True; - memcpy(buf_append(&st->buffer,NONCELEN),st->remoteN,NONCELEN); + BUF_ADD_OBJ(append,&st->buffer,st->remoteN); if (type==LABEL_MSG2) return True; if (hacky_par_mid_failnow()) return False; @@ -1328,8 +1377,8 @@ static void enter_state_run(struct site *st) st->setup_session_id=0; transport_peers_clear(st,&st->setup_peers); - memset(st->localN,0,NONCELEN); - memset(st->remoteN,0,NONCELEN); + FILLZERO(st->localN); + FILLZERO(st->remoteN); dispose_transform(&st->new_transform); memset(st->dhsecret,0,st->dh->len); memset(st->sharedsecret,0,st->sharedsecretlen); @@ -1630,7 +1679,7 @@ 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"); + transport_compute_setupinit_peers(st,0,source); if (process_msg1(st,buf,source,&named_msg)) { slog(st,LOG_SETUP_INIT,"key setup initiated by peer"); bool_t entered=enter_new_state(st,SITE_SENTMSG2); @@ -1696,7 +1745,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, because our peer's forgotten the key */ if (get_uint32(buf->start+4)==st->current.remote_session_id) { bool_t initiated; - initiated = initiate_key_setup(st,"received a NAK",0); + initiated = initiate_key_setup(st,"received a NAK",source); if (!initiated) generate_send_prod(st,source); } else { slog(st,LOG_SEC,"bad incoming NAK");