mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2025-12-31 03:38:07 +03:00
Add multiple fooling options
This commit is contained in:
296
youtubeUnblock.c
296
youtubeUnblock.c
@@ -7,10 +7,10 @@
|
||||
#error "The build aims to the kernel, not userspace"
|
||||
#endif
|
||||
|
||||
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <linux/netfilter/nfnetlink_queue.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <libnetfilter_queue/libnetfilter_queue.h>
|
||||
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
|
||||
@@ -31,6 +31,9 @@
|
||||
#include "args.h"
|
||||
|
||||
pthread_mutex_t rawsocket_lock;
|
||||
int rawsocket = -2;
|
||||
|
||||
|
||||
|
||||
static int open_socket(struct mnl_socket **_nl) {
|
||||
struct mnl_socket *nl = NULL;
|
||||
@@ -67,20 +70,20 @@ static int close_socket(struct mnl_socket **_nl) {
|
||||
}
|
||||
|
||||
static int open_raw_socket(void) {
|
||||
if (config.rawsocket != -2) {
|
||||
if (rawsocket != -2) {
|
||||
errno = EALREADY;
|
||||
perror("Raw socket is already opened");
|
||||
return -1;
|
||||
}
|
||||
|
||||
config.rawsocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
if (config.rawsocket == -1) {
|
||||
rawsocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
if (rawsocket == -1) {
|
||||
perror("Unable to create raw socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
return -1;
|
||||
@@ -89,24 +92,24 @@ static int open_raw_socket(void) {
|
||||
int mst = pthread_mutex_init(&rawsocket_lock, NULL);
|
||||
if (mst) {
|
||||
fprintf(stderr, "Mutex err: %d\n", mst);
|
||||
close(config.rawsocket);
|
||||
close(rawsocket);
|
||||
errno = mst;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return config.rawsocket;
|
||||
return rawsocket;
|
||||
}
|
||||
|
||||
static int close_raw_socket(void) {
|
||||
if (config.rawsocket < 0) {
|
||||
if (rawsocket < 0) {
|
||||
errno = EALREADY;
|
||||
perror("Raw socket is not set");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close(config.rawsocket)) {
|
||||
if (close(rawsocket)) {
|
||||
perror("Unable to close raw socket");
|
||||
pthread_mutex_destroy(&rawsocket_lock);
|
||||
return -1;
|
||||
@@ -114,7 +117,7 @@ static int close_raw_socket(void) {
|
||||
|
||||
pthread_mutex_destroy(&rawsocket_lock);
|
||||
|
||||
config.rawsocket = -2;
|
||||
rawsocket = -2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -191,7 +194,7 @@ static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
|
||||
|
||||
pthread_mutex_lock(&rawsocket_lock);
|
||||
|
||||
int sent = sendto(config.rawsocket,
|
||||
int sent = sendto(rawsocket,
|
||||
pkt, pktlen, 0,
|
||||
(struct sockaddr *)&daddr, sizeof(daddr));
|
||||
|
||||
@@ -203,6 +206,8 @@ static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
|
||||
return sent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct packet_data {
|
||||
uint32_t id;
|
||||
uint16_t hw_proto;
|
||||
@@ -243,7 +248,7 @@ struct dps_t {
|
||||
uint32_t timer;
|
||||
};
|
||||
// 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;
|
||||
|
||||
uint8_t *pkt = dpdt->pkt;
|
||||
@@ -260,206 +265,23 @@ void *delay_packet_send(void *data) {
|
||||
free(dpdt);
|
||||
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
|
||||
printf("packet received (id=%u hw=0x%04x hook=%u, payload len %u)\n",
|
||||
packet.id, packet.hw_proto, packet.hook, packet.payload_len);
|
||||
#endif
|
||||
|
||||
if (packet.hw_proto != ETH_P_IP) {
|
||||
return fallback_accept_packet(packet.id, qdata);
|
||||
}
|
||||
|
||||
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;
|
||||
void delay_packet_send(const unsigned char *data, unsigned int data_len, unsigned int delay_ms) {
|
||||
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
|
||||
dpdt->pkt = malloc(data_len);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
|
||||
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))
|
||||
@@ -600,6 +441,11 @@ void *init_queue_wrapper(void *qdconf) {
|
||||
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 ret;
|
||||
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);
|
||||
}
|
||||
|
||||
switch (config.fake_sni_strategy) {
|
||||
case FKSN_STRAT_TTL:
|
||||
printf("Fake SNI will be sent before each request, TTL strategy will be used with TTL %d\n", config.fake_sni_ttl);
|
||||
if (config.fake_sni) {
|
||||
printf("Fake SNI will be sent before each target client hello\n");
|
||||
} 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;
|
||||
case FRAG_STRAT_IP:
|
||||
printf("Fake SNI will be sent before each request, Ack-Seq strategy will be used\n");
|
||||
break;
|
||||
default:
|
||||
printf("SNI fragmentation is disabled\n");
|
||||
case FAKE_STRAT_ACK_SEQ:
|
||||
printf("Ack-Seq faking strategy will be used\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (config.use_gso) {
|
||||
printf("GSO is enabled\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user