mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2024-12-22 06:15:31 +00:00
Add more custom fake message, random fake message
This commit is contained in:
parent
0fe45ec33f
commit
82c49119d3
2
Kbuild
2
Kbuild
@ -1,3 +1,3 @@
|
||||
obj-m := kyoutubeUnblock.o
|
||||
kyoutubeUnblock-objs := kytunblock.o mangle.o quic.o utils.o kmod_utils.o kargs.o
|
||||
kyoutubeUnblock-objs := kytunblock.o mangle.o quic.o utils.o kmod_utils.o kargs.o tls.o
|
||||
ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement
|
||||
|
79
args.c
79
args.c
@ -7,7 +7,9 @@
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
|
||||
static char custom_fake_buf[MAX_FAKE_SIZE];
|
||||
|
||||
struct config_t config = {
|
||||
.threads = THREADS_NUM,
|
||||
@ -18,6 +20,8 @@ struct config_t config = {
|
||||
.faking_ttl = FAKE_TTL,
|
||||
.fake_sni = 1,
|
||||
.fake_sni_seq_len = 1,
|
||||
.fake_sni_seq_type = FAKE_PAYLOAD_DEFAULT,
|
||||
.fake_sni_type = FAKE_PAYLOAD_DEFAULT,
|
||||
.frag_middle_sni = 1,
|
||||
.frag_sni_pos = 1,
|
||||
.use_ipv6 = 1,
|
||||
@ -55,6 +59,8 @@ struct config_t config = {
|
||||
.queue_start_num = DEFAULT_QUEUE_NUM,
|
||||
.fake_sni_pkt = fake_sni_old,
|
||||
.fake_sni_pkt_sz = sizeof(fake_sni_old) - 1, // - 1 for null-terminator
|
||||
.fake_custom_pkt = custom_fake_buf,
|
||||
.fake_custom_pkt_sz = 0
|
||||
};
|
||||
|
||||
#define OPT_SNI_DOMAINS 1
|
||||
@ -63,6 +69,9 @@ struct config_t config = {
|
||||
#define OPT_FAKING_TTL 3
|
||||
#define OPT_FAKING_STRATEGY 10
|
||||
#define OPT_FAKE_SNI_SEQ_LEN 11
|
||||
#define OPT_FAKE_SNI_SEQ_TYPE 26
|
||||
#define OPT_FAKE_SNI_TYPE 27
|
||||
#define OPT_FAKE_CUSTOM_PAYLOAD 28
|
||||
#define OPT_FRAG 4
|
||||
#define OPT_FRAG_SNI_REVERSE 12
|
||||
#define OPT_FRAG_SNI_FAKED 13
|
||||
@ -83,7 +92,7 @@ struct config_t config = {
|
||||
#define OPT_NO_GSO 8
|
||||
#define OPT_QUEUE_NUM 9
|
||||
|
||||
#define OPT_MAX OPT_SNI_DOMAINS
|
||||
#define OPT_MAX OPT_FAKE_CUSTOM_PAYLOAD
|
||||
|
||||
static struct option long_opt[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
@ -94,6 +103,9 @@ static struct option long_opt[] = {
|
||||
{"synfake", 1, 0, OPT_SYNFAKE},
|
||||
{"synfake-len", 1, 0, OPT_SYNFAKE_LEN},
|
||||
{"fake-sni-seq-len", 1, 0, OPT_FAKE_SNI_SEQ_LEN},
|
||||
{"fake-sni-seq-type", 1, 0, OPT_FAKE_SNI_SEQ_TYPE},
|
||||
{"fake-sni-type", 1, 0, OPT_FAKE_SNI_TYPE},
|
||||
{"fake-custom-payload", 1, 0, OPT_FAKE_CUSTOM_PAYLOAD},
|
||||
{"faking-strategy", 1, 0, OPT_FAKING_STRATEGY},
|
||||
{"fake-seq-offset", 1, 0, OPT_FAKE_SEQ_OFFSET},
|
||||
{"faking-ttl", 1, 0, OPT_FAKING_TTL},
|
||||
@ -150,6 +162,9 @@ void print_usage(const char *argv0) {
|
||||
printf("\t--exclude-domains=<comma separated domain list>\n");
|
||||
printf("\t--fake-sni={1|0}\n");
|
||||
printf("\t--fake-sni-seq-len=<length>\n");
|
||||
printf("\t--fake-sni-seq-type={default|random|custom}\n");
|
||||
printf("\t--fake-sni-type={default|random|custom}\n");
|
||||
printf("\t--fake-custom-payload=<hex payload>\n");
|
||||
printf("\t--fake-seq-offset=<offset>\n");
|
||||
printf("\t--faking-ttl=<ttl>\n");
|
||||
printf("\t--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}\n");
|
||||
@ -299,7 +314,7 @@ int parse_args(int argc, char *argv[]) {
|
||||
break;
|
||||
case OPT_FAKE_SEQ_OFFSET:
|
||||
num = parse_numeric_option(optarg);
|
||||
if (errno != 0 || num < 0) {
|
||||
if (errno != 0) {
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
@ -323,6 +338,66 @@ int parse_args(int argc, char *argv[]) {
|
||||
|
||||
config.fake_sni_seq_len = num;
|
||||
break;
|
||||
case OPT_FAKE_SNI_SEQ_TYPE:
|
||||
if (strcmp(optarg, "default") == 0) {
|
||||
config.fake_sni_seq_type = FAKE_PAYLOAD_DEFAULT;
|
||||
} else if (strcmp(optarg, "random") == 0) {
|
||||
config.fake_sni_seq_type = FAKE_PAYLOAD_RANDOM;
|
||||
} else if (strcmp(optarg, "custom") == 0) {
|
||||
config.fake_sni_seq_type = FAKE_PAYLOAD_CUSTOM;
|
||||
} else {
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
break;
|
||||
case OPT_FAKE_SNI_TYPE:
|
||||
if (strcmp(optarg, "default") == 0) {
|
||||
config.fake_sni_type = FAKE_PAYLOAD_DEFAULT;
|
||||
} else if (strcmp(optarg, "random") == 0) {
|
||||
config.fake_sni_type = FAKE_PAYLOAD_RANDOM;
|
||||
} else if (strcmp(optarg, "custom") == 0) {
|
||||
config.fake_sni_type = FAKE_PAYLOAD_CUSTOM;
|
||||
} else {
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
break;
|
||||
case OPT_FAKE_CUSTOM_PAYLOAD: {
|
||||
uint8_t *const custom_buf = (uint8_t *)custom_fake_buf;
|
||||
|
||||
const char *custom_hex_fake = optarg;
|
||||
size_t custom_hlen = strlen(custom_hex_fake);
|
||||
if ((custom_hlen & 1) == 1) {
|
||||
printf("Custom fake hex should be divisible by two\n");
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
|
||||
size_t custom_len = custom_hlen >> 1;
|
||||
if (custom_len > MAX_FAKE_SIZE) {
|
||||
printf("Custom fake is too large\n");
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
for (int i = 0; i < custom_len; i++) {
|
||||
sscanf(custom_hex_fake + (i << 1), "%2hhx", custom_buf + i);
|
||||
}
|
||||
|
||||
config.fake_custom_pkt_sz = custom_len;
|
||||
config.fake_custom_pkt = (char *)custom_buf;
|
||||
|
||||
// if (strcmp(optarg, "default") == 0) {
|
||||
// config.fake_sni_type = FAKE_PAYLOAD_DEFAULT;
|
||||
// } else if (strcmp(optarg, "random") == 0) {
|
||||
// config.fake_sni_type = FAKE_PAYLOAD_RANDOM;
|
||||
// } else if (strcmp(optarg, "custom") == 0) {
|
||||
// config.fake_sni_type = FAKE_PAYLOAD_CUSTOM;
|
||||
// } else {
|
||||
// goto invalid_opt;
|
||||
// }
|
||||
//
|
||||
}
|
||||
break;
|
||||
case OPT_FK_WINSIZE:
|
||||
num = parse_numeric_option(optarg);
|
||||
if (errno != 0 || num < 0) {
|
||||
|
37
config.h
37
config.h
@ -32,6 +32,14 @@ struct config_t {
|
||||
unsigned char faking_ttl;
|
||||
int fake_sni;
|
||||
unsigned int fake_sni_seq_len;
|
||||
|
||||
#define FAKE_PAYLOAD_RANDOM 0
|
||||
#define FAKE_PAYLOAD_CUSTOM 1
|
||||
// In default mode all other options will be skipped.
|
||||
#define FAKE_PAYLOAD_DEFAULT 2
|
||||
int fake_sni_seq_type;
|
||||
int fake_sni_type;
|
||||
|
||||
#define VERBOSE_INFO 0
|
||||
#define VERBOSE_DEBUG 1
|
||||
#define VERBOSE_TRACE 2
|
||||
@ -47,10 +55,16 @@ struct config_t {
|
||||
const char *exclude_domains_str;
|
||||
unsigned int exclude_domains_strlen;
|
||||
unsigned int all_domains;
|
||||
|
||||
const char *fake_sni_pkt;
|
||||
unsigned int fake_sni_pkt_sz;
|
||||
|
||||
const char *fake_custom_pkt;
|
||||
unsigned int fake_custom_pkt_sz;
|
||||
|
||||
|
||||
unsigned int fk_winsize;
|
||||
unsigned int fakeseq_offset;
|
||||
int fakeseq_offset;
|
||||
unsigned int mark;
|
||||
int synfake;
|
||||
unsigned int synfake_len;
|
||||
@ -89,19 +103,30 @@ extern struct config_t config;
|
||||
#define FAKE_TTL 8
|
||||
|
||||
// Will invalidate fake packets by out-of-ack_seq out-of-seq request
|
||||
#define FAKE_STRAT_RAND_SEQ 1
|
||||
#define FAKE_STRAT_RAND_SEQ (1 << 0)
|
||||
// Will assume that GGC server is located further than FAKE_TTL
|
||||
// Thus, Fake packet will be eliminated automatically.
|
||||
#define FAKE_STRAT_TTL 2
|
||||
#define FAKE_STRAT_PAST_SEQ 3
|
||||
#define FAKE_STRAT_TCP_CHECK 4
|
||||
#define FAKE_STRAT_TCP_MD5SUM 5
|
||||
#define FAKE_STRAT_TTL (1 << 1)
|
||||
#define FAKE_STRAT_PAST_SEQ (1 << 2)
|
||||
#define FAKE_STRAT_TCP_CHECK (1 << 3)
|
||||
#define FAKE_STRAT_TCP_MD5SUM (1 << 4)
|
||||
|
||||
#define FAKE_STRAT_COUNT 5
|
||||
|
||||
/**
|
||||
* This macros iterates through all faking strategies and executes code under it.
|
||||
* destination strategy will be available under name of `strategy` variable.
|
||||
*/
|
||||
#define ITER_FAKE_STRAT(fake_bitmask, strategy) \
|
||||
for (int strategy = 1; strategy <= (1 << FAKE_STRAT_COUNT); strategy <<= 1) \
|
||||
if ((fake_bitmask) & strategy)
|
||||
|
||||
#ifndef FAKING_STRATEGY
|
||||
#define FAKING_STRATEGY FAKE_STRAT_PAST_SEQ
|
||||
#endif
|
||||
|
||||
#define MAX_FAKE_SIZE 1300
|
||||
|
||||
#if !defined(SILENT) && !defined(KERNEL_SPACE)
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
606
mangle.c
606
mangle.c
@ -5,6 +5,7 @@
|
||||
#include "utils.h"
|
||||
#include "quic.h"
|
||||
#include "logging.h"
|
||||
#include "tls.h"
|
||||
|
||||
#ifndef KERNEL_SPACE
|
||||
#include <stdlib.h>
|
||||
@ -527,31 +528,33 @@ send_frag1:
|
||||
|
||||
send_fake:
|
||||
if (config.frag_sni_faked) {
|
||||
uint32_t iphfl, tcphfl;
|
||||
fake_pad_len = f2len;
|
||||
ret = tcp_payload_split(frag2, f2len, NULL, &iphfl, NULL, &tcphfl, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
lgerror("Invalid frag2", ret);
|
||||
goto erret_lc;
|
||||
ITER_FAKE_STRAT(config.faking_strategy, strategy) {
|
||||
uint32_t iphfl, tcphfl;
|
||||
fake_pad_len = f2len;
|
||||
ret = tcp_payload_split(frag2, f2len, NULL, &iphfl, NULL, &tcphfl, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
lgerror("Invalid frag2", ret);
|
||||
goto erret_lc;
|
||||
}
|
||||
memcpy(fake_pad, frag2, iphfl + tcphfl);
|
||||
memset(fake_pad + iphfl + tcphfl, 0, f2len - iphfl - tcphfl);
|
||||
struct tcphdr *fakethdr = (void *)(fake_pad + iphfl);
|
||||
if (config.faking_strategy == FAKE_STRAT_PAST_SEQ) {
|
||||
lgtrace("frag fake sent with %u -> ", ntohl(fakethdr->seq));
|
||||
fakethdr->seq = htonl(ntohl(fakethdr->seq) - dvs);
|
||||
lgtrace_addp("%u, ", ntohl(fakethdr->seq));
|
||||
}
|
||||
ret = fail_packet(strategy,
|
||||
fake_pad, &fake_pad_len, MAX_PACKET_SIZE);
|
||||
if (ret < 0) {
|
||||
lgerror("Failed to fail packet", ret);
|
||||
goto erret_lc;
|
||||
}
|
||||
ret = send_tcp_frags(fake_pad, fake_pad_len, NULL, 0, 0);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
}
|
||||
memcpy(fake_pad, frag2, iphfl + tcphfl);
|
||||
memset(fake_pad + iphfl + tcphfl, 0, f2len - iphfl - tcphfl);
|
||||
struct tcphdr *fakethdr = (void *)(fake_pad + iphfl);
|
||||
if (config.faking_strategy == FAKE_STRAT_PAST_SEQ) {
|
||||
lgtrace("frag fake sent with %u -> ", ntohl(fakethdr->seq));
|
||||
fakethdr->seq = htonl(ntohl(fakethdr->seq) - dvs);
|
||||
lgtrace_addp("%u, ", ntohl(fakethdr->seq));
|
||||
}
|
||||
ret = fail_packet(fake_pad, &fake_pad_len, MAX_PACKET_SIZE);
|
||||
if (ret < 0) {
|
||||
lgerror("Failed to fail packet", ret);
|
||||
goto erret_lc;
|
||||
}
|
||||
ret = send_tcp_frags(fake_pad, fake_pad_len, NULL, 0, 0);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (config.frag_sni_reverse)
|
||||
@ -596,476 +599,131 @@ int post_fake_sni(const void *iph, unsigned int iph_len,
|
||||
void *fsiph = (void *)rfsiph;
|
||||
struct tcphdr *fstcph = (void *)rfstcph;
|
||||
|
||||
for (int i = 0; i < sequence_len; i++) {
|
||||
ITER_FAKE_STRAT(config.faking_strategy, strategy) {
|
||||
struct fake_type fake_seq_type = {
|
||||
.type = FAKE_PAYLOAD_DEFAULT,
|
||||
.strategy = strategy,
|
||||
};
|
||||
|
||||
switch (config.fake_sni_seq_type) {
|
||||
case FAKE_PAYLOAD_RANDOM:
|
||||
fake_seq_type.type = FAKE_PAYLOAD_RANDOM;
|
||||
break;
|
||||
case FAKE_PAYLOAD_CUSTOM:
|
||||
fake_seq_type.type = FAKE_PAYLOAD_CUSTOM;
|
||||
fake_seq_type.fake_data = config.fake_custom_pkt;
|
||||
fake_seq_type.fake_len = config.fake_custom_pkt_sz;
|
||||
break;
|
||||
default:
|
||||
fake_seq_type.type = FAKE_PAYLOAD_DEFAULT;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sequence_len; i++) {
|
||||
NETBUF_ALLOC(fake_sni, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(fake_sni)) {
|
||||
lgerror("Allocation error", -ENOMEM);
|
||||
return -ENOMEM;
|
||||
}
|
||||
uint32_t fsn_len = MAX_PACKET_SIZE;
|
||||
|
||||
ret = gen_fake_sni(
|
||||
fake_seq_type,
|
||||
fsiph, iph_len, fstcph, tcph_len,
|
||||
fake_sni, &fsn_len);
|
||||
if (ret < 0) {
|
||||
lgerror("gen_fake_sni", ret);
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
lgtrace_addp("post fake sni #%d", i + 1);
|
||||
lgtrace_addp("post with %d bytes", fsn_len);
|
||||
ret = instance_config.send_raw_packet(fake_sni, fsn_len);
|
||||
if (ret < 0) {
|
||||
lgerror("send fake sni", ret);
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
if (!(config.faking_strategy == FAKE_STRAT_PAST_SEQ ||
|
||||
config.faking_strategy == FAKE_STRAT_RAND_SEQ)) {
|
||||
|
||||
uint32_t iph_len;
|
||||
uint32_t tcph_len;
|
||||
uint32_t plen;
|
||||
ret = tcp_payload_split(
|
||||
fake_sni, fsn_len,
|
||||
&fsiph, &iph_len,
|
||||
&fstcph, &tcph_len,
|
||||
NULL, &plen);
|
||||
|
||||
if (ret < 0) {
|
||||
lgtrace_addp("continue fake seq");
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
fstcph->seq = htonl(ntohl(fstcph->seq) + plen);
|
||||
memcpy(rfsiph, fsiph, iph_len);
|
||||
memcpy(rfstcph, fstcph, tcph_len);
|
||||
fsiph = (void *)rfsiph;
|
||||
fstcph = (void *)rfstcph;
|
||||
}
|
||||
|
||||
NETBUF_FREE(fake_sni);
|
||||
continue;
|
||||
erret_lc:
|
||||
NETBUF_FREE(fake_sni);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct fake_type ftype = {
|
||||
.type = FAKE_PAYLOAD_DEFAULT,
|
||||
.strategy = strategy
|
||||
};
|
||||
|
||||
switch (config.fake_sni_type) {
|
||||
case FAKE_PAYLOAD_RANDOM:
|
||||
ftype.type = FAKE_PAYLOAD_RANDOM;
|
||||
break;
|
||||
case FAKE_PAYLOAD_CUSTOM:
|
||||
ftype.type = FAKE_PAYLOAD_CUSTOM;
|
||||
ftype.fake_data = config.fake_custom_pkt;
|
||||
ftype.fake_len = config.fake_custom_pkt_sz;
|
||||
break;
|
||||
default:
|
||||
ftype.type = FAKE_PAYLOAD_DEFAULT;
|
||||
}
|
||||
|
||||
NETBUF_ALLOC(fake_sni, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(fake_sni)) {
|
||||
lgerror("Allocation error", -ENOMEM);
|
||||
return -ENOMEM;
|
||||
}
|
||||
uint32_t fsn_len = MAX_PACKET_SIZE;
|
||||
ret = gen_fake_sni(fsiph, iph_len, fstcph, tcph_len,
|
||||
fake_sni, &fsn_len);
|
||||
ret = gen_fake_sni(
|
||||
ftype,
|
||||
iph, iph_len, tcph, tcph_len,
|
||||
fake_sni, &fsn_len);
|
||||
if (ret < 0) {
|
||||
lgerror("gen_fake_sni", ret);
|
||||
goto erret_lc;
|
||||
goto erret_lc_cst;
|
||||
}
|
||||
|
||||
lgtrace_addp("post fake sni #%d", i + 1);
|
||||
lgtrace_addp("post with %d", fsn_len);
|
||||
lgtrace_addp("post normal fake sni");
|
||||
lgtrace_addp("post with %d bytes", fsn_len);
|
||||
ret = instance_config.send_raw_packet(fake_sni, fsn_len);
|
||||
if (ret < 0) {
|
||||
lgerror("send fake sni", ret);
|
||||
goto erret_lc;
|
||||
goto erret_lc_cst;
|
||||
}
|
||||
|
||||
uint32_t iph_len;
|
||||
uint32_t tcph_len;
|
||||
uint32_t plen;
|
||||
tcp_payload_split(
|
||||
fake_sni, fsn_len,
|
||||
&fsiph, &iph_len,
|
||||
&fstcph, &tcph_len,
|
||||
NULL, &plen);
|
||||
goto after_cus2;
|
||||
|
||||
|
||||
fstcph->seq = htonl(ntohl(fstcph->seq) + plen);
|
||||
memcpy(rfsiph, fsiph, iph_len);
|
||||
memcpy(rfstcph, fstcph, tcph_len);
|
||||
fsiph = (void *)rfsiph;
|
||||
fstcph = (void *)rfstcph;
|
||||
|
||||
NETBUF_FREE(fake_sni);
|
||||
continue;
|
||||
erret_lc:
|
||||
erret_lc_cst:
|
||||
NETBUF_FREE(fake_sni);
|
||||
return ret;
|
||||
after_cus2:
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
|
||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
||||
#define TLS_EXTENSION_SNI 0x0000
|
||||
#define TLS_EXTENSION_CLIENT_HELLO_ENCRYPTED 0xfe0d
|
||||
|
||||
/**
|
||||
* Processes tls payload of the tcp request.
|
||||
*
|
||||
* data Payload data of TCP.
|
||||
* dlen Length of `data`.
|
||||
*/
|
||||
struct tls_verdict analyze_tls_data(
|
||||
const uint8_t *data,
|
||||
uint32_t dlen)
|
||||
{
|
||||
struct tls_verdict vrd = {0};
|
||||
|
||||
size_t i = 0;
|
||||
const uint8_t *data_end = data + dlen;
|
||||
|
||||
while (i + 4 < dlen) {
|
||||
const uint8_t *msgData = data + i;
|
||||
|
||||
uint8_t tls_content_type = *msgData;
|
||||
uint8_t tls_vmajor = *(msgData + 1);
|
||||
uint16_t message_length = ntohs(*(uint16_t *)(msgData + 3));
|
||||
|
||||
if (tls_vmajor != 0x03) goto nextMessage;
|
||||
|
||||
if (i + 5 > dlen) break;
|
||||
|
||||
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
|
||||
goto nextMessage;
|
||||
|
||||
if (config.sni_detection == SNI_DETECTION_BRUTE) {
|
||||
goto brute;
|
||||
}
|
||||
|
||||
const uint8_t *handshakeProto = msgData + 5;
|
||||
|
||||
if (handshakeProto + 1 >= data_end) break;
|
||||
|
||||
uint8_t handshakeType = *handshakeProto;
|
||||
|
||||
if (handshakeType != TLS_HANDSHAKE_TYPE_CLIENT_HELLO)
|
||||
goto nextMessage;
|
||||
|
||||
const uint8_t *msgPtr = handshakeProto;
|
||||
msgPtr += 1;
|
||||
msgPtr += 3 + 2 + 32;
|
||||
|
||||
if (msgPtr + 1 >= data_end) break;
|
||||
uint8_t sessionIdLength = *msgPtr;
|
||||
msgPtr++;
|
||||
msgPtr += sessionIdLength;
|
||||
|
||||
if (msgPtr + 2 >= data_end) break;
|
||||
uint16_t ciphersLength = ntohs(*(uint16_t *)msgPtr);
|
||||
msgPtr += 2;
|
||||
msgPtr += ciphersLength;
|
||||
|
||||
if (msgPtr + 1 >= data_end) break;
|
||||
uint8_t compMethodsLen = *msgPtr;
|
||||
msgPtr++;
|
||||
msgPtr += compMethodsLen;
|
||||
|
||||
if (msgPtr + 2 >= data_end) break;
|
||||
uint16_t extensionsLen = ntohs(*(uint16_t *)msgPtr);
|
||||
msgPtr += 2;
|
||||
|
||||
const uint8_t *extensionsPtr = msgPtr;
|
||||
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
|
||||
if (extensions_end > data_end) extensions_end = data_end;
|
||||
|
||||
while (extensionsPtr < extensions_end) {
|
||||
const uint8_t *extensionPtr = extensionsPtr;
|
||||
if (extensionPtr + 4 >= extensions_end) break;
|
||||
|
||||
uint16_t extensionType =
|
||||
ntohs(*(uint16_t *)extensionPtr);
|
||||
extensionPtr += 2;
|
||||
|
||||
uint16_t extensionLen =
|
||||
ntohs(*(uint16_t *)extensionPtr);
|
||||
extensionPtr += 2;
|
||||
|
||||
|
||||
if (extensionPtr + extensionLen > extensions_end)
|
||||
break;
|
||||
|
||||
if (extensionType != TLS_EXTENSION_SNI)
|
||||
goto nextExtension;
|
||||
|
||||
const uint8_t *sni_ext_ptr = extensionPtr;
|
||||
|
||||
if (sni_ext_ptr + 2 >= extensions_end) break;
|
||||
uint16_t sni_ext_dlen = ntohs(*(uint16_t *)sni_ext_ptr);
|
||||
|
||||
sni_ext_ptr += 2;
|
||||
|
||||
const uint8_t *sni_ext_end = sni_ext_ptr + sni_ext_dlen;
|
||||
if (sni_ext_end >= extensions_end) break;
|
||||
|
||||
if (sni_ext_ptr + 3 >= sni_ext_end) break;
|
||||
sni_ext_ptr++;
|
||||
uint16_t sni_len = ntohs(*(uint16_t *)sni_ext_ptr);
|
||||
sni_ext_ptr += 2;
|
||||
|
||||
if (sni_ext_ptr + sni_len > sni_ext_end) break;
|
||||
|
||||
char *sni_name = (char *)sni_ext_ptr;
|
||||
|
||||
vrd.sni_offset = (uint8_t *)sni_name - data;
|
||||
vrd.sni_len = sni_len;
|
||||
|
||||
if (config.all_domains) {
|
||||
vrd.target_sni = 1;
|
||||
goto check_domain;
|
||||
}
|
||||
|
||||
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i <= config.domains_strlen; i++) {
|
||||
if ( i > j &&
|
||||
(i == config.domains_strlen ||
|
||||
config.domains_str[i] == '\0' ||
|
||||
config.domains_str[i] == ',' ||
|
||||
config.domains_str[i] == '\n' )) {
|
||||
|
||||
unsigned int domain_len = (i - j);
|
||||
const char *sni_startp = sni_name + sni_len - domain_len;
|
||||
const char *domain_startp = config.domains_str + j;
|
||||
|
||||
if (sni_len >= domain_len &&
|
||||
sni_len < 128 &&
|
||||
!strncmp(sni_startp,
|
||||
domain_startp,
|
||||
domain_len)) {
|
||||
vrd.target_sni = 1;
|
||||
goto check_domain;
|
||||
}
|
||||
|
||||
j = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
check_domain:
|
||||
if (vrd.target_sni == 1 && config.exclude_domains_strlen != 0) {
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i <= config.exclude_domains_strlen; i++) {
|
||||
if ( i > j &&
|
||||
(i == config.exclude_domains_strlen ||
|
||||
config.exclude_domains_str[i] == '\0' ||
|
||||
config.exclude_domains_str[i] == ',' ||
|
||||
config.exclude_domains_str[i] == '\n' )) {
|
||||
|
||||
unsigned int domain_len = (i - j);
|
||||
const char *sni_startp = sni_name + sni_len - domain_len;
|
||||
const char *domain_startp = config.exclude_domains_str + j;
|
||||
|
||||
if (sni_len >= domain_len &&
|
||||
sni_len < 128 &&
|
||||
!strncmp(sni_startp,
|
||||
domain_startp,
|
||||
domain_len)) {
|
||||
|
||||
vrd.target_sni = 0;
|
||||
lgdebugmsg("Excluded SNI: %.*s",
|
||||
vrd.sni_len, data + vrd.sni_offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
j = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
nextExtension:
|
||||
extensionsPtr += 2 + 2 + extensionLen;
|
||||
}
|
||||
nextMessage:
|
||||
i += 5 + message_length;
|
||||
}
|
||||
|
||||
out:
|
||||
return vrd;
|
||||
|
||||
|
||||
brute:
|
||||
if (config.all_domains) {
|
||||
vrd.target_sni = 1;
|
||||
vrd.sni_len = 0;
|
||||
vrd.sni_offset = dlen / 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i <= config.domains_strlen; i++) {
|
||||
if ( i > j &&
|
||||
(i == config.domains_strlen ||
|
||||
config.domains_str[i] == '\0' ||
|
||||
config.domains_str[i] == ',' ||
|
||||
config.domains_str[i] == '\n' )) {
|
||||
|
||||
unsigned int domain_len = (i - j);
|
||||
const char *domain_startp = config.domains_str + j;
|
||||
|
||||
if (domain_len + dlen + 1> MAX_PACKET_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NETBUF_ALLOC(buf, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(buf)) {
|
||||
lgerror("Allocation error", -ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
NETBUF_ALLOC(nzbuf, MAX_PACKET_SIZE * sizeof(int));
|
||||
if (!NETBUF_CHECK(nzbuf)) {
|
||||
lgerror("Allocation error", -ENOMEM);
|
||||
NETBUF_FREE(buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int *zbuf = (void *)nzbuf;
|
||||
|
||||
memcpy(buf, domain_startp, domain_len);
|
||||
memcpy(buf + domain_len, "#", 1);
|
||||
memcpy(buf + domain_len + 1, data, dlen);
|
||||
|
||||
z_function((char *)buf, zbuf, domain_len + 1 + dlen);
|
||||
|
||||
for (unsigned int k = 0; k < dlen; k++) {
|
||||
if (zbuf[k] == domain_len) {
|
||||
vrd.target_sni = 1;
|
||||
vrd.sni_len = domain_len;
|
||||
vrd.sni_offset = (k - domain_len - 1);
|
||||
NETBUF_FREE(buf);
|
||||
NETBUF_FREE(nzbuf);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
j = i + 1;
|
||||
|
||||
NETBUF_FREE(buf);
|
||||
NETBUF_FREE(nzbuf);
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
int gen_fake_sni(const void *ipxh, uint32_t iph_len,
|
||||
const struct tcphdr *tcph, uint32_t tcph_len,
|
||||
uint8_t *buf, uint32_t *buflen) {
|
||||
|
||||
if (!ipxh || !tcph || !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_TCP;
|
||||
} 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_TCP;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const char *data = config.fake_sni_pkt;
|
||||
size_t data_len = config.fake_sni_pkt_sz;
|
||||
|
||||
uint32_t dlen = iph_len + tcph_len + data_len;
|
||||
|
||||
if (*buflen < dlen)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buf + iph_len, tcph, tcph_len);
|
||||
memcpy(buf + iph_len + tcph_len, data, data_len);
|
||||
|
||||
|
||||
if (ipxv == IP4VERSION) {
|
||||
struct iphdr *niph = (struct iphdr *)buf;
|
||||
niph->tot_len = htons(dlen);
|
||||
} else if (ipxv == IP6VERSION) {
|
||||
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
|
||||
niph->ip6_plen = htons(dlen - iph_len);
|
||||
}
|
||||
|
||||
fail_packet(buf, &dlen, *buflen);
|
||||
*buflen = dlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TCP_MD5SIG_LEN 16
|
||||
#define TCP_MD5SIG_KIND 19
|
||||
struct tcp_md5sig_opt {
|
||||
uint8_t kind;
|
||||
uint8_t len;
|
||||
uint8_t sig[TCP_MD5SIG_LEN];
|
||||
};
|
||||
#define TCP_MD5SIG_OPT_LEN (sizeof(struct tcp_md5sig_opt))
|
||||
// Real length of the option, with NOOP fillers
|
||||
#define TCP_MD5SIG_OPT_RLEN 20
|
||||
|
||||
int fail_packet(uint8_t *payload, uint32_t *plen, uint32_t avail_buflen) {
|
||||
void *iph;
|
||||
uint32_t iph_len;
|
||||
struct tcphdr *tcph;
|
||||
uint32_t tcph_len;
|
||||
uint8_t *data;
|
||||
uint32_t dlen;
|
||||
int ret;
|
||||
|
||||
ret = tcp_payload_split(payload, *plen,
|
||||
&iph, &iph_len, &tcph, &tcph_len,
|
||||
&data, &dlen);
|
||||
|
||||
uint32_t ipxv = netproto_version(payload, *plen);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
if (config.faking_strategy == FAKE_STRAT_RAND_SEQ) {
|
||||
lgtrace("fake seq: %u -> ", ntohl(tcph->seq));
|
||||
|
||||
if (config.fakeseq_offset) {
|
||||
tcph->seq = htonl(ntohl(tcph->seq) - config.fakeseq_offset);
|
||||
} else {
|
||||
#ifdef KERNEL_SPACE
|
||||
tcph->seq = 124;
|
||||
#else
|
||||
tcph->seq = random();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
lgtrace_addp("%u", ntohl(tcph->seq));
|
||||
} else if (config.faking_strategy == FAKE_STRAT_PAST_SEQ) {
|
||||
lgtrace("fake seq: %u -> ", ntohl(tcph->seq));
|
||||
tcph->seq = htonl(ntohl(tcph->seq) - dlen);
|
||||
lgtrace_addp("%u", ntohl(tcph->seq));
|
||||
|
||||
} else if (config.faking_strategy == FAKE_STRAT_TTL) {
|
||||
lgtrace_addp("set fake ttl to %d", config.faking_ttl);
|
||||
|
||||
if (ipxv == IP4VERSION) {
|
||||
((struct iphdr *)iph)->ttl = config.faking_ttl;
|
||||
} else if (ipxv == IP6VERSION) {
|
||||
((struct ip6_hdr *)iph)->ip6_hops = config.faking_ttl;
|
||||
} else {
|
||||
lgerror("fail_packet: IP version is unsupported", -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (config.faking_strategy == FAKE_STRAT_TCP_MD5SUM) {
|
||||
int optp_len = tcph_len - sizeof(struct tcphdr);
|
||||
int delta = TCP_MD5SIG_OPT_RLEN - optp_len;
|
||||
lgtrace_addp("Incr delta %d: %d -> %d", delta, optp_len, optp_len + delta);
|
||||
|
||||
if (delta > 0) {
|
||||
if (avail_buflen - *plen < delta) {
|
||||
return -1;
|
||||
}
|
||||
uint8_t *ndata = data + delta;
|
||||
uint8_t *ndptr = ndata + dlen;
|
||||
uint8_t *dptr = data + dlen;
|
||||
for (size_t i = dlen + 1; i > 0; i--) {
|
||||
*ndptr = *dptr;
|
||||
--ndptr, --dptr;
|
||||
}
|
||||
data = ndata;
|
||||
tcph_len = tcph_len + delta;
|
||||
tcph->doff = tcph_len >> 2;
|
||||
if (ipxv == IP4VERSION) {
|
||||
((struct iphdr *)iph)->tot_len = htons(ntohs(((struct iphdr *)iph)->tot_len) + delta);
|
||||
} else if (ipxv == IP6VERSION) {
|
||||
((struct ip6_hdr *)iph)->ip6_plen = htons(ntohs(((struct ip6_hdr *)iph)->ip6_plen) + delta);
|
||||
} else {
|
||||
lgerror("fail_packet: IP version is unsupported", -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
optp_len += delta;
|
||||
*plen += delta;
|
||||
}
|
||||
|
||||
uint8_t *optplace = (uint8_t *)tcph + sizeof(struct tcphdr);
|
||||
struct tcp_md5sig_opt *mdopt = (void *)optplace;
|
||||
mdopt->kind = TCP_MD5SIG_KIND;
|
||||
mdopt->len = TCP_MD5SIG_OPT_LEN;
|
||||
|
||||
optplace += sizeof(struct tcp_md5sig_opt);
|
||||
optp_len -= sizeof(struct tcp_md5sig_opt);
|
||||
|
||||
while (optp_len-- > 0) {
|
||||
*optplace++ = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
set_ip_checksum(iph, iph_len);
|
||||
set_tcp_checksum(tcph, iph, iph_len);
|
||||
|
||||
if (config.faking_strategy == FAKE_STRAT_TCP_CHECK) {
|
||||
lgtrace_addp("break fake tcp checksum");
|
||||
tcph->check += 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
29
mangle.h
29
mangle.h
@ -3,35 +3,6 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/**
|
||||
* Result of analyze_tls_data function
|
||||
*/
|
||||
struct tls_verdict {
|
||||
int target_sni; /* google video hello packet */
|
||||
int sni_offset; /* offset from start of tcp _payload_ */
|
||||
int sni_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* Processes the packet and finds TLS Client Hello information inside it.
|
||||
* data pointer points to start of TLS Message (TCP Payload)
|
||||
*/
|
||||
struct tls_verdict analyze_tls_data(const uint8_t *data, uint32_t dlen);
|
||||
|
||||
|
||||
/**
|
||||
* Generates fake client hello message
|
||||
*/
|
||||
int gen_fake_sni(const void *iph, uint32_t iph_len,
|
||||
const struct tcphdr *tcph, uint32_t tcph_len,
|
||||
uint8_t *buf, uint32_t *buflen);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
int fail_packet(uint8_t *payload, uint32_t *plen, uint32_t avail_buflen);
|
||||
|
||||
#define PKT_ACCEPT 0
|
||||
#define PKT_DROP 1
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#define FAKE_SNI_MAXLEN 1500
|
||||
|
||||
static const char fake_sni[] = "\026\003\001\002\000\001\000\001\374\003\003\323[\345\201f\362\200:B\356Uq\355X\315i\235*\021\367\331\272\a>\233\254\355\307/\342\372\265 \275\2459l&r\222\313\361\3729`\376\256\233\333O\001\373\33050\r\260f,\231\035 \324^\000>\023\002\023\003\023\001\300,\3000\000\237\314\251\314\250\314\252\300+\300/\000\236\300$\300(\000k\300#\300'\000g\300\n\300\024\0009\300\t\300\023\0003\000\235\000\234\000=\000<\0005\000/\000\377\001\000\001u\000\000\000\023\000\021\000\000\016www.google.com\000\v\000\004\003\000\001\002\000\n\000\026\000\024\000\035\000\027\000\036\000\031\000\030\001\000\001\001\001\002\001\003\001\004\000\020\000\016\000\f\002h2\bhttp/1.1\000\026\000\000\000\027\000\000\0001\000\000\000\r\0000\000.\004\003\005\003\006\003\b\a\b\b\b\032\b\033\b\034\b\t\b\n\b\v\b\004\b\005\b\006\004\001\005\001\006\001\003\003\003\001\003\002\004\002\005\002\006\002\000+\000\005\004\003\004\003\003\000-\000\002\001\001\0003\000&\000$\000\035\000 \004\224\206\021\256\f\222\266\3435\216\202\342\2573\341\3503\2107\341\023\016\240r|6\000^K\310s\000\025\000\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
||||
static const char fake_sni[] = "\026\003\001\002\000\001\000\001\374\003\003\323[\345\201f\362\200:B\356Uq\355X\315i\235*\021\367\331\272\a>\233\254\355\307/\342\372\265 \275\2459l&r\222\313\361\3729`\376\256\233\333O\001\373\33050\r\260f,\231\035 \324^\000>\023\002\023\003\023\001\300,\3000\000\237\314\251\314\250\314\252\300+\300/\000\236\300$\300(\000k\300#\300'\000g\300\n\300\024\0009\300\t\300\023\0003\000\235\000\234\000=\000<\0005\000/\000\377\001\000\001u\000\000\000\023\000\021\000\000\016www.google.com\000\v\000\004\003\000\001\002\000\n\000\026\000\024\000\035\000\027\000\036\000\031\000\030\001\000\001\001\001\002\001\003\001\004\000\020\000\016\000\f\002h2\bhttp/1.1\000\026\000\000\000\027\000\000\0001\000\000\000\r\0000\000.\004\003\005\003\006\003\b\a\b\b\b\032\b\033\b\034\b\t\b\n\b\v\b\004\b\005\b\006\004\001\005\001\006\001\003\003\003\001\003\002\004\002\005\002\006\002\000+\000\005\004\003\004\003\003\000-\000\002\001\001\0003\000&\000$\000\035\000 \004\224\206\021\256\f\222\266\3435\216\202\342\2573\341\3503\2107\341\023\016\240r|6\000^K\310s\000\025\000\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
||||
|
||||
static const char fake_sni_old[] = "\026\003\001\004\316\001\000\004\312\003\003K+\272\314\340\306\374>dw%\f\223\346\225\270\270~\335\027\f\264\341H\267\357\303\216T\322[\371 \245\320\212V6\374\3706\232\0216B\325\273P\b\300>\0332>\362\323\033\322\301\204\022f8\223\214\000\"\023\001\023\003\023\002\300+\300/\314\251\314\250\300,\3000\300\n\300\t\300\023\300\024\000\234\000\235\000/\0005\001\000\004_\000\000\000\023\000\021\000\000\016www.google.com\000\027\000\000\377\001\000\001\000\000\n\000\016\000\f\000\035\000\027\000\030\000\031\001\000\001\001\000\v\000\002\001\000\000\020\000\v\000\t\bhttp/1.1\000\005\000\005\001\000\000\000\000\000\"\000\n\000\b\004\003\005\003\006\003\002\003\0003\000k\000i\000\035\000 \333C\212\234-\t\237#\202\\\231\311\022]\333\341t(\t\276U\373u\234\316J~,^|*Z\000\027\000A\004k\n\255\254\376X\226t\001;n~\033\034.\245\027\024\3762_\352$\374\346^f\fF,\201\275\263\336O\231\001\032\200\357dI\266y\031\323\311vR\232\004\r\366FT\004\335\326\356\256\230B\t\313\000*\000\000\000+\000\005\004\003\004\003\003\000\r\000\030\000\026\004\003\005\003\006\003\b\004\b\005\b\006\004\001\005\001\006\001\002\003\002\001\000-\000\002\001\001\000\034\000\002@\001\376\r\0029\000\000\001\000\003\344\000 \337\306\243\332Y\033\a\252\352\025\365Z\035\223\226\304\255\363\215G\356g\344%}7\217\033n\211^\201\002\017g\267\334\326OD}\336\341ZC\230\226'\225\313\357\211\\\242\273\030k\216\377U\315\206\2410\200\203\332Z\223\005\370\b\304\370f\017\200\023\241\223~?\270{\037b\312\001\270\227\366\356\352\002\314\351\006\237\241q\226\300\314\321o\247{\201\317\230}B\005T\3660\335\320\332r?S\217\tq\036\031\326I|\237]\311 c\f\024r\031\310W\373\257\314q)q\030\237\261\227\217Kd?\257'G\320\020\340\256ND\247\005\341\324\024OP>\370\350\270b\311wAj\t\311\213\365i\203\230x\207\354\245<\274\202\230c\v0Y\263\364\022\303a\200\022\031\314\271rl=\327\336\001\327\264\267\342\353\352=\354[u\224\260\257\034\004\232\023\226}\227\030e\221\"\350\207\027dId\324\305\362N:\035\307`\204\337\201;\221\320\266b\362hrH\345e\206\246%\006\020a4\3430\036\225\215\274\275\360Q&\271\237)\222uK\362\017o\220\226W\357\267#\357\v\023\354\213\2629\331\ad\005/~6k\000[\247\301\270\310qJ\004\303|m5\363\376Y\002\243}6\251x\024\331)GH\335\205rI\032\f\210\a\212\347]\271\030\347.\021\213\365\026\030\340/Ny\r\332\3577\3203\026iX}>\2507\327&XRXU!\017\270I\313\352\350^?\352Uss\017\266pF\222NI\245\307_\305#\361\352\243+-\266\317Q\036s\243\277\355{S&\023>\275\360\215\032V\237XOY\345u>\002\305\252T\354\035\327v{P\352M\233\366\221\270\377\251\261f+rF\201wL2W\266X\252\242X\2536I\337c\205uZ\254Fe\305h\t\371\376\216r\336Y\327h\347*\331\257-ZQ{(\336\226\206\017\037\036\021\341\027z\033\254\235\252\227\224\004?p\243\351\\\263\352\205\327#W\345\255\256\375\267bP\3047\363!*K\003t\212(\306\214P\215\3506j\025\375\213e\254s\000)\001\034\000\367\000\361\002\276W%\232?\326\223\277\211v\017\a\361\347\312N\226\024L\260v\210\271j\324[|\270\344\3773\321-\313b>~\310\253XIR\324)&;\033{g;)\344\255\226\370\347I\\y\020\324\360\211vC\310\226s\267|\273$\341\332\2045qh\245w\2255\214\316\030\255\301\326C\343\304=\245\231h`yd\000#s\002\370\374Z\0336\245\361\226\222\306\032k\2457\016h\314(R;\326T~EHH\352\307\023^\247\363\321`V\340\253Z\233\357\227I\373\337z\177\nv\261\252\371\017\226\223\345\005\315y4\b\236N0\2630\017\215c\305&L\260\346J\237\203Q(\335W\027|>\3553\275j\307?W5\3463kc\350\262C\361 \037w!\371}\214\"I\377|\331@a;\342\3566\312\272Z\327u7\204'\215YBLL\235\236\242\345\215\245T\211a\312\263\342\000! \221\202X$\302\317\203\246\207c{\231\330\264\324\\k\271\272\336\356\002|\261O\207\030+\367P\317\356";
|
||||
static const char fake_sni_old[] = "\026\003\001\004\316\001\000\004\312\003\003K+\272\314\340\306\374>dw%\f\223\346\225\270\270~\335\027\f\264\341H\267\357\303\216T\322[\371 \245\320\212V6\374\3706\232\0216B\325\273P\b\300>\0332>\362\323\033\322\301\204\022f8\223\214\000\"\023\001\023\003\023\002\300+\300/\314\251\314\250\300,\3000\300\n\300\t\300\023\300\024\000\234\000\235\000/\0005\001\000\004_\000\000\000\023\000\021\000\000\016www.google.com\000\027\000\000\377\001\000\001\000\000\n\000\016\000\f\000\035\000\027\000\030\000\031\001\000\001\001\000\v\000\002\001\000\000\020\000\v\000\t\bhttp/1.1\000\005\000\005\001\000\000\000\000\000\"\000\n\000\b\004\003\005\003\006\003\002\003\0003\000k\000i\000\035\000 \333C\212\234-\t\237#\202\\\231\311\022]\333\341t(\t\276U\373u\234\316J~,^|*Z\000\027\000A\004k\n\255\254\376X\226t\001;n~\033\034.\245\027\024\3762_\352$\374\346^f\fF,\201\275\263\336O\231\001\032\200\357dI\266y\031\323\311vR\232\004\r\366FT\004\335\326\356\256\230B\t\313\000*\000\000\000+\000\005\004\003\004\003\003\000\r\000\030\000\026\004\003\005\003\006\003\b\004\b\005\b\006\004\001\005\001\006\001\002\003\002\001\000-\000\002\001\001\000\034\000\002@\001\376\r\0029\000\000\001\000\003\344\000 \337\306\243\332Y\033\a\252\352\025\365Z\035\223\226\304\255\363\215G\356g\344%}7\217\033n\211^\201\002\017g\267\334\326OD}\336\341ZC\230\226'\225\313\357\211\\\242\273\030k\216\377U\315\206\2410\200\203\332Z\223\005\370\b\304\370f\017\200\023\241\223~?\270{\037b\312\001\270\227\366\356\352\002\314\351\006\237\241q\226\300\314\321o\247{\201\317\230}B\005T\3660\335\320\332r?S\217\tq\036\031\326I|\237]\311 c\f\024r\031\310W\373\257\314q)q\030\237\261\227\217Kd?\257'G\320\020\340\256ND\247\005\341\324\024OP>\370\350\270b\311wAj\t\311\213\365i\203\230x\207\354\245<\274\202\230c\v0Y\263\364\022\303a\200\022\031\314\271rl=\327\336\001\327\264\267\342\353\352=\354[u\224\260\257\034\004\232\023\226}\227\030e\221\"\350\207\027dId\324\305\362N:\035\307`\204\337\201;\221\320\266b\362hrH\345e\206\246%\006\020a4\3430\036\225\215\274\275\360Q&\271\237)\222uK\362\017o\220\226W\357\267#\357\v\023\354\213\2629\331\ad\005/~6k\000[\247\301\270\310qJ\004\303|m5\363\376Y\002\243}6\251x\024\331)GH\335\205rI\032\f\210\a\212\347]\271\030\347.\021\213\365\026\030\340/Ny\r\332\3577\3203\026iX}>\2507\327&XRXU!\017\270I\313\352\350^?\352Uss\017\266pF\222NI\245\307_\305#\361\352\243+-\266\317Q\036s\243\277\355{S&\023>\275\360\215\032V\237XOY\345u>\002\305\252T\354\035\327v{P\352M\233\366\221\270\377\251\261f+rF\201wL2W\266X\252\242X\2536I\337c\205uZ\254Fe\305h\t\371\376\216r\336Y\327h\347*\331\257-ZQ{(\336\226\206\017\037\036\021\341\027z\033\254\235\252\227\224\004?p\243\351\\\263\352\205\327#W\345\255\256\375\267bP\3047\363!*K\003t\212(\306\214P\215\3506j\025\375\213e\254s\000)\001\034\000\367\000\361\002\276W%\232?\326\223\277\211v\017\a\361\347\312N\226\024L\260v\210\271j\324[|\270\344\3773\321-\313b>~\310\253XIR\324)&;\033{g;)\344\255\226\370\347I\\y\020\324\360\211vC\310\226s\267|\273$\341\332\2045qh\245w\2255\214\316\030\255\301\326C\343\304=\245\231h`yd\000#s\002\370\374Z\0336\245\361\226\222\306\032k\2457\016h\314(R;\326T~EHH\352\307\023^\247\363\321`V\340\253Z\233\357\227I\373\337z\177\nv\261\252\371\017\226\223\345\005\315y4\b\236N0\2630\017\215c\305&L\260\346J\237\203Q(\335W\027|>\3553\275j\307?W5\3463kc\350\262C\361 \037w!\371}\214\"I\377|\331@a;\342\3566\312\272Z\327u7\204'\215YBLL\235\236\242\345\215\245T\211a\312\263\342\000! \221\202X$\302\317\203\246\207c{\231\330\264\324\\k\271\272\336\356\002|\261O\207\030+\367P\317";
|
||||
|
||||
#endif /*RAW_REPLACEMENTS_H*/
|
||||
|
336
tls.c
Normal file
336
tls.c
Normal file
@ -0,0 +1,336 @@
|
||||
#include "types.h"
|
||||
#include "tls.h"
|
||||
#include "config.h"
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef KERNEL_SPACE
|
||||
#include <stdlib.h>
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
|
||||
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
|
||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
||||
#define TLS_EXTENSION_SNI 0x0000
|
||||
#define TLS_EXTENSION_CLIENT_HELLO_ENCRYPTED 0xfe0d
|
||||
|
||||
/**
|
||||
* Processes tls payload of the tcp request.
|
||||
*
|
||||
* data Payload data of TCP.
|
||||
* dlen Length of `data`.
|
||||
*/
|
||||
struct tls_verdict analyze_tls_data(
|
||||
const uint8_t *data,
|
||||
uint32_t dlen)
|
||||
{
|
||||
struct tls_verdict vrd = {0};
|
||||
|
||||
size_t i = 0;
|
||||
const uint8_t *data_end = data + dlen;
|
||||
|
||||
while (i + 4 < dlen) {
|
||||
const uint8_t *msgData = data + i;
|
||||
|
||||
uint8_t tls_content_type = *msgData;
|
||||
uint8_t tls_vmajor = *(msgData + 1);
|
||||
uint16_t message_length = ntohs(*(uint16_t *)(msgData + 3));
|
||||
|
||||
if (tls_vmajor != 0x03) goto nextMessage;
|
||||
|
||||
if (i + 5 > dlen) break;
|
||||
|
||||
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
|
||||
goto nextMessage;
|
||||
|
||||
if (config.sni_detection == SNI_DETECTION_BRUTE) {
|
||||
goto brute;
|
||||
}
|
||||
|
||||
const uint8_t *handshakeProto = msgData + 5;
|
||||
|
||||
if (handshakeProto + 1 >= data_end) break;
|
||||
|
||||
uint8_t handshakeType = *handshakeProto;
|
||||
|
||||
if (handshakeType != TLS_HANDSHAKE_TYPE_CLIENT_HELLO)
|
||||
goto nextMessage;
|
||||
|
||||
const uint8_t *msgPtr = handshakeProto;
|
||||
msgPtr += 1;
|
||||
msgPtr += 3 + 2 + 32;
|
||||
|
||||
if (msgPtr + 1 >= data_end) break;
|
||||
uint8_t sessionIdLength = *msgPtr;
|
||||
msgPtr++;
|
||||
msgPtr += sessionIdLength;
|
||||
|
||||
if (msgPtr + 2 >= data_end) break;
|
||||
uint16_t ciphersLength = ntohs(*(uint16_t *)msgPtr);
|
||||
msgPtr += 2;
|
||||
msgPtr += ciphersLength;
|
||||
|
||||
if (msgPtr + 1 >= data_end) break;
|
||||
uint8_t compMethodsLen = *msgPtr;
|
||||
msgPtr++;
|
||||
msgPtr += compMethodsLen;
|
||||
|
||||
if (msgPtr + 2 >= data_end) break;
|
||||
uint16_t extensionsLen = ntohs(*(uint16_t *)msgPtr);
|
||||
msgPtr += 2;
|
||||
|
||||
const uint8_t *extensionsPtr = msgPtr;
|
||||
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
|
||||
if (extensions_end > data_end) extensions_end = data_end;
|
||||
|
||||
while (extensionsPtr < extensions_end) {
|
||||
const uint8_t *extensionPtr = extensionsPtr;
|
||||
if (extensionPtr + 4 >= extensions_end) break;
|
||||
|
||||
uint16_t extensionType =
|
||||
ntohs(*(uint16_t *)extensionPtr);
|
||||
extensionPtr += 2;
|
||||
|
||||
uint16_t extensionLen =
|
||||
ntohs(*(uint16_t *)extensionPtr);
|
||||
extensionPtr += 2;
|
||||
|
||||
|
||||
if (extensionPtr + extensionLen > extensions_end)
|
||||
break;
|
||||
|
||||
if (extensionType != TLS_EXTENSION_SNI)
|
||||
goto nextExtension;
|
||||
|
||||
const uint8_t *sni_ext_ptr = extensionPtr;
|
||||
|
||||
if (sni_ext_ptr + 2 >= extensions_end) break;
|
||||
uint16_t sni_ext_dlen = ntohs(*(uint16_t *)sni_ext_ptr);
|
||||
|
||||
sni_ext_ptr += 2;
|
||||
|
||||
const uint8_t *sni_ext_end = sni_ext_ptr + sni_ext_dlen;
|
||||
if (sni_ext_end >= extensions_end) break;
|
||||
|
||||
if (sni_ext_ptr + 3 >= sni_ext_end) break;
|
||||
sni_ext_ptr++;
|
||||
uint16_t sni_len = ntohs(*(uint16_t *)sni_ext_ptr);
|
||||
sni_ext_ptr += 2;
|
||||
|
||||
if (sni_ext_ptr + sni_len > sni_ext_end) break;
|
||||
|
||||
char *sni_name = (char *)sni_ext_ptr;
|
||||
|
||||
vrd.sni_offset = (uint8_t *)sni_name - data;
|
||||
vrd.sni_len = sni_len;
|
||||
|
||||
if (config.all_domains) {
|
||||
vrd.target_sni = 1;
|
||||
goto check_domain;
|
||||
}
|
||||
|
||||
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i <= config.domains_strlen; i++) {
|
||||
if ( i > j &&
|
||||
(i == config.domains_strlen ||
|
||||
config.domains_str[i] == '\0' ||
|
||||
config.domains_str[i] == ',' ||
|
||||
config.domains_str[i] == '\n' )) {
|
||||
|
||||
unsigned int domain_len = (i - j);
|
||||
const char *sni_startp = sni_name + sni_len - domain_len;
|
||||
const char *domain_startp = config.domains_str + j;
|
||||
|
||||
if (sni_len >= domain_len &&
|
||||
sni_len < 128 &&
|
||||
!strncmp(sni_startp,
|
||||
domain_startp,
|
||||
domain_len)) {
|
||||
vrd.target_sni = 1;
|
||||
goto check_domain;
|
||||
}
|
||||
|
||||
j = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
check_domain:
|
||||
if (vrd.target_sni == 1 && config.exclude_domains_strlen != 0) {
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i <= config.exclude_domains_strlen; i++) {
|
||||
if ( i > j &&
|
||||
(i == config.exclude_domains_strlen ||
|
||||
config.exclude_domains_str[i] == '\0' ||
|
||||
config.exclude_domains_str[i] == ',' ||
|
||||
config.exclude_domains_str[i] == '\n' )) {
|
||||
|
||||
unsigned int domain_len = (i - j);
|
||||
const char *sni_startp = sni_name + sni_len - domain_len;
|
||||
const char *domain_startp = config.exclude_domains_str + j;
|
||||
|
||||
if (sni_len >= domain_len &&
|
||||
sni_len < 128 &&
|
||||
!strncmp(sni_startp,
|
||||
domain_startp,
|
||||
domain_len)) {
|
||||
|
||||
vrd.target_sni = 0;
|
||||
lgdebugmsg("Excluded SNI: %.*s",
|
||||
vrd.sni_len, data + vrd.sni_offset);
|
||||
goto out;
|
||||
}
|
||||
|
||||
j = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
nextExtension:
|
||||
extensionsPtr += 2 + 2 + extensionLen;
|
||||
}
|
||||
nextMessage:
|
||||
i += 5 + message_length;
|
||||
}
|
||||
|
||||
out:
|
||||
return vrd;
|
||||
|
||||
|
||||
brute:
|
||||
if (config.all_domains) {
|
||||
vrd.target_sni = 1;
|
||||
vrd.sni_len = 0;
|
||||
vrd.sni_offset = dlen / 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i <= config.domains_strlen; i++) {
|
||||
if ( i > j &&
|
||||
(i == config.domains_strlen ||
|
||||
config.domains_str[i] == '\0' ||
|
||||
config.domains_str[i] == ',' ||
|
||||
config.domains_str[i] == '\n' )) {
|
||||
|
||||
unsigned int domain_len = (i - j);
|
||||
const char *domain_startp = config.domains_str + j;
|
||||
|
||||
if (domain_len + dlen + 1> MAX_PACKET_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NETBUF_ALLOC(buf, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(buf)) {
|
||||
lgerror("Allocation error", -ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
NETBUF_ALLOC(nzbuf, MAX_PACKET_SIZE * sizeof(int));
|
||||
if (!NETBUF_CHECK(nzbuf)) {
|
||||
lgerror("Allocation error", -ENOMEM);
|
||||
NETBUF_FREE(buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int *zbuf = (void *)nzbuf;
|
||||
|
||||
memcpy(buf, domain_startp, domain_len);
|
||||
memcpy(buf + domain_len, "#", 1);
|
||||
memcpy(buf + domain_len + 1, data, dlen);
|
||||
|
||||
z_function((char *)buf, zbuf, domain_len + 1 + dlen);
|
||||
|
||||
for (unsigned int k = 0; k < dlen; k++) {
|
||||
if (zbuf[k] == domain_len) {
|
||||
vrd.target_sni = 1;
|
||||
vrd.sni_len = domain_len;
|
||||
vrd.sni_offset = (k - domain_len - 1);
|
||||
NETBUF_FREE(buf);
|
||||
NETBUF_FREE(nzbuf);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
j = i + 1;
|
||||
|
||||
NETBUF_FREE(buf);
|
||||
NETBUF_FREE(nzbuf);
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
int gen_fake_sni(struct fake_type type,
|
||||
const void *ipxh, uint32_t iph_len,
|
||||
const struct tcphdr *tcph, uint32_t tcph_len,
|
||||
uint8_t *buf, uint32_t *buflen) {
|
||||
|
||||
uint32_t data_len = type.fake_len;
|
||||
if (type.type == FAKE_PAYLOAD_RANDOM && data_len == 0) {
|
||||
data_len = random() % 1200;
|
||||
} else if (type.type == FAKE_PAYLOAD_DEFAULT) {
|
||||
data_len = config.fake_sni_pkt_sz;
|
||||
}
|
||||
|
||||
if (!ipxh || !tcph || !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_TCP;
|
||||
} 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_TCP;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint32_t dlen = iph_len + tcph_len + data_len;
|
||||
|
||||
if (*buflen < dlen)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buf + iph_len, tcph, tcph_len);
|
||||
uint8_t *bfdptr = buf + iph_len + tcph_len;
|
||||
|
||||
switch (type.type) {
|
||||
case FAKE_PAYLOAD_DEFAULT:
|
||||
memcpy(bfdptr, config.fake_sni_pkt, data_len);
|
||||
break;
|
||||
case FAKE_PAYLOAD_DATA:
|
||||
memcpy(bfdptr, type.fake_data, data_len);
|
||||
break;
|
||||
default: // FAKE_PAYLOAD_RANDOM
|
||||
getrandom(bfdptr, data_len, 0);
|
||||
}
|
||||
|
||||
if (ipxv == IP4VERSION) {
|
||||
struct iphdr *niph = (struct iphdr *)buf;
|
||||
niph->tot_len = htons(dlen);
|
||||
} else if (ipxv == IP6VERSION) {
|
||||
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
|
||||
niph->ip6_plen = htons(dlen - iph_len);
|
||||
}
|
||||
|
||||
fail_packet(type.strategy, buf, &dlen, *buflen);
|
||||
|
||||
*buflen = dlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
53
tls.h
Normal file
53
tls.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef TLS_H
|
||||
#define TLS_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
/**
|
||||
* Result of analyze_tls_data function
|
||||
*/
|
||||
struct tls_verdict {
|
||||
int target_sni; /* google video hello packet */
|
||||
int sni_offset; /* offset from start of tcp _payload_ */
|
||||
int sni_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* Processes the packet and finds TLS Client Hello information inside it.
|
||||
* data pointer points to start of TLS Message (TCP Payload)
|
||||
*/
|
||||
struct tls_verdict analyze_tls_data(const uint8_t *data, uint32_t dlen);
|
||||
|
||||
|
||||
struct fake_type {
|
||||
|
||||
#define FAKE_PAYLOAD_RANDOM 0
|
||||
#define FAKE_PAYLOAD_DATA 1
|
||||
// In default mode all other options will be skipped.
|
||||
#define FAKE_PAYLOAD_DEFAULT 2
|
||||
int type;
|
||||
|
||||
// Length of the final fake message.
|
||||
// Pass 0 in RANDOM mode to make it random
|
||||
uint16_t fake_len;
|
||||
|
||||
// Payload of the fake message of fake_len length.
|
||||
// Will be omitted in RANDOM mode.
|
||||
const char *fake_data;
|
||||
|
||||
// faking strategy of the fake packet.
|
||||
// Does not support bitmask, pass standalone strategy.
|
||||
// Pass 0 if you don't want any faking procedures.
|
||||
unsigned int strategy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates the fake client hello message
|
||||
*/
|
||||
int gen_fake_sni(struct fake_type type,
|
||||
const void *iph, uint32_t iph_len,
|
||||
const struct tcphdr *tcph, uint32_t tcph_len,
|
||||
uint8_t *buf, uint32_t *buflen);
|
||||
|
||||
#endif /* TLS_H */
|
@ -31,7 +31,7 @@ export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CF
|
||||
|
||||
APP:=$(BUILD_DIR)/youtubeUnblock
|
||||
|
||||
SRCS := youtubeUnblock.c mangle.c args.c utils.c quic.c
|
||||
SRCS := youtubeUnblock.c mangle.c args.c utils.c quic.c tls.c
|
||||
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
||||
|
||||
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.la
|
||||
|
116
utils.c
116
utils.c
@ -523,3 +523,119 @@ void z_function(const char *str, int *zbuf, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
#define TCP_MD5SIG_LEN 16
|
||||
#define TCP_MD5SIG_KIND 19
|
||||
struct tcp_md5sig_opt {
|
||||
uint8_t kind;
|
||||
uint8_t len;
|
||||
uint8_t sig[TCP_MD5SIG_LEN];
|
||||
};
|
||||
#define TCP_MD5SIG_OPT_LEN (sizeof(struct tcp_md5sig_opt))
|
||||
// Real length of the option, with NOOP fillers
|
||||
#define TCP_MD5SIG_OPT_RLEN 20
|
||||
|
||||
int fail_packet(unsigned int strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen) {
|
||||
void *iph;
|
||||
uint32_t iph_len;
|
||||
struct tcphdr *tcph;
|
||||
uint32_t tcph_len;
|
||||
uint8_t *data;
|
||||
uint32_t dlen;
|
||||
int ret;
|
||||
|
||||
ret = tcp_payload_split(payload, *plen,
|
||||
&iph, &iph_len, &tcph, &tcph_len,
|
||||
&data, &dlen);
|
||||
|
||||
uint32_t ipxv = netproto_version(payload, *plen);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
if (strategy == FAKE_STRAT_RAND_SEQ) {
|
||||
lgtrace("fake seq: %u -> ", ntohl(tcph->seq));
|
||||
|
||||
if (config.fakeseq_offset) {
|
||||
tcph->seq = htonl(ntohl(tcph->seq) - config.fakeseq_offset);
|
||||
} else {
|
||||
#ifdef KERNEL_SPACE
|
||||
tcph->seq = 124;
|
||||
#else
|
||||
tcph->seq = random();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
lgtrace_addp("%u", ntohl(tcph->seq));
|
||||
} else if (strategy == FAKE_STRAT_PAST_SEQ) {
|
||||
lgtrace("fake seq: %u -> ", ntohl(tcph->seq));
|
||||
tcph->seq = htonl(ntohl(tcph->seq) - dlen);
|
||||
lgtrace_addp("%u", ntohl(tcph->seq));
|
||||
|
||||
} else if (strategy == FAKE_STRAT_TTL) {
|
||||
lgtrace_addp("set fake ttl to %d", config.faking_ttl);
|
||||
|
||||
if (ipxv == IP4VERSION) {
|
||||
((struct iphdr *)iph)->ttl = config.faking_ttl;
|
||||
} else if (ipxv == IP6VERSION) {
|
||||
((struct ip6_hdr *)iph)->ip6_hops = config.faking_ttl;
|
||||
} else {
|
||||
lgerror("fail_packet: IP version is unsupported", -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (strategy == FAKE_STRAT_TCP_MD5SUM) {
|
||||
int optp_len = tcph_len - sizeof(struct tcphdr);
|
||||
int delta = TCP_MD5SIG_OPT_RLEN - optp_len;
|
||||
lgtrace_addp("Incr delta %d: %d -> %d", delta, optp_len, optp_len + delta);
|
||||
|
||||
if (delta > 0) {
|
||||
if (avail_buflen - *plen < delta) {
|
||||
return -1;
|
||||
}
|
||||
uint8_t *ndata = data + delta;
|
||||
uint8_t *ndptr = ndata + dlen;
|
||||
uint8_t *dptr = data + dlen;
|
||||
for (size_t i = dlen + 1; i > 0; i--) {
|
||||
*ndptr = *dptr;
|
||||
--ndptr, --dptr;
|
||||
}
|
||||
data = ndata;
|
||||
tcph_len = tcph_len + delta;
|
||||
tcph->doff = tcph_len >> 2;
|
||||
if (ipxv == IP4VERSION) {
|
||||
((struct iphdr *)iph)->tot_len = htons(ntohs(((struct iphdr *)iph)->tot_len) + delta);
|
||||
} else if (ipxv == IP6VERSION) {
|
||||
((struct ip6_hdr *)iph)->ip6_plen = htons(ntohs(((struct ip6_hdr *)iph)->ip6_plen) + delta);
|
||||
} else {
|
||||
lgerror("fail_packet: IP version is unsupported", -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
optp_len += delta;
|
||||
*plen += delta;
|
||||
}
|
||||
|
||||
uint8_t *optplace = (uint8_t *)tcph + sizeof(struct tcphdr);
|
||||
struct tcp_md5sig_opt *mdopt = (void *)optplace;
|
||||
mdopt->kind = TCP_MD5SIG_KIND;
|
||||
mdopt->len = TCP_MD5SIG_OPT_LEN;
|
||||
|
||||
optplace += sizeof(struct tcp_md5sig_opt);
|
||||
optp_len -= sizeof(struct tcp_md5sig_opt);
|
||||
|
||||
while (optp_len-- > 0) {
|
||||
*optplace++ = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
set_ip_checksum(iph, iph_len);
|
||||
set_tcp_checksum(tcph, iph, iph_len);
|
||||
|
||||
if (strategy == FAKE_STRAT_TCP_CHECK) {
|
||||
lgtrace_addp("break fake tcp checksum");
|
||||
tcph->check += 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
10
utils.h
10
utils.h
@ -101,4 +101,14 @@ int set_tcp_checksum(struct tcphdr *tcph, void *iph, uint32_t iphb_len);
|
||||
|
||||
void z_function(const char *str, int *zbuf, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* Does not support bitmask, pass standalone strategy.
|
||||
*/
|
||||
int fail_packet(unsigned int strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen);
|
||||
|
||||
|
||||
#endif /* UTILS_H */
|
||||
|
Loading…
Reference in New Issue
Block a user