Massive update of argparse system

This is required for furhter maintance of kernel module. Aims to provide
common interface for both
This commit is contained in:
Vadim Vetrov 2024-12-08 16:06:50 +03:00
parent 9b5c8a729d
commit 457a7a7f04
No known key found for this signature in database
GPG Key ID: E8A308689D7A73A5
13 changed files with 1582 additions and 852 deletions

2
Kbuild
View File

@ -1,3 +1,3 @@
obj-m := kyoutubeUnblock.o obj-m := kyoutubeUnblock.o
kyoutubeUnblock-objs := kytunblock.o mangle.o quic.o utils.o kargs.o tls.o kyoutubeUnblock-objs := kytunblock.o mangle.o quic.o utils.o kargs.o tls.o getopt.o args.o
ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement

771
args.c
View File

@ -1,33 +1,219 @@
#include "config.h" #include "config.h"
#include <stdbool.h> #include "types.h"
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include "types.h" #include "types.h"
#include "args.h" #include "args.h"
#include "logging.h" #include "logging.h"
#include "getopt.h"
#include "raw_replacements.h"
static char custom_fake_buf[MAX_FAKE_SIZE]; #ifdef KERNEL_SPACE
static int errno = 0;
#define strtol kstrtol
#endif
struct config_t config = { struct config_t config = default_config_set;
.threads = THREADS_NUM,
.queue_start_num = DEFAULT_QUEUE_NUM,
.mark = DEFAULT_RAWSOCKET_MARK,
.use_ipv6 = 1,
.verbose = VERBOSE_DEBUG, static int parse_sni_domains(struct domains_list **dlist, const char *domains_str, size_t domains_strlen) {
.use_gso = true, // Empty and shouldn't be used
struct domains_list ndomain = {0};
struct domains_list *cdomain = &ndomain;
.default_config = default_section_config, unsigned int j = 0;
.custom_configs_len = 0, for (unsigned int i = 0; i <= domains_strlen; i++) {
if (( i == domains_strlen ||
domains_str[i] == '\0' ||
domains_str[i] == ',' ||
domains_str[i] == '\n' )) {
.daemonize = 0, if (i == j) {
.noclose = 0, j++;
.syslog = 0, continue;
}
unsigned int domain_len = (i - j);
const char *domain_startp = domains_str + j;
struct domains_list *edomain = malloc(sizeof(struct domains_list));
*edomain = (struct domains_list){0};
if (edomain == NULL) {
return -ENOMEM;
}
edomain->domain_len = domain_len;
edomain->domain_name = malloc(domain_len + 1);
if (edomain->domain_name == NULL) {
return -ENOMEM;
}
strncpy(edomain->domain_name, domain_startp, domain_len);
edomain->domain_name[domain_len] = '\0';
cdomain->next = edomain;
cdomain = edomain;
j = i + 1;
}
}
*dlist = ndomain.next;
return 0;
}
static void free_sni_domains(struct domains_list *dlist) {
for (struct domains_list *ldl = dlist; ldl != NULL;) {
struct domains_list *ndl = ldl->next;
printf("freeing domains\n");
SFREE(ldl->domain_name);
SFREE(ldl);
ldl = ndl;
}
}
static long parse_numeric_option(const char* value) {
errno = 0;
if (*value == '\0') {
errno = EINVAL;
return 0;
}
long result;
int len;
sscanf(value, "%ld%n", &result, &len);
if (*(value + len) != '\0') {
errno = EINVAL;
return 0;
}
return result;
}
static int parse_udp_dport_range(char *str, struct udp_dport_range **udpr, int *udpr_len) {
int ret = 0;
int seclen = 1;
const char *p = str;
while (*p != '\0') {
if (*p == ',')
seclen++;
p++;
}
#ifdef KERNEL_SPACE
struct udp_dport_range *udp_dport_ranges = kmalloc(
seclen * sizeof(struct udp_dport_range), GFP_KERNEL);
#else
struct udp_dport_range *udp_dport_ranges = malloc(
seclen * sizeof(struct udp_dport_range));
#endif
if (udp_dport_ranges == NULL) {
return -ENOMEM;
}
int i = 0;
p = str;
const char *ep = p;
while (1) {
if (*ep == '\0' || *ep == ',') {
if (ep == p) {
if (*ep == '\0')
break;
p++, ep++;
continue;
}
const char *endp;
long num1;
int len;
sscanf(p, "%ld%n", &num1, &len);
endp = p + len;
long num2 = num1;
if (endp != ep) {
if (*endp == '-') {
endp++;
int len;
sscanf(endp, "%ld%n", &num2, &len);
endp = endp + len;
if (endp != ep)
goto erret;
} else {
goto erret;
}
}
if (
!(num1 > 0 && num1 < (1 << 16)) ||
!(num2 > 0 && num2 < (1 << 16)) ||
num2 < num1
)
goto erret;
udp_dport_ranges[i] = (struct udp_dport_range){
.start = num1,
.end = num2
}; };
i++;
if (*ep == '\0') {
break;
} else {
p = ep + 1;
ep = p;
}
} else {
ep++;
}
}
if (i == 0) {
free(udp_dport_ranges);
}
*udpr = udp_dport_ranges;
*udpr_len = i;
return 0;
erret:
free(udp_dport_ranges);
return -1;
}
// Allocates and fills custom fake buffer
static int parse_fake_custom_payload(
const char *custom_hex_fake,
char **custom_fake_buf, unsigned int *custom_fake_len) {
int ret;
size_t custom_hlen = strlen(custom_hex_fake);
if ((custom_hlen & 1) == 1) {
printf("Custom fake hex should be divisible by two\n");
return -EINVAL;
}
size_t custom_len = custom_hlen >> 1;
if (custom_len > MAX_FAKE_SIZE) {
printf("Custom fake is too large\n");
return -EINVAL;
}
unsigned char *custom_buf = malloc(custom_len);
for (int i = 0; i < custom_len; i++) {
ret = sscanf(custom_hex_fake + (i << 1), "%2hhx", custom_buf + i);
if (ret != 1) {
free(custom_buf);
return -EINVAL;
}
}
*custom_fake_buf = (char *)custom_buf;
*custom_fake_len = custom_len;
return 0;
}
enum { enum {
OPT_SNI_DOMAINS, OPT_SNI_DOMAINS,
@ -69,11 +255,14 @@ enum {
OPT_UDP_DPORT_FILTER, OPT_UDP_DPORT_FILTER,
OPT_UDP_FILTER_QUIC, OPT_UDP_FILTER_QUIC,
OPT_TLS_ENABLED, OPT_TLS_ENABLED,
OPT_CLS,
OPT_HELP,
OPT_VERSION,
}; };
static struct option long_opt[] = { static struct option long_opt[] = {
{"help", 0, 0, 'h'}, {"help", 0, 0, OPT_HELP},
{"version", 0, 0, 'v'}, {"version", 0, 0, OPT_VERSION},
{"sni-domains", 1, 0, OPT_SNI_DOMAINS}, {"sni-domains", 1, 0, OPT_SNI_DOMAINS},
{"exclude-domains", 1, 0, OPT_EXCLUDE_DOMAINS}, {"exclude-domains", 1, 0, OPT_EXCLUDE_DOMAINS},
{"fake-sni", 1, 0, OPT_FAKE_SNI}, {"fake-sni", 1, 0, OPT_FAKE_SNI},
@ -113,27 +302,10 @@ static struct option long_opt[] = {
{"packet-mark", 1, 0, OPT_PACKET_MARK}, {"packet-mark", 1, 0, OPT_PACKET_MARK},
{"fbegin", 0, 0, OPT_START_SECTION}, {"fbegin", 0, 0, OPT_START_SECTION},
{"fend", 0, 0, OPT_END_SECTION}, {"fend", 0, 0, OPT_END_SECTION},
{0,0,0,0} {"cls", 0, 0, OPT_CLS},
{0, 0, 0, 0},
}; };
static long parse_numeric_option(const char* value) {
errno = 0;
if (*value == '\0') {
errno = EINVAL;
return 0;
}
char* end;
long result = strtol(value, &end, 10);
if (*end != '\0') {
errno = EINVAL;
return 0;
}
return result;
}
void print_version(void) { void print_version(void) {
printf("youtubeUnblock" printf("youtubeUnblock"
#if defined(PKG_VERSION) #if defined(PKG_VERSION)
@ -192,93 +364,22 @@ void print_usage(const char *argv0) {
printf("\n"); printf("\n");
} }
int parse_udp_dport_range(char *str, struct udp_dport_range **udpr, int *udpr_len) { int yparse_args(int argc, char *argv[]) {
int ret = 0;
int seclen = 1;
int strlen = 0;
const char *p = optarg;
while (*p != '\0') {
if (*p == ',')
seclen++;
p++;
}
strlen = p - optarg;
struct udp_dport_range *udp_dport_ranges = malloc(
seclen * sizeof(struct udp_dport_range));
int i = 0;
p = optarg;
const char *ep = p;
while (1) {
if (*ep == '\0' || *ep == ',') {
if (ep == p) {
if (*ep == '\0')
break;
p++, ep++;
continue;
}
char *endp;
long num1 = strtol(p, &endp, 10);
long num2 = num1;
if (errno)
goto erret;
if (endp != ep) {
if (*endp == '-') {
endp++;
num2 = strtol(endp, &endp, 10);
if (endp != ep || errno)
goto erret;
} else {
goto erret;
}
}
if (
!(num1 > 0 && num1 < (1 << 16)) ||
!(num2 > 0 && num2 < (1 << 16)) ||
num2 < num1
)
goto erret;
udp_dport_ranges[i] = (struct udp_dport_range){
.start = num1,
.end = num2
};
i++;
if (*ep == '\0') {
break;
} else {
p = ep + 1;
ep = p;
}
} else {
ep++;
}
}
*udpr = udp_dport_ranges;
*udpr_len = seclen;
return 0;
erret:
free(udp_dport_ranges);
return -1;
}
int parse_args(int argc, char *argv[]) {
int opt; int opt;
int optIdx = 0; int optIdx = 0;
optind=1, opterr=1, optreset=0;
long num; long num;
int ret;
struct section_config_t *sect_config = &config.default_config; struct config_t rep_config;
ret = init_config(&rep_config);
if (ret < 0)
return ret;
struct section_config_t *default_section = rep_config.last_section;
struct section_config_t *sect_config = rep_config.last_section;
int sect_i = 0;
sect_config->id = sect_i++;
#define SECT_ITER_DEFAULT 1 #define SECT_ITER_DEFAULT 1
#define SECT_ITER_INSIDE 2 #define SECT_ITER_INSIDE 2
@ -286,86 +387,95 @@ int parse_args(int argc, char *argv[]) {
int section_iter = SECT_ITER_DEFAULT; int section_iter = SECT_ITER_DEFAULT;
while ((opt = getopt_long(argc, argv, "hv", long_opt, &optIdx)) != -1) { while ((opt = getopt_long(argc, argv, "", long_opt, &optIdx)) != -1) {
switch (opt) { switch (opt) {
case OPT_CLS:
free_config(rep_config);
ret = init_config(&rep_config);
if (ret < 0)
return ret;
default_section = rep_config.last_section;
sect_config = rep_config.last_section;
sect_i = 0;
sect_config->id = sect_i++;
section_iter = SECT_ITER_DEFAULT;
break;
/* config_t scoped configs */ /* config_t scoped configs */
case 'h': case OPT_HELP:
print_usage(argv[0]); print_usage(argv[0]);
#ifndef KERNEL_SPACE
goto stop_exec; goto stop_exec;
case 'v': #else
break;
#endif
case OPT_VERSION:
print_version(); print_version();
#ifndef KERNEL_SPACE
goto stop_exec; goto stop_exec;
#else
break;
#endif
case OPT_TRACE: case OPT_TRACE:
if (section_iter != SECT_ITER_DEFAULT) rep_config.verbose = 2;
goto invalid_opt;
config.verbose = 2;
break; break;
case OPT_SILENT: case OPT_SILENT:
if (section_iter != SECT_ITER_DEFAULT) rep_config.verbose = 0;
goto invalid_opt;
config.verbose = 0;
break; break;
case OPT_NO_GSO: case OPT_NO_GSO:
if (section_iter != SECT_ITER_DEFAULT) rep_config.use_gso = 0;
goto invalid_opt;
config.use_gso = 0;
break; break;
case OPT_NO_IPV6: case OPT_NO_IPV6:
if (section_iter != SECT_ITER_DEFAULT) rep_config.use_ipv6 = 0;
goto invalid_opt;
config.use_ipv6 = 0;
break; break;
case OPT_DAEMONIZE: case OPT_DAEMONIZE:
config.daemonize = 1; rep_config.daemonize = 1;
break; break;
case OPT_NOCLOSE: case OPT_NOCLOSE:
config.noclose = 1; rep_config.noclose = 1;
break; break;
case OPT_SYSLOG: case OPT_SYSLOG:
config.syslog = 1; rep_config.syslog = 1;
break; break;
case OPT_THREADS: case OPT_THREADS:
if (section_iter != SECT_ITER_DEFAULT)
goto invalid_opt;
num = parse_numeric_option(optarg); num = parse_numeric_option(optarg);
if (errno != 0 || num < 0 || num > MAX_THREADS) { if (errno != 0 || num < 0 || num > MAX_THREADS) {
goto invalid_opt; goto invalid_opt;
} }
config.threads = num; rep_config.threads = num;
break; break;
case OPT_QUEUE_NUM: case OPT_QUEUE_NUM:
if (section_iter != SECT_ITER_DEFAULT)
goto invalid_opt;
num = parse_numeric_option(optarg); num = parse_numeric_option(optarg);
if (errno != 0 || num < 0) { if (errno != 0 || num < 0) {
goto invalid_opt; goto invalid_opt;
} }
config.queue_start_num = num; rep_config.queue_start_num = num;
break; break;
case OPT_PACKET_MARK: case OPT_PACKET_MARK:
if (section_iter != SECT_ITER_DEFAULT)
goto invalid_opt;
num = parse_numeric_option(optarg); num = parse_numeric_option(optarg);
if (errno != 0 || num < 0) { if (errno != 0 || num < 0) {
goto invalid_opt; goto invalid_opt;
} }
config.mark = num; rep_config.mark = num;
break; break;
case OPT_START_SECTION: case OPT_START_SECTION:
if (section_iter != SECT_ITER_DEFAULT && section_iter != SECT_ITER_OUTSIDE) if (section_iter != SECT_ITER_DEFAULT && section_iter != SECT_ITER_OUTSIDE)
goto invalid_opt; goto invalid_opt;
sect_config = &config.custom_configs[config.custom_configs_len++]; struct section_config_t *nsect;
*sect_config = (struct section_config_t)default_section_config; ret = init_section_config(&nsect, rep_config.last_section);
if (ret < 0) {
goto error;
}
rep_config.last_section->next = nsect;
rep_config.last_section = nsect;
sect_config = nsect;
sect_config->id = sect_i++;
section_iter = SECT_ITER_INSIDE; section_iter = SECT_ITER_INSIDE;
break; break;
@ -374,7 +484,7 @@ int parse_args(int argc, char *argv[]) {
goto invalid_opt; goto invalid_opt;
section_iter = SECT_ITER_OUTSIDE; section_iter = SECT_ITER_OUTSIDE;
sect_config = &config.default_config; sect_config = default_section;
break; break;
/* section_config_t scoped configs */ /* section_config_t scoped configs */
@ -389,16 +499,20 @@ int parse_args(int argc, char *argv[]) {
break; break;
case OPT_SNI_DOMAINS: case OPT_SNI_DOMAINS:
sect_config->all_domains = 0;
if (!strcmp(optarg, "all")) { if (!strcmp(optarg, "all")) {
sect_config->all_domains = 1; sect_config->all_domains = 1;
} }
sect_config->domains_str = optarg; ret = parse_sni_domains(&sect_config->sni_domains, optarg, strlen(optarg));
sect_config->domains_strlen = strlen(sect_config->domains_str); if (ret < 0)
goto error;
break; break;
case OPT_EXCLUDE_DOMAINS: case OPT_EXCLUDE_DOMAINS:
sect_config->exclude_domains_str = optarg; ret = parse_sni_domains(&sect_config->exclude_sni_domains, optarg, strlen(optarg));
sect_config->exclude_domains_strlen = strlen(sect_config->exclude_domains_str); if (ret < 0)
goto error;
break; break;
case OPT_FRAG: case OPT_FRAG:
if (strcmp(optarg, "tcp") == 0) { if (strcmp(optarg, "tcp") == 0) {
@ -512,30 +626,16 @@ int parse_args(int argc, char *argv[]) {
} }
break; break;
case OPT_FAKE_CUSTOM_PAYLOAD: { case OPT_FAKE_CUSTOM_PAYLOAD:
uint8_t *const custom_buf = (uint8_t *)custom_fake_buf; SFREE(sect_config->udp_dport_range);
const char *custom_hex_fake = optarg; ret = parse_fake_custom_payload(optarg, &sect_config->fake_custom_pkt, &sect_config->fake_custom_pkt_sz);
size_t custom_hlen = strlen(custom_hex_fake); if (ret == -EINVAL) {
if ((custom_hlen & 1) == 1) {
printf("Custom fake hex should be divisible by two\n");
goto invalid_opt; goto invalid_opt;
} else if (ret < 0) {
goto error;
} }
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);
}
sect_config->fake_custom_pkt_sz = custom_len;
sect_config->fake_custom_pkt = (char *)custom_buf;
}
break; break;
case OPT_FK_WINSIZE: case OPT_FK_WINSIZE:
num = parse_numeric_option(optarg); num = parse_numeric_option(optarg);
@ -623,13 +723,10 @@ int parse_args(int argc, char *argv[]) {
break; break;
case OPT_UDP_DPORT_FILTER: case OPT_UDP_DPORT_FILTER:
{ {
struct udp_dport_range *udp_dport_range; SFREE(sect_config->udp_dport_range);
int udp_range_len = 0; if (parse_udp_dport_range(optarg, &sect_config->udp_dport_range, &sect_config->udp_dport_range_len) < 0) {
if (parse_udp_dport_range(optarg, &udp_dport_range, &udp_range_len) < 0) {
goto invalid_opt; goto invalid_opt;
} }
sect_config->udp_dport_range = udp_dport_range;
sect_config->udp_dport_range_len = udp_range_len;
break; break;
} }
case OPT_UDP_FILTER_QUIC: case OPT_UDP_FILTER_QUIC:
@ -648,22 +745,248 @@ int parse_args(int argc, char *argv[]) {
} }
struct config_t old_config = config;
config = rep_config;
free_config(old_config);
errno = 0; errno = 0;
return 0; return 0;
stop_exec: stop_exec:
free_config(rep_config);
errno = 0; errno = 0;
return 1; return 1;
invalid_opt: invalid_opt:
printf("Invalid option %s\n", long_opt[optIdx].name); printf("Invalid option %s\n", long_opt[optIdx].name);
ret = -EINVAL;
error: error:
#ifndef KERNEL_SPACE
print_usage(argv[0]); print_usage(argv[0]);
errno = EINVAL; #endif
if (ret != -EINVAL) {
lgerror(ret, "Error thrown in %s\n", long_opt[optIdx].name);
}
errno = -ret;
free_config(rep_config);
return -errno; return -errno;
} }
#define print_cnf_raw(fmt, ...) do { \
sz = snprintf(buf_ptr, buf_sz, fmt, ##__VA_ARGS__); \
if (sz > buf_sz) { buf_sz = 0; } \
else { buf_sz -= sz; } \
buf_ptr += sz; \
} while(0)
#define print_cnf_buf(fmt, ...) print_cnf_raw(fmt " ", ##__VA_ARGS__)
// Returns written buffer size
static size_t print_config_section(const struct section_config_t *section, char *buffer, size_t buffer_size) {
char *buf_ptr = buffer;
size_t buf_sz = buffer_size;
size_t sz;
if (section->tls_enabled) {
print_cnf_buf("--tls=enabled");
if (section->sni_domains != NULL) {
print_cnf_raw("--sni-domains=");
for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) {
print_cnf_raw("%s,", sne->domain_name);
}
print_cnf_raw(" ");
}
if (section->exclude_sni_domains != NULL) {
print_cnf_raw("--exclude-domains=");
for (struct domains_list *sne = section->exclude_sni_domains; sne != NULL; sne = sne->next) {
print_cnf_raw("%s,", sne->domain_name);
}
print_cnf_raw(" ");
}
switch(section->fragmentation_strategy) {
case FRAG_STRAT_IP:
print_cnf_buf("--frag=ip");
break;
case FRAG_STRAT_TCP:
print_cnf_buf("--frag=tcp");
break;
case FRAG_STRAT_NONE:
print_cnf_buf("--frag=none");
break;
}
print_cnf_buf("frag-sni-reverse=%d", section->frag_sni_reverse);
print_cnf_buf("frag-sni-faked=%d", section->frag_sni_faked);
print_cnf_buf("frag-middle-sni=%d", section->frag_middle_sni);
print_cnf_buf("frag-sni-pos=%d", section->frag_sni_pos);
print_cnf_buf("fk-winsize=%d", section->fk_winsize);
if (section->fake_sni) {
print_cnf_buf("--fake-sni=1");
print_cnf_buf("--fake-sni-seq-len=%d", section->fake_sni_seq_len);
switch(section->fake_sni_type) {
case FAKE_PAYLOAD_CUSTOM:
print_cnf_buf("--fake-sni-type=custom");
print_cnf_buf("--fake-custom-payload=<hidden>");
break;
case FAKE_PAYLOAD_RANDOM:
print_cnf_buf("--fake-sni-type=random");
break;
case FAKE_PAYLOAD_DEFAULT:
print_cnf_buf("--fake-sni-type=default");
break;
}
switch(section->faking_strategy) {
case FAKE_STRAT_TTL:
print_cnf_buf("--faking-strategy=ttl");
print_cnf_buf("--faking-ttl=%d", section->faking_ttl);
break;
case FAKE_STRAT_RAND_SEQ:
print_cnf_buf("--faking-strategy=randseq");
break;
case FAKE_STRAT_TCP_CHECK:
print_cnf_buf("--faking-strategy=tcp_check");
break;
case FAKE_STRAT_TCP_MD5SUM:
print_cnf_buf("--faking-strategy=md5sum");
break;
case FAKE_STRAT_PAST_SEQ:
print_cnf_buf("--faking-strategy=pastseq");
print_cnf_buf("--fake-seq-offset=%d", section->fakeseq_offset);
break;
}
switch(section->sni_detection) {
case SNI_DETECTION_BRUTE:
print_cnf_buf("--sni_detection=brute");
break;
case SNI_DETECTION_PARSE:
print_cnf_buf("--sni_detection=parse");
break;
}
print_cnf_buf("--seg2delay=%d", section->seg2_delay);
}
} else {
print_cnf_buf("--tls=disabled");
}
if (section->synfake) {
print_cnf_buf("--synfake=1");
print_cnf_buf("--synfake-len=%d", section->synfake_len);
} else {
print_cnf_buf("--synfake=0");
}
if (section->udp_filter_quic == UDP_FILTER_QUIC_ALL && section->udp_mode == UDP_MODE_DROP) {
print_cnf_buf("--drop-quic");
}
switch(section->udp_filter_quic) {
case UDP_FILTER_QUIC_ALL:
print_cnf_buf("--udp-filter-quic=all");
break;
case UDP_FILTER_QUIC_DISABLED:
print_cnf_buf("--udp-filter-quic=disabled");
break;
}
if (section->udp_dport_range_len != 0)
print_cnf_raw("--udp-dport-filter=");
for (int i = 0; i < section->udp_dport_range_len; i++) {
struct udp_dport_range range = section->udp_dport_range[i];
print_cnf_raw("%d-%d,", range.start, range.end);
}
print_cnf_raw(" ");
if (section->udp_filter_quic != UDP_FILTER_QUIC_DISABLED || section->udp_dport_range_len != 0) {
switch(section->udp_mode) {
case UDP_MODE_DROP:
print_cnf_buf("--udp-mode=drop");
break;
case UDP_MODE_FAKE:
print_cnf_buf("--udp-mode=fake");
print_cnf_buf("--udp-fake-seq-len=%d", section->udp_fake_seq_len);
{
switch(section->udp_faking_strategy) {
case FAKE_STRAT_UDP_CHECK:
print_cnf_buf("--udp-faking-strategy=checksum");
break;
case FAKE_STRAT_TTL:
print_cnf_buf("--udp-faking-strategy=ttl");
}
}
break;
}
}
return buffer_size - buf_sz;
}
// Returns written buffer length
size_t print_config(char *buffer, size_t buffer_size) {
char *buf_ptr = buffer;
size_t buf_sz = buffer_size;
size_t sz;
#ifndef KERNEL_SPACE
print_cnf_buf("--queue-num=%d", config.queue_start_num);
print_cnf_buf("--threads=%d", config.threads);
#endif
print_cnf_buf("--mark=%d", config.mark);
#ifndef KERNEL_SPACE
if (config.daemonize) {
print_cnf_buf("--daemonize");
}
if (config.syslog) {
print_cnf_buf("--syslog");
}
if (config.noclose) {
print_cnf_buf("--noclose");
}
if (!config.use_gso) {
print_cnf_buf("--no-gso");
}
#endif
if (!config.use_ipv6) {
print_cnf_buf("--no-ipv6");
}
if (config.verbose == VERBOSE_TRACE) {
print_cnf_buf("--trace");
}
if (config.verbose == VERBOSE_INFO) {
print_cnf_buf("--silent");
}
size_t wbuf_len = print_config_section(config.first_section, buf_ptr, buf_sz);
buf_ptr += wbuf_len;
buf_sz -= wbuf_len;
for (struct section_config_t *section = config.first_section->next;
section != NULL; section = section->next) {
print_cnf_buf("--fbegin");
wbuf_len = print_config_section(section, buf_ptr, buf_sz);
buf_ptr += wbuf_len;
buf_sz -= wbuf_len;
print_cnf_buf("--fend");
}
return buffer_size - buf_sz;
}
void print_welcome(void) { void print_welcome(void) {
char welcome_message[4000];
size_t sz = print_config(welcome_message, 4000);
printf("Running with flags: %.*s\n", (int)sz, welcome_message);
return;
/**
if (config.syslog) { if (config.syslog) {
printf("Logging to system log\n"); printf("Logging to system log\n");
} }
@ -762,5 +1085,73 @@ void print_welcome(void) {
lginfo("Target sni domains: %s\n", section->domains_str); lginfo("Target sni domains: %s\n", section->domains_str);
} }
} }
*/
} }
int init_section_config(struct section_config_t **section, struct section_config_t *prev) {
struct section_config_t *def_section = NULL;
int ret;
#ifdef KERNEL_SPACE
def_section = kmalloc(sizeof(struct section_config_t), GFP_KERNEL);
#else
def_section = malloc(sizeof(struct section_config_t));
#endif
*def_section = (struct section_config_t)default_section_config;
def_section->prev = prev;
if (def_section == NULL)
return -ENOMEM;
ret = parse_sni_domains(&def_section->sni_domains, default_snistr, sizeof(default_snistr));
if (ret < 0) {
free(def_section);
return ret;
}
def_section->fake_sni_pkt = fake_sni_old;
def_section->fake_sni_pkt_sz = sizeof(fake_sni_old) - 1;
*section = def_section;
return 0;
}
int init_config(struct config_t *config) {
struct config_t def_config = default_config_set;
int ret = 0;
struct section_config_t *def_section = NULL;
ret = init_section_config(&def_section, NULL);
if (ret < 0)
return ret;
def_config.last_section = def_section;
def_config.first_section = def_section;
*config = def_config;
return 0;
}
void free_config_section(struct section_config_t *section) {
lginfo("freeing %d\n", section->id);
if (section->udp_dport_range_len != 0) {
SFREE(section->udp_dport_range);
}
free_sni_domains(section->sni_domains);
section->sni_domains = NULL;
free_sni_domains(section->exclude_sni_domains);
section->exclude_sni_domains = NULL;
section->fake_custom_pkt_sz = 0;
SFREE(section->fake_custom_pkt);
free(section);
}
void free_config(struct config_t config) {
lginfo("freeing config\n");
for (struct section_config_t *sct = config.last_section; sct != NULL;) {
struct section_config_t *psct = sct->prev;
free_config_section(sct);
sct = psct;
}
}

14
args.h
View File

@ -1,9 +1,21 @@
#ifndef ARGS_H #ifndef ARGS_H
#define ARGS_H #define ARGS_H
#include "types.h"
#include "config.h"
void print_version(void); void print_version(void);
void print_usage(const char *argv0); void print_usage(const char *argv0);
int parse_args(int argc, char *argv[]); int yparse_args(int argc, char *argv[]);
size_t print_config(char *buffer, size_t buffer_size);
// Initializes configuration storage.
int init_config(struct config_t *config);
// Allocates and initializes configuration section.
int init_section_config(struct section_config_t **section, struct section_config_t *prev);
// Frees configuration section
void free_config_section(struct section_config_t *config);
// Frees sections under config
void free_config(struct config_t config);
/* Prints starting messages */ /* Prints starting messages */
void print_welcome(void); void print_welcome(void);

View File

@ -5,7 +5,6 @@
#define USER_SPACE #define USER_SPACE
#endif #endif
#include "raw_replacements.h"
#include "types.h" #include "types.h"
typedef int (*raw_send_t)(const unsigned char *data, unsigned int data_len); typedef int (*raw_send_t)(const unsigned char *data, unsigned int data_len);
@ -26,9 +25,21 @@ struct udp_dport_range {
uint16_t end; uint16_t end;
}; };
struct domains_list {
char *domain_name;
uint16_t domain_len;
struct domains_list *next;
};
struct section_config_t { struct section_config_t {
const char *domains_str; int id;
unsigned int domains_strlen; struct section_config_t *next;
struct section_config_t *prev;
struct domains_list *sni_domains;
struct domains_list *exclude_sni_domains;
unsigned int all_domains;
int tls_enabled; int tls_enabled;
@ -53,14 +64,10 @@ struct section_config_t {
int synfake; int synfake;
unsigned int synfake_len; unsigned int synfake_len;
const char *exclude_domains_str;
unsigned int exclude_domains_strlen;
unsigned int all_domains;
const char *fake_sni_pkt; const char *fake_sni_pkt;
unsigned int fake_sni_pkt_sz; unsigned int fake_sni_pkt_sz;
const char *fake_custom_pkt; char *fake_custom_pkt;
unsigned int fake_custom_pkt_sz; unsigned int fake_custom_pkt_sz;
unsigned int fk_winsize; unsigned int fk_winsize;
@ -98,17 +105,16 @@ struct config_t {
#define VERBOSE_TRACE 2 #define VERBOSE_TRACE 2
int verbose; int verbose;
struct section_config_t default_config; struct section_config_t *first_section;
struct section_config_t custom_configs[MAX_CONFIGLIST_LEN]; struct section_config_t *last_section;
int custom_configs_len;
}; };
extern struct config_t config; extern struct config_t config;
#define ITER_CONFIG_SECTIONS(section) \ #define ITER_CONFIG_SECTIONS(config, section) \
for (struct section_config_t *section = &config.default_config + config.custom_configs_len; section >= &config.default_config; section--) for (struct section_config_t *section = (config)->last_section; section != NULL; section = section->prev)
#define CONFIG_SECTION_NUMBER(section) (int)((section) - &config.default_config) #define CONFIG_SECTION_NUMBER(section) ((section)->id)
#define MAX_THREADS 16 #define MAX_THREADS 16
@ -180,7 +186,7 @@ if ((fake_bitmask) & strategy)
#define DEFAULT_SNISTR "googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com" #define DEFAULT_SNISTR "googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com"
static const char defaul_snistr[] = DEFAULT_SNISTR; static const char default_snistr[] = DEFAULT_SNISTR;
enum { enum {
UDP_MODE_DROP, UDP_MODE_DROP,
@ -193,6 +199,9 @@ enum {
}; };
#define default_section_config { \ #define default_section_config { \
.sni_domains = NULL, \
.exclude_sni_domains = NULL, \
.all_domains = 0, \
.tls_enabled = 1, \ .tls_enabled = 1, \
.frag_sni_reverse = 1, \ .frag_sni_reverse = 1, \
.frag_sni_faked = 0, \ .frag_sni_faked = 0, \
@ -202,6 +211,8 @@ enum {
.fake_sni = 1, \ .fake_sni = 1, \
.fake_sni_seq_len = 1, \ .fake_sni_seq_len = 1, \
.fake_sni_type = FAKE_PAYLOAD_DEFAULT, \ .fake_sni_type = FAKE_PAYLOAD_DEFAULT, \
.fake_custom_pkt = NULL, \
.fake_custom_pkt_sz = 0, \
.frag_middle_sni = 1, \ .frag_middle_sni = 1, \
.frag_sni_pos = 1, \ .frag_sni_pos = 1, \
.fakeseq_offset = 10000, \ .fakeseq_offset = 10000, \
@ -210,16 +221,6 @@ enum {
\ \
.seg2_delay = 0, \ .seg2_delay = 0, \
\ \
.domains_str = defaul_snistr, \
.domains_strlen = sizeof(defaul_snistr), \
\
.exclude_domains_str = "", \
.exclude_domains_strlen = 0, \
\
.fake_sni_pkt = fake_sni_old, \
.fake_sni_pkt_sz = sizeof(fake_sni_old) - 1, \
.fake_custom_pkt = custom_fake_buf, \
.fake_custom_pkt_sz = 0, \
.sni_detection = SNI_DETECTION_PARSE, \ .sni_detection = SNI_DETECTION_PARSE, \
\ \
.udp_mode = UDP_MODE_FAKE, \ .udp_mode = UDP_MODE_FAKE, \
@ -229,6 +230,32 @@ enum {
.udp_dport_range = NULL, \ .udp_dport_range = NULL, \
.udp_dport_range_len = 0, \ .udp_dport_range_len = 0, \
.udp_filter_quic = UDP_FILTER_QUIC_DISABLED, \ .udp_filter_quic = UDP_FILTER_QUIC_DISABLED, \
\
.prev = NULL, \
.next = NULL, \
.id = 0, \
} }
#define default_config_set { \
.threads = THREADS_NUM, \
.queue_start_num = DEFAULT_QUEUE_NUM, \
.mark = DEFAULT_RAWSOCKET_MARK, \
.use_ipv6 = 1, \
\
.verbose = VERBOSE_DEBUG, \
.use_gso = 1, \
\
.first_section = NULL, \
.last_section = NULL, \
\
.daemonize = 0, \
.noclose = 0, \
.syslog = 0, \
}
#define CONFIG_SET(config) \
struct config_t config = default_config_set; \
config->last_section = &(config.default_config) \
#endif /* YTB_CONFIG_H */ #endif /* YTB_CONFIG_H */

204
getopt.c Normal file
View File

@ -0,0 +1,204 @@
#include "types.h"
#include "logging.h"
#include "getopt.h"
char *optarg;
int optind=1, opterr=1, optopt, __optpos, optreset=0;
#define optpos __optpos
static void __getopt_msg(const char *b, const char *c, size_t l)
{
lgerr("%s %.*s\n", b, (int)l, c);
}
int getopt(int argc, char * const argv[], const char *optstring)
{
int i, c, d;
int k, l;
char *optchar;
if (!optind || optreset) {
optreset = 0;
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind])
return -1;
if (argv[optind][0] != '-') {
if (optstring[0] == '-') {
optarg = argv[optind++];
return 1;
}
return -1;
}
if (!argv[optind][1])
return -1;
if (argv[optind][1] == '-' && !argv[optind][2])
return optind++, -1;
if (!optpos) optpos++;
c = argv[optind][optpos], k = 1;
optchar = argv[optind]+optpos;
optopt = c;
optpos += k;
if (!argv[optind][optpos]) {
optind++;
optpos = 0;
}
if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
i = 0;
d = 0;
do {
d = optstring[i], l = 1;
if (l>0) i+=l; else i++;
} while (l && d != c);
if (d != c) {
if (optstring[0] != ':' && opterr)
__getopt_msg("Unrecognized option: ", optchar, k);
return '?';
}
if (optstring[i] == ':') {
if (optstring[i+1] == ':') optarg = 0;
else if (optind >= argc) {
if (optstring[0] == ':') return ':';
if (opterr) __getopt_msg("Option requires an argument: ",
optchar, k);
return '?';
}
if (optstring[i+1] != ':' || optpos) {
optarg = argv[optind++] + optpos;
optpos = 0;
}
}
return c;
}
static void permute(char *const *argv, int dest, int src)
{
char **av = (char **)argv;
char *tmp = av[src];
int i;
for (i=src; i>dest; i--)
av[i] = av[i-1];
av[dest] = tmp;
}
static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{
optarg = 0;
if (longopts && argv[optind][0] == '-' &&
((longonly && argv[optind][1] && argv[optind][1] != '-') ||
(argv[optind][1] == '-' && argv[optind][2])))
{
int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
int i, cnt, match = -1;
char *opt;
for (cnt=i=0; longopts[i].name; i++) {
const char *name = longopts[i].name;
opt = argv[optind]+1;
if (*opt == '-') opt++;
for (; *name && *name == *opt; name++, opt++);
if (*opt && *opt != '=') continue;
match = i;
if (!*name) {
cnt = 1;
break;
}
cnt++;
}
if (cnt==1) {
i = match;
optind++;
optopt = longopts[i].val;
if (*opt == '=') {
if (!longopts[i].has_arg) {
if (colon || !opterr)
return '?';
__getopt_msg(
"Option does not take an argument: ",
longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optarg = opt+1;
} else if (longopts[i].has_arg == required_argument) {
if (!(optarg = argv[optind])) {
if (colon) return ':';
if (!opterr) return '?';
__getopt_msg(
"Option requires an argument: ",
longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optind++;
}
if (idx) *idx = i;
if (longopts[i].flag) {
*longopts[i].flag = longopts[i].val;
return 0;
}
return longopts[i].val;
}
if (argv[optind][1] == '-') {
if (!colon && opterr)
__getopt_msg(cnt ?
"Option is ambiguous: " :
"Unrecognized option: ",
argv[optind]+2,
strlen(argv[optind]+2));
optind++;
return '?';
}
}
return getopt(argc, argv, optstring);
}
static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{
int ret, skipped, resumed;
if (!optind || optreset) {
optreset = 0;
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind]) return -1;
skipped = optind;
if (optstring[0] != '+' && optstring[0] != '-') {
int i;
for (i=optind; ; i++) {
if (i >= argc || !argv[i]) return -1;
if (argv[i][0] == '-' && argv[i][1]) break;
}
optind = i;
}
resumed = optind;
ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
if (resumed > skipped) {
int i, cnt = optind-resumed;
for (i=0; i<cnt; i++)
permute(argv, skipped, optind-1);
optind = skipped + cnt;
}
return ret;
}
int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}
int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
}

45
getopt.h Normal file
View File

@ -0,0 +1,45 @@
/*
Copyright 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _GETOPT_H
#define _GETOPT_H
int getopt(int, char * const [], const char *);
extern char *optarg;
extern int optind, opterr, optopt, optreset;
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long(int, char *const *, const char *, const struct option *, int *);
int getopt_long_only(int, char *const *, const char *, const struct option *, int *);
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#endif

1041
kargs.c

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "utils.h" #include "utils.h"
#include "logging.h" #include "logging.h"
#include "args.h"
#if defined(PKG_VERSION) #if defined(PKG_VERSION)
MODULE_VERSION(PKG_VERSION); MODULE_VERSION(PKG_VERSION);
@ -206,9 +207,9 @@ erret_lc:
int ipvx = netproto_version(pkt, pktlen); int ipvx = netproto_version(pkt, pktlen);
if (ipvx == IP4VERSION) { if (ipvx == IP4VERSION) {
return send_raw_ipv4(pkt, pktlen); ret = send_raw_ipv4(pkt, pktlen);
} else if (ipvx == IP6VERSION) { } else if (ipvx == IP6VERSION) {
return send_raw_ipv6(pkt, pktlen); ret = send_raw_ipv6(pkt, pktlen);
} else { } else {
printf("proto version %d is unsupported\n", ipvx); printf("proto version %d is unsupported\n", ipvx);
return -EINVAL; return -EINVAL;
@ -346,6 +347,8 @@ static struct nf_hook_ops ykb6_nf_reg __read_mostly = {
static int __init ykb_init(void) { static int __init ykb_init(void) {
int ret = 0; int ret = 0;
ret = init_config(&config);
if (ret < 0) goto err;
ret = open_raw_socket(); ret = open_raw_socket();
if (ret < 0) goto err; if (ret < 0) goto err;
@ -420,6 +423,8 @@ static void __exit ykb_destroy(void) {
#endif #endif
close_raw_socket(); close_raw_socket();
free_config(config);
lginfo("youtubeUnblock kernel module destroyed.\n"); lginfo("youtubeUnblock kernel module destroyed.\n");
} }

View File

@ -62,7 +62,7 @@ int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
lgtrace_addp("UDP"); lgtrace_addp("UDP");
ITER_CONFIG_SECTIONS(section) { ITER_CONFIG_SECTIONS(&config, section) {
lgtrace_addp("Section #%d", CONFIG_SECTION_NUMBER(section)); lgtrace_addp("Section #%d", CONFIG_SECTION_NUMBER(section));
switch (transport_proto) { switch (transport_proto) {

251
tls.c
View File

@ -9,6 +9,114 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
static int bruteforce_analyze_sni_str(
const struct section_config_t *section,
const uint8_t *data, size_t dlen,
struct tls_verdict *vrd
) {
if (section->all_domains) {
vrd->target_sni = 1;
vrd->sni_len = 0;
vrd->sni_offset = dlen / 2;
return 0;
}
for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) {
const char *domain_startp = sne->domain_name;
int domain_len = sne->domain_len;
if (sne->domain_len + dlen + 1 > MAX_PACKET_SIZE) {
continue;
}
NETBUF_ALLOC(buf, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(buf)) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
NETBUF_ALLOC(nzbuf, MAX_PACKET_SIZE * sizeof(int));
if (!NETBUF_CHECK(nzbuf)) {
lgerror(-ENOMEM, "Allocation error");
NETBUF_FREE(buf);
return -ENOMEM;
}
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);
vrd->sni_target_offset = vrd->sni_offset;
vrd->sni_target_len = vrd->sni_len;
NETBUF_FREE(buf);
NETBUF_FREE(nzbuf);
return 0;
}
}
NETBUF_FREE(buf);
NETBUF_FREE(nzbuf);
}
return 0;
}
static int analyze_sni_str(
const struct section_config_t *section,
const char *sni_name, int sni_len, const uint8_t *data,
struct tls_verdict *vrd
) {
if (section->all_domains) {
vrd->target_sni = 1;
goto check_domain;
}
for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) {
const char *sni_startp = sni_name + sni_len - sne->domain_len;
const char *domain_startp = sne->domain_name;
if (sni_len >= sne->domain_len &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
sne->domain_len)) {
vrd->target_sni = 1;
vrd->sni_target_offset = (const uint8_t *)sni_startp - data;
vrd->sni_target_len = sne->domain_len;
break;
}
}
check_domain:
if (vrd->target_sni == 1) {
for (struct domains_list *sne = section->exclude_sni_domains; sne != NULL; sne = sne->next) {
const char *sni_startp = sni_name + sni_len - sne->domain_len;
const char *domain_startp = sne->domain_name;
if (sni_len >= sne->domain_len &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
sne->domain_len)) {
vrd->target_sni = 0;
lgdebugmsg("Excluded SNI: %.*s",
vrd->sni_len, data + vrd->sni_offset);
}
}
}
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
#define TLS_EXTENSION_SNI 0x0000 #define TLS_EXTENSION_SNI 0x0000
@ -26,10 +134,16 @@ struct tls_verdict analyze_tls_data(
uint32_t dlen) uint32_t dlen)
{ {
struct tls_verdict vrd = {0}; struct tls_verdict vrd = {0};
int ret;
size_t i = 0; size_t i = 0;
const uint8_t *data_end = data + dlen; const uint8_t *data_end = data + dlen;
if (section->sni_detection == SNI_DETECTION_BRUTE) {
ret = bruteforce_analyze_sni_str(section, data, dlen, &vrd);
goto out;
}
while (i + 4 < dlen) { while (i + 4 < dlen) {
const uint8_t *msgData = data + i; const uint8_t *msgData = data + i;
@ -44,10 +158,6 @@ struct tls_verdict analyze_tls_data(
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE) if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
goto nextMessage; goto nextMessage;
if (section->sni_detection == SNI_DETECTION_BRUTE) {
goto brute;
}
const uint8_t *handshakeProto = msgData + 5; const uint8_t *handshakeProto = msgData + 5;
if (handshakeProto + 1 >= data_end) break; if (handshakeProto + 1 >= data_end) break;
@ -120,76 +230,14 @@ struct tls_verdict analyze_tls_data(
if (sni_ext_ptr + sni_len > sni_ext_end) break; if (sni_ext_ptr + sni_len > sni_ext_end) break;
char *sni_name = (char *)sni_ext_ptr; const char *sni_name = (char *)sni_ext_ptr;
vrd.sni_offset = (uint8_t *)sni_name - data; vrd.sni_offset = (uint8_t *)sni_name - data;
vrd.sni_target_offset = vrd.sni_offset; vrd.sni_target_offset = vrd.sni_offset;
vrd.sni_len = sni_len; vrd.sni_len = sni_len;
vrd.sni_target_len = vrd.sni_len; vrd.sni_target_len = vrd.sni_len;
if (section->all_domains) { ret = analyze_sni_str(section, sni_name, sni_len, data, &vrd);
vrd.target_sni = 1;
goto check_domain;
}
unsigned int j = 0;
for (unsigned int i = 0; i <= section->domains_strlen; i++) {
if ( i > j &&
(i == section->domains_strlen ||
section->domains_str[i] == '\0' ||
section->domains_str[i] == ',' ||
section->domains_str[i] == '\n' )) {
unsigned int domain_len = (i - j);
const char *sni_startp = sni_name + sni_len - domain_len;
const char *domain_startp = section->domains_str + j;
if (sni_len >= domain_len &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
domain_len)) {
vrd.target_sni = 1;
vrd.sni_target_offset = (const uint8_t *)sni_startp - data;
vrd.sni_target_len = domain_len;
goto check_domain;
}
j = i + 1;
}
}
check_domain:
if (vrd.target_sni == 1 && section->exclude_domains_strlen != 0) {
unsigned int j = 0;
for (unsigned int i = 0; i <= section->exclude_domains_strlen; i++) {
if ( i > j &&
(i == section->exclude_domains_strlen ||
section->exclude_domains_str[i] == '\0' ||
section->exclude_domains_str[i] == ',' ||
section->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 = section->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; goto out;
nextExtension: nextExtension:
@ -201,73 +249,6 @@ nextMessage:
out: out:
return vrd; return vrd;
brute:
if (section->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 <= section->domains_strlen; i++) {
if ( i > j &&
(i == section->domains_strlen ||
section->domains_str[i] == '\0' ||
section->domains_str[i] == ',' ||
section->domains_str[i] == '\n' )) {
unsigned int domain_len = (i - j);
const char *domain_startp = section->domains_str + j;
if (domain_len + dlen + 1> MAX_PACKET_SIZE) {
continue;
}
NETBUF_ALLOC(buf, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(buf)) {
lgerror(-ENOMEM, "Allocation error");
goto out;
}
NETBUF_ALLOC(nzbuf, MAX_PACKET_SIZE * sizeof(int));
if (!NETBUF_CHECK(nzbuf)) {
lgerror(-ENOMEM, "Allocation error");
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);
vrd.sni_target_offset = vrd.sni_offset;
vrd.sni_target_len = vrd.sni_len;
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, int gen_fake_sni(struct fake_type type,

View File

@ -34,6 +34,9 @@
#include <linux/tcp.h> // IWYU pragma: export #include <linux/tcp.h> // IWYU pragma: export
#include <linux/version.h> #include <linux/version.h>
#define free kfree
#define malloc(size) kmalloc((size), GFP_KERNEL)
#define ip6_hdr ipv6hdr #define ip6_hdr ipv6hdr
/* from <netinet/ip.h> */ /* from <netinet/ip.h> */
@ -67,6 +70,11 @@
#include <netinet/udp.h> // IWYU pragma: export #include <netinet/udp.h> // IWYU pragma: export
#endif #endif
#define SFREE(item) do { \
free((item)); \
(item) = NULL; \
} while (0)
#ifndef KERNEL_SPACE #ifndef KERNEL_SPACE
#define max(a,b)__extension__\ #define max(a,b)__extension__\

View File

@ -31,7 +31,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 utils.c quic.c tls.c SRCS := youtubeUnblock.c mangle.c args.c utils.c quic.c tls.c getopt.c
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o) OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.la LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.la

View File

@ -612,7 +612,7 @@ struct instance_config_t instance_config = {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int ret; int ret;
if ((ret = parse_args(argc, argv)) != 0) { if ((ret = yparse_args(argc, argv)) != 0) {
if (ret < 0) { if (ret < 0) {
lgerror(-errno, "Unable to parse args"); lgerror(-errno, "Unable to parse args");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);