From 76e916f94d9726311281c63b2850e21eee22df19 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 13 May 2026 00:47:40 +0300 Subject: [PATCH] add transparent outbound TCP proxying: dynamic listen on unknown ports, fwd to exit --- src/tcp_proxy.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/tcp_proxy.c b/src/tcp_proxy.c index 1c319174..134c7efd 100644 --- a/src/tcp_proxy.c +++ b/src/tcp_proxy.c @@ -215,6 +215,7 @@ static err_t proxy_accept_cb(void *arg, struct tcp_pcb *newpcb, err_t err) { 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; } + else { memcpy(pc->dest_ip, &newpcb->local_ip, 4); pc->dest_port = htons(newpcb->local_port); } pc->tun_ip = newpcb->local_ip; tcp_arg(newpcb, pc); @@ -333,6 +334,24 @@ static err_t proxy_connected_cb(void *arg, struct tcp_pcb *pcb, err_t err) { return LERR_OK; } +// ==================================================================== +// Ensure dynamic listen pcb for transparent outbound TCP proxying +// ==================================================================== +static void tcp_proxy_ensure_outbound_listen(struct tcp_proxy* p, uint16_t dport_net) { + if (!p->has_remote_mappings) return; + uint16_t dport_host = ntohs(dport_net); + struct tcp_pcb* lp = p->lwip->listen_pcbs; + while (lp) { if (lp->local_port == dport_host) return; lp = lp->next; } + struct tcp_pcb* lpcb = tcp_new(p->lwip); + if (!lpcb) return; + tcp_bind(lpcb, INADDR_ANY, dport_host); + struct tcp_pcb* listen_pcb = tcp_listen(lpcb); + if (listen_pcb) { + tcp_arg(listen_pcb, p); tcp_accept(listen_pcb, proxy_accept_cb); + DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "TCP proxy: dynamic listen on port %u", dport_host); + } +} + // ==================================================================== // Input: IP packet → lwip_tcp // ==================================================================== @@ -367,6 +386,8 @@ static void tcp_proxy_raw_read(int fd, void* arg) { uint16_t ip_hdr_len = (pkt[0] & 0x0F) * 4; uint16_t ip_total = ((uint16_t)pkt[2] << 8) | pkt[3]; if (ip_hdr_len >= 20 && ip_total >= ip_hdr_len && (size_t)ip_total <= remaining) { + uint16_t dport_net; memcpy(&dport_net, pkt + ip_hdr_len + 2, 2); + tcp_proxy_ensure_outbound_listen(p, dport_net); uint32_t src_ip, dst_ip; memcpy(&src_ip, pkt + 12, 4); memcpy(&dst_ip, pkt + 16, 4); uint16_t tcp_len = ip_total - ip_hdr_len; @@ -393,6 +414,8 @@ static void tcp_proxy_tun_input(struct ll_queue* q, void* arg) { uint16_t ip_hdr_len = (ip[0] & 0x0F) * 4; uint16_t ip_total = ((uint16_t)ip[2] << 8) | ip[3]; if (ip_hdr_len >= 20 && ip_total >= ip_hdr_len && len >= ip_total) { + uint16_t dport_net; memcpy(&dport_net, ip + ip_hdr_len + 2, 2); + tcp_proxy_ensure_outbound_listen(p, dport_net); uint32_t src_ip, dst_ip; memcpy(&src_ip, ip + 12, 4); memcpy(&dst_ip, ip + 16, 4); uint16_t tcp_len = ip_total - ip_hdr_len;