mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2025-12-06 03:26:45 +03:00
2
Kbuild
2
Kbuild
@@ -1,3 +1,3 @@
|
||||
obj-m := kyoutubeUnblock.o
|
||||
kyoutubeUnblock-objs := src/kytunblock.o src/mangle.o src/quic.o src/quic_crypto.o src/utils.o src/kargs.o src/tls.o src/getopt.o src/inet_ntop.o src/args.o deps/cyclone/aes.o deps/cyclone/cpu_endian.o deps/cyclone/ecb.o deps/cyclone/gcm.o deps/cyclone/hkdf.o deps/cyclone/hmac.o deps/cyclone/sha256.o
|
||||
kyoutubeUnblock-objs := src/kytunblock.o src/mangle.o src/quic.o src/quic_crypto.o src/utils.o src/tls.o src/getopt.o src/inet_ntop.o src/args.o deps/cyclone/aes.o deps/cyclone/cpu_endian.o deps/cyclone/ecb.o deps/cyclone/gcm.o deps/cyclone/hkdf.o deps/cyclone/hmac.o deps/cyclone/sha256.o
|
||||
ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement -I$(src)/src -I$(src)/deps/cyclone/include
|
||||
|
||||
@@ -278,6 +278,8 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
|
||||
|
||||
- `--quic-drop` Drop all QUIC packets which goes to youtubeUnblock. Won't affect any other UDP packets. Just an alias for `--udp-filter-quic=all --udp-mode=drop`.
|
||||
|
||||
- `--no-dport-filter` By default, youtubeUnblock will filter for TLS and QUIC 443. If you want to disable it, pass this flag. (this does not affect `--udp-dport-filter`)
|
||||
|
||||
## UDP/QUIC
|
||||
|
||||
UDP is another communication protocol. Well-known technologies that use it are DNS, QUIC, voice chats. UDP does not provide reliable connection and its header is much simpler than TCP thus fragmentation is limited. The support provided primarily by faking.
|
||||
|
||||
123
src/args.c
123
src/args.c
@@ -34,12 +34,18 @@ size_t ylgh_leftbuf = LOGGING_BUFSIZE;
|
||||
char *ylgh_curptr = ylgh_buf;
|
||||
int ylgh_ndnl = 0;
|
||||
|
||||
struct logging_config_t logging_conf = default_logging_config_set;
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
static int errno = 0;
|
||||
#define strtol kstrtol
|
||||
#endif
|
||||
|
||||
struct config_t config = default_config_set;
|
||||
void parse_global_lgconf(const struct config_t *config) {
|
||||
logging_conf.syslog = config->syslog;
|
||||
logging_conf.verbose = config->verbose;
|
||||
logging_conf.instaflush = config->instaflush;
|
||||
}
|
||||
|
||||
static int parse_sni_domains(struct domains_list **dlist, const char *domains_str, size_t domains_strlen) {
|
||||
// Empty and shouldn't be used
|
||||
@@ -269,6 +275,7 @@ enum {
|
||||
OPT_PACKET_MARK,
|
||||
OPT_SYNFAKE,
|
||||
OPT_SYNFAKE_LEN,
|
||||
OPT_NO_DPORT_FILTER,
|
||||
OPT_SEG2DELAY,
|
||||
OPT_THREADS,
|
||||
OPT_SILENT,
|
||||
@@ -318,6 +325,7 @@ static struct option long_opt[] = {
|
||||
{"udp-faking-strategy", 1, 0, OPT_UDP_FAKING_STRATEGY},
|
||||
{"udp-dport-filter", 1, 0, OPT_UDP_DPORT_FILTER},
|
||||
{"udp-filter-quic", 1, 0, OPT_UDP_FILTER_QUIC},
|
||||
{"no-dport-filter", 0, 0, OPT_NO_DPORT_FILTER},
|
||||
{"threads", 1, 0, OPT_THREADS},
|
||||
{"silent", 0, 0, OPT_SILENT},
|
||||
{"trace", 0, 0, OPT_TRACE},
|
||||
@@ -381,6 +389,7 @@ void print_usage(const char *argv0) {
|
||||
printf("\t--udp-faking-strategy={checksum|ttl|none}\n");
|
||||
printf("\t--udp-dport-filter=<5,6,200-500>\n");
|
||||
printf("\t--udp-filter-quic={disabled|all|parse}\n");
|
||||
printf("\t--no-dport-filter\n");
|
||||
printf("\t--threads=<threads number>\n");
|
||||
printf("\t--packet-mark=<mark>\n");
|
||||
printf("\t--connbytes-limit=<pkts>\n");
|
||||
@@ -398,20 +407,19 @@ void print_usage(const char *argv0) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int yparse_args(int argc, char *argv[]) {
|
||||
int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
||||
int opt;
|
||||
int optIdx = 0;
|
||||
optind=1, opterr=1, optreset=0;
|
||||
long num;
|
||||
int ret;
|
||||
|
||||
struct config_t rep_config;
|
||||
ret = init_config(&rep_config);
|
||||
ret = init_config(config);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
struct section_config_t *default_section = rep_config.last_section;
|
||||
struct section_config_t *default_section = config->last_section;
|
||||
|
||||
struct section_config_t *sect_config = rep_config.last_section;
|
||||
struct section_config_t *sect_config = config->last_section;
|
||||
int sect_i = 0;
|
||||
sect_config->id = sect_i++;
|
||||
|
||||
@@ -424,13 +432,13 @@ int yparse_args(int argc, char *argv[]) {
|
||||
while ((opt = getopt_long(argc, argv, "", long_opt, &optIdx)) != -1) {
|
||||
switch (opt) {
|
||||
case OPT_CLS:
|
||||
free_config(rep_config);
|
||||
ret = init_config(&rep_config);
|
||||
free_config(config);
|
||||
ret = init_config(config);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
default_section = rep_config.last_section;
|
||||
default_section = config->last_section;
|
||||
|
||||
sect_config = rep_config.last_section;
|
||||
sect_config = config->last_section;
|
||||
sect_i = 0;
|
||||
sect_config->id = sect_i++;
|
||||
section_iter = SECT_ITER_DEFAULT;
|
||||
@@ -453,17 +461,17 @@ int yparse_args(int argc, char *argv[]) {
|
||||
break;
|
||||
#endif
|
||||
case OPT_TRACE:
|
||||
rep_config.verbose = VERBOSE_TRACE;
|
||||
config->verbose = VERBOSE_TRACE;
|
||||
break;
|
||||
case OPT_INSTAFLUSH:
|
||||
rep_config.instaflush = 1;
|
||||
config->instaflush = 1;
|
||||
break;
|
||||
case OPT_SILENT:
|
||||
rep_config.verbose = VERBOSE_INFO;
|
||||
config->verbose = VERBOSE_INFO;
|
||||
break;
|
||||
case OPT_NO_GSO:
|
||||
#ifndef KERNEL_SPACE
|
||||
rep_config.use_gso = 0;
|
||||
config->use_gso = 0;
|
||||
#else
|
||||
lgerr("--no-gso is not supported in kernel space");
|
||||
goto invalid_opt;
|
||||
@@ -471,23 +479,31 @@ int yparse_args(int argc, char *argv[]) {
|
||||
break;
|
||||
case OPT_NO_CONNTRACK:
|
||||
#ifndef KERNEL_SPACE
|
||||
rep_config.use_conntrack = 0;
|
||||
config->use_conntrack = 0;
|
||||
#else
|
||||
lgerr("--no-conntrack is not supported in kernel space. Compile with make kmake EXTRA_CFLAGS=\"-DNO_CONNTRACK\" instead." );
|
||||
goto invalid_opt;
|
||||
#endif
|
||||
break;
|
||||
case OPT_NO_IPV6:
|
||||
rep_config.use_ipv6 = 0;
|
||||
#ifndef KERNEL_SPACE
|
||||
config->use_ipv6 = 0;
|
||||
#else
|
||||
lgerr("--no-ipv6 argument is not available "
|
||||
"in the kernel module. "
|
||||
"If you want to disable ipv6, compile with "
|
||||
"make kmake EXTRA_CFLAGS=\"-DNO_IPV6\".");
|
||||
goto invalid_opt;
|
||||
#endif
|
||||
break;
|
||||
case OPT_DAEMONIZE:
|
||||
rep_config.daemonize = 1;
|
||||
config->daemonize = 1;
|
||||
break;
|
||||
case OPT_NOCLOSE:
|
||||
rep_config.noclose = 1;
|
||||
config->noclose = 1;
|
||||
break;
|
||||
case OPT_SYSLOG:
|
||||
rep_config.syslog = 1;
|
||||
config->syslog = 1;
|
||||
break;
|
||||
case OPT_THREADS:
|
||||
num = parse_numeric_option(optarg);
|
||||
@@ -495,7 +511,7 @@ int yparse_args(int argc, char *argv[]) {
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
rep_config.threads = num;
|
||||
config->threads = num;
|
||||
break;
|
||||
case OPT_QUEUE_NUM:
|
||||
num = parse_numeric_option(optarg);
|
||||
@@ -503,7 +519,7 @@ int yparse_args(int argc, char *argv[]) {
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
rep_config.queue_start_num = num;
|
||||
config->queue_start_num = num;
|
||||
break;
|
||||
case OPT_PACKET_MARK:
|
||||
num = parse_numeric_option(optarg);
|
||||
@@ -511,24 +527,24 @@ int yparse_args(int argc, char *argv[]) {
|
||||
goto invalid_opt;
|
||||
}
|
||||
|
||||
rep_config.mark = num;
|
||||
config->mark = num;
|
||||
break;
|
||||
case OPT_CONNBYTES_LIMIT:
|
||||
num = parse_numeric_option(optarg);
|
||||
if (errno != 0 || num < 0) {
|
||||
goto invalid_opt;
|
||||
}
|
||||
rep_config.connbytes_limit = num;
|
||||
config->connbytes_limit = num;
|
||||
break;
|
||||
case OPT_START_SECTION:
|
||||
{
|
||||
struct section_config_t *nsect;
|
||||
ret = init_section_config(&nsect, rep_config.last_section);
|
||||
ret = init_section_config(&nsect, config->last_section);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
rep_config.last_section->next = nsect;
|
||||
rep_config.last_section = nsect;
|
||||
config->last_section->next = nsect;
|
||||
config->last_section = nsect;
|
||||
sect_config = nsect;
|
||||
sect_config->id = sect_i++;
|
||||
section_iter = SECT_ITER_INSIDE;
|
||||
@@ -704,6 +720,9 @@ int yparse_args(int argc, char *argv[]) {
|
||||
sect_config->fk_winsize = num;
|
||||
break;
|
||||
|
||||
case OPT_NO_DPORT_FILTER:
|
||||
sect_config->dport_filter = 0;
|
||||
break;
|
||||
case OPT_SEG2DELAY:
|
||||
num = parse_numeric_option(optarg);
|
||||
if (errno != 0 || num < 0) {
|
||||
@@ -807,16 +826,12 @@ int yparse_args(int argc, char *argv[]) {
|
||||
|
||||
}
|
||||
|
||||
struct config_t old_config = config;
|
||||
config = rep_config;
|
||||
free_config(old_config);
|
||||
|
||||
errno = 0;
|
||||
return 0;
|
||||
|
||||
#ifndef KERNEL_SPACE
|
||||
stop_exec:
|
||||
free_config(rep_config);
|
||||
free_config(config);
|
||||
errno = 0;
|
||||
return 1;
|
||||
#endif
|
||||
@@ -835,7 +850,7 @@ error:
|
||||
}
|
||||
|
||||
errno = -ret;
|
||||
free_config(rep_config);
|
||||
free_config(config);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1006,59 +1021,63 @@ static size_t print_config_section(const struct section_config_t *section, char
|
||||
}
|
||||
}
|
||||
|
||||
if (section->dport_filter == 0) {
|
||||
print_cnf_buf("--no-dport-filter");
|
||||
}
|
||||
|
||||
return buffer_size - buf_sz;
|
||||
}
|
||||
// Returns written buffer length
|
||||
size_t print_config(char *buffer, size_t buffer_size) {
|
||||
size_t print_config(const struct config_t *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);
|
||||
print_cnf_buf("--queue-num=%d", config->queue_start_num);
|
||||
print_cnf_buf("--threads=%d", config->threads);
|
||||
#endif
|
||||
print_cnf_buf("--packet-mark=%d", config.mark);
|
||||
print_cnf_buf("--packet-mark=%d", config->mark);
|
||||
|
||||
#ifndef KERNEL_SPACE
|
||||
if (config.daemonize) {
|
||||
if (config->daemonize) {
|
||||
print_cnf_buf("--daemonize");
|
||||
}
|
||||
if (config.syslog) {
|
||||
if (config->syslog) {
|
||||
print_cnf_buf("--syslog");
|
||||
}
|
||||
if (config.noclose) {
|
||||
if (config->noclose) {
|
||||
print_cnf_buf("--noclose");
|
||||
}
|
||||
if (!config.use_gso) {
|
||||
if (!config->use_gso) {
|
||||
print_cnf_buf("--no-gso");
|
||||
}
|
||||
if (!config.use_conntrack) {
|
||||
if (!config->use_conntrack) {
|
||||
print_cnf_buf("--no-conntrack");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
print_cnf_buf("--connbytes-limit=%d", config.connbytes_limit);
|
||||
print_cnf_buf("--connbytes-limit=%d", config->connbytes_limit);
|
||||
#endif
|
||||
if (!config.use_ipv6) {
|
||||
if (!config->use_ipv6) {
|
||||
print_cnf_buf("--no-ipv6");
|
||||
}
|
||||
if (config.verbose == VERBOSE_TRACE) {
|
||||
if (config->verbose == VERBOSE_TRACE) {
|
||||
print_cnf_buf("--trace");
|
||||
}
|
||||
if (config.instaflush) {
|
||||
if (config->instaflush) {
|
||||
print_cnf_buf("--instaflush");
|
||||
}
|
||||
if (config.verbose == VERBOSE_INFO) {
|
||||
if (config->verbose == VERBOSE_INFO) {
|
||||
print_cnf_buf("--silent");
|
||||
}
|
||||
|
||||
size_t wbuf_len = print_config_section(config.first_section, buf_ptr, buf_sz);
|
||||
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;
|
||||
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);
|
||||
@@ -1070,12 +1089,12 @@ size_t print_config(char *buffer, size_t buffer_size) {
|
||||
return buffer_size - buf_sz;
|
||||
}
|
||||
|
||||
void print_welcome(void) {
|
||||
void print_welcome(const struct config_t *config) {
|
||||
char *welcome_message = malloc(4000);
|
||||
if (welcome_message == NULL)
|
||||
return;
|
||||
|
||||
size_t sz = print_config(welcome_message, 4000);
|
||||
size_t sz = print_config(config, welcome_message, 4000);
|
||||
printf("Running with flags: %.*s\n", (int)sz, welcome_message);
|
||||
free(welcome_message);
|
||||
}
|
||||
@@ -1138,8 +1157,8 @@ void free_config_section(struct section_config_t *section) {
|
||||
free(section);
|
||||
}
|
||||
|
||||
void free_config(struct config_t config) {
|
||||
for (struct section_config_t *sct = config.last_section; sct != NULL;) {
|
||||
void free_config(struct config_t *config) {
|
||||
for (struct section_config_t *sct = config->last_section; sct != NULL;) {
|
||||
struct section_config_t *psct = sct->prev;
|
||||
free_config_section(sct);
|
||||
sct = psct;
|
||||
|
||||
12
src/args.h
12
src/args.h
@@ -24,8 +24,12 @@
|
||||
|
||||
void print_version(void);
|
||||
void print_usage(const char *argv0);
|
||||
int yparse_args(int argc, char *argv[]);
|
||||
size_t print_config(char *buffer, size_t buffer_size);
|
||||
/**
|
||||
* Initializes _config_ and parses args to it.
|
||||
*/
|
||||
int yparse_args(struct config_t *config, int argc, char *argv[]);
|
||||
size_t print_config(const struct config_t *config, char *buffer, size_t buffer_size);
|
||||
void parse_global_lgconf(const struct config_t *config);
|
||||
|
||||
// Initializes configuration storage.
|
||||
int init_config(struct config_t *config);
|
||||
@@ -34,9 +38,9 @@ int init_section_config(struct section_config_t **section, struct section_config
|
||||
// Frees configuration section
|
||||
void free_config_section(struct section_config_t *config);
|
||||
// Frees sections under config
|
||||
void free_config(struct config_t config);
|
||||
void free_config(struct config_t *config);
|
||||
|
||||
/* Prints starting messages */
|
||||
void print_welcome(void);
|
||||
void print_welcome(const struct config_t *config);
|
||||
|
||||
#endif /* ARGS_H */
|
||||
|
||||
27
src/config.h
27
src/config.h
@@ -39,6 +39,14 @@ struct instance_config_t {
|
||||
};
|
||||
extern struct instance_config_t instance_config;
|
||||
|
||||
|
||||
struct logging_config_t {
|
||||
int verbose;
|
||||
int instaflush;
|
||||
int syslog;
|
||||
};
|
||||
extern struct logging_config_t logging_conf;
|
||||
|
||||
struct udp_dport_range {
|
||||
uint16_t start;
|
||||
uint16_t end;
|
||||
@@ -92,6 +100,8 @@ struct section_config_t {
|
||||
unsigned int fk_winsize;
|
||||
int fakeseq_offset;
|
||||
|
||||
int dport_filter;
|
||||
|
||||
#define SNI_DETECTION_PARSE 0
|
||||
#define SNI_DETECTION_BRUTE 1
|
||||
int sni_detection;
|
||||
@@ -130,9 +140,12 @@ struct config_t {
|
||||
|
||||
struct section_config_t *first_section;
|
||||
struct section_config_t *last_section;
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
struct kref refcount;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct config_t config;
|
||||
|
||||
#define ITER_CONFIG_SECTIONS(config, section) \
|
||||
for (struct section_config_t *section = (config)->last_section; section != NULL; section = section->prev)
|
||||
@@ -206,7 +219,7 @@ if ((fake_bitmask) & strategy)
|
||||
|
||||
#define DEFAULT_QUEUE_NUM 537
|
||||
|
||||
#define MAX_PACKET_SIZE 8192
|
||||
#define MAX_PACKET_SIZE (1 << 16)
|
||||
|
||||
#define DEFAULT_SNISTR "googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,youtubei.googleapis.com,youtube.googleapis.com,youtubeembeddedplayer.googleapis.com,googleusercontent.com,gstatic.com,l.google.com"
|
||||
|
||||
@@ -244,6 +257,7 @@ enum {
|
||||
.synfake = 0, \
|
||||
.synfake_len = 0, \
|
||||
\
|
||||
.dport_filter = 1, \
|
||||
.seg2_delay = 0, \
|
||||
\
|
||||
.sni_detection = SNI_DETECTION_PARSE, \
|
||||
@@ -281,10 +295,11 @@ enum {
|
||||
.instaflush = 0, \
|
||||
}
|
||||
|
||||
#define CONFIG_SET(config) \
|
||||
struct config_t config = default_config_set; \
|
||||
config->last_section = &(config.default_config) \
|
||||
|
||||
#define default_logging_config_set { \
|
||||
.verbose = VERBOSE_DEBUG, \
|
||||
.syslog = 0, \
|
||||
.instaflush = 0, \
|
||||
}
|
||||
|
||||
struct ytb_conntrack {
|
||||
uint32_t mask;
|
||||
|
||||
76
src/kargs.c
76
src/kargs.c
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
youtubeUnblock - https://github.com/Waujito/youtubeUnblock
|
||||
|
||||
Copyright (C) 2024-2025 Vadim Vetrov <vetrovvd@gmail.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include <linux/moduleparam.h>
|
||||
#include "types.h"
|
||||
#include "args.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define MAX_ARGC 1024
|
||||
static char *argv[MAX_ARGC];
|
||||
|
||||
static int params_set(const char *cval, const struct kernel_param *kp) {
|
||||
int ret = 0;
|
||||
|
||||
int cv_len = strlen(cval);
|
||||
if (cv_len >= 1 && cval[cv_len - 1] == '\n') {
|
||||
cv_len--;
|
||||
}
|
||||
|
||||
const char *ytb_prefix = "youtubeUnblock ";
|
||||
int ytbp_len = strlen(ytb_prefix);
|
||||
int len = cv_len + ytbp_len;
|
||||
|
||||
char *val = kmalloc(len + 1, GFP_KERNEL); // 1 for null-terminator
|
||||
strncpy(val, ytb_prefix, ytbp_len);
|
||||
strncpy(val + ytbp_len, cval, cv_len);
|
||||
val[len] = '\0';
|
||||
|
||||
int argc = 0;
|
||||
argv[argc++] = val;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (val[i] == ' ') {
|
||||
val[i] = '\0';
|
||||
|
||||
// safe because of null-terminator
|
||||
if (val[i + 1] != ' ' && val[i + 1] != '\0') {
|
||||
argv[argc++] = val + i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = yparse_args(argc, argv);
|
||||
kfree(val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int params_get(char *buffer, const struct kernel_param *kp) {
|
||||
size_t len = print_config(buffer, 4000);
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops params_ops = {
|
||||
.set = params_set,
|
||||
.get = params_get,
|
||||
};
|
||||
|
||||
module_param_cb(parameters, ¶ms_ops, NULL, 0664);
|
||||
334
src/kytunblock.c
334
src/kytunblock.c
@@ -61,9 +61,93 @@ MODULE_AUTHOR("Vadim Vetrov <vetrovvd@gmail.com>");
|
||||
MODULE_DESCRIPTION("Linux kernel module for youtubeUnblock");
|
||||
|
||||
static struct socket *rawsocket;
|
||||
|
||||
static struct socket *raw6socket;
|
||||
|
||||
#define MAX_ARGC 1024
|
||||
static char *argv[MAX_ARGC];
|
||||
|
||||
static struct config_t *cur_config;
|
||||
|
||||
static void config_release(struct kref *ref)
|
||||
{
|
||||
struct config_t *config = container_of(ref, struct config_t, refcount);
|
||||
free_config(config);
|
||||
kfree(config);
|
||||
pr_warn("Config release\n");
|
||||
}
|
||||
|
||||
static int params_set(const char *cval, const struct kernel_param *kp) {
|
||||
int ret;
|
||||
|
||||
int cv_len = strlen(cval);
|
||||
if (cv_len >= 1 && cval[cv_len - 1] == '\n') {
|
||||
cv_len--;
|
||||
}
|
||||
|
||||
const char *ytb_prefix = "youtubeUnblock ";
|
||||
int ytbp_len = strlen(ytb_prefix);
|
||||
int len = cv_len + ytbp_len;
|
||||
|
||||
char *val = kmalloc(len + 1, GFP_KERNEL); // 1 for null-terminator
|
||||
strncpy(val, ytb_prefix, ytbp_len);
|
||||
strncpy(val + ytbp_len, cval, cv_len);
|
||||
val[len] = '\0';
|
||||
|
||||
int argc = 0;
|
||||
argv[argc++] = val;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (val[i] == ' ') {
|
||||
val[i] = '\0';
|
||||
|
||||
// safe because of null-terminator
|
||||
if (val[i + 1] != ' ' && val[i + 1] != '\0') {
|
||||
argv[argc++] = val + i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct config_t *config;
|
||||
|
||||
config = kmalloc(sizeof(*config), GFP_KERNEL);
|
||||
if (!config) {
|
||||
ret = -ENOMEM;
|
||||
goto ret_fval;
|
||||
}
|
||||
|
||||
ret = yparse_args(config, argc, argv);
|
||||
|
||||
if (ret < 0) {
|
||||
kfree(config);
|
||||
goto ret_fval;
|
||||
}
|
||||
kref_init(&config->refcount);
|
||||
|
||||
struct config_t *old_config = cur_config;
|
||||
cur_config = config;
|
||||
parse_global_lgconf(cur_config);
|
||||
|
||||
kref_put(&old_config->refcount, config_release);
|
||||
|
||||
ret_fval:
|
||||
kfree(val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int params_get(char *buffer, const struct kernel_param *kp) {
|
||||
size_t len = print_config(cur_config, buffer, 4000);
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops params_ops = {
|
||||
.set = params_set,
|
||||
.get = params_get,
|
||||
};
|
||||
|
||||
module_param_cb(parameters, ¶ms_ops, NULL, 0664);
|
||||
|
||||
|
||||
static int open_raw_socket(void) {
|
||||
int ret = 0;
|
||||
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
|
||||
@@ -75,7 +159,7 @@ static int open_raw_socket(void) {
|
||||
|
||||
// That's funny, but this is how it is done in the kernel
|
||||
// https://elixir.bootlin.com/linux/v3.17.7/source/net/core/sock.c#L916
|
||||
rawsocket->sk->sk_mark=config.mark;
|
||||
rawsocket->sk->sk_mark=cur_config->mark;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -85,10 +169,15 @@ err:
|
||||
|
||||
static void close_raw_socket(void) {
|
||||
sock_release(rawsocket);
|
||||
rawsocket = NULL;
|
||||
}
|
||||
|
||||
static int send_raw_ipv4(const uint8_t *pkt, size_t pktlen) {
|
||||
int ret = 0;
|
||||
if (rawsocket == NULL) {
|
||||
return -ENOTSOCK;
|
||||
|
||||
}
|
||||
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
|
||||
|
||||
struct iphdr *iph;
|
||||
@@ -137,7 +226,7 @@ static int open_raw6_socket(void) {
|
||||
|
||||
// That's funny, but this is how it is done in the kernel
|
||||
// https://elixir.bootlin.com/linux/v3.17.7/source/net/core/sock.c#L916
|
||||
raw6socket->sk->sk_mark=config.mark;
|
||||
raw6socket->sk->sk_mark=cur_config->mark;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -147,10 +236,16 @@ err:
|
||||
|
||||
static void close_raw6_socket(void) {
|
||||
sock_release(raw6socket);
|
||||
raw6socket = NULL;
|
||||
}
|
||||
|
||||
static int send_raw_ipv6(const uint8_t *pkt, size_t pktlen) {
|
||||
int ret = 0;
|
||||
if (raw6socket == NULL) {
|
||||
return -ENOTSOCK;
|
||||
|
||||
}
|
||||
|
||||
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
|
||||
|
||||
struct ip6_hdr *iph;
|
||||
@@ -189,21 +284,21 @@ static int send_raw_socket(const uint8_t *pkt, size_t pktlen) {
|
||||
int ret;
|
||||
|
||||
if (pktlen > AVAILABLE_MTU) {
|
||||
lgdebug("The packet is too big and may cause issues!");
|
||||
lgtrace("Split packet!");
|
||||
|
||||
NETBUF_ALLOC(buff1, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(buff1)) {
|
||||
size_t buff1_size = pktlen;
|
||||
uint8_t *buff1 = malloc(buff1_size);
|
||||
if (buff1 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
return -ENOMEM;
|
||||
}
|
||||
NETBUF_ALLOC(buff2, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(buff2)) {
|
||||
size_t buff2_size = pktlen;
|
||||
uint8_t *buff2 = malloc(buff2_size);
|
||||
if (buff2 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
NETBUF_FREE(buff2);
|
||||
free(buff1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
size_t buff1_size = MAX_PACKET_SIZE;
|
||||
size_t buff2_size = MAX_PACKET_SIZE;
|
||||
|
||||
if ((ret = tcp_frag(pkt, pktlen, AVAILABLE_MTU-128,
|
||||
buff1, &buff1_size, buff2, &buff2_size)) < 0) {
|
||||
@@ -224,13 +319,13 @@ static int send_raw_socket(const uint8_t *pkt, size_t pktlen) {
|
||||
else {
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
NETBUF_FREE(buff1);
|
||||
NETBUF_FREE(buff2);
|
||||
|
||||
free(buff1);
|
||||
free(buff2);
|
||||
return sent;
|
||||
erret_lc:
|
||||
NETBUF_FREE(buff1);
|
||||
NETBUF_FREE(buff2);
|
||||
free(buff1);
|
||||
free(buff2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -379,154 +474,185 @@ static int conntrack_parse(const struct sk_buff *skb,
|
||||
|
||||
#endif /* RHEL or not RHEL */
|
||||
|
||||
|
||||
|
||||
static NF_CALLBACK(ykb_nf_hook, skb) {
|
||||
int ret;
|
||||
struct packet_data pd = {0};
|
||||
uint8_t *data_buf = NULL;
|
||||
int nf_verdict = NF_ACCEPT;
|
||||
|
||||
if ((skb->mark & config.mark) == config.mark)
|
||||
goto accept;
|
||||
struct config_t *config = cur_config;
|
||||
kref_get(&config->refcount);
|
||||
|
||||
if ((skb->mark & config->mark) == config->mark) {
|
||||
goto send_verdict;
|
||||
}
|
||||
|
||||
if (skb->head == NULL)
|
||||
goto accept;
|
||||
if (skb->head == NULL) {
|
||||
goto send_verdict;
|
||||
}
|
||||
|
||||
if (skb->len > MAX_PACKET_SIZE)
|
||||
goto accept;
|
||||
if (skb->len >= MAX_PACKET_SIZE) {
|
||||
goto send_verdict;
|
||||
}
|
||||
|
||||
ret = conntrack_parse(skb, &pd.yct);
|
||||
if (ret < 0) {
|
||||
lgtrace("[TRACE] conntrack_parse error code\n");
|
||||
}
|
||||
|
||||
if (config.connbytes_limit != 0 && yct_is_mask_attr(YCTATTR_ORIG_PACKETS, &pd.yct) && pd.yct.orig_packets > config.connbytes_limit)
|
||||
goto accept;
|
||||
if (config->connbytes_limit != 0 && yct_is_mask_attr(YCTATTR_ORIG_PACKETS, &pd.yct) && pd.yct.orig_packets > config->connbytes_limit)
|
||||
goto send_verdict;
|
||||
|
||||
|
||||
ret = skb_linearize(skb);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "Cannot linearize");
|
||||
goto accept;
|
||||
if (skb_is_nonlinear(skb)) {
|
||||
data_buf = kmalloc(skb->len, GFP_KERNEL);
|
||||
if (data_buf == NULL) {
|
||||
lgerror(-ENOMEM, "Cannot allocate packet buffer");
|
||||
}
|
||||
ret = skb_copy_bits(skb, 0, data_buf, skb->len);
|
||||
if (ret) {
|
||||
lgerror(ret, "Cannot copy bits");
|
||||
goto send_verdict;
|
||||
}
|
||||
|
||||
pd.payload = data_buf;
|
||||
} else {
|
||||
pd.payload = skb->data;
|
||||
}
|
||||
|
||||
pd.payload = skb->data;
|
||||
pd.payload_len = skb->len;
|
||||
|
||||
int vrd = process_packet(&pd);
|
||||
int vrd = process_packet(config, &pd);
|
||||
|
||||
switch(vrd) {
|
||||
case PKT_ACCEPT:
|
||||
goto accept;
|
||||
nf_verdict = NF_ACCEPT;
|
||||
break;
|
||||
case PKT_DROP:
|
||||
goto drop;
|
||||
nf_verdict = NF_STOLEN;
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
|
||||
accept:
|
||||
return NF_ACCEPT;
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return NF_STOLEN;
|
||||
send_verdict:
|
||||
kfree(data_buf);
|
||||
kref_put(&config->refcount, config_release);
|
||||
return nf_verdict;
|
||||
}
|
||||
|
||||
|
||||
static struct nf_hook_ops ykb_nf_reg __read_mostly = {
|
||||
static struct nf_hook_ops ykb_hook_ops[] = {
|
||||
{
|
||||
.hook = ykb_nf_hook,
|
||||
.pf = NFPROTO_IPV4,
|
||||
.hooknum = NF_INET_POST_ROUTING,
|
||||
.priority = NF_IP_PRI_MANGLE,
|
||||
};
|
||||
|
||||
static struct nf_hook_ops ykb6_nf_reg __read_mostly = {
|
||||
}
|
||||
#ifndef NO_IPV6
|
||||
,{
|
||||
.hook = ykb_nf_hook,
|
||||
.pf = NFPROTO_IPV6,
|
||||
.hooknum = NF_INET_POST_ROUTING,
|
||||
.priority = NF_IP6_PRI_MANGLE,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
static const size_t ykb_hooks_sz = sizeof(ykb_hook_ops) / sizeof(struct nf_hook_ops);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
||||
static int ykb_net_init(struct net *net)
|
||||
{
|
||||
int ret;
|
||||
ret = nf_register_net_hooks(net, ykb_hook_ops, ykb_hooks_sz);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ykb_net_exit(struct net *net)
|
||||
{
|
||||
nf_unregister_net_hooks(net, ykb_hook_ops, ykb_hooks_sz);
|
||||
}
|
||||
|
||||
static struct pernet_operations ykb_pernet_ops = {
|
||||
.init = ykb_net_init,
|
||||
.exit = ykb_net_exit
|
||||
};
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */
|
||||
|
||||
static int __init ykb_init(void) {
|
||||
#ifdef NO_CONNTRACK
|
||||
lgwarning("Conntrack disabled.");
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
int ret = 0;
|
||||
ret = init_config(&config);
|
||||
if (ret < 0) goto err;
|
||||
#ifdef NO_CONNTRACK
|
||||
lgwarning("Conntrack is disabled.");
|
||||
#endif
|
||||
#ifdef NO_IPV6
|
||||
lgwarning("IPv6 is disabled.");
|
||||
#endif
|
||||
cur_config = kmalloc(sizeof(*cur_config), GFP_KERNEL);
|
||||
if (!cur_config) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = init_config(cur_config);
|
||||
if (ret < 0) {
|
||||
kfree(cur_config);
|
||||
goto err;
|
||||
}
|
||||
|
||||
kref_init(&cur_config->refcount);
|
||||
|
||||
ret = open_raw_socket();
|
||||
if (ret < 0) goto err;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
struct net *n;
|
||||
|
||||
for_each_net(n) {
|
||||
ret = nf_register_net_hook(n, &ykb_nf_reg);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "register net_hook");
|
||||
}
|
||||
}
|
||||
#else
|
||||
ret = nf_register_hook(&ykb_nf_reg);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "register net_hook");
|
||||
lgerror(ret, "ipv4 rawsocket initialization failed!");
|
||||
goto err_config;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_IPV6
|
||||
ret = open_raw6_socket();
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "ipv6 rawsocket initialization failed!");
|
||||
goto err_close4_sock;
|
||||
}
|
||||
#endif /* NO_IPV6 */
|
||||
|
||||
if (config.use_ipv6) {
|
||||
ret = open_raw6_socket();
|
||||
if (ret < 0) {
|
||||
config.use_ipv6 = 0;
|
||||
lgwarning("ipv6 disabled!");
|
||||
goto ipv6_fallback;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
struct net *n;
|
||||
for_each_net(n) {
|
||||
ret = nf_register_net_hook(n, &ykb6_nf_reg);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "register net6_hook");
|
||||
}
|
||||
}
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
||||
ret = register_pernet_subsys(&ykb_pernet_ops);
|
||||
#else
|
||||
ret = nf_register_hook(&ykb6_nf_reg);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "register net6_hook");
|
||||
}
|
||||
ret = nf_register_hooks(ykb_hook_ops, ykb_hooks_sz);
|
||||
#endif
|
||||
}
|
||||
|
||||
ipv6_fallback:
|
||||
if (ret < 0)
|
||||
goto err_close_sock;
|
||||
|
||||
|
||||
lginfo("youtubeUnblock kernel module started.\n");
|
||||
return 0;
|
||||
|
||||
err_close_sock:
|
||||
#ifndef NO_IPV6
|
||||
close_raw6_socket();
|
||||
#endif
|
||||
err_close4_sock:
|
||||
close_raw_socket();
|
||||
err_config:
|
||||
kref_put(&cur_config->refcount, config_release);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ykb_destroy(void) {
|
||||
if (config.use_ipv6) {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
struct net *n;
|
||||
for_each_net(n)
|
||||
nf_unregister_net_hook(n, &ykb6_nf_reg);
|
||||
static void __exit ykb_destroy(void) {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
||||
unregister_pernet_subsys(&ykb_pernet_ops);
|
||||
#else
|
||||
nf_unregister_hook(&ykb6_nf_reg);
|
||||
nf_unregister_hooks(ykb_hook_ops, ykb_hooks_sz);
|
||||
#endif
|
||||
close_raw6_socket();
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
struct net *n;
|
||||
for_each_net(n)
|
||||
nf_unregister_net_hook(n, &ykb_nf_reg);
|
||||
#else
|
||||
nf_unregister_hook(&ykb_nf_reg);
|
||||
#ifndef NO_IPV6
|
||||
close_raw6_socket();
|
||||
#endif
|
||||
|
||||
close_raw_socket();
|
||||
|
||||
free_config(config);
|
||||
kref_put(&cur_config->refcount, config_release);
|
||||
lginfo("youtubeUnblock kernel module destroyed.\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -21,29 +21,10 @@
|
||||
#define LOGGING_H
|
||||
#include "config.h"
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#define printf pr_info
|
||||
#define perror pr_err
|
||||
|
||||
#define LOG_ERR KERN_ERR
|
||||
#define LOG_INFO KERN_INFO
|
||||
#define LOG_WARN KERN_WARNING
|
||||
|
||||
#define print_message(level, msg, ...) \
|
||||
(printk(level msg, ##__VA_ARGS__))
|
||||
|
||||
#else
|
||||
#include <stdio.h> // IWYU pragma: export
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define print_message(level, msg, ...) \
|
||||
(config.syslog ? (void)(syslog((level), msg, ##__VA_ARGS__)) : (void)(printf(msg, ##__VA_ARGS__) + fflush(stdout)))
|
||||
|
||||
#endif /* PROGRAM_SPACE */
|
||||
|
||||
/**
|
||||
* Defined in args.c
|
||||
*/
|
||||
@@ -53,7 +34,27 @@ extern size_t ylgh_leftbuf;
|
||||
extern char *ylgh_curptr;
|
||||
extern int ylgh_ndnl;
|
||||
|
||||
#define LOG_LEVEL (config.verbose)
|
||||
#define LOG_LEVEL (logging_conf.verbose)
|
||||
#define DO_INSTAFLUSH (logging_conf.instaflush)
|
||||
#define DO_SYSLOG (logging_conf.syslog)
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#define printf pr_info
|
||||
#define perror pr_err
|
||||
#define print_message(level, msg, ...) \
|
||||
(printk(level msg, ##__VA_ARGS__))
|
||||
|
||||
#else
|
||||
#include <stdio.h> // IWYU pragma: export
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define print_message(level, msg, ...) \
|
||||
(DO_SYSLOG ? (void)(syslog((level), msg, ##__VA_ARGS__)) : (void)(printf(msg, ##__VA_ARGS__) + fflush(stdout)))
|
||||
|
||||
#endif /* PROGRAM_SPACE */
|
||||
|
||||
/**
|
||||
* For flushing only. Use log_buf_write for writing.
|
||||
@@ -128,7 +129,7 @@ extern int ylgh_ndnl;
|
||||
if (LOG_LEVEL >= VERBOSE_TRACE) { \
|
||||
ylgh_ndnl = 1; \
|
||||
log_buf(LOG_INFO, msg, ##__VA_ARGS__); \
|
||||
if (config.instaflush) { \
|
||||
if (DO_INSTAFLUSH) { \
|
||||
log_buf_flush(LOG_INFO); \
|
||||
} \
|
||||
} \
|
||||
|
||||
390
src/mangle.c
390
src/mangle.c
@@ -32,7 +32,7 @@
|
||||
#include "linux/inet.h"
|
||||
#endif
|
||||
|
||||
int process_packet(const struct packet_data *pd) {
|
||||
int process_packet(const struct config_t *config, const struct packet_data *pd) {
|
||||
const uint8_t *raw_payload = pd->payload;
|
||||
uint32_t raw_payload_len = pd->payload_len;
|
||||
|
||||
@@ -65,7 +65,9 @@ int process_packet(const struct packet_data *pd) {
|
||||
|
||||
transport_proto = iph->protocol;
|
||||
|
||||
} else if (ipver == IP6VERSION && config.use_ipv6) {
|
||||
}
|
||||
#ifndef NO_IPV6
|
||||
else if (ipver == IP6VERSION && config->use_ipv6) {
|
||||
ret = ip6_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
||||
(struct ip6_hdr **)&ip6h, &iph_len,
|
||||
(uint8_t **)&ip_payload, &ip_payload_len);
|
||||
@@ -75,7 +77,9 @@ int process_packet(const struct packet_data *pd) {
|
||||
|
||||
transport_proto = ip6h->ip6_nxt;
|
||||
|
||||
} else {
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
lgtrace("Unknown layer 3 protocol version: %d", ipver);
|
||||
goto accept;
|
||||
}
|
||||
@@ -142,7 +146,7 @@ int process_packet(const struct packet_data *pd) {
|
||||
lgtrace_write();
|
||||
|
||||
lgtrace_wr("Transport payload: [ ");
|
||||
for (int i = 0; i < min(16, transport_payload_len); i++) {
|
||||
for (int i = 0; i < min((int)16, (int)transport_payload_len); i++) {
|
||||
lgtrace_wr("%02x ", transport_payload[i]);
|
||||
}
|
||||
lgtrace_wr("]");
|
||||
@@ -151,7 +155,7 @@ int process_packet(const struct packet_data *pd) {
|
||||
|
||||
int verdict = PKT_CONTINUE;
|
||||
|
||||
ITER_CONFIG_SECTIONS(&config, section) {
|
||||
ITER_CONFIG_SECTIONS(config, section) {
|
||||
lgtrace_wr("Section #%d: ", CONFIG_SECTION_NUMBER(section));
|
||||
|
||||
switch (transport_proto) {
|
||||
@@ -211,28 +215,33 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
|
||||
|
||||
|
||||
if (ret < 0) {
|
||||
goto accept;
|
||||
return PKT_ACCEPT;
|
||||
}
|
||||
|
||||
// As defined by TLS standard.
|
||||
if (section->dport_filter && ntohs(tcph->dest) != 443) {
|
||||
return PKT_ACCEPT;
|
||||
}
|
||||
|
||||
if (tcph->syn && section->synfake) {
|
||||
lgtrace_addp("TCP syn alter");
|
||||
|
||||
NETBUF_ALLOC(payload, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(payload)) {
|
||||
size_t fake_len = section->fake_sni_pkt_sz;
|
||||
if (section->synfake_len)
|
||||
fake_len = min((int)section->synfake_len, (int)fake_len);
|
||||
|
||||
|
||||
size_t payload_len = iph_len + tcph_len + fake_len;
|
||||
uint8_t *payload = malloc(payload_len);
|
||||
if (payload == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
goto accept;
|
||||
return PKT_ACCEPT;
|
||||
}
|
||||
|
||||
memcpy(payload, ipxh, iph_len);
|
||||
memcpy(payload + iph_len, tcph, tcph_len);
|
||||
size_t fake_len = section->fake_sni_pkt_sz;
|
||||
|
||||
if (section->synfake_len)
|
||||
fake_len = min(section->synfake_len, fake_len);
|
||||
|
||||
memcpy(payload + iph_len, tcph, tcph_len);
|
||||
memcpy(payload + iph_len + tcph_len, section->fake_sni_pkt, fake_len);
|
||||
|
||||
|
||||
struct tcphdr *tcph = (struct tcphdr *)(payload + iph_len);
|
||||
if (ipxv == IP4VERSION) {
|
||||
struct iphdr *iph = (struct iphdr *)payload;
|
||||
@@ -247,22 +256,23 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
|
||||
}
|
||||
|
||||
|
||||
ret = instance_config.send_raw_packet(payload, iph_len + tcph_len + fake_len);
|
||||
ret = instance_config.send_raw_packet(payload, payload_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "send_syn_altered");
|
||||
|
||||
NETBUF_FREE(payload);
|
||||
goto accept;
|
||||
free(payload);
|
||||
return PKT_ACCEPT;
|
||||
}
|
||||
|
||||
NETBUF_FREE(payload);
|
||||
goto drop;
|
||||
free(payload);
|
||||
return PKT_DROP;
|
||||
}
|
||||
|
||||
if (tcph->syn) goto continue_flow;
|
||||
if (tcph->syn)
|
||||
return PKT_CONTINUE;
|
||||
|
||||
if (!section->tls_enabled)
|
||||
goto continue_flow;
|
||||
return PKT_CONTINUE;
|
||||
|
||||
struct tls_verdict vrd = analyze_tls_data(section, data, dlen);
|
||||
lgtrace_addp("TLS analyzed");
|
||||
@@ -273,16 +283,14 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
|
||||
|
||||
if (vrd.target_sni) {
|
||||
lgdebug("Target SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
|
||||
size_t sni_offset = vrd.sni_ptr - data;
|
||||
size_t target_sni_offset = vrd.target_sni_ptr - data;
|
||||
|
||||
size_t payload_len = raw_payload_len;
|
||||
NETBUF_ALLOC(payload, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(payload)) {
|
||||
uint8_t *payload = malloc(raw_payload_len);
|
||||
if (payload == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
goto accept;
|
||||
return PKT_ACCEPT;
|
||||
}
|
||||
|
||||
memcpy(payload, raw_payload, raw_payload_len);
|
||||
|
||||
void *iph;
|
||||
@@ -306,6 +314,7 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
|
||||
set_tcp_checksum(tcph, iph, iph_len);
|
||||
}
|
||||
|
||||
/*
|
||||
if (0) {
|
||||
int delta = 2;
|
||||
ret = seqovl_packet(payload, &payload_len, delta);
|
||||
@@ -316,116 +325,108 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
|
||||
lgerror(ret, "seqovl_packet delta %d", delta);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
if (dlen > 1480 && config.verbose) {
|
||||
if (dlen > AVAILABLE_MTU) {
|
||||
lgdebug("WARNING! Client Hello packet is too big and may cause issues!");
|
||||
}
|
||||
|
||||
if (section->fake_sni) {
|
||||
post_fake_sni(args_default_fake_type(section), iph, iph_len, tcph, tcph_len);
|
||||
post_fake_sni(args_default_fake_type(section), iph, iph_len, tcph, tcph_len);
|
||||
}
|
||||
|
||||
size_t ipd_offset;
|
||||
size_t mid_offset;
|
||||
|
||||
switch (section->fragmentation_strategy) {
|
||||
case FRAG_STRAT_TCP: {
|
||||
ipd_offset = target_sni_offset;
|
||||
mid_offset = ipd_offset + vrd.target_sni_len / 2;
|
||||
case FRAG_STRAT_TCP:
|
||||
{
|
||||
ipd_offset = target_sni_offset;
|
||||
mid_offset = ipd_offset + vrd.target_sni_len / 2;
|
||||
|
||||
size_t poses[2];
|
||||
int cnt = 0;
|
||||
size_t poses[2];
|
||||
int cnt = 0;
|
||||
|
||||
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
|
||||
poses[cnt++] = section->frag_sni_pos;
|
||||
}
|
||||
|
||||
if (section->frag_middle_sni) {
|
||||
poses[cnt++] = mid_offset;
|
||||
}
|
||||
|
||||
if (cnt > 1 && poses[0] > poses[1]) {
|
||||
size_t tmp = poses[0];
|
||||
poses[0] = poses[1];
|
||||
poses[1] = tmp;
|
||||
}
|
||||
|
||||
ret = send_tcp_frags(section, payload, payload_len, poses, cnt, 0);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "tcp4 send frags");
|
||||
goto accept_lc;
|
||||
}
|
||||
|
||||
goto drop_lc;
|
||||
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
|
||||
poses[cnt++] = section->frag_sni_pos;
|
||||
}
|
||||
break;
|
||||
case FRAG_STRAT_IP:
|
||||
if (ipxv == IP4VERSION) {
|
||||
ipd_offset = ((char *)data - (char *)tcph) + target_sni_offset;
|
||||
mid_offset = ipd_offset + vrd.target_sni_len / 2;
|
||||
mid_offset += 8 - mid_offset % 8;
|
||||
|
||||
size_t poses[2];
|
||||
int cnt = 0;
|
||||
|
||||
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
|
||||
poses[cnt] = section->frag_sni_pos + ((char *)data - (char *)tcph);
|
||||
poses[cnt] += 8 - poses[cnt] % 8;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
if (section->frag_middle_sni) {
|
||||
poses[cnt++] = mid_offset;
|
||||
}
|
||||
|
||||
if (cnt > 1 && poses[0] > poses[1]) {
|
||||
size_t tmp = poses[0];
|
||||
poses[0] = poses[1];
|
||||
poses[1] = tmp;
|
||||
}
|
||||
|
||||
ret = send_ip4_frags(section, payload, payload_len, poses, cnt, 0);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "ip4 send frags");
|
||||
goto accept_lc;
|
||||
}
|
||||
|
||||
goto drop_lc;
|
||||
} else {
|
||||
lginfo("WARNING: IP fragmentation is supported only for IPv4");
|
||||
goto default_send;
|
||||
if (section->frag_middle_sni) {
|
||||
poses[cnt++] = mid_offset;
|
||||
}
|
||||
default:
|
||||
default_send:
|
||||
ret = instance_config.send_raw_packet(payload, payload_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "raw pack send");
|
||||
goto accept_lc;
|
||||
}
|
||||
|
||||
goto drop_lc;
|
||||
if (cnt > 1 && poses[0] > poses[1]) {
|
||||
size_t tmp = poses[0];
|
||||
poses[0] = poses[1];
|
||||
poses[1] = tmp;
|
||||
}
|
||||
|
||||
ret = send_tcp_frags(section, payload, payload_len, poses, cnt, 0);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "tcp4 send frags");
|
||||
goto accept_lc;
|
||||
}
|
||||
|
||||
goto drop_lc;
|
||||
}
|
||||
break;
|
||||
case FRAG_STRAT_IP:
|
||||
if (ipxv == IP4VERSION) {
|
||||
ipd_offset = ((char *)data - (char *)tcph) + target_sni_offset;
|
||||
mid_offset = ipd_offset + vrd.target_sni_len / 2;
|
||||
mid_offset += 8 - mid_offset % 8;
|
||||
|
||||
size_t poses[2];
|
||||
int cnt = 0;
|
||||
|
||||
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
|
||||
poses[cnt] = section->frag_sni_pos + ((char *)data - (char *)tcph);
|
||||
poses[cnt] += 8 - poses[cnt] % 8;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
if (section->frag_middle_sni) {
|
||||
poses[cnt++] = mid_offset;
|
||||
}
|
||||
|
||||
if (cnt > 1 && poses[0] > poses[1]) {
|
||||
size_t tmp = poses[0];
|
||||
poses[0] = poses[1];
|
||||
poses[1] = tmp;
|
||||
}
|
||||
|
||||
ret = send_ip4_frags(section, payload, payload_len, poses, cnt, 0);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "ip4 send frags");
|
||||
goto accept_lc;
|
||||
}
|
||||
|
||||
goto drop_lc;
|
||||
} else {
|
||||
lginfo("WARNING: IP fragmentation is supported only for IPv4");
|
||||
goto default_send;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default_send:
|
||||
ret = instance_config.send_raw_packet(payload, payload_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "raw pack send");
|
||||
goto accept_lc;
|
||||
}
|
||||
|
||||
goto drop_lc;
|
||||
|
||||
accept_lc:
|
||||
NETBUF_FREE(payload);
|
||||
goto accept;
|
||||
free(payload);
|
||||
return PKT_ACCEPT;
|
||||
drop_lc:
|
||||
NETBUF_FREE(payload);
|
||||
goto drop;
|
||||
|
||||
free(payload);
|
||||
return PKT_DROP;
|
||||
}
|
||||
|
||||
continue_flow:
|
||||
return PKT_CONTINUE;
|
||||
accept:
|
||||
return PKT_ACCEPT;
|
||||
drop:
|
||||
return PKT_DROP;
|
||||
}
|
||||
|
||||
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, size_t pktlen) {
|
||||
@@ -453,12 +454,8 @@ int process_udp_packet(const struct section_config_t *section, const uint8_t *pk
|
||||
goto drop;
|
||||
else if (section->udp_mode == UDP_MODE_FAKE) {
|
||||
for (int i = 0; i < section->udp_fake_seq_len; i++) {
|
||||
NETBUF_ALLOC(fake_udp, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(fake_udp)) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
return -ENOMEM;
|
||||
}
|
||||
size_t fsn_len = MAX_PACKET_SIZE;
|
||||
uint8_t *fake_udp;
|
||||
size_t fake_udp_len;
|
||||
|
||||
struct udp_fake_type fake_type = {
|
||||
.fake_len = section->udp_fake_len,
|
||||
@@ -467,24 +464,25 @@ int process_udp_packet(const struct section_config_t *section, const uint8_t *pk
|
||||
.faking_ttl = section->faking_ttl,
|
||||
},
|
||||
};
|
||||
ret = gen_fake_udp(fake_type, iph, iph_len, udph, fake_udp, &fsn_len);
|
||||
ret = gen_fake_udp(fake_type, iph, iph_len, udph, &fake_udp, &fake_udp_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "gen_fake_udp");
|
||||
goto erret_lc;
|
||||
goto erret;
|
||||
}
|
||||
|
||||
lgtrace_addp("post fake udp #%d", i + 1);
|
||||
|
||||
ret = instance_config.send_raw_packet(fake_udp, fsn_len);
|
||||
ret = instance_config.send_raw_packet(fake_udp, fake_udp_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "send fake udp");
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
NETBUF_FREE(fake_udp);
|
||||
free(fake_udp);
|
||||
continue;
|
||||
erret_lc:
|
||||
NETBUF_FREE(fake_udp);
|
||||
free(fake_udp);
|
||||
erret:
|
||||
goto accept;
|
||||
}
|
||||
|
||||
@@ -519,33 +517,21 @@ int send_ip4_frags(const struct section_config_t *section, const uint8_t *packet
|
||||
packet, pktlen);
|
||||
}
|
||||
} else {
|
||||
NETBUF_ALLOC(frag1, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(frag1)) {
|
||||
size_t f1len = pktlen;
|
||||
uint8_t *frag1 = malloc(f1len);
|
||||
if (frag1 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
NETBUF_ALLOC(frag2, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(frag2)) {
|
||||
size_t f2len = pktlen;
|
||||
uint8_t *frag2 = malloc(f2len);
|
||||
if (frag2 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
NETBUF_FREE(frag1);
|
||||
free(frag1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
NETBUF_ALLOC(fake_pad, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(fake_pad)) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
NETBUF_FREE(frag1);
|
||||
NETBUF_FREE(frag2);
|
||||
return -ENOMEM;
|
||||
}
|
||||
*/
|
||||
|
||||
size_t f1len = MAX_PACKET_SIZE;
|
||||
size_t f2len = MAX_PACKET_SIZE;
|
||||
// size_t fake_pad_len = MAX_PACKET_SIZE;
|
||||
|
||||
int ret;
|
||||
|
||||
if (dvs > poses[0]) {
|
||||
@@ -565,8 +551,6 @@ int send_ip4_frags(const struct section_config_t *section, const uint8_t *packet
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
dvs += frag_pos;
|
||||
|
||||
if (section->frag_sni_reverse)
|
||||
goto send_frag2;
|
||||
send_frag1:
|
||||
@@ -578,54 +562,22 @@ send_frag1:
|
||||
if (section->frag_sni_reverse)
|
||||
goto out_lc;
|
||||
|
||||
send_fake:
|
||||
/*
|
||||
if (section->frag_sni_faked) {
|
||||
ITER_FAKE_STRAT(section->faking_strategy, strategy) {
|
||||
size_t iphfl;
|
||||
fake_pad_len = f2len;
|
||||
ret = ip4_payload_split(frag2, f2len, NULL, &iphfl, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
lgerror("Invalid frag2", ret);
|
||||
goto erret_lc;
|
||||
}
|
||||
memcpy(fake_pad, frag2, iphfl + sizeof(struct udphdr));
|
||||
memset(fake_pad + iphfl + sizeof(struct udphdr), 0, f2len - iphfl - sizeof(struct udphdr));
|
||||
((struct iphdr *)fake_pad)->tot_len = htons(fake_pad_len);
|
||||
((struct iphdr *)fake_pad)->id = 1;
|
||||
((struct iphdr *)fake_pad)->ttl = 8;
|
||||
((struct iphdr *)fake_pad)->frag_off = 0;
|
||||
ip4_set_checksum((struct iphdr*)fake_pad);
|
||||
// *(struct udphdr *)(fake_pad + iphfl) = *(struct udphdr *)(frag2 + iphfl);
|
||||
ret = send_ip4_frags(fake_pad, fake_pad_len, NULL, 0, 0);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (section->frag_sni_reverse)
|
||||
goto send_frag1;
|
||||
|
||||
send_frag2:
|
||||
ret = send_ip4_frags(section, frag2, f2len, poses + 1, poses_sz - 1, dvs);
|
||||
ret = send_ip4_frags(section, frag2, f2len, poses + 1, poses_sz - 1, poses[0]);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
if (section->frag_sni_reverse)
|
||||
goto send_fake;
|
||||
goto send_frag1;
|
||||
|
||||
out_lc:
|
||||
NETBUF_FREE(frag1);
|
||||
NETBUF_FREE(frag2);
|
||||
// NETBUF_FREE(fake_pad);
|
||||
free(frag1);
|
||||
free(frag2);
|
||||
goto out;
|
||||
erret_lc:
|
||||
NETBUF_FREE(frag1);
|
||||
NETBUF_FREE(frag2);
|
||||
// NETBUF_FREE(fake_pad);
|
||||
free(frag1);
|
||||
free(frag2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -651,22 +603,21 @@ int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet
|
||||
packet, pktlen);
|
||||
}
|
||||
} else {
|
||||
NETBUF_ALLOC(frag1, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(frag1)) {
|
||||
size_t f1len = pktlen;
|
||||
uint8_t *frag1 = malloc(f1len);
|
||||
if (frag1 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
NETBUF_ALLOC(frag2, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(frag2)) {
|
||||
size_t f2len = pktlen;
|
||||
uint8_t *frag2 = malloc(f2len);
|
||||
if (frag2 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
NETBUF_FREE(frag1);
|
||||
free(frag1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
size_t f1len = MAX_PACKET_SIZE;
|
||||
size_t f2len = MAX_PACKET_SIZE;
|
||||
|
||||
int ret;
|
||||
|
||||
if (dvs > poses[0]) {
|
||||
@@ -675,7 +626,6 @@ int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
|
||||
ret = tcp_frag(packet, pktlen, poses[0] - dvs,
|
||||
frag1, &f1len, frag2, &f2len);
|
||||
|
||||
@@ -692,16 +642,14 @@ int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet
|
||||
goto send_frag2;
|
||||
|
||||
send_frag1:
|
||||
{
|
||||
ret = send_tcp_frags(section, frag1, f1len, NULL, 0, 0);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
if (section->frag_sni_reverse)
|
||||
goto out_lc;
|
||||
ret = send_tcp_frags(section, frag1, f1len, NULL, 0, 0);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
if (section->frag_sni_reverse)
|
||||
goto out_lc;
|
||||
|
||||
send_fake:
|
||||
if (section->frag_sni_faked) {
|
||||
size_t iphfl, tcphfl;
|
||||
@@ -724,22 +672,20 @@ send_fake:
|
||||
goto send_frag1;
|
||||
|
||||
send_frag2:
|
||||
{
|
||||
ret = send_tcp_frags(section, frag2, f2len, poses + 1, poses_sz - 1, poses[0]);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
if (section->frag_sni_reverse)
|
||||
goto send_fake;
|
||||
ret = send_tcp_frags(section, frag2, f2len, poses + 1, poses_sz - 1, poses[0]);
|
||||
if (ret < 0) {
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
if (section->frag_sni_reverse)
|
||||
goto send_fake;
|
||||
out_lc:
|
||||
NETBUF_FREE(frag1);
|
||||
NETBUF_FREE(frag2);
|
||||
free(frag1);
|
||||
free(frag2);
|
||||
goto out;
|
||||
erret_lc:
|
||||
NETBUF_FREE(frag1);
|
||||
NETBUF_FREE(frag2);
|
||||
free(frag1);
|
||||
free(frag2);
|
||||
return ret;
|
||||
}
|
||||
out:
|
||||
@@ -768,28 +714,24 @@ int post_fake_sni(struct fake_type f_type,
|
||||
|
||||
// one goes for default fake
|
||||
for (int i = 0; i < fake_seq_type.sequence_len; i++) {
|
||||
NETBUF_ALLOC(fake_sni, MAX_PACKET_SIZE);
|
||||
if (!NETBUF_CHECK(fake_sni)) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
return -ENOMEM;
|
||||
}
|
||||
size_t fsn_len = MAX_PACKET_SIZE;
|
||||
|
||||
uint8_t *fake_sni;
|
||||
size_t fake_sni_len;
|
||||
|
||||
ret = gen_fake_sni(
|
||||
fake_seq_type,
|
||||
fsiph, iph_len, fstcph, tcph_len,
|
||||
fake_sni, &fsn_len);
|
||||
&fake_sni, &fake_sni_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "gen_fake_sni");
|
||||
goto erret_lc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
lgtrace_addp("post fake sni #%d", i + 1);
|
||||
|
||||
if (f_type.seg2delay) {
|
||||
ret = instance_config.send_delayed_packet(fake_sni, fsn_len, f_type.seg2delay);
|
||||
ret = instance_config.send_delayed_packet(fake_sni, fake_sni_len, f_type.seg2delay);
|
||||
} else {
|
||||
ret = instance_config.send_raw_packet(fake_sni, fsn_len);
|
||||
ret = instance_config.send_raw_packet(fake_sni, fake_sni_len);
|
||||
}
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "send fake sni");
|
||||
@@ -799,7 +741,7 @@ int post_fake_sni(struct fake_type f_type,
|
||||
size_t tcph_len;
|
||||
size_t plen;
|
||||
ret = tcp_payload_split(
|
||||
fake_sni, fsn_len,
|
||||
fake_sni, fake_sni_len,
|
||||
&fsiph, &iph_len,
|
||||
&fstcph, &tcph_len,
|
||||
NULL, &plen);
|
||||
@@ -825,10 +767,10 @@ int post_fake_sni(struct fake_type f_type,
|
||||
fsiph = (void *)rfsiph;
|
||||
fstcph = (void *)rfstcph;
|
||||
|
||||
NETBUF_FREE(fake_sni);
|
||||
free(fake_sni);
|
||||
continue;
|
||||
erret_lc:
|
||||
NETBUF_FREE(fake_sni);
|
||||
free(fake_sni);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* Processes the packet and returns verdict.
|
||||
* This is the primary function that traverses the packet.
|
||||
*/
|
||||
int process_packet(const struct packet_data *pd);
|
||||
int process_packet(const struct config_t *config, const struct packet_data *pd);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
43
src/quic.c
43
src/quic.c
@@ -285,13 +285,25 @@ int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, size
|
||||
int gen_fake_udp(struct udp_fake_type type,
|
||||
const void *ipxh, size_t iph_len,
|
||||
const struct udphdr *udph,
|
||||
uint8_t *buf, size_t *buflen) {
|
||||
uint8_t **ubuf, size_t *ubuflen) {
|
||||
size_t data_len = type.fake_len;
|
||||
int ret;
|
||||
|
||||
if (!ipxh || !udph || !buf || !buflen)
|
||||
if (!ipxh || !udph || !ubuf || !ubuflen)
|
||||
return -EINVAL;
|
||||
|
||||
int ipxv = netproto_version(ipxh, iph_len);
|
||||
|
||||
if (ipxv == IP6VERSION) {
|
||||
iph_len = sizeof(struct ip6_hdr);
|
||||
}
|
||||
|
||||
size_t dlen = iph_len + sizeof(struct udphdr) + data_len;
|
||||
size_t buffer_len = dlen + 50;
|
||||
uint8_t *buf = malloc(buffer_len);
|
||||
if (buf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ipxv == IP4VERSION) {
|
||||
const struct iphdr *iph = ipxh;
|
||||
@@ -303,20 +315,15 @@ int gen_fake_udp(struct udp_fake_type type,
|
||||
} else if (ipxv == IP6VERSION) {
|
||||
const struct ip6_hdr *iph = ipxh;
|
||||
|
||||
iph_len = sizeof(struct ip6_hdr);
|
||||
memcpy(buf, iph, iph_len);
|
||||
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
|
||||
|
||||
niph->ip6_nxt = IPPROTO_UDP;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
size_t dlen = iph_len + sizeof(struct udphdr) + data_len;
|
||||
|
||||
if (*buflen < dlen)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buf + iph_len, udph, sizeof(struct udphdr));
|
||||
uint8_t *bfdptr = buf + iph_len + sizeof(struct udphdr);
|
||||
|
||||
@@ -336,11 +343,19 @@ int gen_fake_udp(struct udp_fake_type type,
|
||||
|
||||
set_udp_checksum(nudph, buf, iph_len);
|
||||
|
||||
udp_fail_packet(type.strategy, buf, &dlen, *buflen);
|
||||
ret = udp_fail_packet(type.strategy, buf, &dlen, buffer_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "udp_fail_packet");
|
||||
goto error;
|
||||
}
|
||||
|
||||
*buflen = dlen;
|
||||
*ubuflen = dlen;
|
||||
*ubuf = buf;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int parse_quic_decrypted(
|
||||
@@ -351,8 +366,6 @@ int parse_quic_decrypted(
|
||||
const uint8_t *curptr = decrypted_message;
|
||||
ssize_t curptr_len = decrypted_message_len;
|
||||
ssize_t fret;
|
||||
int ret;
|
||||
struct tls_verdict tlsv = {0};
|
||||
struct quic_frame_crypto fr_cr;
|
||||
|
||||
uint8_t *crypto_message = calloc(AVAILABLE_MTU, 1);
|
||||
@@ -431,6 +444,10 @@ int detect_udp_filtered(const struct section_config_t *section,
|
||||
}
|
||||
|
||||
if (section->udp_filter_quic != UDP_FILTER_QUIC_DISABLED) {
|
||||
if (section->dport_filter && ntohs(udph->dest) != 443)
|
||||
goto match_port;
|
||||
|
||||
|
||||
const struct quic_lhdr *qch;
|
||||
size_t qch_len;
|
||||
struct quic_cids qci;
|
||||
|
||||
@@ -234,11 +234,11 @@ int parse_quic_decrypted(
|
||||
// Like fail_packet for TCP
|
||||
int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, size_t *plen, size_t avail_buflen);
|
||||
|
||||
// Like gen_fake_sni for TCP
|
||||
// Like gen_fake_sni for TCP, Allocates and generates udp fake
|
||||
int gen_fake_udp(struct udp_fake_type type,
|
||||
const void *ipxh, size_t iph_len,
|
||||
const struct udphdr *udph,
|
||||
uint8_t *buf, size_t *buflen);
|
||||
uint8_t **buf, size_t *buflen);
|
||||
|
||||
int detect_udp_filtered(const struct section_config_t *section,
|
||||
const uint8_t *payload, size_t plen);
|
||||
|
||||
90
src/tls.c
90
src/tls.c
@@ -41,27 +41,28 @@ int bruteforce_analyze_sni_str(
|
||||
vrd->sni_ptr = data + dlen / 2;
|
||||
return 0;
|
||||
}
|
||||
int max_domain_len = 0;
|
||||
|
||||
for (struct domains_list *sne = section->sni_domains; sne != NULL;
|
||||
sne = sne->next) {
|
||||
max_domain_len = max((int)sne->domain_len, max_domain_len);
|
||||
}
|
||||
|
||||
size_t buf_size = max_domain_len + dlen + 1;
|
||||
uint8_t *buf = malloc(buf_size);
|
||||
if (buf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
int *nzbuf = malloc(buf_size * sizeof(int));
|
||||
if (nzbuf == NULL) {
|
||||
free(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -70,24 +71,20 @@ int bruteforce_analyze_sni_str(
|
||||
|
||||
z_function((char *)buf, zbuf, domain_len + 1 + dlen);
|
||||
|
||||
for (unsigned int k = 0; k < dlen; k++) {
|
||||
for (size_t k = 0; k < domain_len + 1 + dlen; k++) {
|
||||
if (zbuf[k] == domain_len) {
|
||||
vrd->target_sni = 1;
|
||||
vrd->sni_len = domain_len;
|
||||
vrd->sni_ptr = data + (k - domain_len - 1);
|
||||
vrd->target_sni_ptr = vrd->sni_ptr;
|
||||
vrd->target_sni_len = vrd->sni_len;
|
||||
NETBUF_FREE(buf);
|
||||
NETBUF_FREE(nzbuf);
|
||||
return 0;
|
||||
goto return_vrd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NETBUF_FREE(buf);
|
||||
NETBUF_FREE(nzbuf);
|
||||
}
|
||||
|
||||
return_vrd:
|
||||
free(buf);
|
||||
free(nzbuf);
|
||||
return 0;
|
||||
}
|
||||
static int analyze_sni_str(
|
||||
@@ -277,7 +274,7 @@ struct tls_verdict analyze_tls_data(
|
||||
if (tls_vmajor != 0x03) break;
|
||||
message_ptr++;
|
||||
|
||||
uint8_t tls_vminor = *message_ptr;
|
||||
// uint8_t tls_vminor = *message_ptr;
|
||||
message_ptr++;
|
||||
|
||||
uint16_t message_length = ntohs(*(const uint16_t *)message_ptr);
|
||||
@@ -286,7 +283,7 @@ struct tls_verdict analyze_tls_data(
|
||||
|
||||
const uint8_t *tls_message_data = message_ptr;
|
||||
// Since real length may be truncated use minimum of two
|
||||
size_t tls_message_length = min(message_length, data_end - message_ptr);
|
||||
size_t tls_message_length = min((int)message_length, (int)(data_end - message_ptr));
|
||||
|
||||
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
|
||||
goto nextMessage;
|
||||
@@ -319,18 +316,31 @@ out:
|
||||
int gen_fake_sni(struct fake_type type,
|
||||
const void *ipxh, size_t iph_len,
|
||||
const struct tcphdr *tcph, size_t tcph_len,
|
||||
uint8_t *buf, size_t *buflen) {
|
||||
uint8_t **ubuf, size_t *ubuflen) {
|
||||
size_t data_len = type.fake_len;
|
||||
uint8_t *buf = NULL;
|
||||
int ret;
|
||||
|
||||
if (type.type == FAKE_PAYLOAD_RANDOM && data_len == 0) {
|
||||
data_len = (size_t)randint() % 1200;
|
||||
}
|
||||
|
||||
if (!ipxh || !tcph || !buf || !buflen)
|
||||
if (!ipxh || !tcph || !ubuf || !ubuflen)
|
||||
return -EINVAL;
|
||||
|
||||
int ipxv = netproto_version(ipxh, iph_len);
|
||||
|
||||
if (ipxv == IP6VERSION) {
|
||||
iph_len = sizeof(struct ip6_hdr);
|
||||
}
|
||||
|
||||
size_t dlen = iph_len + tcph_len + data_len;
|
||||
size_t buffer_len = dlen + 50;
|
||||
buf = malloc(buffer_len);
|
||||
if (buf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ipxv == IP4VERSION) {
|
||||
const struct iphdr *iph = ipxh;
|
||||
|
||||
@@ -341,20 +351,15 @@ int gen_fake_sni(struct fake_type type,
|
||||
} 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;
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
size_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;
|
||||
|
||||
@@ -391,10 +396,19 @@ int gen_fake_sni(struct fake_type type,
|
||||
niph->ip6_plen = htons(dlen - iph_len);
|
||||
}
|
||||
|
||||
fail_packet(type.strategy, buf, &dlen, *buflen);
|
||||
ret = fail_packet(type.strategy, buf, &dlen, buffer_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "fail_packet");
|
||||
goto error;
|
||||
}
|
||||
|
||||
*buflen = dlen;
|
||||
|
||||
*ubuflen = dlen;
|
||||
*ubuf = buf;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,11 +75,11 @@ struct tls_verdict analyze_tls_data(const struct section_config_t *section, cons
|
||||
|
||||
|
||||
/**
|
||||
* Generates the fake client hello message
|
||||
* Allocates and generates the fake client hello message
|
||||
*/
|
||||
int gen_fake_sni(struct fake_type type,
|
||||
const void *iph, size_t iph_len,
|
||||
const struct tcphdr *tcph, size_t tcph_len,
|
||||
uint8_t *buf, size_t *buflen);
|
||||
uint8_t **ubuf, size_t *ubuflen);
|
||||
|
||||
#endif /* TLS_H */
|
||||
|
||||
25
src/types.h
25
src/types.h
@@ -126,31 +126,6 @@ free((item)); \
|
||||
|
||||
#endif /* not a KERNEL_SPACE */
|
||||
|
||||
/* An alternative memory allocation strategy for userspace app */
|
||||
// #define ALLOC_MALLOC
|
||||
|
||||
/**
|
||||
* Use NETBUF_ALLOC and NETBUF_FREE as an abstraction of memory allocation.
|
||||
* Do not use it within expressions, consider these defines as separate statements.
|
||||
*
|
||||
* Use NETBUF_CHECK to check that buffer was properly allocated.
|
||||
*/
|
||||
#ifdef KERNEL_SPACE
|
||||
#include <linux/gfp.h>
|
||||
#define NETBUF_ALLOC(buf, buf_len) __u8* buf = kmalloc(buf_len, GFP_KERNEL);
|
||||
#define NETBUF_CHECK(buf) ((buf) != NULL)
|
||||
#define NETBUF_FREE(buf) kfree(buf);
|
||||
#elif defined(ALLOC_MALLOC)
|
||||
#include <stdlib.h>
|
||||
#define NETBUF_ALLOC(buf, buf_len) __u8* buf = malloc(buf_len);
|
||||
#define NETBUF_CHECK(buf) ((buf) != NULL)
|
||||
#define NETBUF_FREE(buf) free(buf);
|
||||
#else
|
||||
#define NETBUF_ALLOC(buf, buf_len) __u8 buf[buf_len];
|
||||
#define NETBUF_CHECK(buf) (1)
|
||||
#define NETBUF_FREE(buf) ;
|
||||
#endif
|
||||
|
||||
static inline int randint(void) {
|
||||
int rnd;
|
||||
|
||||
|
||||
@@ -154,7 +154,9 @@ int ip4_payload_split(uint8_t *pkt, size_t buflen,
|
||||
size_t hdr_len = hdr->ihl * 4;
|
||||
size_t pktlen = ntohs(hdr->tot_len);
|
||||
if (buflen < pktlen || hdr_len > pktlen) {
|
||||
lgerror(-EINVAL, "ip4_payload_split: buflen cmp pktlen");
|
||||
lgerror(-EINVAL, "ip4_payload_split: buflen cmp pktlen: "
|
||||
"buflen = %zu pktlen = %zu hdr_len = %zu",
|
||||
buflen, pktlen, hdr_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -229,7 +231,8 @@ int ip6_payload_split(uint8_t *pkt, size_t buflen,
|
||||
size_t hdr_len = sizeof(struct ip6_hdr);
|
||||
size_t pktlen = ntohs(hdr->ip6_plen);
|
||||
if (buflen < pktlen) {
|
||||
lgerror(-EINVAL, "ip6_payload_split: buflen cmp pktlen: %zu %zu", buflen, pktlen);
|
||||
lgerror(-EINVAL, "ip6_payload_split: buflen cmp pktlen: "
|
||||
"buflen = %zu pktlen = %zu", buflen, pktlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ int rawsocket = -2;
|
||||
pthread_mutex_t raw6socket_lock;
|
||||
int raw6socket = -2;
|
||||
|
||||
static struct config_t *cur_config = NULL;
|
||||
|
||||
static int open_socket(struct mnl_socket **_nl) {
|
||||
struct mnl_socket *nl = NULL;
|
||||
nl = mnl_socket_open(NETLINK_NETFILTER);
|
||||
@@ -106,7 +108,7 @@ static int open_raw_socket(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mark = config.mark;
|
||||
int mark = cur_config->mark;
|
||||
if (setsockopt(rawsocket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
|
||||
{
|
||||
lgerror(-errno, "setsockopt(SO_MARK, %d) failed", mark);
|
||||
@@ -158,7 +160,7 @@ static int open_raw6_socket(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mark = config.mark;
|
||||
int mark = cur_config->mark;
|
||||
if (setsockopt(raw6socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
|
||||
{
|
||||
lgerror(-errno, "setsockopt(SO_MARK, %d) failed", mark);
|
||||
@@ -442,14 +444,14 @@ static int send_raw_ipv4(const uint8_t *pkt, size_t pktlen) {
|
||||
}
|
||||
};
|
||||
|
||||
if (config.threads != 1)
|
||||
if (cur_config->threads != 1)
|
||||
pthread_mutex_lock(&rawsocket_lock);
|
||||
|
||||
int sent = sendto(rawsocket,
|
||||
pkt, pktlen, MSG_DONTWAIT,
|
||||
(struct sockaddr *)&daddr, sizeof(daddr));
|
||||
|
||||
if (config.threads != 1)
|
||||
if (cur_config->threads != 1)
|
||||
pthread_mutex_unlock(&rawsocket_lock);
|
||||
|
||||
/* The function will return -errno on error as well as errno value set itself */
|
||||
@@ -477,7 +479,7 @@ static int send_raw_ipv6(const uint8_t *pkt, size_t pktlen) {
|
||||
.sin6_addr = iph->ip6_dst
|
||||
};
|
||||
|
||||
if (config.threads != 1)
|
||||
if (cur_config->threads != 1)
|
||||
pthread_mutex_lock(&rawsocket_lock);
|
||||
|
||||
int sent = sendto(raw6socket,
|
||||
@@ -486,7 +488,7 @@ static int send_raw_ipv6(const uint8_t *pkt, size_t pktlen) {
|
||||
|
||||
lgtrace_addp("rawsocket sent %d", sent);
|
||||
|
||||
if (config.threads != 1)
|
||||
if (cur_config->threads != 1)
|
||||
pthread_mutex_unlock(&rawsocket_lock);
|
||||
|
||||
/* The function will return -errno on error as well as errno value set itself */
|
||||
@@ -501,50 +503,46 @@ static int send_raw_socket(const uint8_t *pkt, size_t pktlen) {
|
||||
if (pktlen > AVAILABLE_MTU) {
|
||||
lgtrace("Split packet!");
|
||||
|
||||
NETBUF_ALLOC(buff1, MNL_SOCKET_BUFFER_SIZE);
|
||||
if (!NETBUF_CHECK(buff1)) {
|
||||
size_t buff1_size = pktlen;
|
||||
uint8_t *buff1 = malloc(buff1_size);
|
||||
if (buff1 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
NETBUF_ALLOC(buff2, MNL_SOCKET_BUFFER_SIZE);
|
||||
if (!NETBUF_CHECK(buff2)) {
|
||||
size_t buff2_size = pktlen;
|
||||
uint8_t *buff2 = malloc(buff2_size);
|
||||
if (buff2 == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
NETBUF_FREE(buff1);
|
||||
free(buff1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
size_t buff1_size = MNL_SOCKET_BUFFER_SIZE;
|
||||
size_t buff2_size = MNL_SOCKET_BUFFER_SIZE;
|
||||
|
||||
if ((ret = tcp_frag(pkt, pktlen, AVAILABLE_MTU-128,
|
||||
buff1, &buff1_size, buff2, &buff2_size)) < 0) {
|
||||
|
||||
errno = -ret;
|
||||
goto free_buffs;
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
int sent = 0;
|
||||
int status = send_raw_socket(buff1, buff1_size);
|
||||
ret = send_raw_socket(buff1, buff1_size);
|
||||
|
||||
if (status >= 0) sent += status;
|
||||
if (ret >= 0) sent += ret;
|
||||
else {
|
||||
ret = status;
|
||||
goto free_buffs;
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
status = send_raw_socket(buff2, buff2_size);
|
||||
if (status >= 0) sent += status;
|
||||
ret = send_raw_socket(buff2, buff2_size);
|
||||
if (ret >= 0) sent += ret;
|
||||
else {
|
||||
ret = status;
|
||||
goto free_buffs;
|
||||
goto erret_lc;
|
||||
}
|
||||
|
||||
ret = sent;
|
||||
|
||||
free_buffs:
|
||||
NETBUF_FREE(buff1)
|
||||
NETBUF_FREE(buff2)
|
||||
free(buff1);
|
||||
free(buff2);
|
||||
return sent;
|
||||
erret_lc:
|
||||
free(buff1);
|
||||
free(buff2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -555,7 +553,7 @@ free_buffs:
|
||||
} else if (ipvx == IP6VERSION) {
|
||||
ret = send_raw_ipv6(pkt, pktlen);
|
||||
} else {
|
||||
lginfo("proto version %d is unsupported", ipvx);
|
||||
printf("proto version %d is unsupported\n", ipvx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -563,6 +561,7 @@ free_buffs:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Per-queue data. Passed to queue_cb.
|
||||
struct queue_data {
|
||||
struct mnl_socket **_nl;
|
||||
@@ -669,8 +668,8 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
||||
|
||||
if (attr[NFQA_MARK] != NULL) {
|
||||
// Skip packets sent by rawsocket to escape infinity loop.
|
||||
if ((ntohl(mnl_attr_get_u32(attr[NFQA_MARK])) & config.mark) ==
|
||||
config.mark) {
|
||||
if ((ntohl(mnl_attr_get_u32(attr[NFQA_MARK])) & cur_config->mark) ==
|
||||
cur_config->mark) {
|
||||
return fallback_accept_packet(id, *qdata);
|
||||
}
|
||||
}
|
||||
@@ -693,7 +692,7 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
||||
ct_out:
|
||||
verdnlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qdata->queue_num);
|
||||
|
||||
ret = process_packet(&packet);
|
||||
ret = process_packet(cur_config, &packet);
|
||||
|
||||
switch (ret) {
|
||||
case PKT_DROP:
|
||||
@@ -725,12 +724,11 @@ int init_queue(int queue_num) {
|
||||
uint32_t portid = mnl_socket_get_portid(nl);
|
||||
|
||||
struct nlmsghdr *nlh;
|
||||
NETBUF_ALLOC(bbuf, BUF_SIZE);
|
||||
if (!NETBUF_CHECK(bbuf)) {
|
||||
char *buf = malloc(BUF_SIZE);
|
||||
if (buf == NULL) {
|
||||
lgerror(-ENOMEM, "Allocation error");
|
||||
goto die_alloc;
|
||||
}
|
||||
char *buf = (char *)bbuf;
|
||||
|
||||
/* Support for kernels versions < 3.8 */
|
||||
// Obsolete and ignored in kernel version 3.8
|
||||
@@ -752,7 +750,7 @@ int init_queue(int queue_num) {
|
||||
goto die;
|
||||
}
|
||||
|
||||
if (config.use_ipv6) {
|
||||
if (cur_config->use_ipv6) {
|
||||
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
|
||||
nfq_nlmsg_cfg_put_cmd(nlh, PF_INET6, NFQNL_CFG_CMD_PF_UNBIND);
|
||||
|
||||
@@ -785,10 +783,10 @@ int init_queue(int queue_num) {
|
||||
unsigned int cfg_flags = NFQA_CFG_F_GSO | NFQA_CFG_F_CONNTRACK | NFQA_CFG_F_FAIL_OPEN;
|
||||
unsigned int cfg_mask = 0;
|
||||
|
||||
if (config.use_gso) {
|
||||
if (cur_config->use_gso) {
|
||||
cfg_mask |= NFQA_CFG_F_GSO;
|
||||
}
|
||||
if (config.use_conntrack) {
|
||||
if (cur_config->use_conntrack) {
|
||||
cfg_mask |= NFQA_CFG_F_CONNTRACK;
|
||||
}
|
||||
cfg_mask |= NFQA_CFG_F_FAIL_OPEN;
|
||||
@@ -837,12 +835,12 @@ int init_queue(int queue_num) {
|
||||
}
|
||||
|
||||
|
||||
NETBUF_FREE(bbuf)
|
||||
free(buf);
|
||||
close_socket(&nl);
|
||||
return 0;
|
||||
|
||||
die:
|
||||
NETBUF_FREE(bbuf)
|
||||
free(buf);
|
||||
die_alloc:
|
||||
close_socket(&nl);
|
||||
return -1;
|
||||
@@ -879,7 +877,9 @@ struct instance_config_t instance_config = {
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int ret;
|
||||
if ((ret = yparse_args(argc, argv)) != 0) {
|
||||
struct config_t config;
|
||||
|
||||
if ((ret = yparse_args(&config, argc, argv)) != 0) {
|
||||
if (ret < 0) {
|
||||
lgerror(-errno, "Unable to parse args");
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -888,7 +888,10 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
print_version();
|
||||
print_welcome();
|
||||
print_welcome(&config);
|
||||
|
||||
parse_global_lgconf(&config);
|
||||
cur_config = &config;
|
||||
|
||||
|
||||
if (open_raw_socket() < 0) {
|
||||
|
||||
21
test/tls.c
21
test/tls.c
@@ -1,5 +1,7 @@
|
||||
static const char tls_chlo_message[] = "\001\000\002\000\003\003*{D\360FDTZ\305\231\272\006\240\246oa\365}ut\321\033\354\361}\334\227\342\215\257]\332\000\000\006\023\001\023\002\023\003\001\000\001\321\0009\000_\t\002@g\017\000\005\004\200`\000\000q'\004\200\001\026\210\a\004\200`\000\000\001\004\200\000u0\003\002E\300\006\004\200`\000\000\316E,\310\0160;\306\003g\201k\004\004\200\360\000\000\200\000GR\004\000\000\000\001 \004\200\001\000\000\200\377s\333\f\000\000\000\001\n\212\nJ\000\000\000\001\b\002@d\000\020\000\005\000\003\002h3\000+\000\003\002\003\004\000\n\000\b\000\006\000\035\000\027\000\030\000\033\000\003\002\000\002Di\000\005\000\003\002h3\000\r\000\024\000\022\004\003\b\004\004\001\005\003\b\005\005\001\b\006\006\001\002\001\000-\000\002\001\001\376\r\000\332\000\000\001\000\001|\000 \004\256\340\330}\337lC3\304gv\325}\rT\370O,i^\001\357\323\373?\205@3\023\354{\000\260\247cf\207\3276\312\205G\017\213Y\231\b\301~\225r\v\001X\026\335\254H\231\237\237\263\027b\b\327\0351W\000\177tc\213:^\f\362\340\225_\272\331\351\002\026rds\326\034\345*5!\221\265\206\270\240\375\nw\v\340 \003\340\307\230H\203#\212\371\364\257H\220\230L\230{\243\355\v'\325@\240EZ\306\230a\233;\033|=(\372P\232\216\215\203\374\234\222\375\004\3058l\275+?\f\306\335\342Q\313\"F\377G<2Jqb\033\033,|\302w\337bO\032\276\374\312X\364}\255xq\274\2348\247K\345t\327\345\322M\004\220\376*\344\365\0003\000&\000$\000\035\000 W\356I\271\201\350\263[cn\\H?\376s``\v\230\306?E=2\017u\306\027\nc{c\000\000\000\030\000\026\000\000\023abc.defghijklm.ndev";
|
||||
|
||||
static const char tls_bruteforce_message[] = "ahl qlwer 12oi34j 1l2kjrdosij f982j jfa osdijwoeij rasdjf oiajsqw9erj pqwoijf lasdj foijyoutube.com";
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_fixture.h"
|
||||
|
||||
@@ -31,8 +33,27 @@ TEST(TLSTest, Test_CHLO_message_detect)
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("abc.defghijklm.ndev", tlsv.sni_ptr, 19);
|
||||
}
|
||||
|
||||
TEST(TLSTest, Test_Bruteforce_detects)
|
||||
{
|
||||
struct tls_verdict tlsv;
|
||||
struct domains_list dmns = {
|
||||
.domain_name = "youtube.com",
|
||||
.domain_len = 11,
|
||||
.next = NULL
|
||||
};
|
||||
sconf.sni_domains = &dmns;
|
||||
|
||||
int ret = bruteforce_analyze_sni_str(&sconf, (const uint8_t *)tls_bruteforce_message, sizeof(tls_bruteforce_message) - 1, &tlsv);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL(11, tlsv.sni_len);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("youtube.com", tlsv.sni_ptr, 11);
|
||||
TEST_ASSERT_EQUAL_PTR(tls_bruteforce_message +
|
||||
sizeof(tls_bruteforce_message) - 12, tlsv.sni_ptr);
|
||||
}
|
||||
|
||||
|
||||
TEST_GROUP_RUNNER(TLSTest)
|
||||
{
|
||||
RUN_TEST_CASE(TLSTest, Test_CHLO_message_detect);
|
||||
RUN_TEST_CASE(TLSTest, Test_Bruteforce_detects);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user