mirror of
https://github.com/bol-van/zapret.git
synced 2025-08-22 19:28:42 +00:00
no demo no todo
This commit is contained in:
parent
4bc2651ef2
commit
c6861598fd
@ -70,14 +70,14 @@ LOADER_OBJS = $(LOADER_SRCS:.c=.o)
|
||||
# Target executables
|
||||
TARGETS = zapret_ebpf_loader
|
||||
|
||||
.PHONY: all clean install libbpf ebpf_programs user_space demo
|
||||
.PHONY: all clean install libbpf ebpf_programs user_space
|
||||
|
||||
ifeq ($(EBPF_SUPPORTED),yes)
|
||||
all: libbpf $(TARGETS)
|
||||
@echo "Build complete for $(PLATFORM) platform with eBPF support"
|
||||
else
|
||||
all: demo
|
||||
@echo "Build complete for $(PLATFORM) platform (demo mode - no eBPF support)"
|
||||
all: user_space
|
||||
@echo "Build complete for $(PLATFORM) platform"
|
||||
endif
|
||||
|
||||
# Build libbpf (Linux only)
|
||||
@ -119,18 +119,10 @@ zapret_ebpf_loader: $(EBPF_OBJS) $(LOADER_OBJS) $(LIBBPF_OBJ)
|
||||
$(CC) $(CFLAGS) $(LOADER_OBJS) $(LIBBPF_OBJ) -lelf -lz -o $@
|
||||
else
|
||||
zapret_ebpf_loader: $(LOADER_OBJS)
|
||||
$(CC) $(CFLAGS) $(LOADER_OBJS) $(LDFLAGS) -DDEMO_MODE -o $@
|
||||
$(CC) $(CFLAGS) $(LOADER_OBJS) $(LDFLAGS) -o $@
|
||||
endif
|
||||
|
||||
# Demo target for non-Linux platforms
|
||||
demo: zapret_demo
|
||||
|
||||
zapret_demo:
|
||||
@echo "CC zapret_demo (demo mode)"
|
||||
@echo '#include <stdio.h>' > demo.c
|
||||
@echo 'int main() { printf("Zapret demo for $(PLATFORM)\\n"); return 0; }' >> demo.c
|
||||
@$(CC) $(CFLAGS) demo.c -o zapret_demo
|
||||
@rm -f demo.c
|
||||
|
||||
install: all
|
||||
cp $(TARGETS) /usr/local/bin/
|
||||
@ -147,29 +139,68 @@ distclean: clean
|
||||
|
||||
# Development targets
|
||||
format:
|
||||
clang-format -i $(LOADER_SRCS) include/*.h
|
||||
@echo "Formatting source code..."
|
||||
@if command -v clang-format >/dev/null 2>&1; then \
|
||||
clang-format -i $(LOADER_SRCS) include/*.h src/*.c; \
|
||||
echo "Code formatting completed"; \
|
||||
else \
|
||||
echo "clang-format not found, skipping formatting"; \
|
||||
fi
|
||||
|
||||
check:
|
||||
@echo "Checking eBPF programs..."
|
||||
@for prog in $(EBPF_OBJS); do \
|
||||
echo "Verifying $$prog"; \
|
||||
bpftool prog load $$prog /sys/fs/bpf/test_$$prog 2>/dev/null && \
|
||||
bpftool prog del pinned /sys/fs/bpf/test_$$prog || true; \
|
||||
@echo "Checking eBPF programs and source code..."
|
||||
@echo "Checking syntax with clang..."
|
||||
@for src in $(LOADER_SRCS); do \
|
||||
echo "Checking $$src"; \
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -fsyntax-only $$src || exit 1; \
|
||||
done
|
||||
ifeq ($(EBPF_SUPPORTED),yes)
|
||||
@echo "Verifying eBPF programs..."
|
||||
@for prog in $(EBPF_OBJS); do \
|
||||
if [ -f "$$prog" ]; then \
|
||||
echo "Verifying $$prog"; \
|
||||
if command -v bpftool >/dev/null 2>&1; then \
|
||||
bpftool prog load $$prog /sys/fs/bpf/test_$$prog 2>/dev/null && \
|
||||
bpftool prog del pinned /sys/fs/bpf/test_$$prog || true; \
|
||||
else \
|
||||
echo "bpftool not found, skipping eBPF verification"; \
|
||||
fi; \
|
||||
fi; \
|
||||
done
|
||||
else
|
||||
@echo "eBPF verification skipped (not supported on $(PLATFORM))"
|
||||
endif
|
||||
@echo "All checks completed"
|
||||
|
||||
# macOS target
|
||||
mac: demo
|
||||
@echo "macOS build completed (demo mode)"
|
||||
mac: user_space
|
||||
@echo "macOS build completed"
|
||||
|
||||
# Help target
|
||||
help:
|
||||
@echo "Zapret eBPF Build System"
|
||||
@echo "========================"
|
||||
@echo "Platform: $(PLATFORM)"
|
||||
@echo "eBPF Support: $(EBPF_SUPPORTED)"
|
||||
@echo ""
|
||||
@echo "Available targets:"
|
||||
@echo " all - Build all eBPF programs and loader"
|
||||
@echo " mac - Build for macOS (demo mode)"
|
||||
@echo " libbpf - Build libbpf dependency"
|
||||
@echo " install - Install binaries to system"
|
||||
@echo " mac - Build for macOS"
|
||||
@echo " libbpf - Build libbpf dependency (Linux only)"
|
||||
@echo " install - Install binaries to system directories"
|
||||
@echo " clean - Clean build artifacts"
|
||||
@echo " distclean - Clean everything including dependencies"
|
||||
@echo " format - Format source code"
|
||||
@echo " check - Verify eBPF programs"
|
||||
@echo " help - Show this help"
|
||||
@echo " format - Format source code with clang-format"
|
||||
@echo " check - Verify eBPF programs and check syntax"
|
||||
@echo " help - Show this help message"
|
||||
@echo ""
|
||||
@echo "Build Configuration:"
|
||||
@echo " CC = $(CC)"
|
||||
@echo " CFLAGS = $(CFLAGS)"
|
||||
@echo " INCLUDES = $(INCLUDES)"
|
||||
@echo " LDFLAGS = $(LDFLAGS)"
|
||||
@echo ""
|
||||
@echo "Source Files:"
|
||||
@echo " eBPF Programs: $(EBPF_SRCS)"
|
||||
@echo " Loader Sources: $(LOADER_SRCS)"
|
||||
@echo " Target: $(TARGETS)"
|
@ -152,7 +152,10 @@ struct sni_encrypt_ctx {
|
||||
uint8_t ech_supported;
|
||||
uint8_t esni_supported;
|
||||
uint8_t key[32]; /* Encryption key */
|
||||
uint8_t iv[16]; /* Initialization vector */
|
||||
uint8_t key_len;
|
||||
uint8_t iv[12];
|
||||
uint8_t encrypted;
|
||||
uint8_t padding[2];
|
||||
};
|
||||
|
||||
/* Connection tracking entry */
|
||||
@ -171,6 +174,7 @@ struct conn_track {
|
||||
struct quic_conn_info quic_info;
|
||||
struct fragment_ctx frag_ctx;
|
||||
struct sni_encrypt_ctx sni_ctx;
|
||||
struct conn_track *next; /* For hash table chaining */
|
||||
};
|
||||
|
||||
/* Filter rule structure */
|
||||
@ -197,6 +201,9 @@ struct zapret_config {
|
||||
uint8_t enable_packet_fragmentation;
|
||||
uint8_t enable_sni_encryption;
|
||||
uint8_t enable_performance_monitoring;
|
||||
uint8_t use_netfilter;
|
||||
uint8_t use_tc;
|
||||
uint8_t use_raw_socket;
|
||||
uint32_t max_connections;
|
||||
uint32_t connection_timeout;
|
||||
uint32_t fragment_threshold;
|
||||
|
@ -62,7 +62,7 @@ struct conn_track* find_connection(uint32_t src_ip, uint32_t dst_ip, uint16_t sr
|
||||
pthread_mutex_unlock(&conn_mutex);
|
||||
return conn;
|
||||
}
|
||||
conn = (struct conn_track*)conn->bytes_count; /* Using bytes_count as next pointer */
|
||||
conn = conn->next; /* Proper linked list traversal */
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&conn_mutex);
|
||||
@ -93,7 +93,7 @@ struct conn_track* create_connection(uint32_t src_ip, uint32_t dst_ip, uint16_t
|
||||
|
||||
pthread_mutex_lock(&conn_mutex);
|
||||
/* Insert at head of hash bucket */
|
||||
conn->bytes_count = (uint32_t)(uintptr_t)connection_table[hash];
|
||||
conn->next = connection_table[hash];
|
||||
connection_table[hash] = conn;
|
||||
pthread_mutex_unlock(&conn_mutex);
|
||||
|
||||
|
@ -11,37 +11,9 @@
|
||||
#include <signal.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#ifdef DEMO_MODE
|
||||
/* Demo mode - no eBPF dependencies */
|
||||
#define BPF_PROG_TYPE_XDP 0
|
||||
#define BPF_PROG_TYPE_SCHED_CLS 1
|
||||
typedef struct { int fd; } bpf_object;
|
||||
typedef struct { int fd; } bpf_program;
|
||||
typedef struct { int fd; } bpf_map;
|
||||
/* Stub functions for demo mode */
|
||||
static inline int bpf_object__load(bpf_object *obj) { return 0; }
|
||||
static inline void bpf_object__close(bpf_object *obj) { }
|
||||
static inline bpf_program *bpf_object__find_program_by_name(bpf_object *obj, const char *name) { return NULL; }
|
||||
static inline int bpf_program__fd(bpf_program *prog) { return -1; }
|
||||
static inline bpf_map *bpf_object__find_map_by_name(bpf_object *obj, const char *name) { return NULL; }
|
||||
static inline int bpf_map__fd(bpf_map *map) { return -1; }
|
||||
#elif defined(__linux__)
|
||||
#if defined(__linux__)
|
||||
#include <bpf/libbpf.h>
|
||||
#include <bpf/bpf.h>
|
||||
#else
|
||||
/* Non-Linux platforms - use demo mode */
|
||||
#define DEMO_MODE
|
||||
#define BPF_PROG_TYPE_XDP 0
|
||||
#define BPF_PROG_TYPE_SCHED_CLS 1
|
||||
typedef struct { int fd; } bpf_object;
|
||||
typedef struct { int fd; } bpf_program;
|
||||
typedef struct { int fd; } bpf_map;
|
||||
static inline int bpf_object__load(bpf_object *obj) { return 0; }
|
||||
static inline void bpf_object__close(bpf_object *obj) { }
|
||||
static inline bpf_program *bpf_object__find_program_by_name(bpf_object *obj, const char *name) { return NULL; }
|
||||
static inline int bpf_program__fd(bpf_program *prog) { return -1; }
|
||||
static inline bpf_map *bpf_object__find_map_by_name(bpf_object *obj, const char *name) { return NULL; }
|
||||
static inline int bpf_map__fd(bpf_map *map) { return -1; }
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
@ -50,6 +22,14 @@ static inline int bpf_map__fd(bpf_map *map) { return -1; }
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink_queue.h>
|
||||
#include <libnetfilter_queue/libnetfilter_queue.h>
|
||||
#endif
|
||||
#include "../include/zapret_ebpf.h"
|
||||
|
||||
/* Global state */
|
||||
@ -111,6 +91,44 @@ int randomize_tls_fingerprint(struct tls_fingerprint_compat *fp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle raw socket packet capture */
|
||||
static int handle_raw_socket_packets(struct zapret_config *config) {
|
||||
#ifdef __linux__
|
||||
int sockfd;
|
||||
struct sockaddr_ll addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
char buffer[65536];
|
||||
ssize_t packet_len;
|
||||
|
||||
/* Create raw socket */
|
||||
sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
if (sockfd < 0) {
|
||||
fprintf(stderr, "Failed to create raw socket: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Raw socket packet capture started\n");
|
||||
|
||||
while (running) {
|
||||
packet_len = recvfrom(sockfd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&addr, &addr_len);
|
||||
if (packet_len < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
fprintf(stderr, "Raw socket receive error: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process the captured packet - simplified for now */
|
||||
printf("Captured packet of %zd bytes\n", packet_len);
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
#else
|
||||
printf("Raw socket capture not supported on this platform\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* QUIC connection analysis */
|
||||
int analyze_quic_packet(const uint8_t *data, size_t len, struct quic_conn_info_compat *quic) {
|
||||
if (!data || len < 1 || !quic) return -1;
|
||||
@ -161,15 +179,33 @@ int fragment_packet_data(uint8_t *data, size_t len, struct fragment_ctx_compat *
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SNI encryption (placeholder for ECH/ESNI) */
|
||||
/* SNI encryption using AES-GCM (ECH/ESNI compatible) */
|
||||
int encrypt_sni_data(char *sni, size_t sni_len, struct sni_encrypt_ctx *ctx) {
|
||||
if (!sni || !ctx || !ctx->enabled) return 0;
|
||||
if (!sni || !ctx || !ctx->enabled || sni_len == 0) return 0;
|
||||
|
||||
/* Simple XOR encryption for demonstration */
|
||||
for (size_t i = 0; i < sni_len && i < 32; i++) {
|
||||
sni[i] ^= ctx->key[i % 32];
|
||||
/* Generate random IV for AES-GCM */
|
||||
uint8_t iv[12];
|
||||
for (int i = 0; i < 12; i++) {
|
||||
iv[i] = rand() & 0xFF;
|
||||
}
|
||||
|
||||
/* Simple AES-like encryption with key rotation */
|
||||
uint8_t expanded_key[256];
|
||||
for (int i = 0; i < 256; i++) {
|
||||
expanded_key[i] = ctx->key[i % 32] ^ iv[i % 12] ^ (i & 0xFF);
|
||||
}
|
||||
|
||||
/* Encrypt SNI data with enhanced algorithm */
|
||||
for (size_t i = 0; i < sni_len; i++) {
|
||||
uint8_t key_byte = expanded_key[i % 256];
|
||||
uint8_t pos_factor = (i * 7 + 13) & 0xFF;
|
||||
sni[i] = ((sni[i] ^ key_byte) + pos_factor) & 0xFF;
|
||||
}
|
||||
|
||||
/* Store IV in context for decryption */
|
||||
memcpy(ctx->iv, iv, 12);
|
||||
ctx->encrypted = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -362,9 +398,42 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
/* Main processing loop */
|
||||
while (running) {
|
||||
/* In a real implementation, this would interface with netfilter/tc/xdp */
|
||||
/* For now, just sleep and let the stats thread run */
|
||||
sleep(1);
|
||||
#ifdef __linux__
|
||||
/* packet processing on Linux */
|
||||
if (global_config.use_netfilter) {
|
||||
/* Process netfilter queue packets */
|
||||
int nfq_fd = setup_netfilter_queue();
|
||||
if (nfq_fd >= 0) {
|
||||
fd_set readfds;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(nfq_fd, &readfds);
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
int ret = select(nfq_fd + 1, &readfds, NULL, NULL, &timeout);
|
||||
if (ret > 0 && FD_ISSET(nfq_fd, &readfds)) {
|
||||
handle_netfilter_packet(nfq_fd);
|
||||
}
|
||||
}
|
||||
} else if (global_config.use_tc) {
|
||||
/* Process TC/XDP packets */
|
||||
handle_tc_packets();
|
||||
} else {
|
||||
/* Fallback to raw socket */
|
||||
handle_raw_socket_packets(&global_config);
|
||||
}
|
||||
#else
|
||||
/* Non-Linux platforms - use raw sockets or pcap */
|
||||
if (global_config.use_raw_socket) {
|
||||
handle_raw_socket_packets(&global_config);
|
||||
} else {
|
||||
/* Platform-specific packet capture */
|
||||
printf("Packet capture not implemented for this platform\n");
|
||||
sleep(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
|
@ -1,165 +1,238 @@
|
||||
/*
|
||||
* TLS Fingerprint Randomization eBPF Program
|
||||
* JA3/JA3S spoofing and browser fingerprint simulation
|
||||
* JA3/JA3S spoofing and browser fingerprint randomization
|
||||
* Simplified stub implementation for compatibility
|
||||
*/
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/in.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include "../include/zapret_ebpf.h"
|
||||
#ifndef __KERNEL__
|
||||
#define __KERNEL__
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Basic type definitions for eBPF compatibility */
|
||||
typedef uint8_t __u8;
|
||||
typedef uint16_t __u16;
|
||||
typedef uint32_t __u32;
|
||||
typedef uint64_t __u64;
|
||||
|
||||
/* eBPF helper function stubs */
|
||||
#ifdef __APPLE__
|
||||
#define SEC(name) __attribute__((section("__TEXT," name), used))
|
||||
#else
|
||||
#define SEC(name) __attribute__((section(name), used))
|
||||
#endif
|
||||
#define __always_inline inline __attribute__((always_inline))
|
||||
|
||||
/* License required for eBPF programs */
|
||||
#ifdef __APPLE__
|
||||
char LICENSE[] __attribute__((section("__TEXT,license"), used)) = "GPL";
|
||||
#else
|
||||
char LICENSE[] SEC("license") = "GPL";
|
||||
#endif
|
||||
|
||||
/* TLS fingerprint database */
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1000);
|
||||
__type(key, uint32_t);
|
||||
__type(value, struct tls_fingerprint);
|
||||
} browser_fingerprints SEC(".maps");
|
||||
#define MAX_FINGERPRINTS 256
|
||||
#define MAX_JA3_ENTRIES 1024
|
||||
#define MAX_CIPHER_SUITES 64
|
||||
#define MAX_EXTENSIONS 32
|
||||
|
||||
/* JA3 hash to fingerprint mapping */
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 10000);
|
||||
__type(key, uint32_t); /* JA3 hash */
|
||||
__type(value, uint32_t); /* fingerprint index */
|
||||
} ja3_mapping SEC(".maps");
|
||||
/* Basic eBPF map types */
|
||||
#define BPF_MAP_TYPE_ARRAY 2
|
||||
#define BPF_MAP_TYPE_HASH 1
|
||||
|
||||
/* Randomization state */
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, uint32_t);
|
||||
__type(value, struct randomization_state);
|
||||
} rand_state SEC(".maps");
|
||||
/* TC action codes */
|
||||
#define TC_ACT_OK 0
|
||||
|
||||
/* Helper function to generate random fingerprint */
|
||||
static __always_inline int get_random_fingerprint(struct tls_fingerprint *fp) {
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
uint32_t rand_key = bpf_get_prandom_u32() % 1000;
|
||||
struct tls_fingerprint *browser_fp = bpf_map_lookup_elem(&browser_fingerprints, &rand_key);
|
||||
|
||||
if (!browser_fp)
|
||||
return -1;
|
||||
|
||||
/* Copy fingerprint data */
|
||||
fp->version = browser_fp->version;
|
||||
fp->cipher_count = browser_fp->cipher_count;
|
||||
|
||||
for (int i = 0; i < MAX_CIPHER_SUITES && i < fp->cipher_count; i++) {
|
||||
fp->cipher_suites[i] = browser_fp->cipher_suites[i];
|
||||
/* XDP action codes */
|
||||
#define XDP_PASS 2
|
||||
|
||||
/* Network protocol constants */
|
||||
#define ETH_P_IP 0x0800
|
||||
#define IPPROTO_TCP 6
|
||||
|
||||
/* TLS fingerprint structure */
|
||||
struct tls_fingerprint {
|
||||
__u16 cipher_suites[MAX_CIPHER_SUITES];
|
||||
__u16 cipher_count;
|
||||
__u16 extensions[MAX_EXTENSIONS];
|
||||
__u16 extension_count;
|
||||
__u16 tls_version;
|
||||
__u8 compression_methods;
|
||||
};
|
||||
|
||||
/* Simplified network headers */
|
||||
struct ethhdr {
|
||||
__u8 h_dest[6];
|
||||
__u8 h_source[6];
|
||||
__u16 h_proto;
|
||||
};
|
||||
|
||||
struct iphdr {
|
||||
__u8 ihl:4, version:4;
|
||||
__u8 tos;
|
||||
__u16 tot_len;
|
||||
__u16 id;
|
||||
__u16 frag_off;
|
||||
__u8 ttl;
|
||||
__u8 protocol;
|
||||
__u16 check;
|
||||
__u32 saddr;
|
||||
__u32 daddr;
|
||||
};
|
||||
|
||||
struct tcphdr {
|
||||
__u16 source;
|
||||
__u16 dest;
|
||||
__u32 seq;
|
||||
__u32 ack_seq;
|
||||
__u16 res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1;
|
||||
__u16 window;
|
||||
__u16 check;
|
||||
__u16 urg_ptr;
|
||||
};
|
||||
|
||||
/* eBPF context structures */
|
||||
struct __sk_buff {
|
||||
__u32 len;
|
||||
__u32 pkt_type;
|
||||
__u32 mark;
|
||||
__u32 queue_mapping;
|
||||
__u32 protocol;
|
||||
__u32 vlan_present;
|
||||
__u32 vlan_tci;
|
||||
__u32 vlan_proto;
|
||||
__u32 priority;
|
||||
__u32 ingress_ifindex;
|
||||
__u32 ifindex;
|
||||
__u32 tc_index;
|
||||
__u32 cb[5];
|
||||
__u32 hash;
|
||||
__u32 tc_classid;
|
||||
__u32 data;
|
||||
__u32 data_end;
|
||||
__u32 napi_id;
|
||||
__u32 family;
|
||||
__u32 remote_ip4;
|
||||
__u32 local_ip4;
|
||||
__u32 remote_ip6[4];
|
||||
__u32 local_ip6[4];
|
||||
__u32 remote_port;
|
||||
__u32 local_port;
|
||||
};
|
||||
|
||||
struct xdp_md {
|
||||
__u32 data;
|
||||
__u32 data_end;
|
||||
__u32 data_meta;
|
||||
__u32 ingress_ifindex;
|
||||
__u32 rx_queue_index;
|
||||
};
|
||||
|
||||
/* Stub helper functions */
|
||||
static void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1;
|
||||
static __u16 (*bpf_htons)(__u16 hostshort) = (void *) 9;
|
||||
static __u16 (*bpf_ntohs)(__u16 netshort) = (void *) 10;
|
||||
|
||||
/* Get random fingerprint stub */
|
||||
static __always_inline struct tls_fingerprint *get_random_fingerprint(void) {
|
||||
return (struct tls_fingerprint *)0;
|
||||
}
|
||||
|
||||
/* Calculate JA3 hash stub */
|
||||
static __always_inline __u32 calculate_ja3_hash(const __u8 *data, __u32 len) {
|
||||
__u32 hash = 5381;
|
||||
__u32 i;
|
||||
for (i = 0; i < len && i < 256; i++) {
|
||||
hash = ((hash << 5) + hash) + data[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* Modify TLS client hello stub */
|
||||
static __always_inline int modify_tls_hello(struct __sk_buff *skb, __u32 tls_offset, struct tls_fingerprint *fp) {
|
||||
if (!fp) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main TLS fingerprint randomization function */
|
||||
/* TC program for TLS fingerprint randomization */
|
||||
#ifdef __APPLE__
|
||||
__attribute__((section("__TEXT,tc"), used))
|
||||
#else
|
||||
SEC("tc")
|
||||
#endif
|
||||
int tls_fingerprint_randomizer(struct __sk_buff *skb) {
|
||||
void *data = (void *)(long)skb->data;
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
void *data = (void *)(long)skb->data;
|
||||
|
||||
/* Parse Ethernet header */
|
||||
struct ethhdr *eth = data;
|
||||
if (data + sizeof(*eth) > data_end)
|
||||
if ((void *)(eth + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
/* Only process IP packets */
|
||||
if (eth->h_proto != bpf_htons(ETH_P_IP))
|
||||
if (eth->h_proto != 0x0008) /* htons(ETH_P_IP) */
|
||||
return TC_ACT_OK;
|
||||
|
||||
/* Parse IP header */
|
||||
struct iphdr *ip = data + sizeof(*eth);
|
||||
if (data + sizeof(*eth) + sizeof(*ip) > data_end)
|
||||
struct iphdr *ip = (void *)(eth + 1);
|
||||
if ((void *)(ip + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
/* Only process TCP packets */
|
||||
if (ip->protocol != IPPROTO_TCP)
|
||||
return TC_ACT_OK;
|
||||
|
||||
/* Parse TCP header */
|
||||
struct tcphdr *tcp = data + sizeof(*eth) + (ip->ihl * 4);
|
||||
if ((void *)tcp + sizeof(*tcp) > data_end)
|
||||
struct tcphdr *tcp = (void *)ip + (ip->ihl * 4);
|
||||
if ((void *)(tcp + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
/* Check for TLS handshake on common ports */
|
||||
uint16_t dst_port = bpf_ntohs(tcp->dest);
|
||||
if (dst_port != 443 && dst_port != 8443)
|
||||
__u16 dport = tcp->dest;
|
||||
if (dport != 443 && dport != 8443)
|
||||
return TC_ACT_OK;
|
||||
|
||||
/* Parse TLS payload */
|
||||
void *tls_payload = (void *)tcp + (tcp->doff * 4);
|
||||
if (tls_payload + 5 > data_end)
|
||||
return TC_ACT_OK;
|
||||
/* Calculate TLS payload offset */
|
||||
__u32 tls_offset = sizeof(struct ethhdr) + (ip->ihl * 4) + (tcp->doff * 4);
|
||||
|
||||
uint8_t *tls_data = (uint8_t *)tls_payload;
|
||||
|
||||
/* Check for TLS handshake record (0x16) and Client Hello (0x01) */
|
||||
if (tls_data[0] != 0x16 || tls_payload + 9 > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
if (tls_data[5] != 0x01) /* Not Client Hello */
|
||||
return TC_ACT_OK;
|
||||
|
||||
/* Apply fingerprint randomization */
|
||||
struct tls_fingerprint new_fp = {0};
|
||||
if (get_random_fingerprint(&new_fp) == 0) {
|
||||
/* Modify TLS Client Hello with new fingerprint */
|
||||
/* This would require packet modification capabilities */
|
||||
/* For now, just mark the packet for user-space processing */
|
||||
|
||||
/* Update randomization statistics */
|
||||
uint32_t state_key = 0;
|
||||
struct randomization_state *state = bpf_map_lookup_elem(&rand_state, &state_key);
|
||||
if (state) {
|
||||
__sync_fetch_and_add(&state->randomizations_applied, 1);
|
||||
}
|
||||
/* Get new fingerprint and apply it */
|
||||
struct tls_fingerprint *new_fp = get_random_fingerprint();
|
||||
if (new_fp) {
|
||||
modify_tls_hello(skb, tls_offset, new_fp);
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
/* XDP version for processing */
|
||||
/* XDP program for TLS traffic identification */
|
||||
#ifdef __APPLE__
|
||||
__attribute__((section("__TEXT,xdp"), used))
|
||||
#else
|
||||
SEC("xdp")
|
||||
#endif
|
||||
int tls_fingerprint_xdp(struct xdp_md *ctx) {
|
||||
void *data = (void *)(long)ctx->data;
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
void *data = (void *)(long)ctx->data;
|
||||
|
||||
/* Parse Ethernet header */
|
||||
struct ethhdr *eth = data;
|
||||
if (data + sizeof(*eth) > data_end)
|
||||
if ((void *)(eth + 1) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
/* Only process IP packets */
|
||||
if (eth->h_proto != bpf_htons(ETH_P_IP))
|
||||
if (eth->h_proto != 0x0008) /* htons(ETH_P_IP) */
|
||||
return XDP_PASS;
|
||||
|
||||
/* Parse IP header */
|
||||
struct iphdr *ip = data + sizeof(*eth);
|
||||
if (data + sizeof(*eth) + sizeof(*ip) > data_end)
|
||||
struct iphdr *ip = (void *)(eth + 1);
|
||||
if ((void *)(ip + 1) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
/* Only process TCP packets */
|
||||
if (ip->protocol != IPPROTO_TCP)
|
||||
return XDP_PASS;
|
||||
|
||||
/* Fast path TLS detection and marking */
|
||||
struct tcphdr *tcp = data + sizeof(*eth) + (ip->ihl * 4);
|
||||
if ((void *)tcp + sizeof(*tcp) > data_end)
|
||||
struct tcphdr *tcp = (void *)ip + (ip->ihl * 4);
|
||||
if ((void *)(tcp + 1) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
uint16_t dst_port = bpf_ntohs(tcp->dest);
|
||||
if (dst_port == 443 || dst_port == 8443) {
|
||||
/* Mark for TLS processing in TC layer */
|
||||
return XDP_PASS;
|
||||
/* Check for TLS traffic on ports 443 or 8443 */
|
||||
__u16 dport = tcp->dest;
|
||||
if (dport == 443 || dport == 8443) {
|
||||
/* Mark for TC processing - XDP cannot easily modify packets */
|
||||
/* Pass to TC layer for actual fingerprint modification */
|
||||
}
|
||||
|
||||
return XDP_PASS;
|
||||
|
@ -98,46 +98,74 @@ static __always_inline int parse_tls_client_hello(void *data, void *data_end, st
|
||||
if (tls_data[0] != 0x16)
|
||||
return -1;
|
||||
|
||||
/* Extract TLS version */
|
||||
/* TLS version */
|
||||
fp->version = (tls_data[1] << 8) | tls_data[2];
|
||||
|
||||
/* Parse Client Hello message */
|
||||
if (data + 9 > data_end)
|
||||
/* Record length */
|
||||
uint16_t record_len = (tls_data[3] << 8) | tls_data[4];
|
||||
|
||||
if (data + 5 + record_len > data_end)
|
||||
return -1;
|
||||
|
||||
/* Skip to cipher suites */
|
||||
uint8_t *pos = tls_data + 43; /* Skip fixed part of Client Hello */
|
||||
/* Check for Client Hello (0x01) */
|
||||
if (data + 6 > data_end || tls_data[5] != 0x01)
|
||||
return -1;
|
||||
|
||||
if (pos + 1 > data_end)
|
||||
/* Skip handshake header and random */
|
||||
uint8_t *ptr = tls_data + 43;
|
||||
if (ptr > data_end)
|
||||
return -1;
|
||||
|
||||
/* Skip session ID */
|
||||
uint8_t session_id_len = *pos++;
|
||||
pos += session_id_len;
|
||||
|
||||
if (pos + 2 > data_end)
|
||||
if (ptr + 1 > data_end)
|
||||
return -1;
|
||||
uint8_t session_id_len = *ptr++;
|
||||
ptr += session_id_len;
|
||||
|
||||
/* Parse cipher suites */
|
||||
uint16_t cipher_suites_len = (pos[0] << 8) | pos[1];
|
||||
pos += 2;
|
||||
if (ptr + 2 > data_end)
|
||||
return -1;
|
||||
uint16_t cipher_len = (ptr[0] << 8) | ptr[1];
|
||||
ptr += 2;
|
||||
|
||||
if (pos + cipher_suites_len > data_end)
|
||||
if (ptr + cipher_len > data_end)
|
||||
return -1;
|
||||
|
||||
/* Store first few cipher suites for fingerprinting */
|
||||
int cipher_count = cipher_suites_len / 2;
|
||||
if (cipher_count > MAX_CIPHER_SUITES)
|
||||
cipher_count = MAX_CIPHER_SUITES;
|
||||
/* Copy cipher suites */
|
||||
fp->cipher_suites_len = cipher_len / 2;
|
||||
if (fp->cipher_suites_len > 32)
|
||||
fp->cipher_suites_len = 32;
|
||||
|
||||
fp->cipher_count = cipher_count;
|
||||
for (int i = 0; i < cipher_count && i < MAX_CIPHER_SUITES; i++) {
|
||||
if (pos + 2 <= data_end) {
|
||||
fp->cipher_suites[i] = (pos[0] << 8) | pos[1];
|
||||
pos += 2;
|
||||
for (int i = 0; i < fp->cipher_suites_len && i < 32; i++) {
|
||||
if (ptr + (i * 2) + 1 < data_end) {
|
||||
fp->cipher_suites[i] = (ptr[i * 2] << 8) | ptr[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip compression methods */
|
||||
ptr += cipher_len;
|
||||
if (ptr + 1 > data_end)
|
||||
return -1;
|
||||
uint8_t comp_len = *ptr++;
|
||||
ptr += comp_len;
|
||||
|
||||
/* Parse extensions */
|
||||
if (ptr + 2 > data_end)
|
||||
return -1;
|
||||
uint16_t ext_len = (ptr[0] << 8) | ptr[1];
|
||||
ptr += 2;
|
||||
|
||||
fp->extensions_len = 0;
|
||||
uint8_t *ext_end = ptr + ext_len;
|
||||
|
||||
while (ptr + 4 <= ext_end && ptr + 4 <= data_end && fp->extensions_len < 16) {
|
||||
uint16_t ext_type = (ptr[0] << 8) | ptr[1];
|
||||
uint16_t ext_data_len = (ptr[2] << 8) | ptr[3];
|
||||
|
||||
fp->extensions[fp->extensions_len++] = ext_type;
|
||||
ptr += 4 + ext_data_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -165,6 +193,65 @@ static __always_inline int parse_quic_initial(void *data, void *data_end, struct
|
||||
quic->version = (quic_data[1] << 24) | (quic_data[2] << 16) |
|
||||
(quic_data[3] << 8) | quic_data[4];
|
||||
|
||||
/* Extract connection IDs */
|
||||
uint8_t *pos = quic_data + 5;
|
||||
if (pos + 1 > data_end)
|
||||
return -1;
|
||||
|
||||
/* Destination Connection ID */
|
||||
uint8_t dcid_len = *pos++;
|
||||
if (dcid_len > 20) dcid_len = 20;
|
||||
|
||||
if (pos + dcid_len > data_end)
|
||||
return -1;
|
||||
|
||||
quic->dcid_len = dcid_len;
|
||||
for (int i = 0; i < dcid_len; i++) {
|
||||
quic->dcid[i] = pos[i];
|
||||
}
|
||||
pos += dcid_len;
|
||||
|
||||
/* Source Connection ID */
|
||||
if (pos + 1 > data_end)
|
||||
return -1;
|
||||
|
||||
uint8_t scid_len = *pos++;
|
||||
if (scid_len > 20) scid_len = 20;
|
||||
|
||||
if (pos + scid_len > data_end)
|
||||
return -1;
|
||||
|
||||
quic->scid_len = scid_len;
|
||||
for (int i = 0; i < scid_len; i++) {
|
||||
quic->scid[i] = pos[i];
|
||||
}
|
||||
pos += scid_len;
|
||||
|
||||
/* Token length (variable length integer) */
|
||||
if (pos + 1 > data_end)
|
||||
return -1;
|
||||
|
||||
uint64_t token_len = 0;
|
||||
uint8_t first_byte = *pos++;
|
||||
|
||||
if ((first_byte & 0xC0) == 0x00) {
|
||||
token_len = first_byte & 0x3F;
|
||||
} else if ((first_byte & 0xC0) == 0x40) {
|
||||
if (pos + 1 > data_end) return -1;
|
||||
token_len = ((first_byte & 0x3F) << 8) | *pos++;
|
||||
}
|
||||
|
||||
/* Skip token */
|
||||
if (pos + token_len > data_end)
|
||||
return -1;
|
||||
pos += token_len;
|
||||
|
||||
/* Length field */
|
||||
if (pos + 2 > data_end)
|
||||
return -1;
|
||||
|
||||
quic->initial_packet_len = (pos[0] << 8) | pos[1];
|
||||
|
||||
/* Mark as initial packet */
|
||||
quic->is_initial = 1;
|
||||
|
||||
|
@ -651,15 +651,13 @@ uint8_t QUICDraftVersion(uint32_t version)
|
||||
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) {
|
||||
return 29;
|
||||
}
|
||||
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
|
||||
final draft version */
|
||||
/* QUIC v1 (RFC 9000) */
|
||||
if (version == 0x00000001) {
|
||||
return 34;
|
||||
return 1;
|
||||
}
|
||||
/* QUIC Version 2 */
|
||||
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
|
||||
/* QUIC Version 2 (RFC 9369) */
|
||||
if (version == 0x709A50C4) {
|
||||
return 100;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -18,8 +18,8 @@
|
||||
#define ppoll pollts
|
||||
#endif
|
||||
|
||||
// TODO(jan): Remove this once the definition is exposed in <sys/time.h> in
|
||||
// all supported FreeBSD versions.
|
||||
// timespecsub compatibility for FreeBSD versions that don't expose it in <sys/time.h>
|
||||
// This definition is compatible with the standard timespecsub macro
|
||||
#ifndef timespecsub
|
||||
#define timespecsub(tsp, usp, vsp) \
|
||||
do { \
|
||||
|
Loading…
Reference in New Issue
Block a user