mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2024-12-22 14:26:11 +00:00
Add initial support for QUIC, improve logging capabilities.
Add TRACE logging mode
This commit is contained in:
parent
4a8f0d18a9
commit
f3db464b97
24
args.c
24
args.c
@ -32,10 +32,11 @@ struct config_t config = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
.verbose = true,
|
.verbose = 1,
|
||||||
#else
|
#else
|
||||||
.verbose = false,
|
.verbose = 0,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.domains_str = defaul_snistr,
|
.domains_str = defaul_snistr,
|
||||||
.domains_strlen = sizeof(defaul_snistr),
|
.domains_strlen = sizeof(defaul_snistr),
|
||||||
|
|
||||||
@ -53,13 +54,15 @@ struct config_t config = {
|
|||||||
#define OPT_FRAG_SNI_REVERSE 12
|
#define OPT_FRAG_SNI_REVERSE 12
|
||||||
#define OPT_FRAG_SNI_FAKED 13
|
#define OPT_FRAG_SNI_FAKED 13
|
||||||
#define OPT_FK_WINSIZE 14
|
#define OPT_FK_WINSIZE 14
|
||||||
|
#define OPT_TRACE 15
|
||||||
|
#define OPT_QUIC_DROP 16
|
||||||
#define OPT_SEG2DELAY 5
|
#define OPT_SEG2DELAY 5
|
||||||
#define OPT_THREADS 6
|
#define OPT_THREADS 6
|
||||||
#define OPT_SILENT 7
|
#define OPT_SILENT 7
|
||||||
#define OPT_NO_GSO 8
|
#define OPT_NO_GSO 8
|
||||||
#define OPT_QUEUE_NUM 9
|
#define OPT_QUEUE_NUM 9
|
||||||
|
|
||||||
#define OPT_MAX OPT_FRAG_SNI_FAKED
|
#define OPT_MAX OPT_QUIC_DROP
|
||||||
|
|
||||||
static struct option long_opt[] = {
|
static struct option long_opt[] = {
|
||||||
{"help", 0, 0, 'h'},
|
{"help", 0, 0, 'h'},
|
||||||
@ -73,9 +76,11 @@ static struct option long_opt[] = {
|
|||||||
{"frag-sni-reverse", 1, 0, OPT_FRAG_SNI_REVERSE},
|
{"frag-sni-reverse", 1, 0, OPT_FRAG_SNI_REVERSE},
|
||||||
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
|
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
|
||||||
{"fk-winsize", 1, 0, OPT_FK_WINSIZE},
|
{"fk-winsize", 1, 0, OPT_FK_WINSIZE},
|
||||||
|
{"quic-drop", 0, 0, OPT_QUIC_DROP},
|
||||||
{"seg2delay", 1, 0, OPT_SEG2DELAY},
|
{"seg2delay", 1, 0, OPT_SEG2DELAY},
|
||||||
{"threads", 1, 0, OPT_THREADS},
|
{"threads", 1, 0, OPT_THREADS},
|
||||||
{"silent", 0, 0, OPT_SILENT},
|
{"silent", 0, 0, OPT_SILENT},
|
||||||
|
{"trace", 0, 0, OPT_TRACE},
|
||||||
{"no-gso", 0, 0, OPT_NO_GSO},
|
{"no-gso", 0, 0, OPT_NO_GSO},
|
||||||
{"queue-num", 1, 0, OPT_QUEUE_NUM},
|
{"queue-num", 1, 0, OPT_QUEUE_NUM},
|
||||||
{0,0,0,0}
|
{0,0,0,0}
|
||||||
@ -120,9 +125,11 @@ void print_usage(const char *argv0) {
|
|||||||
printf("\t--frag-sni-reverse={0|1}\n");
|
printf("\t--frag-sni-reverse={0|1}\n");
|
||||||
printf("\t--frag-sni-faked={0|1}\n");
|
printf("\t--frag-sni-faked={0|1}\n");
|
||||||
printf("\t--fk-winsize=<winsize>\n");
|
printf("\t--fk-winsize=<winsize>\n");
|
||||||
|
printf("\t--quic-drop\n");
|
||||||
printf("\t--seg2delay=<delay>\n");
|
printf("\t--seg2delay=<delay>\n");
|
||||||
printf("\t--threads=<threads number>\n");
|
printf("\t--threads=<threads number>\n");
|
||||||
printf("\t--silent\n");
|
printf("\t--silent\n");
|
||||||
|
printf("\t--trace\n");
|
||||||
printf("\t--no-gso\n");
|
printf("\t--no-gso\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
@ -140,12 +147,18 @@ int parse_args(int argc, char *argv[]) {
|
|||||||
case 'v':
|
case 'v':
|
||||||
print_version();
|
print_version();
|
||||||
goto stop_exec;
|
goto stop_exec;
|
||||||
|
case OPT_TRACE:
|
||||||
|
config.verbose = 2;
|
||||||
|
break;
|
||||||
case OPT_SILENT:
|
case OPT_SILENT:
|
||||||
config.verbose = 0;
|
config.verbose = 0;
|
||||||
break;
|
break;
|
||||||
case OPT_NO_GSO:
|
case OPT_NO_GSO:
|
||||||
config.use_gso = 0;
|
config.use_gso = 0;
|
||||||
break;
|
break;
|
||||||
|
case OPT_QUIC_DROP:
|
||||||
|
config.quic_drop = 1;
|
||||||
|
break;
|
||||||
case OPT_SNI_DOMAINS:
|
case OPT_SNI_DOMAINS:
|
||||||
if (!strcmp(optarg, "all")) {
|
if (!strcmp(optarg, "all")) {
|
||||||
config.all_domains = 1;
|
config.all_domains = 1;
|
||||||
@ -329,7 +342,12 @@ void print_welcome() {
|
|||||||
printf("GSO is enabled\n");
|
printf("GSO is enabled\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.quic_drop) {
|
||||||
|
printf("All QUIC packets will be dropped\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (config.all_domains) {
|
if (config.all_domains) {
|
||||||
printf("All Client Hello will be targetted by youtubeUnblock!\n");
|
printf("All Client Hello will be targetted by youtubeUnblock!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
4
config.h
4
config.h
@ -25,7 +25,11 @@ struct config_t {
|
|||||||
unsigned char faking_ttl;
|
unsigned char faking_ttl;
|
||||||
int fake_sni;
|
int fake_sni;
|
||||||
unsigned int fake_sni_seq_len;
|
unsigned int fake_sni_seq_len;
|
||||||
|
#define VERBOSE_INFO 0
|
||||||
|
#define VERBOSE_DEBUG 1
|
||||||
|
#define VERBOSE_TRACE 2
|
||||||
int verbose;
|
int verbose;
|
||||||
|
int quic_drop;
|
||||||
/* In milliseconds */
|
/* In milliseconds */
|
||||||
unsigned int seg2_delay;
|
unsigned int seg2_delay;
|
||||||
const char *domains_str;
|
const char *domains_str;
|
||||||
|
39
logging.h
Normal file
39
logging.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef LOGGING_H
|
||||||
|
#define LOGGING_H
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define LOG_LEVEL (config.verbose)
|
||||||
|
|
||||||
|
#ifdef KERNEL_SPACE
|
||||||
|
#include <linux/printk.h>
|
||||||
|
#define printf pr_info
|
||||||
|
#define perror pr_err
|
||||||
|
#define lgerror(msg, ret, ...) __extension__ ({ \
|
||||||
|
printf(msg ": %d\n", ##__VA_ARGS__, ret); \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#include <stdio.h> // IWYU pragma: export
|
||||||
|
#include <errno.h>
|
||||||
|
#define lgerror(msg, ret, ...) __extension__ ({ \
|
||||||
|
errno = -(ret); \
|
||||||
|
printf(msg ": %s\n", ##__VA_ARGS__, strerror(errno)); \
|
||||||
|
})
|
||||||
|
#endif /* PROGRAM_SPACE */
|
||||||
|
|
||||||
|
|
||||||
|
#define lgdebugmsg(msg, ...) \
|
||||||
|
(LOG_LEVEL >= VERBOSE_DEBUG ? printf(msg "\n", ##__VA_ARGS__) : 0)
|
||||||
|
|
||||||
|
#define lgtracemsg(msg, ...) \
|
||||||
|
(LOG_LEVEL >= VERBOSE_TRACE ? printf(msg "\n", ##__VA_ARGS__) : 0)
|
||||||
|
|
||||||
|
#define lgtrace_start(msg, ...) \
|
||||||
|
(LOG_LEVEL >= VERBOSE_TRACE ? printf("[TRACE] " msg " ( ", ##__VA_ARGS__) : 0)
|
||||||
|
|
||||||
|
#define lgtrace_addp(msg, ...) \
|
||||||
|
(LOG_LEVEL >= VERBOSE_TRACE ? printf(msg", ", ##__VA_ARGS__) : 0)
|
||||||
|
|
||||||
|
#define lgtrace_end() \
|
||||||
|
(LOG_LEVEL >= VERBOSE_TRACE ? printf(") \n") : 0)
|
||||||
|
|
||||||
|
#endif /* LOGGING_H */
|
397
mangle.c
397
mangle.c
@ -2,22 +2,50 @@
|
|||||||
#include "types.h" // IWYU pragma: keep
|
#include "types.h" // IWYU pragma: keep
|
||||||
#include "mangle.h"
|
#include "mangle.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "quic.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
#ifdef KERNEL_SPACE
|
#ifndef KERNEL_SCOPE
|
||||||
#include <linux/ip.h>
|
|
||||||
|
|
||||||
#else
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
|
|
||||||
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
|
int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
|
||||||
if (raw_payload_len > MAX_PACKET_SIZE) {
|
if (raw_payload_len > MAX_PACKET_SIZE) {
|
||||||
return PKT_ACCEPT;
|
return PKT_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct iphdr *iph;
|
||||||
|
uint32_t iph_len;
|
||||||
|
const uint8_t *ip_payload;
|
||||||
|
uint32_t ip_payload_len;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ip4_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
||||||
|
(struct iphdr **)&iph, &iph_len,
|
||||||
|
(uint8_t **)&ip_payload, &ip_payload_len);
|
||||||
|
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto accept;
|
||||||
|
|
||||||
|
switch (iph->protocol) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
return process_tcp4_packet(raw_payload, raw_payload_len);
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
return process_udp4_packet(raw_payload, raw_payload_len);
|
||||||
|
default:
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept:
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
drop:
|
||||||
|
return PKT_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_tcp4_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
|
||||||
const struct iphdr *iph;
|
const struct iphdr *iph;
|
||||||
uint32_t iph_len;
|
uint32_t iph_len;
|
||||||
const struct tcphdr *tcph;
|
const struct tcphdr *tcph;
|
||||||
@ -36,8 +64,7 @@ int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
|
|||||||
struct tls_verdict vrd = analyze_tls_data(data, dlen);
|
struct tls_verdict vrd = analyze_tls_data(data, dlen);
|
||||||
|
|
||||||
if (vrd.target_sni) {
|
if (vrd.target_sni) {
|
||||||
if (config.verbose)
|
lgdebugmsg("Target SNI detected: %.*s", vrd.sni_len, data + vrd.sni_offset);
|
||||||
printf("Target SNI detected: %.*s\n", vrd.sni_len, data + vrd.sni_offset);
|
|
||||||
|
|
||||||
uint8_t payload[MAX_PACKET_SIZE];
|
uint8_t payload[MAX_PACKET_SIZE];
|
||||||
uint32_t payload_len = raw_payload_len;
|
uint32_t payload_len = raw_payload_len;
|
||||||
@ -63,7 +90,7 @@ int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
|
|||||||
|
|
||||||
|
|
||||||
if (dlen > 1480 && config.verbose) {
|
if (dlen > 1480 && config.verbose) {
|
||||||
printf("WARNING! Client Hello packet is too big and may cause issues!\n");
|
lgdebugmsg("WARNING! Client Hello packet is too big and may cause issues!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.fake_sni) {
|
if (config.fake_sni) {
|
||||||
@ -126,6 +153,79 @@ drop:
|
|||||||
return PKT_DROP;
|
return PKT_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int process_udp4_packet(const uint8_t *pkt, uint32_t pktlen) {
|
||||||
|
const struct iphdr *iph;
|
||||||
|
uint32_t iph_len;
|
||||||
|
const struct udphdr *udph;
|
||||||
|
const uint8_t *data;
|
||||||
|
uint32_t dlen;
|
||||||
|
|
||||||
|
int ret = udp4_payload_split((uint8_t *)pkt, pktlen,
|
||||||
|
(struct iphdr **)&iph, &iph_len,
|
||||||
|
(struct udphdr **)&udph,
|
||||||
|
(uint8_t **)&data, &dlen);
|
||||||
|
|
||||||
|
lgtrace_start("Got udp packet");
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
lgtrace_addp("undefined");
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dlen > 10 && config.verbose >= VERBOSE_TRACE) {
|
||||||
|
printf("UDP payload start: [ ");
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
printf("%02x ", data[i]);
|
||||||
|
}
|
||||||
|
printf("], ");
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_addp("QUIC probe");
|
||||||
|
const struct quic_lhdr *qch;
|
||||||
|
uint32_t qch_len;
|
||||||
|
struct quic_cids qci;
|
||||||
|
uint8_t *quic_raw_payload;
|
||||||
|
uint32_t quic_raw_plen;
|
||||||
|
ret = quic_parse_data((uint8_t *)data, dlen,
|
||||||
|
(struct quic_lhdr **)&qch, &qch_len, &qci,
|
||||||
|
&quic_raw_payload, &quic_raw_plen);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
lgtrace_addp("undefined type");
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_addp("QUIC detected");
|
||||||
|
uint8_t qtype = qch->type;
|
||||||
|
|
||||||
|
if (config.quic_drop) {
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qch->version == QUIC_V1)
|
||||||
|
qtype = quic_convtype_v1(qtype);
|
||||||
|
else if (qch->version == QUIC_V2)
|
||||||
|
qtype = quic_convtype_v2(qtype);
|
||||||
|
|
||||||
|
if (qtype != QUIC_INITIAL_TYPE) {
|
||||||
|
lgtrace_addp("quic message type: %d", qtype);
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_addp("quic initial message");
|
||||||
|
|
||||||
|
accept:
|
||||||
|
lgtrace_addp("accepted");
|
||||||
|
lgtrace_end();
|
||||||
|
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
drop:
|
||||||
|
lgtrace_addp("dropped");
|
||||||
|
lgtrace_end();
|
||||||
|
|
||||||
|
return PKT_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
int send_ip4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *poses, uint32_t poses_sz, uint32_t dvs) {
|
int send_ip4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *poses, uint32_t poses_sz, uint32_t dvs) {
|
||||||
if (poses_sz == 0) {
|
if (poses_sz == 0) {
|
||||||
if (config.seg2_delay && ((dvs > 0) ^ config.frag_sni_reverse)) {
|
if (config.seg2_delay && ((dvs > 0) ^ config.frag_sni_reverse)) {
|
||||||
@ -150,7 +250,7 @@ int send_ip4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *poses
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (dvs > poses[0]) {
|
if (dvs > poses[0]) {
|
||||||
printf("send_frags: Recursive dvs(%d) is more than poses0(%d)\n", dvs, poses[0]);
|
lgerror("send_frags: Recursive dvs(%d) is more than poses0(%d)", -EINVAL, dvs, poses[0]);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,8 +258,7 @@ int send_ip4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *poses
|
|||||||
frag1, &f1len, frag2, &f2len);
|
frag1, &f1len, frag2, &f2len);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
lgerror("send_frags: frag", ret);
|
lgerror("send_frags: frag: with context packet with size %d, position: %d, recursive dvs: %d", ret, pktlen, poses[0], dvs);
|
||||||
printf("Error context: packet with size %d, position: %d, recursive dvs: %d\n", pktlen, poses[0], dvs);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +313,7 @@ int send_tcp4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *pose
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (dvs > poses[0]) {
|
if (dvs > poses[0]) {
|
||||||
printf("send_frags: Recursive dvs(%d) is more than poses0(%d)\n", dvs, poses[0]);
|
lgerror("send_frags: Recursive dvs(%d) is more than poses0(%d)", -EINVAL, dvs, poses[0]);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,8 +321,7 @@ int send_tcp4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *pose
|
|||||||
frag1, &f1len, frag2, &f2len);
|
frag1, &f1len, frag2, &f2len);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
lgerror("send_frags: frag", ret);
|
lgerror("send_frags: frag: with context packet with size %d, position: %d, recursive dvs: %d", ret, pktlen, poses[0], dvs);
|
||||||
printf("Error context: packet with size %d, position: %d, recursive dvs: %d\n", pktlen, poses[0], dvs);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,269 +428,7 @@ int post_fake_sni(const struct iphdr *iph, unsigned int iph_len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
|
|
||||||
{
|
|
||||||
#ifdef KERNEL_SPACE
|
|
||||||
uint32_t tcp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
|
|
||||||
tcph->check = 0;
|
|
||||||
tcph->check = csum_tcpudp_magic(
|
|
||||||
iph->saddr, iph->daddr, tcp_packet_len,
|
|
||||||
IPPROTO_TCP,
|
|
||||||
csum_partial(tcph, tcp_packet_len, 0));
|
|
||||||
#else
|
|
||||||
nfq_tcp_compute_checksum_ipv4(tcph, iph);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ip4_set_checksum(struct iphdr *iph)
|
|
||||||
{
|
|
||||||
#ifdef KERNEL_SPACE
|
|
||||||
iph->check = 0;
|
|
||||||
iph->check = ip_fast_csum(iph, iph->ihl);
|
|
||||||
#else
|
|
||||||
nfq_ip_set_checksum(iph);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
|
|
||||||
struct iphdr **iph, uint32_t *iph_len,
|
|
||||||
uint8_t **payload, uint32_t *plen) {
|
|
||||||
if (pkt == NULL || buflen < sizeof(struct iphdr)) {
|
|
||||||
lgerror("ip4_payload_split: pkt|buflen", -EINVAL);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iphdr *hdr = (struct iphdr *)pkt;
|
|
||||||
if (hdr->version != IPVERSION) {
|
|
||||||
lgerror("ip4_payload_split: ipversion", -EINVAL);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t hdr_len = hdr->ihl * 4;
|
|
||||||
uint32_t pktlen = ntohs(hdr->tot_len);
|
|
||||||
if (buflen < pktlen || hdr_len > pktlen) {
|
|
||||||
lgerror("ip4_payload_split: buflen cmp pktlen", -EINVAL);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iph)
|
|
||||||
*iph = hdr;
|
|
||||||
if (iph_len)
|
|
||||||
*iph_len = hdr_len;
|
|
||||||
if (payload)
|
|
||||||
*payload = pkt + hdr_len;
|
|
||||||
if (plen)
|
|
||||||
*plen = pktlen - hdr_len;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
|
|
||||||
struct iphdr **iph, uint32_t *iph_len,
|
|
||||||
struct tcphdr **tcph, uint32_t *tcph_len,
|
|
||||||
uint8_t **payload, uint32_t *plen) {
|
|
||||||
struct iphdr *hdr;
|
|
||||||
uint32_t hdr_len;
|
|
||||||
struct tcphdr *thdr;
|
|
||||||
uint32_t thdr_len;
|
|
||||||
|
|
||||||
uint8_t *tcph_pl;
|
|
||||||
uint32_t tcph_plen;
|
|
||||||
|
|
||||||
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
|
|
||||||
&tcph_pl, &tcph_plen)){
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
hdr->protocol != IPPROTO_TCP ||
|
|
||||||
tcph_plen < sizeof(struct tcphdr)) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
thdr = (struct tcphdr *)(tcph_pl);
|
|
||||||
thdr_len = thdr->doff * 4;
|
|
||||||
|
|
||||||
if (thdr_len > tcph_plen) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iph) *iph = hdr;
|
|
||||||
if (iph_len) *iph_len = hdr_len;
|
|
||||||
if (tcph) *tcph = thdr;
|
|
||||||
if (tcph_len) *tcph_len = thdr_len;
|
|
||||||
if (payload) *payload = tcph_pl + thdr_len;
|
|
||||||
if (plen) *plen = tcph_plen - thdr_len;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// split packet to two ipv4 fragments.
|
|
||||||
int ip4_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
|
|
||||||
uint8_t *frag1, uint32_t *f1len,
|
|
||||||
uint8_t *frag2, uint32_t *f2len) {
|
|
||||||
|
|
||||||
struct iphdr *hdr;
|
|
||||||
const uint8_t *payload;
|
|
||||||
uint32_t plen;
|
|
||||||
uint32_t hdr_len;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!frag1 || !f1len || !frag2 || !f2len)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((ret = ip4_payload_split(
|
|
||||||
(uint8_t *)pkt, buflen,
|
|
||||||
&hdr, &hdr_len, (uint8_t **)&payload, &plen)) < 0) {
|
|
||||||
lgerror("ipv4_frag: TCP Header extract error", ret);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plen <= payload_offset) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (payload_offset & ((1 << 3) - 1)) {
|
|
||||||
lgerror("ipv4_frag: Payload offset MUST be a multiply of 8!", -EINVAL);
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t f1_plen = payload_offset;
|
|
||||||
uint32_t f1_dlen = f1_plen + hdr_len;
|
|
||||||
|
|
||||||
uint32_t f2_plen = plen - payload_offset;
|
|
||||||
uint32_t f2_dlen = f2_plen + hdr_len;
|
|
||||||
|
|
||||||
if (*f1len < f1_dlen || *f2len < f2_dlen) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
*f1len = f1_dlen;
|
|
||||||
*f2len = f2_dlen;
|
|
||||||
|
|
||||||
memcpy(frag1, hdr, hdr_len);
|
|
||||||
memcpy(frag2, hdr, hdr_len);
|
|
||||||
|
|
||||||
memcpy(frag1 + hdr_len, payload, f1_plen);
|
|
||||||
memcpy(frag2 + hdr_len, payload + payload_offset, f2_plen);
|
|
||||||
|
|
||||||
struct iphdr *f1_hdr = (void *)frag1;
|
|
||||||
struct iphdr *f2_hdr = (void *)frag2;
|
|
||||||
|
|
||||||
uint16_t f1_frag_off = ntohs(f1_hdr->frag_off);
|
|
||||||
uint16_t f2_frag_off = ntohs(f2_hdr->frag_off);
|
|
||||||
|
|
||||||
f1_frag_off &= IP_OFFMASK;
|
|
||||||
f1_frag_off |= IP_MF;
|
|
||||||
|
|
||||||
if ((f2_frag_off & ~IP_OFFMASK) == IP_MF) {
|
|
||||||
f2_frag_off &= IP_OFFMASK;
|
|
||||||
f2_frag_off |= IP_MF;
|
|
||||||
} else {
|
|
||||||
f2_frag_off &= IP_OFFMASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
f2_frag_off += (uint16_t)payload_offset / 8;
|
|
||||||
|
|
||||||
f1_hdr->frag_off = htons(f1_frag_off);
|
|
||||||
f1_hdr->tot_len = htons(f1_dlen);
|
|
||||||
|
|
||||||
f2_hdr->frag_off = htons(f2_frag_off);
|
|
||||||
f2_hdr->tot_len = htons(f2_dlen);
|
|
||||||
|
|
||||||
|
|
||||||
if (config.verbose)
|
|
||||||
printf("Packet split in portion %u %u\n", f1_plen, f2_plen);
|
|
||||||
|
|
||||||
ip4_set_checksum(f1_hdr);
|
|
||||||
ip4_set_checksum(f2_hdr);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// split packet to two tcp-on-ipv4 segments.
|
|
||||||
int tcp4_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
|
|
||||||
uint8_t *seg1, uint32_t *s1len,
|
|
||||||
uint8_t *seg2, uint32_t *s2len) {
|
|
||||||
|
|
||||||
struct iphdr *hdr;
|
|
||||||
uint32_t hdr_len;
|
|
||||||
struct tcphdr *tcph;
|
|
||||||
uint32_t tcph_len;
|
|
||||||
uint32_t plen;
|
|
||||||
const uint8_t *payload;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!seg1 || !s1len || !seg2 || !s2len)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((ret = tcp4_payload_split((uint8_t *)pkt, buflen,
|
|
||||||
&hdr, &hdr_len,
|
|
||||||
&tcph, &tcph_len,
|
|
||||||
(uint8_t **)&payload, &plen)) < 0) {
|
|
||||||
lgerror("tcp4_frag: tcp4_payload_split", ret);
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
ntohs(hdr->frag_off) & IP_MF ||
|
|
||||||
ntohs(hdr->frag_off) & IP_OFFMASK) {
|
|
||||||
printf("tcp4_frag: frag value: %d\n",
|
|
||||||
ntohs(hdr->frag_off));
|
|
||||||
lgerror("tcp4_frag: ip fragmentation is set", -EINVAL);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (plen <= payload_offset) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t s1_plen = payload_offset;
|
|
||||||
uint32_t s1_dlen = s1_plen + hdr_len + tcph_len;
|
|
||||||
|
|
||||||
uint32_t s2_plen = plen - payload_offset;
|
|
||||||
uint32_t s2_dlen = s2_plen + hdr_len + tcph_len;
|
|
||||||
|
|
||||||
if (*s1len < s1_dlen || *s2len < s2_dlen)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
*s1len = s1_dlen;
|
|
||||||
*s2len = s2_dlen;
|
|
||||||
|
|
||||||
memcpy(seg1, hdr, hdr_len);
|
|
||||||
memcpy(seg2, hdr, hdr_len);
|
|
||||||
|
|
||||||
memcpy(seg1 + hdr_len, tcph, tcph_len);
|
|
||||||
memcpy(seg2 + hdr_len, tcph, tcph_len);
|
|
||||||
|
|
||||||
memcpy(seg1 + hdr_len + tcph_len, payload, s1_plen);
|
|
||||||
memcpy(seg2 + hdr_len + tcph_len, payload + payload_offset, s2_plen);
|
|
||||||
|
|
||||||
struct iphdr *s1_hdr = (void *)seg1;
|
|
||||||
struct iphdr *s2_hdr = (void *)seg2;
|
|
||||||
|
|
||||||
struct tcphdr *s1_tcph = (void *)(seg1 + hdr_len);
|
|
||||||
struct tcphdr *s2_tcph = (void *)(seg2 + hdr_len);
|
|
||||||
|
|
||||||
s1_hdr->tot_len = htons(s1_dlen);
|
|
||||||
s2_hdr->tot_len = htons(s2_dlen);
|
|
||||||
|
|
||||||
s2_tcph->seq = htonl(ntohl(s2_tcph->seq) + payload_offset);
|
|
||||||
|
|
||||||
if (config.verbose)
|
|
||||||
printf("Packet split in portion %u %u\n", s1_plen, s2_plen);
|
|
||||||
|
|
||||||
tcp4_set_checksum(s1_tcph, s1_hdr);
|
|
||||||
tcp4_set_checksum(s2_tcph, s2_hdr);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
|
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
|
||||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
||||||
@ -807,8 +643,13 @@ int fail4_packet(uint8_t *payload, uint32_t plen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.faking_strategy == FAKE_STRAT_ACK_SEQ) {
|
if (config.faking_strategy == FAKE_STRAT_ACK_SEQ) {
|
||||||
|
#ifdef KERNEL_SCOPE
|
||||||
|
tcph->seq = 124;
|
||||||
|
tcph->ack_seq = 124;
|
||||||
|
#else
|
||||||
tcph->seq = random();
|
tcph->seq = random();
|
||||||
tcph->ack_seq = random();
|
tcph->ack_seq = random();
|
||||||
|
#endif
|
||||||
} else if (config.faking_strategy == FAKE_STRAT_TTL) {
|
} else if (config.faking_strategy == FAKE_STRAT_TTL) {
|
||||||
iph->ttl = config.faking_ttl;
|
iph->ttl = config.faking_ttl;
|
||||||
}
|
}
|
||||||
|
74
mangle.h
74
mangle.h
@ -3,30 +3,6 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#ifdef KERNEL_SPACE
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/stddef.h>
|
|
||||||
#include <linux/net.h>
|
|
||||||
#include <linux/in.h>
|
|
||||||
#include <linux/ip.h>
|
|
||||||
#include <linux/tcp.h>
|
|
||||||
|
|
||||||
#include <asm/byteorder.h>
|
|
||||||
|
|
||||||
/* from <netinet/ip.h> */
|
|
||||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
|
||||||
#define IP_DF 0x4000 /* dont fragment flag */
|
|
||||||
#define IP_MF 0x2000 /* more fragments flag */
|
|
||||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
|
||||||
#else
|
|
||||||
#define USER_SPACE
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/ip.h>
|
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result of analyze_tls_data function
|
* Result of analyze_tls_data function
|
||||||
*/
|
*/
|
||||||
@ -42,42 +18,6 @@ struct tls_verdict {
|
|||||||
*/
|
*/
|
||||||
struct tls_verdict analyze_tls_data(const uint8_t *data, uint32_t dlen);
|
struct tls_verdict analyze_tls_data(const uint8_t *data, uint32_t dlen);
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits the packet to two IP fragments on position payload_offset.
|
|
||||||
* payload_offset indicates the position relatively to start of IP payload
|
|
||||||
* (start of transport header)
|
|
||||||
*/
|
|
||||||
int ip4_frag(const uint8_t *pkt, uint32_t pktlen,
|
|
||||||
uint32_t payload_offset,
|
|
||||||
uint8_t *frag1, uint32_t *f1len,
|
|
||||||
uint8_t *frag2, uint32_t *f2len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits the packet to two TCP segments on position payload_offset
|
|
||||||
* payload_offset indicates the position relatively to start of TCP payload.
|
|
||||||
*/
|
|
||||||
int tcp4_frag(const uint8_t *pkt, uint32_t pktlen,
|
|
||||||
uint32_t payload_offset,
|
|
||||||
uint8_t *seg1, uint32_t *s1len,
|
|
||||||
uint8_t *seg2, uint32_t *s2len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits the raw packet payload to ip header and ip payload.
|
|
||||||
*/
|
|
||||||
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
|
|
||||||
struct iphdr **iph, uint32_t *iph_len,
|
|
||||||
uint8_t **payload, uint32_t *plen);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits the raw packet payload to ip header, tcp header and tcp payload.
|
|
||||||
*/
|
|
||||||
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
|
|
||||||
struct iphdr **iph, uint32_t *iph_len,
|
|
||||||
struct tcphdr **tcph, uint32_t *tcph_len,
|
|
||||||
uint8_t **payload, uint32_t *plen);
|
|
||||||
|
|
||||||
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph);
|
|
||||||
void ip4_set_checksum(struct iphdr *iph);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates fake client hello message
|
* Generates fake client hello message
|
||||||
@ -100,6 +40,20 @@ int fail4_packet(uint8_t *payload, uint32_t plen);
|
|||||||
*/
|
*/
|
||||||
int process_packet(const uint8_t *packet, uint32_t packet_len);
|
int process_packet(const uint8_t *packet, uint32_t packet_len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processe the TCP packet.
|
||||||
|
* Returns verdict.
|
||||||
|
*/
|
||||||
|
int process_tcp4_packet(const uint8_t *raw_payload, uint32_t raw_payload_len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the UDP packet.
|
||||||
|
* Returns verdict.
|
||||||
|
*/
|
||||||
|
int process_udp4_packet(const uint8_t *pkt, uint32_t pktlen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends fake client hello.
|
* Sends fake client hello.
|
||||||
*/
|
*/
|
||||||
|
17
quic.c
17
quic.c
@ -1,9 +1,6 @@
|
|||||||
#include "quic.h"
|
#include "quic.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
static const uint32_t supported_versions[] = {
|
|
||||||
1, // version 1, RFC 9000
|
|
||||||
0x6b3343cf, // version 2, RFC 9369
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Packet number.
|
* Packet number.
|
||||||
@ -45,18 +42,24 @@ int quic_parse_data(uint8_t *raw_payload, uint32_t raw_payload_len,
|
|||||||
struct quic_lhdr *nqch = (struct quic_lhdr *)raw_payload;
|
struct quic_lhdr *nqch = (struct quic_lhdr *)raw_payload;
|
||||||
uint32_t left_len = raw_payload_len - sizeof(struct quic_lhdr);
|
uint32_t left_len = raw_payload_len - sizeof(struct quic_lhdr);
|
||||||
uint8_t *cur_rawptr = raw_payload + sizeof(struct quic_lhdr);
|
uint8_t *cur_rawptr = raw_payload + sizeof(struct quic_lhdr);
|
||||||
if (!nqch->fixed)
|
if (!nqch->fixed) {
|
||||||
|
lgtrace_addp("quic fixed uset");
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t found = 0;
|
uint8_t found = 0;
|
||||||
for (uint8_t i = 0; i < sizeof(supported_versions); i++) {
|
for (uint8_t i = 0; i < sizeof(supported_versions); i++) {
|
||||||
if (nqch->version == supported_versions[i]) {
|
if (ntohl(nqch->version) == supported_versions[i]) {
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found) {
|
||||||
|
lgtrace_addp("quic version undefined %d", ntohl(nqch->version));
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_addp("quic version valid %d", ntohl(nqch->version));
|
||||||
|
|
||||||
if (left_len < 2) goto invalid_packet;
|
if (left_len < 2) goto invalid_packet;
|
||||||
struct quic_cids nqci = {0};
|
struct quic_cids nqci = {0};
|
||||||
|
27
quic.h
27
quic.h
@ -2,6 +2,7 @@
|
|||||||
#define QUIC_H
|
#define QUIC_H
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
*
|
*
|
||||||
@ -22,15 +23,30 @@
|
|||||||
"\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb" \
|
"\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb" \
|
||||||
"\xf9\xbd\x2e\xd9"
|
"\xf9\xbd\x2e\xd9"
|
||||||
|
|
||||||
#define QUIC_INITIAL_TYPE_V1 0x00
|
#define QUIC_INITIAL_TYPE 0
|
||||||
#define QUIC_0_RTT_TYPE_V1 0x01
|
#define QUIC_0_RTT_TYPE 1
|
||||||
#define QUIC_HANDSHAKE_TYPE_V1 0x02
|
#define QUIC_HANDSHAKE_TYPE 2
|
||||||
#define QUIC_RETRY_TYPE_V1 0x03
|
#define QUIC_RETRY_TYPE 3
|
||||||
|
|
||||||
|
#define QUIC_INITIAL_TYPE_V1 0b00
|
||||||
|
#define QUIC_0_RTT_TYPE_V1 0b01
|
||||||
|
#define QUIC_HANDSHAKE_TYPE_V1 0b10
|
||||||
|
#define QUIC_RETRY_TYPE_V1 0b11
|
||||||
|
#define quic_convtype_v1(type) (type)
|
||||||
|
|
||||||
#define QUIC_INITIAL_TYPE_V2 0b01
|
#define QUIC_INITIAL_TYPE_V2 0b01
|
||||||
#define QUIC_0_RTT_TYPE_V2 0b10
|
#define QUIC_0_RTT_TYPE_V2 0b10
|
||||||
#define QUIC_HANDSHAKE_TYPE_V2 0b11
|
#define QUIC_HANDSHAKE_TYPE_V2 0b11
|
||||||
#define QUIC_RETRY_TYPE_V2 0b00
|
#define QUIC_RETRY_TYPE_V2 0b00
|
||||||
|
#define quic_convtype_v2(type) (((type) + 1) & 0b11)
|
||||||
|
|
||||||
|
#define QUIC_V1 1 // RFC 9000
|
||||||
|
#define QUIC_V2 0x6b3343cf // RFC 9369
|
||||||
|
|
||||||
|
static const uint32_t supported_versions[] = {
|
||||||
|
QUIC_V1,
|
||||||
|
QUIC_V2,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quic Large Header
|
* Quic Large Header
|
||||||
@ -51,9 +67,8 @@ struct quic_lhdr {
|
|||||||
#else
|
#else
|
||||||
#error "Undefined endian"
|
#error "Undefined endian"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
};
|
}__attribute__((packed));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quic Large Header Ids
|
* Quic Large Header Ids
|
||||||
|
31
types.h
31
types.h
@ -15,22 +15,33 @@ typedef __i8 int8_t;
|
|||||||
typedef __i16 int16_t;
|
typedef __i16 int16_t;
|
||||||
typedef __i32 int32_t;
|
typedef __i32 int32_t;
|
||||||
typedef __i64 int64_t;
|
typedef __i64 int64_t;
|
||||||
|
|
||||||
#include <linux/printk.h>
|
|
||||||
#define printf pr_info
|
|
||||||
#define perror pr_err
|
|
||||||
#define lgerror(msg, ret) (pr_err(msg ": %d\n", ret))
|
|
||||||
|
|
||||||
#else /* USERSPACE_SCOPE */
|
#else /* USERSPACE_SCOPE */
|
||||||
|
|
||||||
#include <errno.h> // IWYU pragma: export
|
#include <errno.h> // IWYU pragma: export
|
||||||
#include <stdint.h> // IWYU pragma: export
|
#include <stdint.h> // IWYU pragma: export
|
||||||
#include <string.h> // IWYU pragma: export
|
#include <string.h> // IWYU pragma: export
|
||||||
|
|
||||||
#include <stdio.h> // IWYU pragma: export
|
|
||||||
#define lgerror(msg, ret) __extension__ ({errno = -ret; perror(msg);})
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SCOPES */
|
#endif /* SCOPES */
|
||||||
|
|
||||||
|
// Network specific structures
|
||||||
|
#ifdef KERNEL_SPACE
|
||||||
|
#include <linux/stddef.h> // IWYU pragma: export
|
||||||
|
#include <linux/net.h> // IWYU pragma: export
|
||||||
|
#include <linux/in.h> // IWYU pragma: export
|
||||||
|
#include <linux/ip.h> // IWYU pragma: export
|
||||||
|
#include <linux/tcp.h> // IWYU pragma: export
|
||||||
|
|
||||||
|
/* from <netinet/ip.h> */
|
||||||
|
#define IP_RF 0x8000 /* reserved fragment flag */
|
||||||
|
#define IP_DF 0x4000 /* dont fragment flag */
|
||||||
|
#define IP_MF 0x2000 /* more fragments flag */
|
||||||
|
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||||
|
#else
|
||||||
|
#define USER_SPACE
|
||||||
|
#include <arpa/inet.h> // IWYU pragma: export
|
||||||
|
#include <netinet/ip.h> // IWYU pragma: export
|
||||||
|
#include <netinet/tcp.h> // IWYU pragma: export
|
||||||
|
#include <netinet/udp.h> // IWYU pragma: export
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* TYPES_H */
|
#endif /* TYPES_H */
|
||||||
|
@ -22,7 +22,7 @@ export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CF
|
|||||||
|
|
||||||
APP:=$(BUILD_DIR)/youtubeUnblock
|
APP:=$(BUILD_DIR)/youtubeUnblock
|
||||||
|
|
||||||
SRCS := youtubeUnblock.c mangle.c args.c
|
SRCS := youtubeUnblock.c mangle.c args.c utils.c quic.c
|
||||||
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
||||||
|
|
||||||
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a
|
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a
|
||||||
|
312
utils.c
Normal file
312
utils.c
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
#include "utils.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#ifdef KERNEL_SPACE
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#else
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
|
||||||
|
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
|
||||||
|
{
|
||||||
|
#ifdef KERNEL_SPACE
|
||||||
|
uint32_t tcp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
|
||||||
|
tcph->check = 0;
|
||||||
|
tcph->check = csum_tcpudp_magic(
|
||||||
|
iph->saddr, iph->daddr, tcp_packet_len,
|
||||||
|
IPPROTO_TCP,
|
||||||
|
csum_partial(tcph, tcp_packet_len, 0));
|
||||||
|
#else
|
||||||
|
nfq_tcp_compute_checksum_ipv4(tcph, iph);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ip4_set_checksum(struct iphdr *iph)
|
||||||
|
{
|
||||||
|
#ifdef KERNEL_SPACE
|
||||||
|
iph->check = 0;
|
||||||
|
iph->check = ip_fast_csum(iph, iph->ihl);
|
||||||
|
#else
|
||||||
|
nfq_ip_set_checksum(iph);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||||
|
struct iphdr **iph, uint32_t *iph_len,
|
||||||
|
uint8_t **payload, uint32_t *plen) {
|
||||||
|
if (pkt == NULL || buflen < sizeof(struct iphdr)) {
|
||||||
|
lgerror("ip4_payload_split: pkt|buflen", -EINVAL);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iphdr *hdr = (struct iphdr *)pkt;
|
||||||
|
if (hdr->version != IPVERSION) {
|
||||||
|
lgerror("ip4_payload_split: ipversion", -EINVAL);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hdr_len = hdr->ihl * 4;
|
||||||
|
uint32_t pktlen = ntohs(hdr->tot_len);
|
||||||
|
if (buflen < pktlen || hdr_len > pktlen) {
|
||||||
|
lgerror("ip4_payload_split: buflen cmp pktlen", -EINVAL);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iph)
|
||||||
|
*iph = hdr;
|
||||||
|
if (iph_len)
|
||||||
|
*iph_len = hdr_len;
|
||||||
|
if (payload)
|
||||||
|
*payload = pkt + hdr_len;
|
||||||
|
if (plen)
|
||||||
|
*plen = pktlen - hdr_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||||
|
struct iphdr **iph, uint32_t *iph_len,
|
||||||
|
struct tcphdr **tcph, uint32_t *tcph_len,
|
||||||
|
uint8_t **payload, uint32_t *plen) {
|
||||||
|
struct iphdr *hdr;
|
||||||
|
uint32_t hdr_len;
|
||||||
|
struct tcphdr *thdr;
|
||||||
|
uint32_t thdr_len;
|
||||||
|
|
||||||
|
uint8_t *tcph_pl;
|
||||||
|
uint32_t tcph_plen;
|
||||||
|
|
||||||
|
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
|
||||||
|
&tcph_pl, &tcph_plen)){
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
hdr->protocol != IPPROTO_TCP ||
|
||||||
|
tcph_plen < sizeof(struct tcphdr)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
thdr = (struct tcphdr *)(tcph_pl);
|
||||||
|
thdr_len = thdr->doff * 4;
|
||||||
|
|
||||||
|
if (thdr_len > tcph_plen) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iph) *iph = hdr;
|
||||||
|
if (iph_len) *iph_len = hdr_len;
|
||||||
|
if (tcph) *tcph = thdr;
|
||||||
|
if (tcph_len) *tcph_len = thdr_len;
|
||||||
|
if (payload) *payload = tcph_pl + thdr_len;
|
||||||
|
if (plen) *plen = tcph_plen - thdr_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int udp4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||||
|
struct iphdr **iph, uint32_t *iph_len,
|
||||||
|
struct udphdr **udph,
|
||||||
|
uint8_t **payload, uint32_t *plen) {
|
||||||
|
struct iphdr *hdr;
|
||||||
|
uint32_t hdr_len;
|
||||||
|
struct udphdr *uhdr;
|
||||||
|
uint32_t uhdr_len;
|
||||||
|
|
||||||
|
uint8_t *ip_ph;
|
||||||
|
uint32_t ip_phlen;
|
||||||
|
|
||||||
|
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
|
||||||
|
&ip_ph, &ip_phlen)){
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
hdr->protocol != IPPROTO_UDP ||
|
||||||
|
ip_phlen < sizeof(struct udphdr)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uhdr = (struct udphdr *)(ip_ph);
|
||||||
|
if (uhdr->len != 0 && ntohs(uhdr->len) != ip_phlen) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iph) *iph = hdr;
|
||||||
|
if (iph_len) *iph_len = hdr_len;
|
||||||
|
if (udph) *udph = uhdr;
|
||||||
|
if (payload) *payload = ip_ph + sizeof(struct udphdr);
|
||||||
|
if (plen) *plen = ip_phlen - sizeof(struct udphdr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split packet to two ipv4 fragments.
|
||||||
|
int ip4_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
|
||||||
|
uint8_t *frag1, uint32_t *f1len,
|
||||||
|
uint8_t *frag2, uint32_t *f2len) {
|
||||||
|
|
||||||
|
struct iphdr *hdr;
|
||||||
|
const uint8_t *payload;
|
||||||
|
uint32_t plen;
|
||||||
|
uint32_t hdr_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!frag1 || !f1len || !frag2 || !f2len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if ((ret = ip4_payload_split(
|
||||||
|
(uint8_t *)pkt, buflen,
|
||||||
|
&hdr, &hdr_len, (uint8_t **)&payload, &plen)) < 0) {
|
||||||
|
lgerror("ipv4_frag: TCP Header extract error", ret);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plen <= payload_offset) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload_offset & ((1 << 3) - 1)) {
|
||||||
|
lgerror("ipv4_frag: Payload offset MUST be a multiply of 8!", -EINVAL);
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t f1_plen = payload_offset;
|
||||||
|
uint32_t f1_dlen = f1_plen + hdr_len;
|
||||||
|
|
||||||
|
uint32_t f2_plen = plen - payload_offset;
|
||||||
|
uint32_t f2_dlen = f2_plen + hdr_len;
|
||||||
|
|
||||||
|
if (*f1len < f1_dlen || *f2len < f2_dlen) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
*f1len = f1_dlen;
|
||||||
|
*f2len = f2_dlen;
|
||||||
|
|
||||||
|
memcpy(frag1, hdr, hdr_len);
|
||||||
|
memcpy(frag2, hdr, hdr_len);
|
||||||
|
|
||||||
|
memcpy(frag1 + hdr_len, payload, f1_plen);
|
||||||
|
memcpy(frag2 + hdr_len, payload + payload_offset, f2_plen);
|
||||||
|
|
||||||
|
struct iphdr *f1_hdr = (void *)frag1;
|
||||||
|
struct iphdr *f2_hdr = (void *)frag2;
|
||||||
|
|
||||||
|
uint16_t f1_frag_off = ntohs(f1_hdr->frag_off);
|
||||||
|
uint16_t f2_frag_off = ntohs(f2_hdr->frag_off);
|
||||||
|
|
||||||
|
f1_frag_off &= IP_OFFMASK;
|
||||||
|
f1_frag_off |= IP_MF;
|
||||||
|
|
||||||
|
if ((f2_frag_off & ~IP_OFFMASK) == IP_MF) {
|
||||||
|
f2_frag_off &= IP_OFFMASK;
|
||||||
|
f2_frag_off |= IP_MF;
|
||||||
|
} else {
|
||||||
|
f2_frag_off &= IP_OFFMASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
f2_frag_off += (uint16_t)payload_offset / 8;
|
||||||
|
|
||||||
|
f1_hdr->frag_off = htons(f1_frag_off);
|
||||||
|
f1_hdr->tot_len = htons(f1_dlen);
|
||||||
|
|
||||||
|
f2_hdr->frag_off = htons(f2_frag_off);
|
||||||
|
f2_hdr->tot_len = htons(f2_dlen);
|
||||||
|
|
||||||
|
|
||||||
|
lgdebugmsg("Packet split in portion %u %u", f1_plen, f2_plen);
|
||||||
|
|
||||||
|
ip4_set_checksum(f1_hdr);
|
||||||
|
ip4_set_checksum(f2_hdr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split packet to two tcp-on-ipv4 segments.
|
||||||
|
int tcp4_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
|
||||||
|
uint8_t *seg1, uint32_t *s1len,
|
||||||
|
uint8_t *seg2, uint32_t *s2len) {
|
||||||
|
|
||||||
|
struct iphdr *hdr;
|
||||||
|
uint32_t hdr_len;
|
||||||
|
struct tcphdr *tcph;
|
||||||
|
uint32_t tcph_len;
|
||||||
|
uint32_t plen;
|
||||||
|
const uint8_t *payload;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!seg1 || !s1len || !seg2 || !s2len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if ((ret = tcp4_payload_split((uint8_t *)pkt, buflen,
|
||||||
|
&hdr, &hdr_len,
|
||||||
|
&tcph, &tcph_len,
|
||||||
|
(uint8_t **)&payload, &plen)) < 0) {
|
||||||
|
lgerror("tcp4_frag: tcp4_payload_split", ret);
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
ntohs(hdr->frag_off) & IP_MF ||
|
||||||
|
ntohs(hdr->frag_off) & IP_OFFMASK) {
|
||||||
|
lgdebugmsg("tcp4_frag: frag value: %d",
|
||||||
|
ntohs(hdr->frag_off));
|
||||||
|
lgerror("tcp4_frag: ip fragmentation is set", -EINVAL);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (plen <= payload_offset) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t s1_plen = payload_offset;
|
||||||
|
uint32_t s1_dlen = s1_plen + hdr_len + tcph_len;
|
||||||
|
|
||||||
|
uint32_t s2_plen = plen - payload_offset;
|
||||||
|
uint32_t s2_dlen = s2_plen + hdr_len + tcph_len;
|
||||||
|
|
||||||
|
if (*s1len < s1_dlen || *s2len < s2_dlen)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*s1len = s1_dlen;
|
||||||
|
*s2len = s2_dlen;
|
||||||
|
|
||||||
|
memcpy(seg1, hdr, hdr_len);
|
||||||
|
memcpy(seg2, hdr, hdr_len);
|
||||||
|
|
||||||
|
memcpy(seg1 + hdr_len, tcph, tcph_len);
|
||||||
|
memcpy(seg2 + hdr_len, tcph, tcph_len);
|
||||||
|
|
||||||
|
memcpy(seg1 + hdr_len + tcph_len, payload, s1_plen);
|
||||||
|
memcpy(seg2 + hdr_len + tcph_len, payload + payload_offset, s2_plen);
|
||||||
|
|
||||||
|
struct iphdr *s1_hdr = (void *)seg1;
|
||||||
|
struct iphdr *s2_hdr = (void *)seg2;
|
||||||
|
|
||||||
|
struct tcphdr *s1_tcph = (void *)(seg1 + hdr_len);
|
||||||
|
struct tcphdr *s2_tcph = (void *)(seg2 + hdr_len);
|
||||||
|
|
||||||
|
s1_hdr->tot_len = htons(s1_dlen);
|
||||||
|
s2_hdr->tot_len = htons(s2_dlen);
|
||||||
|
|
||||||
|
s2_tcph->seq = htonl(ntohl(s2_tcph->seq) + payload_offset);
|
||||||
|
|
||||||
|
lgdebugmsg("Packet split in portion %u %u", s1_plen, s2_plen);
|
||||||
|
|
||||||
|
tcp4_set_checksum(s1_tcph, s1_hdr);
|
||||||
|
tcp4_set_checksum(s2_tcph, s2_hdr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
51
utils.h
Normal file
51
utils.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the packet to two IP fragments on position payload_offset.
|
||||||
|
* payload_offset indicates the position relatively to start of IP payload
|
||||||
|
* (start of transport header)
|
||||||
|
*/
|
||||||
|
int ip4_frag(const uint8_t *pkt, uint32_t pktlen,
|
||||||
|
uint32_t payload_offset,
|
||||||
|
uint8_t *frag1, uint32_t *f1len,
|
||||||
|
uint8_t *frag2, uint32_t *f2len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the packet to two TCP segments on position payload_offset
|
||||||
|
* payload_offset indicates the position relatively to start of TCP payload.
|
||||||
|
*/
|
||||||
|
int tcp4_frag(const uint8_t *pkt, uint32_t pktlen,
|
||||||
|
uint32_t payload_offset,
|
||||||
|
uint8_t *seg1, uint32_t *s1len,
|
||||||
|
uint8_t *seg2, uint32_t *s2len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the raw packet payload to ip header and ip payload.
|
||||||
|
*/
|
||||||
|
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||||
|
struct iphdr **iph, uint32_t *iph_len,
|
||||||
|
uint8_t **payload, uint32_t *plen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the raw packet payload to ip header, tcp header and tcp payload.
|
||||||
|
*/
|
||||||
|
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||||
|
struct iphdr **iph, uint32_t *iph_len,
|
||||||
|
struct tcphdr **tcph, uint32_t *tcph_len,
|
||||||
|
uint8_t **payload, uint32_t *plen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the raw packet payload to ip header, udp header and udp payload.
|
||||||
|
*/
|
||||||
|
int udp4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||||
|
struct iphdr **iph, uint32_t *iph_len,
|
||||||
|
struct udphdr **udph,
|
||||||
|
uint8_t **payload, uint32_t *plen);
|
||||||
|
|
||||||
|
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph);
|
||||||
|
void ip4_set_checksum(struct iphdr *iph);
|
||||||
|
|
||||||
|
#endif /* UTILS_H */
|
@ -31,6 +31,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "mangle.h"
|
#include "mangle.h"
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
pthread_mutex_t rawsocket_lock;
|
pthread_mutex_t rawsocket_lock;
|
||||||
int rawsocket = -2;
|
int rawsocket = -2;
|
||||||
|
Loading…
Reference in New Issue
Block a user