mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2024-12-22 06:15:31 +00:00
Add multiple fooling options
This commit is contained in:
parent
d29177d783
commit
2e96aa150e
127
args.c
127
args.c
@ -9,11 +9,14 @@
|
|||||||
|
|
||||||
|
|
||||||
struct config_t config = {
|
struct config_t config = {
|
||||||
.rawsocket = -2,
|
|
||||||
.threads = THREADS_NUM,
|
.threads = THREADS_NUM,
|
||||||
|
.frag_sni_reverse = 0,
|
||||||
|
.frag_sni_faked = 0,
|
||||||
.fragmentation_strategy = FRAGMENTATION_STRATEGY,
|
.fragmentation_strategy = FRAGMENTATION_STRATEGY,
|
||||||
.fake_sni_strategy = FAKE_SNI_STRATEGY,
|
.faking_strategy = FAKING_STRATEGY,
|
||||||
.fake_sni_ttl = FAKE_SNI_TTL,
|
.faking_ttl = FAKE_TTL,
|
||||||
|
.fake_sni = 1,
|
||||||
|
.fake_sni_seq_len = 1,
|
||||||
|
|
||||||
#ifdef SEG2_DELAY
|
#ifdef SEG2_DELAY
|
||||||
.seg2_delay = SEG2_DELAY,
|
.seg2_delay = SEG2_DELAY,
|
||||||
@ -40,26 +43,36 @@ struct config_t config = {
|
|||||||
|
|
||||||
#define OPT_SNI_DOMAINS 1
|
#define OPT_SNI_DOMAINS 1
|
||||||
#define OPT_FAKE_SNI 2
|
#define OPT_FAKE_SNI 2
|
||||||
#define OPT_FAKE_SNI_TTL 3
|
#define OPT_FAKING_TTL 3
|
||||||
|
#define OPT_FAKING_STRATEGY 10
|
||||||
|
#define OPT_FAKE_SNI_SEQ_LEN 11
|
||||||
#define OPT_FRAG 4
|
#define OPT_FRAG 4
|
||||||
|
#define OPT_FRAG_SNI_REVERSE 12
|
||||||
|
#define OPT_FRAG_SNI_FAKED 13
|
||||||
#define OPT_SEG2DELAY 5
|
#define OPT_SEG2DELAY 5
|
||||||
#define OPT_THREADS 6
|
#define OPT_THREADS 6
|
||||||
#define OPT_SILENT 7
|
#define OPT_SILENT 7
|
||||||
#define OPT_NO_GSO 8
|
#define OPT_NO_GSO 8
|
||||||
#define OPT_QUEUE_NUM 9
|
#define OPT_QUEUE_NUM 9
|
||||||
|
|
||||||
|
#define OPT_MAX OPT_FRAG_SNI_FAKED
|
||||||
|
|
||||||
static struct option long_opt[] = {
|
static struct option long_opt[] = {
|
||||||
{"help", 0, 0, 'h'},
|
{"help", 0, 0, 'h'},
|
||||||
{"version", 0, 0, 'v'},
|
{"version", 0, 0, 'v'},
|
||||||
{"sni-domains", 1, 0, OPT_SNI_DOMAINS},
|
{"sni-domains", 1, 0, OPT_SNI_DOMAINS},
|
||||||
{"fake-sni", 1, 0, OPT_FAKE_SNI},
|
{"fake-sni", 1, 0, OPT_FAKE_SNI},
|
||||||
{"fake-sni-ttl", 1, 0, OPT_FAKE_SNI_TTL},
|
{"fake-sni-seq-len", 1, 0, OPT_FAKE_SNI_SEQ_LEN},
|
||||||
{"frag", 1, 0, OPT_FRAG},
|
{"faking-strategy", 1, 0, OPT_FAKING_STRATEGY},
|
||||||
{"seg2delay", 1, 0, OPT_SEG2DELAY},
|
{"faking-ttl", 1, 0, OPT_FAKING_TTL},
|
||||||
{"threads", 1, 0, OPT_THREADS},
|
{"frag", 1, 0, OPT_FRAG},
|
||||||
{"silent", 0, 0, OPT_SILENT},
|
{"frag-sni-reverse", 1, 0, OPT_FRAG_SNI_REVERSE},
|
||||||
{"no-gso", 0, 0, OPT_NO_GSO},
|
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
|
||||||
{"queue-num", 1, 0, OPT_QUEUE_NUM},
|
{"seg2delay", 1, 0, OPT_SEG2DELAY},
|
||||||
|
{"threads", 1, 0, OPT_THREADS},
|
||||||
|
{"silent", 0, 0, OPT_SILENT},
|
||||||
|
{"no-gso", 0, 0, OPT_NO_GSO},
|
||||||
|
{"queue-num", 1, 0, OPT_QUEUE_NUM},
|
||||||
{0,0,0,0}
|
{0,0,0,0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -93,9 +106,13 @@ void print_usage(const char *argv0) {
|
|||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
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--fake-sni={ack,ttl,none}\n");
|
printf("\t--fake-sni={1|0}\n");
|
||||||
printf("\t--fake-sni-ttl=<ttl>\n");
|
printf("\t--fake-sni-seq-len=<length>\n");
|
||||||
|
printf("\t--faking-ttl=<ttl>\n");
|
||||||
|
printf("\t--faking-strategy={ack,ttl}\n");
|
||||||
printf("\t--frag={tcp,ip,none}\n");
|
printf("\t--frag={tcp,ip,none}\n");
|
||||||
|
printf("\t--frag-sni-reverse={0|1}\n");
|
||||||
|
printf("\t--frag-sni-faked={0|1}\n");
|
||||||
printf("\t--seg2delay=<delay>\n");
|
printf("\t--seg2delay=<delay>\n");
|
||||||
printf("\t--threads=<threads number>\n");
|
printf("\t--threads=<threads number>\n");
|
||||||
printf("\t--silent\n");
|
printf("\t--silent\n");
|
||||||
@ -143,19 +160,72 @@ int parse_args(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case OPT_FAKE_SNI:
|
case OPT_FRAG_SNI_FAKED:
|
||||||
if (strcmp(optarg, "ack") == 0) {
|
if (strcmp(optarg, "1") == 0) {
|
||||||
config.fake_sni_strategy = FKSN_STRAT_ACK_SEQ;
|
config.frag_sni_faked = 1;
|
||||||
} else if (strcmp(optarg, "ttl") == 0) {
|
} else if (strcmp(optarg, "0") == 0) {
|
||||||
config.fake_sni_strategy = FKSN_STRAT_TTL;
|
config.frag_sni_faked = 0;
|
||||||
} else if (strcmp(optarg, "none") == 0) {
|
|
||||||
config.fake_sni_strategy = FKSN_STRAT_NONE;
|
|
||||||
} else {
|
} else {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
printf("Invalid option %s\n", long_opt[optIdx].name);
|
printf("Invalid option %s\n", long_opt[optIdx].name);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPT_FRAG_SNI_REVERSE:
|
||||||
|
if (strcmp(optarg, "1") == 0) {
|
||||||
|
config.frag_sni_reverse = 1;
|
||||||
|
} else if (strcmp(optarg, "0") == 0) {
|
||||||
|
config.frag_sni_reverse = 0;
|
||||||
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
printf("Invalid option %s\n", long_opt[optIdx].name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPT_FAKING_STRATEGY:
|
||||||
|
if (strcmp(optarg, "ack") == 0) {
|
||||||
|
config.faking_strategy = FAKE_STRAT_ACK_SEQ;
|
||||||
|
} else if (strcmp(optarg, "ttl") == 0) {
|
||||||
|
config.faking_strategy = FAKE_STRAT_TTL;
|
||||||
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
printf("Invalid option %s\n", long_opt[optIdx].name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPT_FAKING_TTL:
|
||||||
|
num = parse_numeric_option(optarg);
|
||||||
|
if (errno != 0 || num < 0 || num > 255) {
|
||||||
|
printf("Invalid option %s\n", long_opt[optIdx].name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.faking_ttl = num;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_FAKE_SNI:
|
||||||
|
if (strcmp(optarg, "1") == 0) {
|
||||||
|
config.fake_sni = 1;
|
||||||
|
} else if (strcmp(optarg, "0") == 0) {
|
||||||
|
config.fake_sni = 0;
|
||||||
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
printf("Invalid option %s\n", long_opt[optIdx].name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPT_FAKE_SNI_SEQ_LEN:
|
||||||
|
num = parse_numeric_option(optarg);
|
||||||
|
if (errno != 0 || num < 0 || num > 255) {
|
||||||
|
printf("Invalid option %s\n", long_opt[optIdx].name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.fake_sni_seq_len = num;
|
||||||
break;
|
break;
|
||||||
case OPT_SEG2DELAY:
|
case OPT_SEG2DELAY:
|
||||||
num = parse_numeric_option(optarg);
|
num = parse_numeric_option(optarg);
|
||||||
@ -175,15 +245,6 @@ int parse_args(int argc, char *argv[]) {
|
|||||||
|
|
||||||
config.threads = num;
|
config.threads = num;
|
||||||
break;
|
break;
|
||||||
case OPT_FAKE_SNI_TTL:
|
|
||||||
num = parse_numeric_option(optarg);
|
|
||||||
if (errno != 0 || num < 0 || num > 255) {
|
|
||||||
printf("Invalid option %s\n", long_opt[optIdx].name);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.fake_sni_ttl = num;
|
|
||||||
break;
|
|
||||||
case OPT_QUEUE_NUM:
|
case OPT_QUEUE_NUM:
|
||||||
num = parse_numeric_option(optarg);
|
num = parse_numeric_option(optarg);
|
||||||
if (errno != 0 || num < 0) {
|
if (errno != 0 || num < 0) {
|
||||||
|
52
config.h
52
config.h
@ -1,18 +1,38 @@
|
|||||||
|
#ifndef YTB_CONFIG_H
|
||||||
|
#define YTB_CONFIG_H
|
||||||
|
|
||||||
|
typedef int (*raw_send_t)(const unsigned char *data, unsigned int data_len);
|
||||||
|
/**
|
||||||
|
* Sends the packet after delay_ms. The function should schedule send and return immediately
|
||||||
|
* (for example, open daemon thread)
|
||||||
|
*/
|
||||||
|
typedef void (*delayed_send_t)(const unsigned char *data, unsigned int data_len, unsigned int delay_ms);
|
||||||
|
|
||||||
|
struct instance_config_t {
|
||||||
|
raw_send_t send_raw_packet;
|
||||||
|
delayed_send_t send_delayed_packet;
|
||||||
|
};
|
||||||
|
extern struct instance_config_t instance_config;
|
||||||
|
|
||||||
struct config_t {
|
struct config_t {
|
||||||
unsigned int queue_start_num;
|
unsigned int queue_start_num;
|
||||||
int rawsocket;
|
|
||||||
int threads;
|
int threads;
|
||||||
int use_gso;
|
int use_gso;
|
||||||
int fragmentation_strategy;
|
int fragmentation_strategy;
|
||||||
unsigned char fake_sni_ttl;
|
int frag_sni_reverse;
|
||||||
int fake_sni_strategy;
|
int frag_sni_faked;
|
||||||
|
int faking_strategy;
|
||||||
|
unsigned char faking_ttl;
|
||||||
|
int fake_sni;
|
||||||
|
unsigned int fake_sni_seq_len;
|
||||||
int verbose;
|
int verbose;
|
||||||
|
/* In milliseconds */
|
||||||
unsigned int seg2_delay;
|
unsigned int seg2_delay;
|
||||||
const char *domains_str;
|
const char *domains_str;
|
||||||
unsigned int domains_strlen;
|
unsigned int domains_strlen;
|
||||||
unsigned int all_domains;
|
unsigned int all_domains;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct config_t config;
|
extern struct config_t config;
|
||||||
|
|
||||||
#define MAX_THREADS 16
|
#define MAX_THREADS 16
|
||||||
@ -43,23 +63,17 @@ extern struct config_t config;
|
|||||||
#define SEG2_DELAY 100
|
#define SEG2_DELAY 100
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FAKE_SNI_TTL 8
|
#define FAKE_TTL 8
|
||||||
|
|
||||||
// No fake SNI
|
// Will invalidate fake packets by out-of-ack_seq out-of-seq request
|
||||||
#define FKSN_STRAT_NONE 0
|
#define FAKE_STRAT_ACK_SEQ 1
|
||||||
// Will invalidate fake client hello by out-of-ack_seq out-of-seq request
|
// Will assume that GGC server is located further than FAKE_TTL
|
||||||
#define FKSN_STRAT_ACK_SEQ 1
|
// Thus, Fake packet will be eliminated automatically.
|
||||||
// Will assume that GGC server is located further than FAKE_SNI_TTL
|
#define FAKE_STRAT_TTL 2
|
||||||
// Thus, Fake Client Hello will be eliminated automatically.
|
|
||||||
#define FKSN_STRAT_TTL 2
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef NO_FAKE_SNI
|
#ifndef FAKING_STRATEGY
|
||||||
#define FAKE_SNI_STRATEGY FKSN_STRAT_NONE
|
#define FAKING_STRATEGY FAKE_STRAT_ACK_SEQ
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FAKE_SNI_STRATEGY
|
|
||||||
#define FAKE_SNI_STRATEGY FKSN_STRAT_ACK_SEQ
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(SILENT) && !defined(KERNEL_SPACE)
|
#if !defined(SILENT) && !defined(KERNEL_SPACE)
|
||||||
@ -72,4 +86,8 @@ extern struct config_t config;
|
|||||||
|
|
||||||
#define DEFAULT_QUEUE_NUM 537
|
#define DEFAULT_QUEUE_NUM 537
|
||||||
|
|
||||||
|
#define MAX_PACKET_SIZE 8192
|
||||||
|
|
||||||
static const char defaul_snistr[] = "googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com";
|
static const char defaul_snistr[] = "googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com";
|
||||||
|
|
||||||
|
#endif /* YTB_CONFIG_H */
|
||||||
|
333
mangle.c
333
mangle.c
@ -1,5 +1,5 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include "mangle.h"
|
#include "mangle.h"
|
||||||
#include "raw_replacements.h"
|
#include "raw_replacements.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -23,6 +23,292 @@ typedef uint16_t __u16;
|
|||||||
#define lgerror(msg, ret) __extension__ ({errno = -ret; perror(msg);})
|
#define lgerror(msg, ret) __extension__ ({errno = -ret; perror(msg);})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int send_ip4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *poses, uint32_t poses_sz, uint32_t dvs) {
|
||||||
|
if (poses_sz == 0) {
|
||||||
|
return instance_config.send_raw_packet(packet, pktlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8_t frag1[MAX_PACKET_SIZE];
|
||||||
|
uint8_t frag2[MAX_PACKET_SIZE];
|
||||||
|
uint32_t f1len = MAX_PACKET_SIZE;
|
||||||
|
uint32_t f2len = MAX_PACKET_SIZE;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (dvs > poses[0]) {
|
||||||
|
printf("send_frags: Recursive dvs(%d) is more than poses0(%d)\n", dvs, poses[0]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ip4_frag(packet, pktlen, poses[0] - dvs,
|
||||||
|
frag1, &f1len, frag2, &f2len);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("send_frags: frag", ret);
|
||||||
|
printf("Error context: packet with size %d, position: %d, recursive dvs: %d\n", pktlen, poses[0], dvs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
dvs += poses[0];
|
||||||
|
ret = send_ip4_frags(frag1, f1len, NULL, 0, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = send_ip4_frags(frag2, f2len, poses + 1, poses_sz - 1, dvs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_tcp4_frags(const uint8_t *packet, uint32_t pktlen, const uint32_t *poses, uint32_t poses_sz, uint32_t dvs) {
|
||||||
|
if (poses_sz == 0) {
|
||||||
|
if (config.seg2_delay && dvs > 0) {
|
||||||
|
if (!instance_config.send_delayed_packet) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance_config.send_delayed_packet(
|
||||||
|
packet, pktlen, config.seg2_delay);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return instance_config.send_raw_packet(
|
||||||
|
packet, pktlen);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint8_t frag1[MAX_PACKET_SIZE];
|
||||||
|
uint8_t frag2[MAX_PACKET_SIZE];
|
||||||
|
uint8_t fake_pad[MAX_PACKET_SIZE];
|
||||||
|
uint32_t f1len = MAX_PACKET_SIZE;
|
||||||
|
uint32_t f2len = MAX_PACKET_SIZE;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (dvs > poses[0]) {
|
||||||
|
printf("send_frags: Recursive dvs(%d) is more than poses0(%d)\n", dvs, poses[0]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tcp4_frag(packet, pktlen, poses[0] - dvs,
|
||||||
|
frag1, &f1len, frag2, &f2len);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("send_frags: frag", ret);
|
||||||
|
printf("Error context: packet with size %d, position: %d, recursive dvs: %d\n", pktlen, poses[0], dvs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reverse = config.frag_sni_reverse;
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
goto send_frag2;
|
||||||
|
|
||||||
|
send_frag1:
|
||||||
|
{
|
||||||
|
ret = send_tcp4_frags(frag1, f1len, NULL, 0, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_fake:
|
||||||
|
if (config.frag_sni_faked) {
|
||||||
|
uint32_t iphfl, tcphfl;
|
||||||
|
ret = tcp4_payload_split(frag2, f2len, NULL, &iphfl, NULL, &tcphfl, NULL, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("Invalid frag2", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
memcpy(fake_pad, frag2, iphfl + tcphfl);
|
||||||
|
memset(fake_pad + iphfl + tcphfl, 0, f2len - iphfl - tcphfl);
|
||||||
|
ret = fail4_packet(fake_pad, f2len);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("Failed to fail packet", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = send_tcp4_frags(fake_pad, f2len, NULL, 0, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
goto send_frag1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
send_frag2:
|
||||||
|
{
|
||||||
|
dvs += poses[0];
|
||||||
|
ret = send_tcp4_frags(frag2, f2len, poses + 1, poses_sz - 1, dvs);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
goto send_fake;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
|
||||||
|
if (raw_payload_len > MAX_PACKET_SIZE) {
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct iphdr *iph;
|
||||||
|
uint32_t iph_len;
|
||||||
|
const struct tcphdr *tcph;
|
||||||
|
uint32_t tcph_len;
|
||||||
|
const uint8_t *data;
|
||||||
|
uint32_t dlen;
|
||||||
|
|
||||||
|
int ret = tcp4_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
||||||
|
(struct iphdr **)&iph, &iph_len, (struct tcphdr **)&tcph, &tcph_len,
|
||||||
|
(uint8_t **)&data, &dlen);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct verdict vrd = analyze_tls_data(data, dlen);
|
||||||
|
|
||||||
|
if (vrd.target_sni) {
|
||||||
|
if (config.verbose)
|
||||||
|
printf("SNI target detected\n");
|
||||||
|
|
||||||
|
uint8_t payload[MAX_PACKET_SIZE];
|
||||||
|
uint32_t payload_len = raw_payload_len;
|
||||||
|
memcpy(payload, raw_payload, raw_payload_len);
|
||||||
|
|
||||||
|
struct iphdr *iph;
|
||||||
|
uint32_t iph_len;
|
||||||
|
struct tcphdr *tcph;
|
||||||
|
uint32_t tcph_len;
|
||||||
|
uint8_t *data;
|
||||||
|
uint32_t dlen;
|
||||||
|
|
||||||
|
int ret = tcp4_payload_split(payload, payload_len,
|
||||||
|
&iph, &iph_len, &tcph, &tcph_len,
|
||||||
|
&data, &dlen);
|
||||||
|
ip4_set_checksum(iph);
|
||||||
|
tcp4_set_checksum(tcph, iph);
|
||||||
|
|
||||||
|
|
||||||
|
if (dlen > 1480 && config.verbose) {
|
||||||
|
printf("WARNING! Client Hello packet is too big and may cause issues!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.fake_sni) {
|
||||||
|
uint8_t rfsiph[60];
|
||||||
|
uint8_t rfstcph[60];
|
||||||
|
|
||||||
|
memcpy(rfsiph, iph, iph_len);
|
||||||
|
memcpy(rfstcph, tcph, tcph_len);
|
||||||
|
|
||||||
|
struct iphdr *fsiph = (void *)rfsiph;
|
||||||
|
struct tcphdr *fstcph = (void *)rfstcph;
|
||||||
|
|
||||||
|
for (int i = 0; i < config.fake_sni_seq_len; i++) {
|
||||||
|
uint8_t fake_sni[MAX_PACKET_SIZE];
|
||||||
|
uint32_t fsn_len = MAX_PACKET_SIZE;
|
||||||
|
ret = gen_fake_sni(fsiph, fstcph, fake_sni, &fsn_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("gen_fake_sni", ret);
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = instance_config.send_raw_packet(fake_sni, fsn_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("send fake sni", ret);
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t iph_len;
|
||||||
|
uint32_t tcph_len;
|
||||||
|
uint32_t plen;
|
||||||
|
tcp4_payload_split(fake_sni, fsn_len, &fsiph, &iph_len, &fstcph, &tcph_len, NULL, &plen);
|
||||||
|
|
||||||
|
|
||||||
|
fstcph->seq = htonl(ntohl(fstcph->seq) + plen);
|
||||||
|
memcpy(rfsiph, fsiph, iph_len);
|
||||||
|
memcpy(rfstcph, fstcph, tcph_len);
|
||||||
|
fsiph = (void *)rfsiph;
|
||||||
|
fstcph = (void *)rfstcph;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ipd_offset;
|
||||||
|
size_t mid_offset;
|
||||||
|
|
||||||
|
switch (config.fragmentation_strategy) {
|
||||||
|
case FRAG_STRAT_TCP: {
|
||||||
|
ipd_offset = vrd.sni_offset;
|
||||||
|
mid_offset = ipd_offset + vrd.sni_len / 2;
|
||||||
|
|
||||||
|
uint32_t poses[] = { 2, mid_offset };
|
||||||
|
|
||||||
|
ret = send_tcp4_frags(payload, payload_len, poses, 2, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("tcp4 send frags", ret);
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FRAG_STRAT_IP: {
|
||||||
|
ipd_offset = ((char *)data - (char *)tcph) + vrd.sni_offset;
|
||||||
|
mid_offset = ipd_offset + vrd.sni_len / 2;
|
||||||
|
mid_offset += 8 - mid_offset % 8;
|
||||||
|
|
||||||
|
uint32_t poses[] = { mid_offset };
|
||||||
|
ret = send_tcp4_frags(payload, payload_len, poses, 1, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("ip4 send frags", ret);
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = instance_config.send_raw_packet(payload, payload_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror("raw pack send", ret);
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept:
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
drop:
|
||||||
|
return PKT_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
|
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
|
||||||
{
|
{
|
||||||
#ifdef KERNEL_SPACE
|
#ifdef KERNEL_SPACE
|
||||||
@ -52,15 +338,22 @@ int ip4_payload_split(__u8 *pkt, __u32 buflen,
|
|||||||
struct iphdr **iph, __u32 *iph_len,
|
struct iphdr **iph, __u32 *iph_len,
|
||||||
__u8 **payload, __u32 *plen) {
|
__u8 **payload, __u32 *plen) {
|
||||||
if (pkt == NULL || buflen < sizeof(struct iphdr)) {
|
if (pkt == NULL || buflen < sizeof(struct iphdr)) {
|
||||||
|
lgerror("ip4_payload_split: pkt|buflen", -EINVAL);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iphdr *hdr = (struct iphdr *)pkt;
|
struct iphdr *hdr = (struct iphdr *)pkt;
|
||||||
if (hdr->version != IPVERSION) return -EINVAL;
|
if (hdr->version != IPVERSION) {
|
||||||
|
lgerror("ip4_payload_split: ipversion", -EINVAL);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
__u32 hdr_len = hdr->ihl * 4;
|
__u32 hdr_len = hdr->ihl * 4;
|
||||||
__u32 pktlen = ntohs(hdr->tot_len);
|
__u32 pktlen = ntohs(hdr->tot_len);
|
||||||
if (buflen < pktlen || hdr_len > pktlen) return -EINVAL;
|
if (buflen < pktlen || hdr_len > pktlen) {
|
||||||
|
lgerror("ip4_payload_split: buflen cmp pktlen", -EINVAL);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (iph)
|
if (iph)
|
||||||
*iph = hdr;
|
*iph = hdr;
|
||||||
@ -474,10 +767,10 @@ int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
|
|||||||
ntcph->th_dport = tcph->th_dport;
|
ntcph->th_dport = tcph->th_dport;
|
||||||
ntcph->th_sport = tcph->th_sport;
|
ntcph->th_sport = tcph->th_sport;
|
||||||
|
|
||||||
if (config.fake_sni_strategy == FKSN_STRAT_TTL) {
|
if (config.faking_strategy == FAKE_STRAT_TTL) {
|
||||||
ntcph->seq = tcph->seq;
|
ntcph->seq = tcph->seq;
|
||||||
ntcph->ack_seq = tcph->ack_seq;
|
ntcph->ack_seq = tcph->ack_seq;
|
||||||
niph->ttl = config.fake_sni_ttl;
|
niph->ttl = config.faking_ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -487,3 +780,33 @@ int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fail4_packet(uint8_t *payload, uint32_t plen) {
|
||||||
|
struct iphdr *iph;
|
||||||
|
uint32_t iph_len;
|
||||||
|
struct tcphdr *tcph;
|
||||||
|
uint32_t tcph_len;
|
||||||
|
uint8_t *data;
|
||||||
|
uint32_t dlen;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = tcp4_payload_split(payload, plen,
|
||||||
|
&iph, &iph_len, &tcph, &tcph_len,
|
||||||
|
&data, &dlen);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.faking_strategy == FAKE_STRAT_ACK_SEQ) {
|
||||||
|
tcph->seq = random();
|
||||||
|
tcph->ack_seq = random();
|
||||||
|
} else if (config.faking_strategy == FAKE_STRAT_TTL) {
|
||||||
|
iph->ttl = config.faking_ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip4_set_checksum(iph);
|
||||||
|
tcp4_set_checksum(tcph, iph);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
11
mangle.h
11
mangle.h
@ -63,4 +63,15 @@ void ip4_set_checksum(struct iphdr *iph);
|
|||||||
|
|
||||||
int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
|
int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
|
||||||
uint8_t *buf, uint32_t *buflen);
|
uint8_t *buf, uint32_t *buflen);
|
||||||
|
|
||||||
|
int fail4_packet(uint8_t *payload, uint32_t plen);
|
||||||
|
|
||||||
|
#define PKT_ACCEPT 0
|
||||||
|
#define PKT_DROP 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the packet and returns verdict.
|
||||||
|
* This is the primary function that traverses the packet.
|
||||||
|
*/
|
||||||
|
int process_packet(const uint8_t *packet, uint32_t packet_len);
|
||||||
#endif /* YU_MANGLE_H */
|
#endif /* YU_MANGLE_H */
|
||||||
|
@ -22,7 +22,7 @@ export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CF
|
|||||||
|
|
||||||
APP:=$(BUILD_DIR)/youtubeUnblock
|
APP:=$(BUILD_DIR)/youtubeUnblock
|
||||||
|
|
||||||
SRCS := youtubeUnblock.c mangle.c
|
SRCS := youtubeUnblock.c mangle.c args.c
|
||||||
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
||||||
|
|
||||||
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a
|
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a
|
||||||
|
296
youtubeUnblock.c
296
youtubeUnblock.c
@ -7,10 +7,10 @@
|
|||||||
#error "The build aims to the kernel, not userspace"
|
#error "The build aims to the kernel, not userspace"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <linux/netfilter/nfnetlink_queue.h>
|
||||||
#include <libmnl/libmnl.h>
|
#include <libmnl/libmnl.h>
|
||||||
#include <libnetfilter_queue/libnetfilter_queue.h>
|
#include <libnetfilter_queue/libnetfilter_queue.h>
|
||||||
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
|
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
|
||||||
@ -31,6 +31,9 @@
|
|||||||
#include "args.h"
|
#include "args.h"
|
||||||
|
|
||||||
pthread_mutex_t rawsocket_lock;
|
pthread_mutex_t rawsocket_lock;
|
||||||
|
int rawsocket = -2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int open_socket(struct mnl_socket **_nl) {
|
static int open_socket(struct mnl_socket **_nl) {
|
||||||
struct mnl_socket *nl = NULL;
|
struct mnl_socket *nl = NULL;
|
||||||
@ -67,20 +70,20 @@ static int close_socket(struct mnl_socket **_nl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int open_raw_socket(void) {
|
static int open_raw_socket(void) {
|
||||||
if (config.rawsocket != -2) {
|
if (rawsocket != -2) {
|
||||||
errno = EALREADY;
|
errno = EALREADY;
|
||||||
perror("Raw socket is already opened");
|
perror("Raw socket is already opened");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.rawsocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
rawsocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||||
if (config.rawsocket == -1) {
|
if (rawsocket == -1) {
|
||||||
perror("Unable to create raw socket");
|
perror("Unable to create raw socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mark = RAWSOCKET_MARK;
|
int mark = RAWSOCKET_MARK;
|
||||||
if (setsockopt(config.rawsocket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
|
if (setsockopt(rawsocket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "setsockopt(SO_MARK, %d) failed\n", mark);
|
fprintf(stderr, "setsockopt(SO_MARK, %d) failed\n", mark);
|
||||||
return -1;
|
return -1;
|
||||||
@ -89,24 +92,24 @@ static int open_raw_socket(void) {
|
|||||||
int mst = pthread_mutex_init(&rawsocket_lock, NULL);
|
int mst = pthread_mutex_init(&rawsocket_lock, NULL);
|
||||||
if (mst) {
|
if (mst) {
|
||||||
fprintf(stderr, "Mutex err: %d\n", mst);
|
fprintf(stderr, "Mutex err: %d\n", mst);
|
||||||
close(config.rawsocket);
|
close(rawsocket);
|
||||||
errno = mst;
|
errno = mst;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return config.rawsocket;
|
return rawsocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int close_raw_socket(void) {
|
static int close_raw_socket(void) {
|
||||||
if (config.rawsocket < 0) {
|
if (rawsocket < 0) {
|
||||||
errno = EALREADY;
|
errno = EALREADY;
|
||||||
perror("Raw socket is not set");
|
perror("Raw socket is not set");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close(config.rawsocket)) {
|
if (close(rawsocket)) {
|
||||||
perror("Unable to close raw socket");
|
perror("Unable to close raw socket");
|
||||||
pthread_mutex_destroy(&rawsocket_lock);
|
pthread_mutex_destroy(&rawsocket_lock);
|
||||||
return -1;
|
return -1;
|
||||||
@ -114,7 +117,7 @@ static int close_raw_socket(void) {
|
|||||||
|
|
||||||
pthread_mutex_destroy(&rawsocket_lock);
|
pthread_mutex_destroy(&rawsocket_lock);
|
||||||
|
|
||||||
config.rawsocket = -2;
|
rawsocket = -2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +194,7 @@ static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
|
|||||||
|
|
||||||
pthread_mutex_lock(&rawsocket_lock);
|
pthread_mutex_lock(&rawsocket_lock);
|
||||||
|
|
||||||
int sent = sendto(config.rawsocket,
|
int sent = sendto(rawsocket,
|
||||||
pkt, pktlen, 0,
|
pkt, pktlen, 0,
|
||||||
(struct sockaddr *)&daddr, sizeof(daddr));
|
(struct sockaddr *)&daddr, sizeof(daddr));
|
||||||
|
|
||||||
@ -203,6 +206,8 @@ static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
|
|||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct packet_data {
|
struct packet_data {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint16_t hw_proto;
|
uint16_t hw_proto;
|
||||||
@ -243,7 +248,7 @@ struct dps_t {
|
|||||||
uint32_t timer;
|
uint32_t timer;
|
||||||
};
|
};
|
||||||
// Note that the thread will automatically release dps_t and pkt_buff
|
// Note that the thread will automatically release dps_t and pkt_buff
|
||||||
void *delay_packet_send(void *data) {
|
void *delay_packet_send_fn(void *data) {
|
||||||
struct dps_t *dpdt = data;
|
struct dps_t *dpdt = data;
|
||||||
|
|
||||||
uint8_t *pkt = dpdt->pkt;
|
uint8_t *pkt = dpdt->pkt;
|
||||||
@ -260,206 +265,23 @@ void *delay_packet_send(void *data) {
|
|||||||
free(dpdt);
|
free(dpdt);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_packet(const struct packet_data packet, struct queue_data qdata) {
|
|
||||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
|
||||||
struct nlmsghdr *verdnlh;
|
|
||||||
|
|
||||||
#ifdef DEBUG_LOGGING
|
void delay_packet_send(const unsigned char *data, unsigned int data_len, unsigned int delay_ms) {
|
||||||
printf("packet received (id=%u hw=0x%04x hook=%u, payload len %u)\n",
|
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
|
||||||
packet.id, packet.hw_proto, packet.hook, packet.payload_len);
|
dpdt->pkt = malloc(data_len);
|
||||||
#endif
|
memcpy(dpdt->pkt, data, data_len);
|
||||||
|
dpdt->pktlen = data_len;
|
||||||
if (packet.hw_proto != ETH_P_IP) {
|
dpdt->timer = delay_ms;
|
||||||
return fallback_accept_packet(packet.id, qdata);
|
pthread_t thr;
|
||||||
}
|
pthread_create(&thr, NULL, delay_packet_send_fn, dpdt);
|
||||||
|
pthread_detach(thr);
|
||||||
const int family = AF_INET;
|
|
||||||
|
|
||||||
const uint8_t *raw_payload = packet.payload;
|
|
||||||
size_t raw_payload_len = packet.payload_len;
|
|
||||||
|
|
||||||
const struct iphdr *iph;
|
|
||||||
uint32_t iph_len;
|
|
||||||
const struct tcphdr *tcph;
|
|
||||||
uint32_t tcph_len;
|
|
||||||
const uint8_t *data;
|
|
||||||
uint32_t dlen;
|
|
||||||
|
|
||||||
int ret = tcp4_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
|
||||||
(struct iphdr **)&iph, &iph_len, (struct tcphdr **)&tcph, &tcph_len,
|
|
||||||
(uint8_t **)&data, &dlen);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct verdict vrd = analyze_tls_data(data, dlen);
|
|
||||||
|
|
||||||
verdnlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qdata.queue_num);
|
|
||||||
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_ACCEPT);
|
|
||||||
|
|
||||||
if (vrd.target_sni) {
|
|
||||||
if (config.verbose)
|
|
||||||
printf("SNI target detected\n");
|
|
||||||
|
|
||||||
if (dlen > 1480) {
|
|
||||||
if (config.verbose)
|
|
||||||
fprintf(stderr, "WARNING! Client Hello packet is too big and may cause issues!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t frag1[MNL_SOCKET_BUFFER_SIZE];
|
|
||||||
uint8_t frag2[MNL_SOCKET_BUFFER_SIZE];
|
|
||||||
uint32_t f1len = MNL_SOCKET_BUFFER_SIZE;
|
|
||||||
uint32_t f2len = MNL_SOCKET_BUFFER_SIZE;
|
|
||||||
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_DROP);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
nfq_ip_set_checksum((struct iphdr *)iph);
|
|
||||||
nfq_tcp_compute_checksum_ipv4(
|
|
||||||
(struct tcphdr *)tcph, (struct iphdr *)iph);
|
|
||||||
|
|
||||||
if (config.fake_sni_strategy != FKSN_STRAT_NONE) {
|
|
||||||
uint8_t rfsiph[60];
|
|
||||||
uint8_t rfstcph[60];
|
|
||||||
|
|
||||||
memcpy(rfsiph, iph, iph_len);
|
|
||||||
memcpy(rfstcph, tcph, tcph_len);
|
|
||||||
|
|
||||||
struct iphdr *fsiph = (void *)rfsiph;
|
|
||||||
struct tcphdr *fstcph = (void *)rfstcph;
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
uint8_t fake_sni[MNL_SOCKET_BUFFER_SIZE];
|
|
||||||
uint32_t fsn_len = MNL_SOCKET_BUFFER_SIZE;
|
|
||||||
ret = gen_fake_sni(fsiph, fstcph, fake_sni, &fsn_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
errno = -ret;
|
|
||||||
perror("gen_fake_sni");
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%d\n", i);
|
|
||||||
ret = send_raw_socket(fake_sni, fsn_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
errno = -ret;
|
|
||||||
perror("send fake sni");
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t iph_len;
|
|
||||||
uint32_t tcph_len;
|
|
||||||
uint32_t plen;
|
|
||||||
tcp4_payload_split(fake_sni, fsn_len, &fsiph, &iph_len, &fstcph, &tcph_len, NULL, &plen);
|
|
||||||
|
|
||||||
|
|
||||||
fstcph->seq = htonl(ntohl(tcph->seq) + plen * (i + 1));
|
|
||||||
memcpy(rfsiph, fsiph, iph_len);
|
|
||||||
memcpy(rfstcph, fstcph, tcph_len);
|
|
||||||
fsiph = (void *)rfsiph;
|
|
||||||
fstcph = (void *)rfstcph;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ipd_offset;
|
|
||||||
size_t mid_offset;
|
|
||||||
|
|
||||||
switch (config.fragmentation_strategy) {
|
|
||||||
case FRAG_STRAT_TCP:
|
|
||||||
ipd_offset = vrd.sni_offset;
|
|
||||||
mid_offset = ipd_offset + vrd.sni_len / 2;
|
|
||||||
|
|
||||||
if ((ret = tcp4_frag(raw_payload, raw_payload_len,
|
|
||||||
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
|
|
||||||
|
|
||||||
errno = -ret;
|
|
||||||
perror("tcp4_frag");
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case FRAG_STRAT_IP:
|
|
||||||
ipd_offset = ((char *)data - (char *)tcph) + vrd.sni_offset;
|
|
||||||
mid_offset = ipd_offset + vrd.sni_len / 2;
|
|
||||||
mid_offset += 8 - mid_offset % 8;
|
|
||||||
|
|
||||||
if ((ret = ip4_frag(raw_payload, raw_payload_len,
|
|
||||||
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
|
|
||||||
|
|
||||||
errno = -ret;
|
|
||||||
perror("ip4_frag");
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = send_raw_socket(raw_payload, raw_payload_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
errno = -ret;
|
|
||||||
perror("raw pack send");
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto send_verd;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = send_raw_socket(frag2, f2len);
|
|
||||||
if (ret < 0) {
|
|
||||||
errno = -ret;
|
|
||||||
perror("raw frags send: frag2");
|
|
||||||
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.seg2_delay) {
|
|
||||||
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
|
|
||||||
dpdt->pkt = malloc(f1len);
|
|
||||||
memcpy(dpdt->pkt, frag1, f1len);
|
|
||||||
dpdt->pktlen = f1len;
|
|
||||||
dpdt->timer = config.seg2_delay;
|
|
||||||
pthread_t thr;
|
|
||||||
pthread_create(&thr, NULL, delay_packet_send, dpdt);
|
|
||||||
pthread_detach(thr);
|
|
||||||
} else {
|
|
||||||
ret = send_raw_socket(frag1, f1len);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
errno = -ret;
|
|
||||||
perror("raw frags send: frag1");
|
|
||||||
|
|
||||||
goto fallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (pktb_mangled(pktb)) {
|
|
||||||
if (config.versose)
|
|
||||||
printf("Mangled!\n");
|
|
||||||
|
|
||||||
nfq_nlmsg_verdict_put_pkt(
|
|
||||||
verdnlh, pktb_data(pktb), pktb_len(pktb));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
send_verd:
|
|
||||||
if (mnl_socket_sendto(*qdata._nl, verdnlh, verdnlh->nlmsg_len) < 0) {
|
|
||||||
perror("mnl_socket_send");
|
|
||||||
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MNL_CB_OK;
|
|
||||||
|
|
||||||
fallback:
|
|
||||||
return fallback_accept_packet(packet.id, qdata);
|
|
||||||
error:
|
|
||||||
return MNL_CB_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
||||||
|
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||||
|
|
||||||
struct queue_data *qdata = data;
|
struct queue_data *qdata = data;
|
||||||
|
|
||||||
@ -500,7 +322,26 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return process_packet(packet, *qdata);
|
struct nlmsghdr *verdnlh;
|
||||||
|
verdnlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qdata->queue_num);
|
||||||
|
|
||||||
|
int ret = process_packet(packet.payload, packet.payload_len);
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case PKT_DROP:
|
||||||
|
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_DROP);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_ACCEPT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mnl_socket_sendto(*qdata->_nl, verdnlh, verdnlh->nlmsg_len) < 0) {
|
||||||
|
perror("mnl_socket_send");
|
||||||
|
return MNL_CB_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MNL_CB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BUF_SIZE (0xffff + (MNL_SOCKET_BUFFER_SIZE / 2))
|
#define BUF_SIZE (0xffff + (MNL_SOCKET_BUFFER_SIZE / 2))
|
||||||
@ -600,6 +441,11 @@ void *init_queue_wrapper(void *qdconf) {
|
|||||||
return thres;
|
return thres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct instance_config_t instance_config = {
|
||||||
|
.send_raw_packet = send_raw_socket,
|
||||||
|
.send_delayed_packet = delay_packet_send,
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int ret;
|
int ret;
|
||||||
if ((ret = parse_args(argc, argv)) != 0) {
|
if ((ret = parse_args(argc, argv)) != 0) {
|
||||||
@ -626,18 +472,34 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("Some outgoing googlevideo request segments will be delayed for %d ms as of seg2_delay define\n", config.seg2_delay);
|
printf("Some outgoing googlevideo request segments will be delayed for %d ms as of seg2_delay define\n", config.seg2_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (config.fake_sni_strategy) {
|
if (config.fake_sni) {
|
||||||
case FKSN_STRAT_TTL:
|
printf("Fake SNI will be sent before each target client hello\n");
|
||||||
printf("Fake SNI will be sent before each request, TTL strategy will be used with TTL %d\n", config.fake_sni_ttl);
|
} else {
|
||||||
|
printf("Fake SNI is disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.frag_sni_reverse) {
|
||||||
|
printf("Fragmentation Client Hello will be reversed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.frag_sni_faked) {
|
||||||
|
printf("Fooling packets will be sent near the original Client Hello\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.fake_sni_seq_len > 1) {
|
||||||
|
printf("Faking sequence of length %d will be built as fake sni\n", config.fake_sni_seq_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (config.faking_strategy) {
|
||||||
|
case FAKE_STRAT_TTL:
|
||||||
|
printf("TTL faking strategy will be used with TTL %d\n", config.faking_ttl);
|
||||||
break;
|
break;
|
||||||
case FRAG_STRAT_IP:
|
case FAKE_STRAT_ACK_SEQ:
|
||||||
printf("Fake SNI will be sent before each request, Ack-Seq strategy will be used\n");
|
printf("Ack-Seq faking strategy will be used\n");
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("SNI fragmentation is disabled\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (config.use_gso) {
|
if (config.use_gso) {
|
||||||
printf("GSO is enabled\n");
|
printf("GSO is enabled\n");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user