Merge pull request #223 from Waujito/sni_domains_file

Allow to specify sni domains as file
This commit is contained in:
Vadim Vetrov 2025-01-27 20:03:43 +03:00 committed by GitHub
commit 91f8210437
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 144 additions and 3 deletions

View File

@ -231,8 +231,11 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
- `--fake-sni-seq-len=<length>` This flag specifies **youtubeUnblock** to build a complicated construction of fake client hello packets. length determines how much fakes will be sent. Defaults to **1**. - `--fake-sni-seq-len=<length>` This flag specifies **youtubeUnblock** to build a complicated construction of fake client hello packets. length determines how much fakes will be sent. Defaults to **1**.
- `--fake-sni-type={default|custom|random}` This flag specifies which faking message type should be used for fake packets. For `random`, the message of random length and with random payload will be sent. For `default` the default payload (sni=www.google.com) is used. And for the `custom` option, the payload from `--fake-custom-payload` section utilized. Defaults to `default`. - `--fake-sni-type={default|custom|random}` This flag specifies which faking message type should be used for fake packets. For `random`, the message of random length and with random payload will be sent. For `default` the default payload (sni=www.google.com) is used. And for the `custom` option, the payload from `--fake-custom-payload` section utilized. Defaults to `default`.
- `--fake-custom-payload=<payload>` Useful with `--fake-sni-type=custom`. You should specify the payload for fake message manually. Use hex format: `--fake-custom-payload=0001020304` mean that 5 bytes sequence: `0x00`, `0x01`, `0x02`, `0x03`, `0x04` used as fake. - `--fake-custom-payload=<payload>` Useful with `--fake-sni-type=custom`. You should specify the payload for fake message manually. Use hex format: `--fake-custom-payload=0001020304` mean that 5 bytes sequence: `0x00`, `0x01`, `0x02`, `0x03`, `0x04` used as fake.
- `--fake-custom-payload-file=<binary file containing TLS message>` Same as `--fake-custom-payload` but binary file instead of hex. The file should contain raw binary TLS message (TCP payload).
- `--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}` This flag determines the strategy of fake packets invalidation. Defaults to `randseq` - `--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}` This flag determines the strategy of fake packets invalidation. Defaults to `randseq`
- `randseq` specifies that random sequence/acknowledgment random will be set. This option may be handled by provider which uses *conntrack* with drop on invalid *conntrack* state firewall rule enabled. - `randseq` specifies that random sequence/acknowledgment random will be set. This option may be handled by provider which uses *conntrack* with drop on invalid *conntrack* state firewall rule enabled.
- `ttl` specifies that packet will be invalidated after `--faking-ttl=n` hops. `ttl` is better but may cause issues if unconfigured. - `ttl` specifies that packet will be invalidated after `--faking-ttl=n` hops. `ttl` is better but may cause issues if unconfigured.
@ -268,6 +271,10 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
- `--exclude-domains=<comma separated domain list>` List of domains to be excluded from targeting. - `--exclude-domains=<comma separated domain list>` List of domains to be excluded from targeting.
- `--sni-domains-file=<file contains comma or new-line separated list>` Same as `--sni-domains` but accepts path to container file instead of inline domains list. The format is file may consist of both comma-separated domains list as well as new-line separated list.
- `--exclude-domains-file=<file contains comma or new-line separated list>` Same as `--exclude-domains` but accepts path to container file instead of inline domains list. The format is file may consist of both comma-separated domains list as well as new-line separated list.
- `--udp-mode={drop|fake}` This flag specifies udp handling strategy. If drop udp packets will be dropped (useful for quic when browser can fallback to tcp), if fake udp will be faked. Defaults to fake. - `--udp-mode={drop|fake}` This flag specifies udp handling strategy. If drop udp packets will be dropped (useful for quic when browser can fallback to tcp), if fake udp will be faked. Defaults to fake.
- `--udp-fake-seq-len=<amount of faking packets sent>` Specifies how much faking packets will be sent over the network. Defaults to 6. - `--udp-fake-seq-len=<amount of faking packets sent>` Specifies how much faking packets will be sent over the network. Defaults to 6.

View File

@ -26,6 +26,7 @@
#include "getopt.h" #include "getopt.h"
#include "raw_replacements.h" #include "raw_replacements.h"
/** /**
* Logging definitions * Logging definitions
*/ */
@ -47,6 +48,51 @@ void parse_global_lgconf(const struct config_t *config) {
logging_conf.instaflush = config->instaflush; logging_conf.instaflush = config->instaflush;
} }
#ifndef KERNEL_SPACE
#define MAX_FILE_LENGTH 8196
static uint8_t glob_file_buffer[MAX_FILE_LENGTH];
static size_t glob_file_size = 0;
static int read_file(const char* filename) {
int ret;
FILE* fd = fopen(optarg, "r");
if (fd == NULL) {
return -errno;
}
ret = fseek(fd, 0, SEEK_END);
if (ret < 0) {
ret = -errno;
goto close_file;
}
size_t fsize = ftell(fd);
fseek(fd, 0, SEEK_SET);
if (ret < 0) {
ret = -errno;
goto close_file;
}
if (fsize > MAX_FILE_LENGTH) {
ret = -ENOMEM;
goto close_file;
}
glob_file_size = fsize;
unsigned long uret = fread(glob_file_buffer, sizeof(uint8_t), fsize, fd);
if (uret != fsize) {
ret = -EINVAL;
goto close_file;
}
ret = 0;
close_file:
fclose(fd);
return ret;
}
#endif
static int parse_sni_domains(struct domains_list **dlist, const char *domains_str, size_t domains_strlen) { static int parse_sni_domains(struct domains_list **dlist, const char *domains_str, size_t domains_strlen) {
// Empty and shouldn't be used // Empty and shouldn't be used
struct domains_list ndomain = {0}; struct domains_list ndomain = {0};
@ -57,7 +103,13 @@ static int parse_sni_domains(struct domains_list **dlist, const char *domains_st
if (( i == domains_strlen || if (( i == domains_strlen ||
domains_str[i] == '\0' || domains_str[i] == '\0' ||
domains_str[i] == ',' || domains_str[i] == ',' ||
domains_str[i] == '\n' )) { domains_str[i] == '\n' ||
(
i < domains_strlen - 1 &&
domains_str[i] == '\r' &&
domains_str[i + 1] == '\n'
)
)) {
if (i == j) { if (i == j) {
j++; j++;
@ -249,12 +301,15 @@ static int parse_fake_custom_payload(
enum { enum {
OPT_SNI_DOMAINS, OPT_SNI_DOMAINS,
OPT_EXCLUDE_DOMAINS, OPT_EXCLUDE_DOMAINS,
OPT_SNI_DOMAINS_FILE,
OPT_EXCLUDE_DOMAINS_FILE,
OPT_FAKE_SNI, OPT_FAKE_SNI,
OPT_FAKING_TTL, OPT_FAKING_TTL,
OPT_FAKING_STRATEGY, OPT_FAKING_STRATEGY,
OPT_FAKE_SNI_SEQ_LEN, OPT_FAKE_SNI_SEQ_LEN,
OPT_FAKE_SNI_TYPE, OPT_FAKE_SNI_TYPE,
OPT_FAKE_CUSTOM_PAYLOAD, OPT_FAKE_CUSTOM_PAYLOAD,
OPT_FAKE_CUSTOM_PAYLOAD_FILE,
OPT_START_SECTION, OPT_START_SECTION,
OPT_END_SECTION, OPT_END_SECTION,
OPT_DAEMONIZE, OPT_DAEMONIZE,
@ -300,6 +355,8 @@ static struct option long_opt[] = {
{"version", 0, 0, OPT_VERSION}, {"version", 0, 0, OPT_VERSION},
{"sni-domains", 1, 0, OPT_SNI_DOMAINS}, {"sni-domains", 1, 0, OPT_SNI_DOMAINS},
{"exclude-domains", 1, 0, OPT_EXCLUDE_DOMAINS}, {"exclude-domains", 1, 0, OPT_EXCLUDE_DOMAINS},
{"sni-domains-file", 1, 0, OPT_SNI_DOMAINS_FILE},
{"exclude-domains-file",1, 0, OPT_EXCLUDE_DOMAINS_FILE},
{"fake-sni", 1, 0, OPT_FAKE_SNI}, {"fake-sni", 1, 0, OPT_FAKE_SNI},
{"synfake", 1, 0, OPT_SYNFAKE}, {"synfake", 1, 0, OPT_SYNFAKE},
{"synfake-len", 1, 0, OPT_SYNFAKE_LEN}, {"synfake-len", 1, 0, OPT_SYNFAKE_LEN},
@ -307,6 +364,7 @@ static struct option long_opt[] = {
{"fake-sni-seq-len", 1, 0, OPT_FAKE_SNI_SEQ_LEN}, {"fake-sni-seq-len", 1, 0, OPT_FAKE_SNI_SEQ_LEN},
{"fake-sni-type", 1, 0, OPT_FAKE_SNI_TYPE}, {"fake-sni-type", 1, 0, OPT_FAKE_SNI_TYPE},
{"fake-custom-payload", 1, 0, OPT_FAKE_CUSTOM_PAYLOAD}, {"fake-custom-payload", 1, 0, OPT_FAKE_CUSTOM_PAYLOAD},
{"fake-custom-payload-file", 1, 0, OPT_FAKE_CUSTOM_PAYLOAD_FILE},
{"faking-strategy", 1, 0, OPT_FAKING_STRATEGY}, {"faking-strategy", 1, 0, OPT_FAKING_STRATEGY},
{"fake-seq-offset", 1, 0, OPT_FAKE_SEQ_OFFSET}, {"fake-seq-offset", 1, 0, OPT_FAKE_SEQ_OFFSET},
{"faking-ttl", 1, 0, OPT_FAKING_TTL}, {"faking-ttl", 1, 0, OPT_FAKING_TTL},
@ -364,11 +422,14 @@ void print_usage(const char *argv0) {
printf("\t--queue-num=<number of netfilter queue>\n"); printf("\t--queue-num=<number of netfilter queue>\n");
printf("\t--sni-domains=<comma separated domain list>|all\n"); printf("\t--sni-domains=<comma separated domain list>|all\n");
printf("\t--exclude-domains=<comma separated domain list>\n"); printf("\t--exclude-domains=<comma separated domain list>\n");
printf("\t--sni-domains-file=<file contains comma or new-line separated list>\n");
printf("\t--exclude-domains-file=<file contains comma or new-line separated list>\n");
printf("\t--tls={enabled|disabled}\n"); printf("\t--tls={enabled|disabled}\n");
printf("\t--fake-sni={1|0}\n"); printf("\t--fake-sni={1|0}\n");
printf("\t--fake-sni-seq-len=<length>\n"); printf("\t--fake-sni-seq-len=<length>\n");
printf("\t--fake-sni-type={default|random|custom}\n"); printf("\t--fake-sni-type={default|random|custom}\n");
printf("\t--fake-custom-payload=<hex payload>\n"); printf("\t--fake-custom-payload=<hex payload>\n");
printf("\t--fake-custom-payload-file=<binary file containing TLS message>\n");
printf("\t--fake-seq-offset=<offset>\n"); printf("\t--fake-seq-offset=<offset>\n");
printf("\t--faking-ttl=<ttl>\n"); printf("\t--faking-ttl=<ttl>\n");
printf("\t--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}\n"); printf("\t--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}\n");
@ -581,6 +642,24 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
if (ret < 0) if (ret < 0)
goto error; goto error;
break; break;
case OPT_SNI_DOMAINS_FILE:
#ifdef KERNEL_SPACE
lgerr("--sni-domains-file is not allowed in kernel space. Use --sni-domains argument instead");
goto error;
#else
{
free_sni_domains(sect_config->sni_domains);
ret = read_file(optarg);
if (ret < 0) {
goto error;
}
ret = parse_sni_domains(&sect_config->sni_domains, (char *)glob_file_buffer, glob_file_size);
if (ret < 0)
goto error;
break;
}
#endif
case OPT_EXCLUDE_DOMAINS: case OPT_EXCLUDE_DOMAINS:
free_sni_domains(sect_config->exclude_sni_domains); free_sni_domains(sect_config->exclude_sni_domains);
ret = parse_sni_domains(&sect_config->exclude_sni_domains, optarg, strlen(optarg)); ret = parse_sni_domains(&sect_config->exclude_sni_domains, optarg, strlen(optarg));
@ -588,6 +667,24 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
goto error; goto error;
break; break;
case OPT_EXCLUDE_DOMAINS_FILE:
#ifdef KERNEL_SPACE
lgerr("--sni-domains-file is not allowed in kernel space. Use --sni-domains argument instead");
goto error;
#else
{
free_sni_domains(sect_config->exclude_sni_domains);
ret = read_file(optarg);
if (ret < 0) {
goto error;
}
ret = parse_sni_domains(&sect_config->exclude_sni_domains, (char *)glob_file_buffer, glob_file_size);
if (ret < 0)
goto error;
break;
}
#endif
case OPT_FRAG: case OPT_FRAG:
if (strcmp(optarg, "tcp") == 0) { if (strcmp(optarg, "tcp") == 0) {
sect_config->fragmentation_strategy = FRAG_STRAT_TCP; sect_config->fragmentation_strategy = FRAG_STRAT_TCP;
@ -702,6 +799,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
break; break;
case OPT_FAKE_CUSTOM_PAYLOAD: case OPT_FAKE_CUSTOM_PAYLOAD:
SFREE(sect_config->fake_custom_pkt); SFREE(sect_config->fake_custom_pkt);
sect_config->fake_custom_pkt_sz = 0;
ret = parse_fake_custom_payload(optarg, &sect_config->fake_custom_pkt, &sect_config->fake_custom_pkt_sz); ret = parse_fake_custom_payload(optarg, &sect_config->fake_custom_pkt, &sect_config->fake_custom_pkt_sz);
if (ret == -EINVAL) { if (ret == -EINVAL) {
@ -711,6 +809,36 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
} }
break; break;
case OPT_FAKE_CUSTOM_PAYLOAD_FILE:
#ifdef KERNEL_SPACE
lgerr("--fake-custom-payload-file is not allowed in kernel space. Use --fake-custom-payload argument instead");
goto error;
#else
{
SFREE(sect_config->fake_custom_pkt);
sect_config->fake_custom_pkt_sz = 0;
ret = read_file(optarg);
if (ret < 0) {
goto error;
}
if (glob_file_size > MAX_FAKE_SIZE) {
goto invalid_opt;
}
sect_config->fake_custom_pkt = malloc(glob_file_size);
if (sect_config->fake_custom_pkt != NULL) {
memcpy(sect_config->fake_custom_pkt, glob_file_buffer, glob_file_size);
sect_config->fake_custom_pkt_sz = glob_file_size;
} else {
goto error;
}
break;
}
#endif
case OPT_FK_WINSIZE: case OPT_FK_WINSIZE:
num = parse_numeric_option(optarg); num = parse_numeric_option(optarg);
if (errno != 0 || num < 0) { if (errno != 0 || num < 0) {
@ -837,7 +965,8 @@ stop_exec:
#endif #endif
invalid_opt: invalid_opt:
printf("Invalid option %s\n", long_opt[optIdx].name); if (optind > 0 && optind <= argc)
lgerr("Invalid option %s\n", argv[optind - 1]);
ret = -EINVAL; ret = -EINVAL;
error: error:
#ifndef KERNEL_SPACE #ifndef KERNEL_SPACE
@ -845,7 +974,11 @@ error:
#endif #endif
if (errno) ret = -errno; if (errno) ret = -errno;
if (ret != -EINVAL) { if (ret != -EINVAL) {
lgerror(ret, "argparse: error thrown in %s", long_opt[optIdx].name); if (optind > 0 && optind <= argc)
lgerror(
ret == 0 ? EINVAL : -ret,
"argparse: error thrown in %s", argv[optind - 1]
);
ret = -EINVAL; ret = -EINVAL;
} }
@ -936,6 +1069,7 @@ static size_t print_config_section(const struct section_config_t *section, char
print_cnf_buf("--sni-domains=all"); print_cnf_buf("--sni-domains=all");
} else if (section->sni_domains != NULL) { } else if (section->sni_domains != NULL) {
print_cnf_raw("--sni-domains="); print_cnf_raw("--sni-domains=");
for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) { for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) {
print_cnf_raw("%s,", sne->domain_name); print_cnf_raw("%s,", sne->domain_name);
} }