Browse Source

add transparent outbound TCP proxying: dynamic listen on unknown ports, fwd to exit

congestion
Evgeny 5 months ago
parent
commit
76e916f94d
  1. 23
      src/tcp_proxy.c

23
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); 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; } 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; pc->tun_ip = newpcb->local_ip;
tcp_arg(newpcb, pc); 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; 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 // 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_hdr_len = (pkt[0] & 0x0F) * 4;
uint16_t ip_total = ((uint16_t)pkt[2] << 8) | pkt[3]; 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) { 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; uint32_t src_ip, dst_ip;
memcpy(&src_ip, pkt + 12, 4); memcpy(&dst_ip, pkt + 16, 4); memcpy(&src_ip, pkt + 12, 4); memcpy(&dst_ip, pkt + 16, 4);
uint16_t tcp_len = ip_total - ip_hdr_len; 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_hdr_len = (ip[0] & 0x0F) * 4;
uint16_t ip_total = ((uint16_t)ip[2] << 8) | ip[3]; uint16_t ip_total = ((uint16_t)ip[2] << 8) | ip[3];
if (ip_hdr_len >= 20 && ip_total >= ip_hdr_len && len >= ip_total) { 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; uint32_t src_ip, dst_ip;
memcpy(&src_ip, ip + 12, 4); memcpy(&dst_ip, ip + 16, 4); memcpy(&src_ip, ip + 12, 4); memcpy(&dst_ip, ip + 16, 4);
uint16_t tcp_len = ip_total - ip_hdr_len; uint16_t tcp_len = ip_total - ip_hdr_len;

Loading…
Cancel
Save