From b2ac2e0d0373fe1ff1e10a4b594a3e0db6e025b4 Mon Sep 17 00:00:00 2001 From: Vadim Vetrov Date: Wed, 4 Dec 2024 23:48:18 +0300 Subject: [PATCH] UDP faking support --- config.h | 3 +- mangle.c | 81 ++++++++++++++++++++++++++--------------- quic.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ quic.h | 10 +++++ utils.h | 14 +++++++ 5 files changed, 187 insertions(+), 30 deletions(-) diff --git a/config.h b/config.h index 02c4969..9178fdf 100644 --- a/config.h +++ b/config.h @@ -165,8 +165,9 @@ for (struct section_config_t *section = &config.default_config + config.custom_c #define FAKE_STRAT_PAST_SEQ (1 << 2) #define FAKE_STRAT_TCP_CHECK (1 << 3) #define FAKE_STRAT_TCP_MD5SUM (1 << 4) +#define FAKE_STRAT_UDP_CHECK (1 << 5) -#define FAKE_STRAT_COUNT 5 +#define FAKE_STRAT_COUNT 6 /** * This macros iterates through all faking strategies and executes code under it. diff --git a/mangle.c b/mangle.c index cc8d811..9bd3a7a 100644 --- a/mangle.c +++ b/mangle.c @@ -74,16 +74,32 @@ int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) { break; } - if (verdict == PKT_CONTINUE) + if (verdict == PKT_CONTINUE) { + lgtrace_addp("continue_flow"); continue; + } - lgtrace_end(); - return verdict; + goto ret_verdict; } accept: + verdict = PKT_ACCEPT; + +ret_verdict: + + switch (verdict) { + case PKT_ACCEPT: + lgtrace_addp("accept"); + break; + case PKT_DROP: + lgtrace_addp("drop"); + break; + default: + lgtrace_addp("unknow verdict: %d", verdict); + } lgtrace_end(); - return PKT_ACCEPT; + + return verdict; } int process_tcp_packet(const struct section_config_t *section, const uint8_t *raw_payload, uint32_t raw_payload_len) { @@ -309,13 +325,10 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra } continue_flow: - lgtrace_addp("continue_flow"); return PKT_CONTINUE; accept: - lgtrace_addp("accept"); return PKT_ACCEPT; drop: - lgtrace_addp("drop"); return PKT_DROP; } @@ -350,6 +363,7 @@ int process_udp_packet(const struct section_config_t *section, const uint8_t *pk } + if (section->quic_drop) { lgtrace_addp("QUIC probe"); const struct quic_lhdr *qch; @@ -384,39 +398,48 @@ int process_udp_packet(const struct section_config_t *section, const uint8_t *pk lgtrace_addp("quic initial message"); } -/* if (1) { - lgtrace_addp("Probe udp"); - if (ipver == IP4VERSION && ntohs(udph->dest) > 30) { - lgtrace_addp("udp fool"); - const uint8_t *payload; - uint32_t payload_len; - - uint32_t poses[10]; - int cnt = 3; - - poses[0] = 8; - for (int i = 1; i < cnt; i++) { - poses[i] = poses[i - 1] + 8; + for (int i = 0; i < 6; i++) { + NETBUF_ALLOC(fake_udp, MAX_PACKET_SIZE); + if (!NETBUF_CHECK(fake_udp)) { + lgerror(-ENOMEM, "Allocation error"); + return -ENOMEM; } + uint32_t fsn_len = MAX_PACKET_SIZE; - ret = send_ip4_frags(pkt, pktlen, poses, cnt, 0); + struct udp_fake_type fake_type = { + .fake_len = 64, + .strategy = { + .strategy = FAKE_STRAT_UDP_CHECK, + }, + }; + ret = gen_fake_udp(fake_type, iph, iph_len, udph, fake_udp, &fsn_len); if (ret < 0) { - lgerror("ip4 send frags", ret); - goto accept; + lgerror(ret, "gen_fake_udp"); + goto erret_lc; } - goto drop; - } else { - lginfo("WARNING: IP fragmentation is supported only for IPv4\n"); + lgtrace_addp("post fake udp #%d", i + 1); + + ret = instance_config.send_raw_packet(fake_udp, fsn_len); + if (ret < 0) { + lgerror(ret, "send fake udp"); + goto erret_lc; + } + + NETBUF_FREE(fake_udp); + continue; +erret_lc: + NETBUF_FREE(fake_udp); goto accept; } - } -*/ + + ret = instance_config.send_raw_packet(pkt, pktlen); + goto drop; + } continue_flow: - lgtrace_addp("continue_flow"); return PKT_CONTINUE; accept_quic: accept: diff --git a/quic.c b/quic.c index 66bdb4e..77ea926 100644 --- a/quic.c +++ b/quic.c @@ -138,3 +138,112 @@ int quic_parse_initial_message(uint8_t *inpayload, uint32_t inplen, lgerror(-EINVAL, "QUIC invalid Initial packet"); return -EINVAL; } + +int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen) { + void *iph; + uint32_t iph_len; + struct udphdr *udph; + uint8_t *data; + uint32_t dlen; + int ret; + + ret = udp_payload_split(payload, *plen, + &iph, &iph_len, &udph, + &data, &dlen); + + uint32_t ipxv = netproto_version(payload, *plen); + + if (ret < 0) { + return ret; + } + + + if (strategy.strategy == FAKE_STRAT_TTL) { + lgtrace_addp("set fake ttl to %d", strategy.faking_ttl); + + if (ipxv == IP4VERSION) { + ((struct iphdr *)iph)->ttl = strategy.faking_ttl; + } else if (ipxv == IP6VERSION) { + ((struct ip6_hdr *)iph)->ip6_hops = strategy.faking_ttl; + } else { + lgerror(-EINVAL, "fail_packet: IP version is unsupported"); + return -EINVAL; + } + } + + if (ipxv == IP4VERSION) { + ((struct iphdr *)iph)->frag_off = 0; + } + + + set_ip_checksum(iph, iph_len); + + if (strategy.strategy == FAKE_STRAT_UDP_CHECK) { + lgtrace_addp("break fake tcp checksum"); + udph->check += 1; + } + + return 0; +} + +int gen_fake_udp(struct udp_fake_type type, + const void *ipxh, uint32_t iph_len, + const struct udphdr *udph, + uint8_t *buf, uint32_t *buflen) { + uint32_t data_len = type.fake_len; + int ret; + + + if (!ipxh || !udph || !buf || !buflen) + return -EINVAL; + + int ipxv = netproto_version(ipxh, iph_len); + + if (ipxv == IP4VERSION) { + const struct iphdr *iph = ipxh; + + memcpy(buf, iph, iph_len); + struct iphdr *niph = (struct iphdr *)buf; + + niph->protocol = IPPROTO_UDP; + } else if (ipxv == IP6VERSION) { + const struct ip6_hdr *iph = ipxh; + + iph_len = sizeof(struct ip6_hdr); + memcpy(buf, iph, iph_len); + struct ip6_hdr *niph = (struct ip6_hdr *)buf; + + niph->ip6_nxt = IPPROTO_UDP; + } else { + return -EINVAL; + } + + uint32_t dlen = iph_len + sizeof(struct udphdr) + data_len; + + if (*buflen < dlen) + return -ENOMEM; + + memcpy(buf + iph_len, udph, sizeof(struct udphdr)); + uint8_t *bfdptr = buf + iph_len + sizeof(struct udphdr); + + memset(bfdptr, 0, data_len); + + if (ipxv == IP4VERSION) { + struct iphdr *niph = (struct iphdr *)buf; + niph->tot_len = htons(dlen); + niph->id = randint(); + } else if (ipxv == IP6VERSION) { + struct ip6_hdr *niph = (struct ip6_hdr *)buf; + niph->ip6_plen = htons(dlen - iph_len); + } + + struct udphdr *nudph = (struct udphdr *)(buf + iph_len); + nudph->len = htons(sizeof(struct udphdr) + data_len); + + + udp_fail_packet(type.strategy, buf, &dlen, *buflen); + + *buflen = dlen; + + return 0; +} diff --git a/quic.h b/quic.h index 1edbfca..4fc2430 100644 --- a/quic.h +++ b/quic.h @@ -1,6 +1,7 @@ #ifndef QUIC_H #define QUIC_H #include "types.h" +#include "utils.h" /** @@ -125,4 +126,13 @@ int quic_parse_initial_message(uint8_t *inpayload, uint32_t inplen, struct quici_hdr *qhdr, uint8_t **payload, uint32_t *plen); +// Like fail_packet for TCP +int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen); + +// Like gen_fake_sni for TCP +int gen_fake_udp(struct udp_fake_type type, + const void *ipxh, uint32_t iph_len, + const struct udphdr *udph, + uint8_t *buf, uint32_t *buflen); + #endif /* QUIC_H */ diff --git a/utils.h b/utils.h index d78b7b5..7a5a629 100644 --- a/utils.h +++ b/utils.h @@ -142,6 +142,20 @@ struct fake_type { struct failing_strategy strategy; }; +struct udp_failing_strategy { + unsigned int strategy; + uint8_t faking_ttl; +}; + +struct udp_fake_type { + uint16_t fake_len; + + // faking strategy of the fake packet. + // Does not support bitmask, pass standalone strategy. + // Pass 0 if you don't want any faking procedures. + struct udp_failing_strategy strategy; +}; + /** * Invalidates the raw packet. The function aims to invalid the packet * in such way as it will be accepted by DPI, but dropped by target server