From 4be1e62251e9393f4b0ae31a7edfc78d52a48599 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 29 Sep 2026 03:57:37 +0300 Subject: [PATCH] Parse IPv4 options and reject malformed TUN proxy packets --- src/proxy/tcp_proxy_client.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/proxy/tcp_proxy_client.c b/src/proxy/tcp_proxy_client.c index 1fdfda3d..a4095f3e 100644 --- a/src/proxy/tcp_proxy_client.c +++ b/src/proxy/tcp_proxy_client.c @@ -159,24 +159,27 @@ static int tcp_proxy_client_handle_non_tcp(struct tcp_proxy_client* p, uint8_t* if (len < 20) return 0; uint8_t ip_ver = (buf[0] >> 4) & 0xF; if (ip_ver != 4) return 0; + uint16_t ihl = (buf[0] & 15) * 4; + if (ihl < 20 || len < ihl + 8u) return 0; + uint8_t* transport = buf + ihl; uint8_t proto = buf[9]; if (proto == IPPROTO_UDP) { if (len < 28) return 0; uint32_t src_ip, dst_ip; uint16_t src_port, dst_port; memcpy(&src_ip, buf + 12, 4); memcpy(&dst_ip, buf + 16, 4); - memcpy(&src_port, buf + 20, 2); memcpy(&dst_port, buf + 22, 2); - udp_proxy_send_to_exit(p->inst, p->via_node_id, src_ip, src_port, dst_ip, dst_port, buf + 28, len - 28); + memcpy(&src_port, transport, 2); memcpy(&dst_port, transport + 2, 2); + udp_proxy_send_to_exit(p->inst, p->via_node_id, src_ip, src_port, dst_ip, dst_port, transport + 8, len - ihl - 8); return 1; } if (proto == IPPROTO_ICMP) { if (len < 28) return 0; - uint8_t icmp_type = buf[20]; + uint8_t icmp_type = transport[0]; if (icmp_type != 8) return 0; uint32_t src_ip, dst_ip; memcpy(&src_ip, buf + 12, 4); memcpy(&dst_ip, buf + 16, 4); uint16_t icmp_id, icmp_seq; - memcpy(&icmp_id, buf + 24, 2); memcpy(&icmp_seq, buf + 26, 2); - icmp_proxy_send_to_exit(p->inst, p->via_node_id, dst_ip, src_ip, icmp_id, icmp_seq, buf + 28, len - 28); + memcpy(&icmp_id, transport + 4, 2); memcpy(&icmp_seq, transport + 6, 2); + icmp_proxy_send_to_exit(p->inst, p->via_node_id, dst_ip, src_ip, icmp_id, icmp_seq, transport + 8, len - ihl - 8); return 1; } return 0; @@ -509,13 +512,19 @@ static void tcp_proxy_client_tun_input(struct ll_queue* q, void* arg) { if (!entry) return; if (entry->dgram && entry->len > 1) { uint8_t* ip = entry->dgram + 1; size_t len = entry->len - 1; - if (len > 20 && len <= 2000) { - if (!tcp_proxy_client_handle_non_tcp(p, ip, len)) { + uint16_t ihl = len ? (ip[0] & 15) * 4 : 0; + uint16_t total = len >= 4 ? ((uint16_t)ip[2] << 8) | ip[3] : 0; + if (len < 20 || (ip[0] >> 4) != 4 || ihl < 20 || total < ihl || total > len) { + DEBUG_WARN(DEBUG_CATEGORY_PROXY, "proxy TUN: invalid IPv4 packet len=%zu ihl=%u total=%u", len, ihl, total); + } else if ((ip[6] & 0x3f) || ip[7]) { + DEBUG_WARN(DEBUG_CATEGORY_PROXY, "proxy TUN: fragmented IPv4 packet unsupported flags=%02x%02x", ip[6], ip[7]); + } else { + if (!tcp_proxy_client_handle_non_tcp(p, ip, total)) { uint8_t proto = ip[9]; if (proto == IPPROTO_TCP) { 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) { + if (ip_hdr_len >= 20 && ip_total >= ip_hdr_len + 20 && len >= ip_total) { uint16_t dport_net; memcpy(&dport_net, ip + ip_hdr_len + 2, 2); tcp_proxy_client_ensure_outbound_listen(p, dport_net); uint32_t src_ip, dst_ip;