diff --git a/src/tcp_proxy.c b/src/tcp_proxy.c index c0ce4ff6..ab40b02a 100644 --- a/src/tcp_proxy.c +++ b/src/tcp_proxy.c @@ -211,7 +211,7 @@ static err_t proxy_accept_cb(void *arg, struct tcp_pcb *newpcb, err_t err) { struct proxy_conn *pc = u_calloc(1, sizeof(struct proxy_conn)); if (!pc) return LERR_MEM; - pc->proxy = p; pc->pcb = newpcb; pc->closing = 0; pc->half_closed = 0; + pc->proxy = p; pc->pcb = newpcb; pc->closing_tun = 0; pc->closing_rem = 0; struct tcp_proxy_mapping *m = find_mapping_by_port(p, newpcb->local_port); if (m) { memcpy(pc->dest_ip, m->remote_ip, 4); pc->dest_port = m->remote_port; } @@ -250,22 +250,9 @@ static err_t proxy_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t if (!pc) { if (p) pbuf_free(p); return LERR_OK; } if (p == NULL || err != LERR_OK) { - struct tcp_proxy *proxy = pc->proxy; - DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "TCP proxy: remote closed (FIN/EOF), stream=%s active=%d", + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "TCP proxy: TUN FIN received, stream=%s active=%d", pc->active ? "active" : "passive", pc->active); - pc->closing = 1; - if (pc->transport) { pc->transport->ops->destroy(pc->transport); pc->transport = NULL; } - struct tcp_pcb *pcb = pc->pcb; - if (pcb) { tcp_arg(pcb, NULL); pc->pcb = NULL; tcp_close(pcb); } - struct proxy_conn **prev = &proxy->conns; - while (*prev) { - if (*prev == pc) { *prev = pc->next; proxy->conn_count--; break; } - prev = &(*prev)->next; - } - if (pc->eim_mapping) { pc->eim_mapping->delete_at_tb = get_time_tb() + proxy->eim_timeout_tb; pc->eim_mapping = NULL; } - if (pc->uip_to_transport) { struct ll_entry *e2; while ((e2 = queue_data_get(pc->uip_to_transport))) { queue_dgram_free(e2); queue_entry_free(e2); } queue_free(pc->uip_to_transport); } - if (pc->transport_to_uip) { struct ll_entry *e2; while ((e2 = queue_data_get(pc->transport_to_uip))) { queue_dgram_free(e2); queue_entry_free(e2); } queue_free(pc->transport_to_uip); } - u_free(pc); + pc->closing_tun = 1; return LERR_OK; } @@ -275,7 +262,7 @@ static err_t proxy_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t if (e) queue_data_put(pc->uip_to_transport, e); tcp_recved(pcb, p->tot_len); pbuf_free(p); - } else if (pc->transport && !pc->half_closed) { + } else if (pc->transport && !pc->closing_rem) { uint16_t len = p->tot_len; uint8_t *data = u_malloc(len); if (data) { @@ -305,7 +292,7 @@ static void proxy_err_cb(void *arg, err_t err) { struct proxy_conn *pc = (struct proxy_conn *)arg; if (!pc) return; DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "TCP proxy: tcp error %d", err); - pc->closing = 1; + pc->closing_tun = 1; if (pc->transport) pc->transport->ops->close(pc->transport); } @@ -313,8 +300,16 @@ static err_t proxy_poll_cb(void *arg, struct tcp_pcb *pcb) { struct proxy_conn *pc = (struct proxy_conn *)arg; if (!pc) return LERR_OK; proxy_feed_from_transport(pc); - if (pc->closing && pc->transport == NULL && pc->pcb) { - tcp_arg(pc->pcb, NULL); pc->pcb = NULL; tcp_close(pcb); + if (pc->closing_tun && pc->closing_rem && pc->pcb) { + struct tcp_pcb *save = pc->pcb; + tcp_arg(save, NULL); pc->pcb = NULL; tcp_close(save); + struct tcp_proxy *proxy = pc->proxy; + struct proxy_conn **prev = &proxy->conns; + while (*prev) { if (*prev == pc) { *prev = pc->next; proxy->conn_count--; break; } prev = &(*prev)->next; } + if (pc->eim_mapping) { pc->eim_mapping->delete_at_tb = get_time_tb() + proxy->eim_timeout_tb; pc->eim_mapping = NULL; } + if (pc->uip_to_transport) { struct ll_entry *e2; while ((e2 = queue_data_get(pc->uip_to_transport))) { queue_dgram_free(e2); queue_entry_free(e2); } queue_free(pc->uip_to_transport); } + if (pc->transport_to_uip) { struct ll_entry *e2; while ((e2 = queue_data_get(pc->transport_to_uip))) { queue_dgram_free(e2); queue_entry_free(e2); } queue_free(pc->transport_to_uip); } + u_free(pc); } return LERR_OK; } @@ -324,7 +319,7 @@ static err_t proxy_connected_cb(void *arg, struct tcp_pcb *pcb, err_t err) { if (!pc) return LERR_ABRT; if (err != LERR_OK) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "TCP proxy: active connect failed: %d", err); - pc->closing = 1; + pc->closing_tun = 1; return LERR_ABRT; } DEBUG_ERROR(DEBUG_CATEGORY_TRAFFIC, "TCP proxy: active connect established to %d.%d.%d.%d:%d cwnd=%u snd_wnd=%u snd_buf=%u", @@ -486,7 +481,7 @@ static void sock_transport_close(struct tcp_proxy_transport* t) { if(st->read_id) { uasync_remove_socket_t(st->ua, st->sock); st->read_id = NULL; } if(st->write_id) { uasync_remove_socket_t(st->ua, st->sock); st->write_id = NULL; } socket_close_wrapper(st->sock); st->sock = SOCKET_INVALID; st->connected = 0; - if(pc && !pc->closing) pc->closing = 1; + if(pc && !pc->closing_rem) pc->closing_rem = 1; if(pc) pc->transport = NULL; } @@ -591,7 +586,7 @@ static void etcp_transport_close(struct tcp_proxy_transport* t) { etcp_route_send(et->inst, et->remote_node_id, e); } else queue_entry_free(e); } et->connected = 0; - if (et->conn) et->conn->transport = NULL; + if (et->conn) { et->conn->transport = NULL; et->conn->closing_rem = 1; } } static void etcp_transport_destroy(struct tcp_proxy_transport* t) { @@ -654,7 +649,7 @@ static void handle_connected(struct tcp_proxy* p, uint64_t stream_id, struct ll_ } } else { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "TCP proxy: remote refused stream=%016llx", (unsigned long long)stream_id); - pc->closing = 1; } + pc->closing_rem = 1; } } queue_entry_free(entry); queue_dgram_free(entry); } @@ -699,10 +694,8 @@ void tcp_proxy_etcp_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { if (subcmd == TCP_PROXY_SUBCMD_CLOSE) { struct proxy_conn* pc = find_pc_by_stream(proxy, stream_id); if (pc) { - pc->closing = 1; + pc->closing_rem = 1; if (pc->transport) { pc->transport->ops->destroy(pc->transport); pc->transport = NULL; } - struct tcp_pcb *pcb = pc->pcb; - if (pcb) { tcp_arg(pcb, NULL); pc->pcb = NULL; tcp_close(pcb); } } } } @@ -817,7 +810,7 @@ struct proxy_conn* tcp_proxy_active_open(struct tcp_proxy* p, const char* dest_i struct proxy_conn* pc = u_calloc(1, sizeof(struct proxy_conn)); if (!pc) return NULL; - pc->proxy = p; pc->active = 1; pc->closing = 0; pc->half_closed = 0; + pc->proxy = p; pc->active = 1; pc->closing_tun = 0; pc->closing_rem = 0; pc->dest_port = htons(dest_port); pc->dest_ip[0] = (uint8_t)a0; pc->dest_ip[1] = (uint8_t)a1; pc->dest_ip[2] = (uint8_t)a2; pc->dest_ip[3] = (uint8_t)a3; pc->tun_ip = htonl((a0 << 24) | (a1 << 16) | (a2 << 8) | a3); @@ -869,7 +862,7 @@ ssize_t tcp_proxy_active_recv(struct tcp_proxy* p, struct proxy_conn* pc, uint8_ int tcp_proxy_active_close(struct tcp_proxy* p, struct proxy_conn* pc) { (void)p; if (!pc || !pc->active) return -1; - pc->closing = 1; + pc->closing_tun = 1; tcp_close(pc->pcb); return 0; } @@ -877,7 +870,7 @@ int tcp_proxy_active_close(struct tcp_proxy* p, struct proxy_conn* pc) { int tcp_proxy_active_send_done(struct tcp_proxy* p, struct proxy_conn* pc) { (void)p; if (!pc || !pc->active || !pc->pcb) return 1; - if (pc->closing) return 1; + if (pc->closing_tun) return 1; int q = queue_entry_count(pc->transport_to_uip); if (q > 0) return 0; if (pc->pcb->unsent || pc->pcb->unacked) return 0; diff --git a/src/tcp_proxy.h b/src/tcp_proxy.h index 5781e631..ed57aa45 100644 --- a/src/tcp_proxy.h +++ b/src/tcp_proxy.h @@ -57,8 +57,8 @@ struct proxy_conn { uint8_t dest_ip[4]; // proxy target IP (where to forward OS socket) uint32_t tun_ip; // TUN IP (what client connected to, for uip_hostaddr) uint16_t dest_port; - int closing; - int half_closed; + int closing_tun; // 1 = TUN/lwIP side sent FIN (waiting for remote) + int closing_rem; // 1 = remote/transport closed (waiting for TUN) int active; // 1 = outgoing connection struct tcp_proxy_mapping* eim_mapping; uint64_t remote_stream_id; // stream ID for remote proxy (0=local) diff --git a/tests/test_tcp_proxy.c b/tests/test_tcp_proxy.c index 348d680e..6ff545fd 100644 --- a/tests/test_tcp_proxy.c +++ b/tests/test_tcp_proxy.c @@ -115,7 +115,7 @@ int main(void) { uasync_poll(ua, 100); timeout_ms -= 10; ssize_t n = tcp_proxy_active_recv(a, pc, recv_buf + total_rcvd, TEST_SIZE - total_rcvd); if(n > 0) total_rcvd += n; - if(pc->closing) break; + if(pc->closing_rem && total_rcvd < TEST_SIZE) break; } // 11. Half-close after all data received