Browse Source

Parse IPv4 options and reject malformed TUN proxy packets

proxy
evgeny 2 days ago
parent
commit
4be1e62251
  1. 25
      src/proxy/tcp_proxy_client.c

25
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;

Loading…
Cancel
Save