Add multiple fooling options

This commit is contained in:
Vadim Vetrov
2024-08-11 02:10:18 +03:00
parent d29177d783
commit 2e96aa150e
6 changed files with 548 additions and 273 deletions

View File

@@ -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");
}