diff --git a/src/routing_layer/nat_detection.c b/src/routing_layer/nat_detection.c index 478b2359..a8ad3c93 100644 --- a/src/routing_layer/nat_detection.c +++ b/src/routing_layer/nat_detection.c @@ -679,7 +679,8 @@ void nat_detection_receive_ingress(struct NAT_DETECTION *detector, struct ETCP_S DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT ingress ignored without pending endpoint/valid tag length=%zu", length); return; } uint8_t expected[ROUTE_OBSERVE_TAG_SIZE]; route_ping_make_tag(expected, socket, state->group_id, state->round); - uint8_t step = state->phase == NAT_PRE ? NAT_STEP_PRE : state->phase == NAT_POST ? NAT_STEP_POST : 0; + uint8_t step = state->phase == NAT_PREPARE_C ? NAT_STEP_PREPARE : state->phase == NAT_PRE ? NAT_STEP_PRE : + state->phase == NAT_POST ? NAT_STEP_POST : 0; if (!step || memcmp(tag, expected, sizeof(expected)) || tag[ROUTE_OBSERVE_TAG_SIZE] != step || read64(tag + ROUTE_OBSERVE_TAG_SIZE + 1) != state->token || sc_derive_node_id_from_pubkey(peer_key) != state->helper || memcmp(peer_key, state->helper_key, 32) || @@ -689,7 +690,7 @@ void nat_detection_receive_ingress(struct NAT_DETECTION *detector, struct ETCP_S DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT ingress correlation/source mismatch socket=%s phase=%u round=%016llx source=%s", socket->name, state->phase, (unsigned long long)state->round, sockaddr_storage_to_str(source).str); return; } - if (step == NAT_STEP_PRE) { + if (step == NAT_STEP_PRE || step == NAT_STEP_PREPARE) { if (!state->pre_received) { state->filter_clean = !contacted(state, source); state->helper_address = *source; } state->pre_received = 1; } @@ -756,7 +757,7 @@ static void helper_ping_cb(int success, uint16_t rtt, void *arg, uint64_t nonce, if (probe->cancelled) return; probe->active = 0; probe->tcp = NULL; uint8_t step = probe->message.step; - if (step == NAT_STEP_PREPARE || step == NAT_STEP_ALT) { + if (step == NAT_STEP_ALT || (step == NAT_STEP_PREPARE && probe->alternate_fallback)) { struct ETCP_SOCKET *socket = find_socket(probe->detector, probe->io_socket, probe->io_generation); struct sockaddr_storage mapped; if (success && socket && !route_ping_observation(data, length, socket, probe->group_id, @@ -791,6 +792,12 @@ static void helper_ping_cb(int success, uint16_t rtt, void *arg, uint64_t nonce, helper_finish(probe, NAT_REASON_INVALID_OBSERVATION); return; } probe->message.received++; + if (step == NAT_STEP_PREPARE) { helper_finish(probe, NAT_REASON_NONE); return; } + } + if (step == NAT_STEP_PREPARE && probe->message.sent >= NAT_PROBE_COUNT) { + probe->alternate_fallback = 1; probe->message.sent = 0; + DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT first ingress blocked; discover helper mapping through broker group=%016llx owner=%016llx", + (unsigned long long)probe->group_id, (unsigned long long)read64(probe->message.owner)); } if (probe->message.sent >= NAT_PROBE_COUNT) { helper_finish(probe, NAT_REASON_NONE); return; } } @@ -811,7 +818,7 @@ static int helper_send(struct nat_probe *probe) { if (parameters) { topo_node_reality_config(&reality, parameters); camouflage = &reality; } result = etcp_send_tcp_ping(detector->instance, probe->owner_key, &target, timeout, helper_ping_cb, probe, &probe->tcp, camouflage); - } else if (probe->message.step == NAT_STEP_PREPARE || probe->message.step == NAT_STEP_ALT) { + } else if (probe->message.step == NAT_STEP_ALT || (probe->message.step == NAT_STEP_PREPARE && probe->alternate_fallback)) { struct ETCP_SOCKET *source = find_socket(detector, probe->source_socket, probe->source_generation); if (!source) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT helper source generation disappeared"); return -1; } struct ETCP_SOCKET *socket = helper_socket(detector, source, probe->message.step == NAT_STEP_ALT); @@ -954,7 +961,8 @@ static void handle_result(struct nat_socket *state, const struct nat_wire *messa struct sockaddr_storage primary; if (route_ping_addr_decode(message->primary, &primary) || primary.ss_family != state->local.ss_family || !public_address(state->detector, &primary)) { owner_finish(state, NAT_REASON_INVALID_OBSERVATION); return; } - int same_ip = route_ping_addr_equal(&state->observer_address, &primary, 0), old_contact = contacted(state, &primary); + int same_ip = route_ping_addr_equal(&state->observer_address, &primary, 0); + int old_contact = state->pre_received ? !state->filter_clean : contacted(state, &primary); if (same_ip || (old_contact && !state->using_fallback)) { if (!same_ip && !state->fallback.group) state->fallback = (struct nat_pair){state->group_id, state->observer, state->helper}; DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT try another pair socket=%s group=%016llx helper=%016llx endpoint=%s reason=%s", @@ -963,6 +971,11 @@ static void handle_result(struct nat_socket *state, const struct nat_wire *messa owner_finish(state, same_ip ? NAT_REASON_NO_HELPER : NAT_REASON_CONTACT_HISTORY); return; } state->helper_address = primary; state->filter_clean = !old_contact; + if (state->pre_received) { + state->phase = NAT_OBSERVE_C; + if (owner_observe(state)) owner_finish(state, NAT_REASON_SEND_ERROR); + return; + } if (owner_run(state, NAT_STEP_PRE)) owner_finish(state, NAT_REASON_CONTROL_LOST); return; }