mirror of https://github.com/bol-van/zapret/
8 changed files with 469 additions and 204 deletions
@ -1,165 +1,238 @@ |
|||||
/*
|
/*
|
||||
* TLS Fingerprint Randomization eBPF Program |
* 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> |
#ifndef __KERNEL__ |
||||
#include <linux/if_ether.h> |
#define __KERNEL__ |
||||
#include <linux/ip.h> |
#endif |
||||
#include <linux/tcp.h> |
|
||||
#include <linux/in.h> |
#include <stdint.h> |
||||
#include <bpf/bpf_helpers.h> |
#include <stdbool.h> |
||||
#include <bpf/bpf_endian.h> |
|
||||
#include "../include/zapret_ebpf.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 */ |
/* License required for eBPF programs */ |
||||
|
#ifdef __APPLE__ |
||||
|
char LICENSE[] __attribute__((section("__TEXT,license"), used)) = "GPL"; |
||||
|
#else |
||||
char LICENSE[] SEC("license") = "GPL"; |
char LICENSE[] SEC("license") = "GPL"; |
||||
|
#endif |
||||
|
|
||||
|
#define MAX_FINGERPRINTS 256 |
||||
|
#define MAX_JA3_ENTRIES 1024 |
||||
|
#define MAX_CIPHER_SUITES 64 |
||||
|
#define MAX_EXTENSIONS 32 |
||||
|
|
||||
|
/* Basic eBPF map types */ |
||||
|
#define BPF_MAP_TYPE_ARRAY 2 |
||||
|
#define BPF_MAP_TYPE_HASH 1 |
||||
|
|
||||
|
/* TC action codes */ |
||||
|
#define TC_ACT_OK 0 |
||||
|
|
||||
|
/* 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; |
||||
|
} |
||||
|
|
||||
/* TLS fingerprint database */ |
/* Calculate JA3 hash stub */ |
||||
struct { |
static __always_inline __u32 calculate_ja3_hash(const __u8 *data, __u32 len) { |
||||
__uint(type, BPF_MAP_TYPE_ARRAY); |
__u32 hash = 5381; |
||||
__uint(max_entries, 1000); |
__u32 i; |
||||
__type(key, uint32_t); |
for (i = 0; i < len && i < 256; i++) { |
||||
__type(value, struct tls_fingerprint); |
hash = ((hash << 5) + hash) + data[i]; |
||||
} browser_fingerprints SEC(".maps"); |
|
||||
|
|
||||
/* 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"); |
|
||||
|
|
||||
/* 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"); |
|
||||
|
|
||||
/* 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]; |
|
||||
} |
} |
||||
|
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; |
return 0; |
||||
} |
} |
||||
|
|
||||
/* Main TLS fingerprint randomization function */ |
/* TC program for TLS fingerprint randomization */ |
||||
|
#ifdef __APPLE__ |
||||
|
__attribute__((section("__TEXT,tc"), used)) |
||||
|
#else |
||||
SEC("tc") |
SEC("tc") |
||||
|
#endif |
||||
int tls_fingerprint_randomizer(struct __sk_buff *skb) { |
int tls_fingerprint_randomizer(struct __sk_buff *skb) { |
||||
void *data = (void *)(long)skb->data; |
|
||||
void *data_end = (void *)(long)skb->data_end; |
void *data_end = (void *)(long)skb->data_end; |
||||
|
void *data = (void *)(long)skb->data; |
||||
|
|
||||
/* Parse Ethernet header */ |
|
||||
struct ethhdr *eth = data; |
struct ethhdr *eth = data; |
||||
if (data + sizeof(*eth) > data_end) |
if ((void *)(eth + 1) > data_end) |
||||
return TC_ACT_OK; |
return TC_ACT_OK; |
||||
|
|
||||
/* Only process IP packets */ |
if (eth->h_proto != 0x0008) /* htons(ETH_P_IP) */ |
||||
if (eth->h_proto != bpf_htons(ETH_P_IP)) |
|
||||
return TC_ACT_OK; |
return TC_ACT_OK; |
||||
|
|
||||
/* Parse IP header */ |
struct iphdr *ip = (void *)(eth + 1); |
||||
struct iphdr *ip = data + sizeof(*eth); |
if ((void *)(ip + 1) > data_end) |
||||
if (data + sizeof(*eth) + sizeof(*ip) > data_end) |
|
||||
return TC_ACT_OK; |
return TC_ACT_OK; |
||||
|
|
||||
/* Only process TCP packets */ |
|
||||
if (ip->protocol != IPPROTO_TCP) |
if (ip->protocol != IPPROTO_TCP) |
||||
return TC_ACT_OK; |
return TC_ACT_OK; |
||||
|
|
||||
/* Parse TCP header */ |
struct tcphdr *tcp = (void *)ip + (ip->ihl * 4); |
||||
struct tcphdr *tcp = data + sizeof(*eth) + (ip->ihl * 4); |
if ((void *)(tcp + 1) > data_end) |
||||
if ((void *)tcp + sizeof(*tcp) > data_end) |
|
||||
return TC_ACT_OK; |
return TC_ACT_OK; |
||||
|
|
||||
/* Check for TLS handshake on common ports */ |
/* Check for TLS handshake on common ports */ |
||||
uint16_t dst_port = bpf_ntohs(tcp->dest); |
__u16 dport = tcp->dest; |
||||
if (dst_port != 443 && dst_port != 8443) |
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; |
return TC_ACT_OK; |
||||
|
|
||||
uint8_t *tls_data = (uint8_t *)tls_payload; |
/* Calculate TLS payload offset */ |
||||
|
__u32 tls_offset = sizeof(struct ethhdr) + (ip->ihl * 4) + (tcp->doff * 4); |
||||
|
|
||||
/* Check for TLS handshake record (0x16) and Client Hello (0x01) */ |
/* Get new fingerprint and apply it */ |
||||
if (tls_data[0] != 0x16 || tls_payload + 9 > data_end) |
struct tls_fingerprint *new_fp = get_random_fingerprint(); |
||||
return TC_ACT_OK; |
if (new_fp) { |
||||
|
modify_tls_hello(skb, tls_offset, new_fp); |
||||
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); |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
return TC_ACT_OK; |
return TC_ACT_OK; |
||||
} |
} |
||||
|
|
||||
/* XDP version for processing */ |
/* XDP program for TLS traffic identification */ |
||||
|
#ifdef __APPLE__ |
||||
|
__attribute__((section("__TEXT,xdp"), used)) |
||||
|
#else |
||||
SEC("xdp") |
SEC("xdp") |
||||
|
#endif |
||||
int tls_fingerprint_xdp(struct xdp_md *ctx) { |
int tls_fingerprint_xdp(struct xdp_md *ctx) { |
||||
void *data = (void *)(long)ctx->data; |
|
||||
void *data_end = (void *)(long)ctx->data_end; |
void *data_end = (void *)(long)ctx->data_end; |
||||
|
void *data = (void *)(long)ctx->data; |
||||
|
|
||||
/* Parse Ethernet header */ |
|
||||
struct ethhdr *eth = data; |
struct ethhdr *eth = data; |
||||
if (data + sizeof(*eth) > data_end) |
if ((void *)(eth + 1) > data_end) |
||||
return XDP_PASS; |
return XDP_PASS; |
||||
|
|
||||
/* Only process IP packets */ |
if (eth->h_proto != 0x0008) /* htons(ETH_P_IP) */ |
||||
if (eth->h_proto != bpf_htons(ETH_P_IP)) |
|
||||
return XDP_PASS; |
return XDP_PASS; |
||||
|
|
||||
/* Parse IP header */ |
struct iphdr *ip = (void *)(eth + 1); |
||||
struct iphdr *ip = data + sizeof(*eth); |
if ((void *)(ip + 1) > data_end) |
||||
if (data + sizeof(*eth) + sizeof(*ip) > data_end) |
|
||||
return XDP_PASS; |
return XDP_PASS; |
||||
|
|
||||
/* Only process TCP packets */ |
|
||||
if (ip->protocol != IPPROTO_TCP) |
if (ip->protocol != IPPROTO_TCP) |
||||
return XDP_PASS; |
return XDP_PASS; |
||||
|
|
||||
/* Fast path TLS detection and marking */ |
struct tcphdr *tcp = (void *)ip + (ip->ihl * 4); |
||||
struct tcphdr *tcp = data + sizeof(*eth) + (ip->ihl * 4); |
if ((void *)(tcp + 1) > data_end) |
||||
if ((void *)tcp + sizeof(*tcp) > data_end) |
|
||||
return XDP_PASS; |
return XDP_PASS; |
||||
|
|
||||
uint16_t dst_port = bpf_ntohs(tcp->dest); |
/* Check for TLS traffic on ports 443 or 8443 */ |
||||
if (dst_port == 443 || dst_port == 8443) { |
__u16 dport = tcp->dest; |
||||
/* Mark for TLS processing in TC layer */ |
if (dport == 443 || dport == 8443) { |
||||
return XDP_PASS; |
/* Mark for TC processing - XDP cannot easily modify packets */ |
||||
|
/* Pass to TC layer for actual fingerprint modification */ |
||||
} |
} |
||||
|
|
||||
return XDP_PASS; |
return XDP_PASS; |
||||
|
Loading…
Reference in new issue