mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2026-01-27 12:40:36 +03:00
Compare commits
21 Commits
v1.0.0-rc6
...
v1.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f37c3dd496 | ||
|
|
0cf1035a14 | ||
|
|
7ebaccfa19 | ||
|
|
705da0f4c6 | ||
|
|
df70763b4a | ||
|
|
49304cc111 | ||
|
|
b832541766 | ||
|
|
2884cb72f9 | ||
|
|
34271ece2c | ||
|
|
ad6b84a961 | ||
|
|
5f20220d4e | ||
|
|
6cc23a2991 | ||
|
|
c73885aca3 | ||
|
|
78dd12c526 | ||
|
|
d7489fc08a | ||
|
|
6da6f63541 | ||
|
|
a7b689b320 | ||
|
|
f7d0bed7aa | ||
|
|
d225e673c7 | ||
|
|
d9c360910b | ||
|
|
42917a75fc |
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/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 src/trie.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
|
||||
|
||||
2
Makefile
2
Makefile
@@ -2,7 +2,7 @@ USPACE_TARGETS := default all install uninstall dev run_dev
|
||||
KMAKE_TARGETS := kmake kload kunload kreload xmod xtclean
|
||||
|
||||
PKG_VERSION := 1.0.0
|
||||
PKG_RELEASE := 6
|
||||
PKG_RELEASE := 10
|
||||
|
||||
PKG_FULLVERSION := $(PKG_VERSION)-$(PKG_RELEASE)
|
||||
|
||||
|
||||
10
README.md
10
README.md
@@ -320,6 +320,10 @@ If your browser is using QUIC it may not work properly. Disable it in Chrome in
|
||||
|
||||
It seems like some TSPUs started to block wrongseq packets, so you should play around with faking strategies. I personally recommend to start with `md5sum` faking strategy.
|
||||
|
||||
#### youtube with `--sni-domains=all`
|
||||
|
||||
I know about this issue but it is **basically not an youtubeUnblock problem**. The problem is behind the large `*.googlevideo.com` domain name. All you want is to create a new configuration section for only youtube. It should go after section for all domains. For plain string arguments just `--fbegin` at the end of args list will work. In luci you can create section interactively.
|
||||
|
||||
### TV
|
||||
|
||||
Televisions are the biggest headache.
|
||||
@@ -435,6 +439,12 @@ cat /sys/module/kyoutubeUnblock/parameters/parameters
|
||||
|
||||
and check all the parameters configured.
|
||||
|
||||
You can check up the statistics of youtubeUnblock with
|
||||
|
||||
```sh
|
||||
sudo cat /proc/kyoutubeUnblock
|
||||
```
|
||||
|
||||
### Building kernel module
|
||||
|
||||
#### Building on host system
|
||||
|
||||
2
deps/cyclone/include/compiler_port.h
vendored
2
deps/cyclone/include/compiler_port.h
vendored
@@ -157,7 +157,7 @@ typedef unsigned int uint_t;
|
||||
#elif defined(__GNUC__)
|
||||
int strcasecmp(const char *s1, const char *s2);
|
||||
int strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
#if !(_SVID_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE)
|
||||
#if !(defined(_SVID_SOURCE) || defined(_BSD_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE))
|
||||
char *strtok_r(char *s, const char *delim, char **last);
|
||||
#endif
|
||||
|
||||
|
||||
92
src/args.c
92
src/args.c
@@ -26,6 +26,7 @@
|
||||
#include "getopt.h"
|
||||
#include "raw_replacements.h"
|
||||
|
||||
struct statistics_data global_stats;
|
||||
|
||||
/**
|
||||
* Logging definitions
|
||||
@@ -61,14 +62,18 @@ static int read_file(const char* filename) {
|
||||
}
|
||||
|
||||
ret = fseek(fd, 0, SEEK_END);
|
||||
if (ret < 0) {
|
||||
if (ret != 0) {
|
||||
ret = -errno;
|
||||
goto close_file;
|
||||
}
|
||||
|
||||
size_t fsize = ftell(fd);
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
if (ret < 0) {
|
||||
long fsize = ftell(fd);
|
||||
if (fsize == -1L) {
|
||||
ret = -errno;
|
||||
goto close_file;
|
||||
}
|
||||
ret = fseek(fd, 0, SEEK_SET);
|
||||
if (ret != 0) {
|
||||
ret = -errno;
|
||||
goto close_file;
|
||||
}
|
||||
@@ -93,11 +98,10 @@ close_file:
|
||||
}
|
||||
#endif
|
||||
|
||||
static int parse_sni_domains(struct domains_list **dlist, const char *domains_str, size_t domains_strlen) {
|
||||
// Empty and shouldn't be used
|
||||
struct domains_list ndomain = {0};
|
||||
struct domains_list *cdomain = &ndomain;
|
||||
|
||||
static int parse_sni_domains(struct trie_container *trie, const char *domains_str, size_t domains_strlen) {
|
||||
int ret;
|
||||
trie_init(trie);
|
||||
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 0; i <= domains_strlen; i++) {
|
||||
if (( i == domains_strlen ||
|
||||
@@ -118,38 +122,22 @@ static int parse_sni_domains(struct domains_list **dlist, const char *domains_st
|
||||
|
||||
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;
|
||||
ret = trie_add_string(trie, (const uint8_t *)domain_startp, domain_len);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "trie_add_string");
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
SFREE(ldl->domain_name);
|
||||
SFREE(ldl);
|
||||
ldl = ndl;
|
||||
}
|
||||
static void free_sni_domains(struct trie_container *trie) {
|
||||
trie_destroy(trie);
|
||||
}
|
||||
|
||||
static long parse_numeric_option(const char* value) {
|
||||
@@ -284,6 +272,9 @@ static int parse_fake_custom_payload(
|
||||
return -EINVAL;
|
||||
}
|
||||
unsigned char *custom_buf = malloc(custom_len);
|
||||
if (custom_buf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (int i = 0; i < custom_len; i++) {
|
||||
ret = sscanf(custom_hex_fake + (i << 1), "%2hhx", custom_buf + i);
|
||||
@@ -632,7 +623,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
case OPT_SNI_DOMAINS:
|
||||
free_sni_domains(sect_config->sni_domains);
|
||||
free_sni_domains(§_config->sni_domains);
|
||||
sect_config->all_domains = 0;
|
||||
if (!strcmp(optarg, "all")) {
|
||||
sect_config->all_domains = 1;
|
||||
@@ -648,7 +639,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
||||
goto error;
|
||||
#else
|
||||
{
|
||||
free_sni_domains(sect_config->sni_domains);
|
||||
free_sni_domains(§_config->sni_domains);
|
||||
ret = read_file(optarg);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
@@ -661,7 +652,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
case OPT_EXCLUDE_DOMAINS:
|
||||
free_sni_domains(sect_config->exclude_sni_domains);
|
||||
free_sni_domains(§_config->exclude_sni_domains);
|
||||
ret = parse_sni_domains(§_config->exclude_sni_domains, optarg, strlen(optarg));
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
@@ -673,7 +664,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
||||
goto error;
|
||||
#else
|
||||
{
|
||||
free_sni_domains(sect_config->exclude_sni_domains);
|
||||
free_sni_domains(§_config->exclude_sni_domains);
|
||||
ret = read_file(optarg);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
@@ -1067,20 +1058,11 @@ static size_t print_config_section(const struct section_config_t *section, char
|
||||
|
||||
if (section->all_domains) {
|
||||
print_cnf_buf("--sni-domains=all");
|
||||
} else 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(" ");
|
||||
} else if (section->sni_domains.vx != NULL) {
|
||||
print_cnf_buf("--sni-domains=<trie of %zu vertexes>", section->sni_domains.sz);
|
||||
}
|
||||
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(" ");
|
||||
if (section->exclude_sni_domains.vx != NULL) {
|
||||
print_cnf_buf("--exclude-domains=<trie of %zu vertexes>", section->sni_domains.sz);
|
||||
}
|
||||
|
||||
switch(section->sni_detection) {
|
||||
@@ -1241,11 +1223,11 @@ int init_section_config(struct section_config_t **section, struct section_config
|
||||
#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)
|
||||
if (def_section == NULL)
|
||||
return -ENOMEM;
|
||||
*def_section = (struct section_config_t)default_section_config;
|
||||
|
||||
def_section->prev = prev;
|
||||
|
||||
ret = parse_sni_domains(&def_section->sni_domains, default_snistr, sizeof(default_snistr));
|
||||
if (ret < 0) {
|
||||
@@ -1280,10 +1262,8 @@ void free_config_section(struct section_config_t *section) {
|
||||
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;
|
||||
free_sni_domains(§ion->sni_domains);
|
||||
free_sni_domains(§ion->exclude_sni_domains);
|
||||
|
||||
section->fake_custom_pkt_sz = 0;
|
||||
SFREE(section->fake_custom_pkt);
|
||||
|
||||
25
src/config.h
25
src/config.h
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "trie.h"
|
||||
|
||||
typedef int (*raw_send_t)(const unsigned char *data, size_t data_len);
|
||||
/**
|
||||
@@ -52,20 +53,13 @@ struct udp_dport_range {
|
||||
uint16_t end;
|
||||
};
|
||||
|
||||
struct domains_list {
|
||||
char *domain_name;
|
||||
uint16_t domain_len;
|
||||
|
||||
struct domains_list *next;
|
||||
};
|
||||
|
||||
struct section_config_t {
|
||||
int id;
|
||||
struct section_config_t *next;
|
||||
struct section_config_t *prev;
|
||||
|
||||
struct domains_list *sni_domains;
|
||||
struct domains_list *exclude_sni_domains;
|
||||
struct trie_container sni_domains;
|
||||
struct trie_container exclude_sni_domains;
|
||||
unsigned int all_domains;
|
||||
|
||||
int tls_enabled;
|
||||
@@ -237,8 +231,8 @@ enum {
|
||||
};
|
||||
|
||||
#define default_section_config { \
|
||||
.sni_domains = NULL, \
|
||||
.exclude_sni_domains = NULL, \
|
||||
.sni_domains = {0}, \
|
||||
.exclude_sni_domains = {0}, \
|
||||
.all_domains = 0, \
|
||||
.tls_enabled = 1, \
|
||||
.frag_sni_reverse = 1, \
|
||||
@@ -339,4 +333,13 @@ struct packet_data {
|
||||
struct ytb_conntrack yct;
|
||||
};
|
||||
|
||||
struct statistics_data {
|
||||
unsigned long all_packet_counter;
|
||||
unsigned long packet_counter;
|
||||
unsigned long target_counter;
|
||||
unsigned long sent_counter;
|
||||
};
|
||||
|
||||
extern struct statistics_data global_stats;
|
||||
|
||||
#endif /* YTB_CONFIG_H */
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <linux/net.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
@@ -329,6 +330,8 @@ erret_lc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
++global_stats.sent_counter;
|
||||
|
||||
int ipvx = netproto_version(pkt, pktlen);
|
||||
|
||||
if (ipvx == IP4VERSION) {
|
||||
@@ -483,6 +486,8 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
||||
struct config_t *config = cur_config;
|
||||
kref_get(&config->refcount);
|
||||
|
||||
++global_stats.all_packet_counter;
|
||||
|
||||
if ((skb->mark & config->mark) == config->mark) {
|
||||
goto send_verdict;
|
||||
}
|
||||
@@ -523,12 +528,14 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
||||
pd.payload_len = skb->len;
|
||||
|
||||
int vrd = process_packet(config, &pd);
|
||||
++global_stats.packet_counter;
|
||||
|
||||
switch(vrd) {
|
||||
case PKT_ACCEPT:
|
||||
nf_verdict = NF_ACCEPT;
|
||||
break;
|
||||
case PKT_DROP:
|
||||
++global_stats.target_counter;
|
||||
nf_verdict = NF_STOLEN;
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
@@ -580,6 +587,37 @@ static struct pernet_operations ykb_pernet_ops = {
|
||||
};
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static int proc_stats_show(struct seq_file *s, void *v) {
|
||||
seq_printf(s, "youtubeUnblock stats: \n"
|
||||
"\tCatched: %ld packets\n"
|
||||
"\tProcessed: %ld packets\n"
|
||||
"\tTargetted: %ld packets\n"
|
||||
"\tSent over socket %ld packets\n",
|
||||
global_stats.all_packet_counter, global_stats.packet_counter,
|
||||
global_stats.target_counter, global_stats.sent_counter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0)
|
||||
|
||||
static int proc_stats_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, proc_stats_show, NULL);
|
||||
}
|
||||
static const struct file_operations proc_stats_operations = {
|
||||
.open = proc_stats_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
#endif /* KERNEL_VERSION */
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
static int __init ykb_init(void) {
|
||||
int ret;
|
||||
|
||||
@@ -615,6 +653,18 @@ static int __init ykb_init(void) {
|
||||
}
|
||||
#endif /* NO_IPV6 */
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
|
||||
proc_create_single("kyoutubeUnblock", 0, NULL, proc_stats_show)
|
||||
#else
|
||||
proc_create("kyoutubeUnblock", 0, NULL, &proc_stats_operations)
|
||||
#endif
|
||||
) {
|
||||
lgwarning("kyoutubeUnblock procfs entry creation failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
||||
ret = register_pernet_subsys(&ykb_pernet_ops);
|
||||
#else
|
||||
@@ -651,6 +701,10 @@ static void __exit ykb_destroy(void) {
|
||||
close_raw6_socket();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("kyoutubeUnblock", NULL);
|
||||
#endif
|
||||
|
||||
close_raw_socket();
|
||||
kref_put(&cur_config->refcount, config_release);
|
||||
lginfo("youtubeUnblock kernel module destroyed.\n");
|
||||
|
||||
22
src/mangle.c
22
src/mangle.c
@@ -502,18 +502,11 @@ drop:
|
||||
|
||||
int send_ip4_frags(const struct section_config_t *section, const uint8_t *packet, size_t pktlen, const size_t *poses, size_t poses_sz, size_t dvs) {
|
||||
if (poses_sz == 0) {
|
||||
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
|
||||
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
|
||||
if (!instance_config.send_delayed_packet) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lgtrace_addp("Sent %zu delayed for %d", pktlen, section->seg2_delay);
|
||||
instance_config.send_delayed_packet(
|
||||
return instance_config.send_delayed_packet(
|
||||
packet, pktlen, section->seg2_delay);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
lgtrace_addp("Sent %zu bytes", pktlen);
|
||||
return instance_config.send_raw_packet(
|
||||
packet, pktlen);
|
||||
}
|
||||
@@ -588,18 +581,11 @@ out:
|
||||
|
||||
int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet, size_t pktlen, const size_t *poses, size_t poses_sz, size_t dvs) {
|
||||
if (poses_sz == 0) {
|
||||
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
|
||||
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
|
||||
if (!instance_config.send_delayed_packet) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
instance_config.send_delayed_packet(
|
||||
return instance_config.send_delayed_packet(
|
||||
packet, pktlen, section->seg2_delay);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
|
||||
|
||||
return instance_config.send_raw_packet(
|
||||
packet, pktlen);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ int quic_check_is_initial(const struct quic_lhdr *qch) {
|
||||
uint32_t qversion;
|
||||
int ret;
|
||||
ret = quic_get_version(&qversion, qch);
|
||||
if (qversion < 0) return 0;
|
||||
if (ret < 0) return 0;
|
||||
|
||||
uint8_t qtype = qch->type;
|
||||
|
||||
|
||||
@@ -82,6 +82,10 @@ int quic_parse_initial_message(
|
||||
ret = quic_parse_data(quic_payload, quic_plen,
|
||||
&qch, &qch_len, &qci, &inpayload, &inplen
|
||||
);
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "quic_parse_data");
|
||||
goto error_nfr;
|
||||
}
|
||||
|
||||
ret = quic_get_version(&qversion, qch);
|
||||
if (ret < 0) {
|
||||
@@ -117,10 +121,6 @@ int quic_parse_initial_message(
|
||||
}
|
||||
|
||||
quic_header_len = inpayload - quic_payload;
|
||||
if (ret < 0) {
|
||||
lgerror(ret, "quic_parse_data");
|
||||
goto error_nfr;
|
||||
}
|
||||
|
||||
ret = quic_parse_initial_header(inpayload, inplen, &qich);
|
||||
if (ret < 0) {
|
||||
|
||||
94
src/tls.c
94
src/tls.c
@@ -33,6 +33,8 @@ int bruteforce_analyze_sni_str(
|
||||
const uint8_t *data, size_t dlen,
|
||||
struct tls_verdict *vrd
|
||||
) {
|
||||
size_t offset, offlen;
|
||||
int ret;
|
||||
*vrd = (struct tls_verdict){0};
|
||||
|
||||
if (dlen <= 1) {
|
||||
@@ -47,50 +49,17 @@ int bruteforce_analyze_sni_str(
|
||||
vrd->target_sni_len = vrd->sni_len;
|
||||
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;
|
||||
// It is safe for multithreading, so dp mutability is ok
|
||||
ret = trie_process_str((struct trie_container *)§ion->sni_domains, data, dlen, 0, &offset, &offlen);
|
||||
if (ret) {
|
||||
vrd->target_sni = 1;
|
||||
vrd->sni_len = offlen;
|
||||
vrd->sni_ptr = data + offset;
|
||||
vrd->target_sni_ptr = vrd->sni_ptr;
|
||||
vrd->target_sni_len = vrd->sni_len;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 (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;
|
||||
goto return_vrd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return_vrd:
|
||||
free(buf);
|
||||
free(nzbuf);
|
||||
return 0;
|
||||
}
|
||||
static int analyze_sni_str(
|
||||
@@ -98,42 +67,33 @@ static int analyze_sni_str(
|
||||
const char *sni_name, int sni_len,
|
||||
struct tls_verdict *vrd
|
||||
) {
|
||||
int ret;
|
||||
size_t offset, offlen;
|
||||
|
||||
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->target_sni_ptr = (const uint8_t *)sni_startp;
|
||||
vrd->target_sni_len = sne->domain_len;
|
||||
break;
|
||||
}
|
||||
// It is safe for multithreading, so dp mutability is ok
|
||||
ret = trie_process_str((struct trie_container *)§ion->sni_domains,
|
||||
(const uint8_t *)sni_name, sni_len, TRIE_OPT_MAP_TO_END, &offset, &offlen);
|
||||
if (ret) {
|
||||
vrd->target_sni = 1;
|
||||
vrd->target_sni_ptr = (const uint8_t *)sni_name + offset;
|
||||
vrd->target_sni_len = offlen;
|
||||
}
|
||||
|
||||
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;
|
||||
lgdebug("Excluded SNI: %.*s",
|
||||
vrd->sni_len, vrd->sni_ptr);
|
||||
}
|
||||
// It is safe for multithreading, so dp mutability is ok
|
||||
ret = trie_process_str((struct trie_container *)§ion->exclude_sni_domains,
|
||||
(const uint8_t *)sni_name, sni_len, TRIE_OPT_MAP_TO_END, &offset, &offlen);
|
||||
if (ret) {
|
||||
vrd->target_sni = 0;
|
||||
lgdebug("Excluded SNI: %.*s",
|
||||
vrd->sni_len, vrd->sni_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
197
src/trie.c
Normal file
197
src/trie.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is slightly optimized Aho-Corasick implementation
|
||||
*
|
||||
* Big thanks to e-maxx http://e-maxx.ru/algo/aho_corasick
|
||||
* for the best description and reference code samples
|
||||
*/
|
||||
|
||||
#include "trie.h"
|
||||
|
||||
int trie_init(struct trie_container *trie) {
|
||||
void *vx = malloc(sizeof(struct trie_vertex) * TRIE_STARTSZ);
|
||||
if (vx == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
trie->vx = vx;
|
||||
trie->arrsz = TRIE_STARTSZ;
|
||||
trie->sz = 1;
|
||||
|
||||
struct trie_vertex *trx = trie->vx;
|
||||
trx->p = trx->link = -1;
|
||||
trx->leaf = 0;
|
||||
trx->depth = 0;
|
||||
trx->pch = 0;
|
||||
memset(trx->go, 0xff, sizeof(trie->vx[0].go));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void trie_destroy(struct trie_container *trie) {
|
||||
trie->arrsz = 0;
|
||||
trie->sz = 0;
|
||||
free(trie->vx);
|
||||
trie->vx = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Increases trie vertex container size.
|
||||
* Returns new vertex index or ret < 0 on error
|
||||
*
|
||||
*/
|
||||
static int trie_push_vertex(struct trie_container *trie) {
|
||||
if (trie->sz == NMAX - 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (trie->arrsz == trie->sz) { // realloc
|
||||
void *pt = realloc(trie->vx,
|
||||
sizeof(struct trie_vertex) * trie->arrsz * 2);
|
||||
if (pt == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
trie->arrsz *= 2;
|
||||
trie->vx = pt;
|
||||
}
|
||||
|
||||
return trie->sz++;
|
||||
}
|
||||
|
||||
|
||||
int trie_add_string(struct trie_container *trie,
|
||||
const uint8_t *str, size_t strlen) {
|
||||
if (trie == NULL || trie->vx == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int v = 0;
|
||||
int nv;
|
||||
|
||||
for (size_t i = 0; i < strlen; ++i) {
|
||||
uint8_t c = str[i];
|
||||
if (c >= TRIE_ALPHABET) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (trie->vx[v].go[c] == -1) {
|
||||
nv = trie_push_vertex(trie);
|
||||
if (nv < 0) {
|
||||
return nv;
|
||||
}
|
||||
struct trie_vertex *tvx = trie->vx + nv;
|
||||
|
||||
memset(tvx->go, 0xff, sizeof(tvx->go));
|
||||
tvx->link = -1;
|
||||
tvx->p = v;
|
||||
tvx->depth = trie->vx[v].depth + 1;
|
||||
tvx->leaf = 0;
|
||||
tvx->pch = c;
|
||||
trie->vx[v].go[c] = nv;
|
||||
}
|
||||
v = trie->vx[v].go[c];
|
||||
}
|
||||
|
||||
if (v != 0) {
|
||||
trie->vx[v].leaf = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trie_go(struct trie_container *trie,
|
||||
int v, uint8_t c);
|
||||
|
||||
static int trie_get_link(struct trie_container *trie,
|
||||
int v) {
|
||||
struct trie_vertex *tvx = trie->vx + v;
|
||||
|
||||
if (tvx->link == -1) {
|
||||
if (v == 0 || tvx->p == 0) {
|
||||
tvx->link = 0;
|
||||
} else {
|
||||
tvx->link = trie_go(trie,
|
||||
trie_get_link(trie, tvx->p), tvx->pch);
|
||||
}
|
||||
}
|
||||
|
||||
return tvx->link;
|
||||
}
|
||||
|
||||
static int trie_go(struct trie_container *trie, int v, uint8_t c) {
|
||||
struct trie_vertex *tvx = trie->vx + v;
|
||||
|
||||
if (tvx->go[c] == -1) {
|
||||
tvx->go[c] = v == 0 ? 0 :
|
||||
trie_go(trie, trie_get_link(trie, v), c);
|
||||
}
|
||||
|
||||
return tvx->go[c];
|
||||
}
|
||||
|
||||
|
||||
int trie_process_str(
|
||||
struct trie_container *trie,
|
||||
const uint8_t *str, size_t strlen,
|
||||
int flags,
|
||||
size_t *offset, size_t *offlen
|
||||
) {
|
||||
if (trie == NULL || trie->vx == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v = 0;
|
||||
size_t i = 0;
|
||||
uint8_t c;
|
||||
int len;
|
||||
|
||||
for (; i < strlen; ++i) {
|
||||
c = str[i];
|
||||
if (c >= TRIE_ALPHABET) {
|
||||
v = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
v = trie->vx[v].go[c] != -1 ? trie->vx[v].go[c] :
|
||||
trie_go(trie, v, str[i]);
|
||||
|
||||
if (trie->vx[v].leaf &&
|
||||
((flags & TRIE_OPT_MAP_TO_END) != TRIE_OPT_MAP_TO_END ||
|
||||
i == strlen - 1)
|
||||
) {
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
len = trie->vx[v].depth;
|
||||
if ( trie->vx[v].leaf &&
|
||||
i >= len
|
||||
) {
|
||||
size_t sp = i - len;
|
||||
*offset = sp;
|
||||
*offlen = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
92
src/trie.h
Normal file
92
src/trie.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is slightly optimized Aho-Corasick implementation
|
||||
*
|
||||
* Big thanks to e-maxx http://e-maxx.ru/algo/aho_corasick
|
||||
* for the best description and reference code samples
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* This algorithm allows us to search inside the string
|
||||
* for a list of patterns in the linear time.
|
||||
*
|
||||
* The algorithm will lazily initialize itself while
|
||||
* youtubeUnblock works. Lazy initializations considered
|
||||
* safe for multithreading and operate without atomicity
|
||||
* or synchronization primitives.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRIE_H
|
||||
#define TRIE_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// ASCII alphabet
|
||||
#define TRIE_ALPHABET 128
|
||||
// Maximum of vertexes in the trie
|
||||
#define NMAX ((1 << 15) - 1)
|
||||
|
||||
struct trie_vertex {
|
||||
int leaf; // boolean flag
|
||||
int depth; // depth of tree (length of substring)
|
||||
int p; // parent
|
||||
uint8_t pch; // vertex char
|
||||
int link; // sufflink
|
||||
int16_t go[TRIE_ALPHABET]; // dynamically filled pushes
|
||||
};
|
||||
|
||||
struct trie_container {
|
||||
struct trie_vertex *vx;
|
||||
size_t arrsz;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
#define TRIE_STARTSZ 32
|
||||
int trie_init(struct trie_container *trie);
|
||||
void trie_destroy(struct trie_container *trie);
|
||||
|
||||
int trie_add_string(struct trie_container *trie,
|
||||
const uint8_t *str, size_t strlen);
|
||||
|
||||
/**
|
||||
* Aligns the pattern to the end
|
||||
*/
|
||||
#define TRIE_OPT_MAP_TO_END (1 << 1)
|
||||
|
||||
/**
|
||||
* Searches the string for the patterns.
|
||||
* flags is TRIE_OPT binary mask with options for search.
|
||||
* offset, offlen are destination variables with
|
||||
* offset of the given string and length of target.
|
||||
*
|
||||
* returns 1 if target found, 0 otherwise
|
||||
*/
|
||||
int trie_process_str(
|
||||
struct trie_container *trie,
|
||||
const uint8_t *str, size_t strlen,
|
||||
int flags,
|
||||
size_t *offset, size_t *offlen
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -68,6 +68,7 @@ typedef __s16 int_least16_t; /* integer of >= 16 bits */
|
||||
|
||||
#define free kfree
|
||||
#define malloc(size) kmalloc((size), GFP_KERNEL)
|
||||
#define realloc(pt, size) krealloc((pt), (size), GFP_KERNEL)
|
||||
#define calloc(n, size) kcalloc((n), (size), GFP_KERNEL)
|
||||
|
||||
#define ip6_hdr ipv6hdr
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <linux/netfilter.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mangle.h"
|
||||
@@ -546,6 +547,7 @@ erret_lc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
++global_stats.sent_counter;
|
||||
int ipvx = netproto_version(pkt, pktlen);
|
||||
|
||||
if (ipvx == IP4VERSION) {
|
||||
@@ -612,14 +614,33 @@ void *delay_packet_send_fn(void *data) {
|
||||
}
|
||||
|
||||
int delay_packet_send(const unsigned char *data, size_t data_len, unsigned int delay_ms) {
|
||||
int ret;
|
||||
|
||||
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
|
||||
if (dpdt == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
*dpdt = (struct dps_t){0};
|
||||
|
||||
dpdt->pkt = malloc(data_len);
|
||||
if (dpdt->pkt == NULL) {
|
||||
free(dpdt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(dpdt->pkt, data, data_len);
|
||||
|
||||
dpdt->pktlen = data_len;
|
||||
dpdt->timer = delay_ms;
|
||||
pthread_t thr;
|
||||
pthread_create(&thr, NULL, delay_packet_send_fn, dpdt);
|
||||
pthread_detach(thr);
|
||||
pthread_t thr = {0};
|
||||
ret = pthread_create(&thr, NULL, delay_packet_send_fn, dpdt);
|
||||
if (ret != 0) {
|
||||
free(dpdt->pkt);
|
||||
free(dpdt);
|
||||
return -ret;
|
||||
}
|
||||
|
||||
ret = pthread_detach(thr);
|
||||
|
||||
lgtrace_addp("Scheduled packet send after %d ms", delay_ms);
|
||||
|
||||
return 0;
|
||||
@@ -640,6 +661,8 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
||||
uint16_t l3num;
|
||||
uint32_t id;
|
||||
|
||||
++global_stats.all_packet_counter;
|
||||
|
||||
if (nfq_nlmsg_parse(nlh, attr) < 0) {
|
||||
lgerror(-errno, "Attr parse");
|
||||
return MNL_CB_ERROR;
|
||||
@@ -694,8 +717,11 @@ ct_out:
|
||||
|
||||
ret = process_packet(cur_config, &packet);
|
||||
|
||||
++global_stats.packet_counter;
|
||||
|
||||
switch (ret) {
|
||||
case PKT_DROP:
|
||||
++global_stats.target_counter;
|
||||
nfq_nlmsg_verdict_put(verdnlh, id, NF_DROP);
|
||||
break;
|
||||
default:
|
||||
@@ -875,6 +901,16 @@ struct instance_config_t instance_config = {
|
||||
.send_delayed_packet = delay_packet_send,
|
||||
};
|
||||
|
||||
void sigint_handler(int s) {
|
||||
lginfo("youtubeUnblock stats: catched %ld packets, "
|
||||
"processed %ld packets, "
|
||||
"targetted %ld packets, sent over socket %ld packets",
|
||||
global_stats.all_packet_counter, global_stats.packet_counter,
|
||||
global_stats.target_counter, global_stats.sent_counter);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int ret;
|
||||
struct config_t config;
|
||||
@@ -893,6 +929,8 @@ int main(int argc, char *argv[]) {
|
||||
parse_global_lgconf(&config);
|
||||
cur_config = &config;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
signal(SIGTERM, sigint_handler);
|
||||
|
||||
if (open_raw_socket() < 0) {
|
||||
lgerror(-errno, "Unable to open raw socket");
|
||||
|
||||
@@ -10,6 +10,7 @@ static void RunAllTests(void)
|
||||
{
|
||||
RUN_TEST_GROUP(TLSTest)
|
||||
RUN_TEST_GROUP(QuicTest);
|
||||
RUN_TEST_GROUP(TrieTest);
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
|
||||
15
test/tls.c
15
test/tls.c
@@ -36,22 +36,21 @@ TEST(TLSTest, Test_CHLO_message_detect)
|
||||
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;
|
||||
struct trie_container trie;
|
||||
int ret;
|
||||
ret = trie_init(&trie);
|
||||
ret = trie_add_string(&trie, (uint8_t *)"youtube.com", 11);
|
||||
sconf.sni_domains = trie;
|
||||
|
||||
int ret = bruteforce_analyze_sni_str(&sconf, (const uint8_t *)tls_bruteforce_message, sizeof(tls_bruteforce_message) - 1, &tlsv);
|
||||
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);
|
||||
trie_destroy(&trie);
|
||||
}
|
||||
|
||||
|
||||
TEST_GROUP_RUNNER(TLSTest)
|
||||
{
|
||||
RUN_TEST_CASE(TLSTest, Test_CHLO_message_detect);
|
||||
|
||||
147
test/trie.c
Normal file
147
test/trie.c
Normal file
@@ -0,0 +1,147 @@
|
||||
#include "unity.h"
|
||||
#include "unity_fixture.h"
|
||||
|
||||
#include "trie.h"
|
||||
|
||||
TEST_GROUP(TrieTest);
|
||||
|
||||
TEST_SETUP(TrieTest)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_TEAR_DOWN(TrieTest)
|
||||
{
|
||||
}
|
||||
|
||||
const char ASTR[] = "abacaba";
|
||||
const char BSTR[] = "BABABABA";
|
||||
const char CSTR[] = "abracadabra";
|
||||
|
||||
const char tstr[] = "aBABABABDADAabacabracadabraabbbabacabaaaaaabacaba";
|
||||
|
||||
|
||||
TEST(TrieTest, Trie_string_adds)
|
||||
{
|
||||
int ret;
|
||||
size_t offset;
|
||||
size_t offlen;
|
||||
struct trie_container trie;
|
||||
|
||||
ret = trie_init(&trie);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
TEST_ASSERT_EQUAL(25, trie.sz);
|
||||
|
||||
trie_destroy(&trie);
|
||||
}
|
||||
|
||||
TEST(TrieTest, Trie_string_finds)
|
||||
{
|
||||
int ret;
|
||||
size_t offset;
|
||||
size_t offlen;
|
||||
struct trie_container trie;
|
||||
|
||||
ret = trie_init(&trie);
|
||||
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
|
||||
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
|
||||
|
||||
ret = trie_process_str(&trie,
|
||||
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||
0, &offset, &offlen
|
||||
);
|
||||
TEST_ASSERT_EQUAL(1, ret);
|
||||
TEST_ASSERT_EQUAL(11, offlen);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("abracadabra", tstr + offset, offlen);
|
||||
|
||||
trie_destroy(&trie);
|
||||
}
|
||||
|
||||
TEST(TrieTest, Trie_string_finds_opt_end)
|
||||
{
|
||||
int ret;
|
||||
size_t offset;
|
||||
size_t offlen;
|
||||
struct trie_container trie;
|
||||
|
||||
ret = trie_init(&trie);
|
||||
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
|
||||
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
|
||||
|
||||
ret = trie_process_str(&trie,
|
||||
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||
TRIE_OPT_MAP_TO_END,
|
||||
&offset, &offlen
|
||||
);
|
||||
TEST_ASSERT_EQUAL(1, ret);
|
||||
TEST_ASSERT_EQUAL(7, offlen);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("abacaba", tstr + offset, offlen);
|
||||
|
||||
ret = trie_process_str(&trie,
|
||||
(uint8_t *)tstr, sizeof(tstr),
|
||||
TRIE_OPT_MAP_TO_END,
|
||||
&offset, &offlen
|
||||
);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
trie_destroy(&trie);
|
||||
}
|
||||
|
||||
TEST(TrieTest, Trie_single_vertex)
|
||||
{
|
||||
int ret;
|
||||
size_t offset;
|
||||
size_t offlen;
|
||||
struct trie_container trie;
|
||||
|
||||
ret = trie_init(&trie);
|
||||
|
||||
ret = trie_process_str(&trie,
|
||||
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||
0,
|
||||
&offset, &offlen
|
||||
);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
trie_destroy(&trie);
|
||||
|
||||
}
|
||||
|
||||
TEST(TrieTest, Trie_uninitialized)
|
||||
{
|
||||
int ret;
|
||||
size_t offset;
|
||||
size_t offlen;
|
||||
struct trie_container trie = {0};
|
||||
|
||||
// ret = trie_init(&trie);
|
||||
|
||||
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||
TEST_ASSERT_EQUAL(-EINVAL, ret);
|
||||
|
||||
ret = trie_process_str(&trie,
|
||||
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||
0,
|
||||
&offset, &offlen
|
||||
);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST_GROUP_RUNNER(TrieTest)
|
||||
{
|
||||
RUN_TEST_CASE(TrieTest, Trie_string_adds);
|
||||
RUN_TEST_CASE(TrieTest, Trie_string_finds);
|
||||
RUN_TEST_CASE(TrieTest, Trie_string_finds_opt_end);
|
||||
RUN_TEST_CASE(TrieTest, Trie_single_vertex);
|
||||
RUN_TEST_CASE(TrieTest, Trie_uninitialized);
|
||||
}
|
||||
@@ -34,7 +34,7 @@ export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CF
|
||||
APP:=$(BUILD_DIR)/youtubeUnblock
|
||||
TEST_APP:=$(BUILD_DIR)/testYoutubeUnblock
|
||||
|
||||
SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c
|
||||
SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c trie.c
|
||||
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
||||
APP_EXEC := youtubeUnblock.c
|
||||
APP_OBJ := $(APP_EXEC:%.c=$(BUILD_DIR)/%.o)
|
||||
|
||||
Reference in New Issue
Block a user