mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2024-12-22 06:15:31 +00:00
Add support for bruteforce mode of parsing SNI from Client Hello.
This commit is contained in:
parent
7f340fb033
commit
044801efb9
@ -142,6 +142,8 @@ Available flags:
|
|||||||
|
|
||||||
- `--fk-winsize=<winsize>` Specifies window size for the fragmented TCP packet. Applicable if you want for response to be fragmented. May slowdown connection initialization.
|
- `--fk-winsize=<winsize>` Specifies window size for the fragmented TCP packet. Applicable if you want for response to be fragmented. May slowdown connection initialization.
|
||||||
|
|
||||||
|
- `--sni-detection={parse|brute}` Specifies how to detect SNI. Parse will normally detect it by parsing the Client Hello message. Brute will go through the entire message and check possibility of SNI occurrence. Please note, that when `--sni-domains` option is not all brute will be O(nm) time complexity where n stands for length of the message and m is number of domains. Defaults to parse.
|
||||||
|
|
||||||
- `--seg2delay=<delay>` This flag forces **youtubeUnblock** to wait a little bit before send the 2nd part of the split packet.
|
- `--seg2delay=<delay>` This flag forces **youtubeUnblock** to wait a little bit before send the 2nd part of the split packet.
|
||||||
|
|
||||||
- `--silent` Disables verbose mode.
|
- `--silent` Disables verbose mode.
|
||||||
|
19
args.c
19
args.c
@ -19,6 +19,8 @@ struct config_t config = {
|
|||||||
.fake_sni = 1,
|
.fake_sni = 1,
|
||||||
.fake_sni_seq_len = 1,
|
.fake_sni_seq_len = 1,
|
||||||
|
|
||||||
|
.sni_detection = SNI_DETECTION_PARSE,
|
||||||
|
|
||||||
#ifdef SEG2_DELAY
|
#ifdef SEG2_DELAY
|
||||||
.seg2_delay = SEG2_DELAY,
|
.seg2_delay = SEG2_DELAY,
|
||||||
#else
|
#else
|
||||||
@ -56,6 +58,7 @@ struct config_t config = {
|
|||||||
#define OPT_FK_WINSIZE 14
|
#define OPT_FK_WINSIZE 14
|
||||||
#define OPT_TRACE 15
|
#define OPT_TRACE 15
|
||||||
#define OPT_QUIC_DROP 16
|
#define OPT_QUIC_DROP 16
|
||||||
|
#define OPT_SNI_DETECTION 17
|
||||||
#define OPT_SEG2DELAY 5
|
#define OPT_SEG2DELAY 5
|
||||||
#define OPT_THREADS 6
|
#define OPT_THREADS 6
|
||||||
#define OPT_SILENT 7
|
#define OPT_SILENT 7
|
||||||
@ -77,6 +80,7 @@ static struct option long_opt[] = {
|
|||||||
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
|
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
|
||||||
{"fk-winsize", 1, 0, OPT_FK_WINSIZE},
|
{"fk-winsize", 1, 0, OPT_FK_WINSIZE},
|
||||||
{"quic-drop", 0, 0, OPT_QUIC_DROP},
|
{"quic-drop", 0, 0, OPT_QUIC_DROP},
|
||||||
|
{"sni-detection", 1, 0, OPT_SNI_DETECTION},
|
||||||
{"seg2delay", 1, 0, OPT_SEG2DELAY},
|
{"seg2delay", 1, 0, OPT_SEG2DELAY},
|
||||||
{"threads", 1, 0, OPT_THREADS},
|
{"threads", 1, 0, OPT_THREADS},
|
||||||
{"silent", 0, 0, OPT_SILENT},
|
{"silent", 0, 0, OPT_SILENT},
|
||||||
@ -126,6 +130,7 @@ void print_usage(const char *argv0) {
|
|||||||
printf("\t--frag-sni-faked={0|1}\n");
|
printf("\t--frag-sni-faked={0|1}\n");
|
||||||
printf("\t--fk-winsize=<winsize>\n");
|
printf("\t--fk-winsize=<winsize>\n");
|
||||||
printf("\t--quic-drop\n");
|
printf("\t--quic-drop\n");
|
||||||
|
printf("\t--sni-detection={parse|brute}\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");
|
||||||
@ -166,6 +171,16 @@ int parse_args(int argc, char *argv[]) {
|
|||||||
|
|
||||||
config.domains_str = optarg;
|
config.domains_str = optarg;
|
||||||
config.domains_strlen = strlen(config.domains_str);
|
config.domains_strlen = strlen(config.domains_str);
|
||||||
|
break;
|
||||||
|
case OPT_SNI_DETECTION:
|
||||||
|
if (strcmp(optarg, "parse") == 0) {
|
||||||
|
config.sni_detection = SNI_DETECTION_PARSE;
|
||||||
|
} else if (strcmp(optarg, "brute") == 0) {
|
||||||
|
config.sni_detection = SNI_DETECTION_BRUTE;
|
||||||
|
} else {
|
||||||
|
goto invalid_opt;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case OPT_FRAG:
|
case OPT_FRAG:
|
||||||
if (strcmp(optarg, "tcp") == 0) {
|
if (strcmp(optarg, "tcp") == 0) {
|
||||||
@ -346,6 +361,10 @@ void print_welcome() {
|
|||||||
printf("All QUIC packets will be dropped\n");
|
printf("All QUIC packets will be dropped\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.sni_detection == SNI_DETECTION_BRUTE) {
|
||||||
|
printf("Server Name Extension will be parsed in the bruteforce mode\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (config.all_domains) {
|
if (config.all_domains) {
|
||||||
printf("All Client Hello will be targetted by youtubeUnblock!\n");
|
printf("All Client Hello will be targetted by youtubeUnblock!\n");
|
||||||
}
|
}
|
||||||
|
5
config.h
5
config.h
@ -30,6 +30,9 @@ struct config_t {
|
|||||||
#define VERBOSE_TRACE 2
|
#define VERBOSE_TRACE 2
|
||||||
int verbose;
|
int verbose;
|
||||||
int quic_drop;
|
int quic_drop;
|
||||||
|
#define SNI_DETECTION_PARSE 0
|
||||||
|
#define SNI_DETECTION_BRUTE 1
|
||||||
|
int sni_detection;
|
||||||
/* In milliseconds */
|
/* In milliseconds */
|
||||||
unsigned int seg2_delay;
|
unsigned int seg2_delay;
|
||||||
const char *domains_str;
|
const char *domains_str;
|
||||||
@ -89,7 +92,7 @@ extern struct config_t config;
|
|||||||
|
|
||||||
// The Maximum Transmission Unit size for rawsocket
|
// The Maximum Transmission Unit size for rawsocket
|
||||||
// Larger packets will be fragmented. Applicable for Chrome's kyber.
|
// Larger packets will be fragmented. Applicable for Chrome's kyber.
|
||||||
#define AVAILABLE_MTU 1384
|
#define AVAILABLE_MTU 1500
|
||||||
|
|
||||||
#define DEFAULT_QUEUE_NUM 537
|
#define DEFAULT_QUEUE_NUM 537
|
||||||
|
|
||||||
|
72
mangle.c
72
mangle.c
@ -428,7 +428,25 @@ int post_fake_sni(const struct iphdr *iph, unsigned int iph_len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void z_function(const char *str, int *zbuf, size_t len) {
|
||||||
|
zbuf[0] = len;
|
||||||
|
|
||||||
|
ssize_t lh = 0, rh = 1;
|
||||||
|
for (ssize_t i = 1; i < len; i++) {
|
||||||
|
zbuf[i] = 0;
|
||||||
|
if (i < rh) {
|
||||||
|
zbuf[i] = min(zbuf[i - lh], rh - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i + zbuf[i] < len && str[zbuf[i]] == str[i + zbuf[i]])
|
||||||
|
zbuf[i]++;
|
||||||
|
|
||||||
|
if (i + zbuf[i] > rh) {
|
||||||
|
lh = i;
|
||||||
|
rh = i + zbuf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
|
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
|
||||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
||||||
@ -463,12 +481,16 @@ struct tls_verdict analyze_tls_data(
|
|||||||
uint16_t message_length = ntohs(*(uint16_t *)(msgData + 3));
|
uint16_t message_length = ntohs(*(uint16_t *)(msgData + 3));
|
||||||
const uint8_t *message_length_ptr = msgData + 3;
|
const uint8_t *message_length_ptr = msgData + 3;
|
||||||
|
|
||||||
|
if (tls_vmajor != 0x03) goto nextMessage;
|
||||||
|
|
||||||
if (i + 5 + message_length > dlen) break;
|
if (i + 5 > dlen) break;
|
||||||
|
|
||||||
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
|
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
|
||||||
goto nextMessage;
|
goto nextMessage;
|
||||||
|
|
||||||
|
if (config.sni_detection == SNI_DETECTION_BRUTE) {
|
||||||
|
goto brute;
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t *handshakeProto = msgData + 5;
|
const uint8_t *handshakeProto = msgData + 5;
|
||||||
|
|
||||||
@ -506,7 +528,7 @@ struct tls_verdict analyze_tls_data(
|
|||||||
|
|
||||||
const uint8_t *extensionsPtr = msgPtr;
|
const uint8_t *extensionsPtr = msgPtr;
|
||||||
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
|
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
|
||||||
if (extensions_end > data_end) break;
|
if (extensions_end > data_end) extensions_end = data_end;
|
||||||
|
|
||||||
while (extensionsPtr < extensions_end) {
|
while (extensionsPtr < extensions_end) {
|
||||||
const uint8_t *extensionPtr = extensionsPtr;
|
const uint8_t *extensionPtr = extensionsPtr;
|
||||||
@ -590,8 +612,54 @@ nextMessage:
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
return vrd;
|
return vrd;
|
||||||
|
|
||||||
|
brute:
|
||||||
|
if (config.all_domains) {
|
||||||
|
vrd.target_sni = 1;
|
||||||
|
vrd.sni_len = 0;
|
||||||
|
vrd.sni_offset = dlen / 2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int j = 0;
|
||||||
|
for (unsigned int i = 0; i <= config.domains_strlen; i++) {
|
||||||
|
if ( i > j &&
|
||||||
|
(i == config.domains_strlen ||
|
||||||
|
config.domains_str[i] == '\0' ||
|
||||||
|
config.domains_str[i] == ',' ||
|
||||||
|
config.domains_str[i] == '\n' )) {
|
||||||
|
|
||||||
|
uint8_t buf[MAX_PACKET_SIZE];
|
||||||
|
int zbuf[MAX_PACKET_SIZE];
|
||||||
|
unsigned int domain_len = (i - j);
|
||||||
|
const char *domain_startp = config.domains_str + j;
|
||||||
|
|
||||||
|
if (domain_len + dlen + 1> MAX_PACKET_SIZE) continue;
|
||||||
|
|
||||||
|
memcpy(buf, domain_startp, domain_len);
|
||||||
|
memcpy(buf + domain_len, "#", 1);
|
||||||
|
memcpy(buf + domain_len + 1, data, dlen);
|
||||||
|
|
||||||
|
z_function((char *)buf, zbuf, domain_len + 1 + dlen);
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < dlen; k++) {
|
||||||
|
if (zbuf[k] == domain_len) {
|
||||||
|
vrd.target_sni = 1;
|
||||||
|
vrd.sni_len = domain_len;
|
||||||
|
vrd.sni_offset = (k - domain_len - 1);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
j = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
||||||
|
|
||||||
|
14
types.h
14
types.h
@ -44,4 +44,18 @@ typedef __i64 int64_t;
|
|||||||
#include <netinet/udp.h> // IWYU pragma: export
|
#include <netinet/udp.h> // IWYU pragma: export
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define max(a,b)__extension__\
|
||||||
|
({ \
|
||||||
|
__typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a > _b ? _a : _b; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define min(a,b)__extension__\
|
||||||
|
({ \
|
||||||
|
__typeof__ (a) _a = (a); \
|
||||||
|
__typeof__ (b) _b = (b); \
|
||||||
|
_a < _b ? _a : _b; \
|
||||||
|
})
|
||||||
|
|
||||||
#endif /* TYPES_H */
|
#endif /* TYPES_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user