Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conntrack support #211

Merged
merged 4 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ modules.order
Module.symvers
*.so
*.ko
*.a

!/.github
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock

- `--instaflush` Used with tracing. Flushes the buffer instantly, without waiting for explicit new line. Highly useful for debugging crushes.

- `--no-gso` Disables support for Google Chrome fat packets which uses GSO. This feature is well tested now, so this flag probably won't fix anything.
- `--no-gso` Disables support for TCP fat packets which uses GSO. This feature is well tested now, so this flag probably won't fix anything.

- `--no-conntrack` Disables support for conntrack in youtubeUnblock.

- `--no-ipv6` Disables support for ipv6. May be useful if you don't want for ipv6 socket to be opened.

Expand Down Expand Up @@ -332,6 +334,11 @@ Where you have to replace 192.168.. with ip of your television.
* send fake sni EPERM: Fake SNI is out-of-state thing and will likely corrupt the connection (the behavior is expected). conntrack considers it as an invalid packet. By default OpenWRT set up to drop outgoing packets like this one. You may delete nftables/iptables rule that drops packets with invalid conntrack state, but I don't recommend to do this. The step 3 is better solution.
* Step 3, ultimate solution. Use mark (don't confuse with connmark). The youtubeUnblock uses mark internally to avoid infinity packet loops (when the packet is sent by youtubeUnblock but on next step handled by itself). Currently it uses mark (1 << 15) = 32768. You should put iptables/nftables that ultimately accepts such marks at the very start of the filter OUTPUT chain: `iptables -I OUTPUT -m mark --mark 32768/32768 -j ACCEPT` or `nft insert rule inet fw4 output mark and 0x8000 == 0x8000 counter accept`.

### Conntrack

youtubeUnblock *optionally* depends on conntrack.
For kernel module, if conntrack breaks dependencies, compile it with `make kmake EXTRA_CFLAGS="-DNO_CONNTRACK"` to disable it completly.

## Compilation

Before compilation make sure `gcc`, `make`, `autoconf`, `automake`, `pkg-config` and `libtool` is installed. For Fedora `glibc-static` should be installed as well.
Expand Down
Binary file removed deps/cyclone/libcyclone.a
Binary file not shown.
4 changes: 3 additions & 1 deletion kmake.mk
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ LDFLAGS :=

KERNEL_BUILDER_MAKEDIR:=/lib/modules/$(shell uname -r)/build

override EXTRA_CFLAGS += -DPKG_VERSION=\"$(PKG_FULLVERSION)\"

.PHONY: kmake kload kunload kreload kclean kmclean xclean
kmake: kmod

kmod:
$(MAKE) -C $(KERNEL_BUILDER_MAKEDIR) M=$(PWD) EXTRA_CFLAGS='-DPKG_VERSION=\"$(PKG_FULLVERSION)\"' modules
$(MAKE) -C $(KERNEL_BUILDER_MAKEDIR) M=$(PWD) EXTRA_CFLAGS='$(EXTRA_CFLAGS)' modules

kload:
insmod kyoutubeUnblock.ko
Expand Down
19 changes: 19 additions & 0 deletions src/args.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ enum {
OPT_THREADS,
OPT_SILENT,
OPT_NO_GSO,
OPT_NO_CONNTRACK,
OPT_QUEUE_NUM,
OPT_UDP_MODE,
OPT_UDP_FAKE_SEQ_LEN,
Expand Down Expand Up @@ -322,6 +323,7 @@ static struct option long_opt[] = {
{"trace", 0, 0, OPT_TRACE},
{"instaflush", 0, 0, OPT_INSTAFLUSH},
{"no-gso", 0, 0, OPT_NO_GSO},
{"no-conntrack", 0, 0, OPT_NO_CONNTRACK},
{"no-ipv6", 0, 0, OPT_NO_IPV6},
{"daemonize", 0, 0, OPT_DAEMONIZE},
{"noclose", 0, 0, OPT_NOCLOSE},
Expand Down Expand Up @@ -386,6 +388,7 @@ void print_usage(const char *argv0) {
printf("\t--trace\n");
printf("\t--instaflush\n");
printf("\t--no-gso\n");
printf("\t--no-conntrack\n");
printf("\t--no-ipv6\n");
printf("\t--daemonize\n");
printf("\t--noclose\n");
Expand Down Expand Up @@ -459,7 +462,20 @@ int yparse_args(int argc, char *argv[]) {
rep_config.verbose = VERBOSE_INFO;
break;
case OPT_NO_GSO:
#ifndef KERNEL_SPACE
rep_config.use_gso = 0;
#else
lgerr("--no-gso is not supported in kernel space");
goto invalid_opt;
#endif
break;
case OPT_NO_CONNTRACK:
#ifndef KERNEL_SPACE
rep_config.use_conntrack = 0;
#else
lgerr("--no-conntrack is not supported in kernel space. Compile with make kmake EXTRA_CFLAGS=\"-DNO_CONNTRACK\" instead." );
goto invalid_opt;
#endif
break;
case OPT_NO_IPV6:
rep_config.use_ipv6 = 0;
Expand Down Expand Up @@ -1017,6 +1033,9 @@ size_t print_config(char *buffer, size_t buffer_size) {
if (!config.use_gso) {
print_cnf_buf("--no-gso");
}
if (!config.use_conntrack) {
print_cnf_buf("--no-conntrack");
}
#endif

#ifdef KERNEL_SPACE
Expand Down
40 changes: 40 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ struct config_t {
int threads;
int use_gso;
int use_ipv6;
int use_conntrack;
unsigned int mark;
int daemonize;
// Same as daemon() noclose
Expand Down Expand Up @@ -269,6 +270,7 @@ enum {
\
.verbose = VERBOSE_DEBUG, \
.use_gso = 1, \
.use_conntrack = 1, \
\
.first_section = NULL, \
.last_section = NULL, \
Expand All @@ -284,4 +286,42 @@ struct config_t config = default_config_set; \
config->last_section = &(config.default_config) \


struct ytb_conntrack {
uint32_t mask;

uint64_t orig_packets;
uint64_t repl_packets;
uint64_t orig_bytes;
uint64_t repl_bytes;
uint32_t connmark;
uint32_t id;
};

enum yct_attrs {
YCTATTR_ORIG_PACKETS,
YCTATTR_REPL_PACKETS,
YCTATTR_ORIG_BYTES,
YCTATTR_REPL_BYTES,
YCTATTR_CONNMARK,
YCTATTR_CONNID,
};
/* enum yct_attrs attr, struct ytb_conntrack * yct */
#define yct_set_mask_attr(attr, yct) \
((yct)->mask |= (1 << (attr)))

/* enum yct_attrs attr, const struct ytb_conntrack * yct */
#define yct_is_mask_attr(attr, yct) \
(((yct)->mask & (1 << (attr))) == (1 << (attr)))

/* enum yct_attrs attr, struct ytb_conntrack * yct */
#define yct_del_mask_attr(attr, yct) \
(yct)->mask &= ~(1 << (attr))


struct packet_data {
const uint8_t *payload;
size_t payload_len;
struct ytb_conntrack yct;
};

#endif /* YTB_CONFIG_H */
63 changes: 57 additions & 6 deletions src/kytunblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,16 @@
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>

#ifdef IS_ENABLED
#if !(IS_ENABLED(CONFIG_NF_CONNTRACK))
#define NO_CONNTRACK
#endif /* IS CONNTRACK ENABLED */
#endif /* ifdef IS_ENABLED */

#ifndef NO_CONNTRACK
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_acct.h>
#endif

#include "mangle.h"
#include "config.h"
Expand Down Expand Up @@ -251,10 +259,12 @@ struct instance_config_t instance_config = {
.send_delayed_packet = delay_packet_send,
};

static int connbytes_pkts(const struct sk_buff *skb) {
static int conntrack_parse(const struct sk_buff *skb,
struct ytb_conntrack *yct) {
#ifndef NO_CONNTRACK

const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
u_int64_t pkts = 0;
const struct nf_conn_counter *counters;

ct = nf_ct_get(skb, &ctinfo);
Expand All @@ -273,9 +283,36 @@ static int connbytes_pkts(const struct sk_buff *skb) {
return -1;
#endif

pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
yct->orig_packets = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
yct->orig_bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
yct->repl_packets = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
yct->repl_bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
#else
yct->orig_packets = counters[IP_CT_DIR_ORIGINAL].packets;
yct->orig_bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
yct->repl_packets = counters[IP_CT_DIR_REPLY].packets;
yct->repl_bytes = counters[IP_CT_DIR_REPLY].bytes;
#endif
yct_set_mask_attr(YCTATTR_ORIG_PACKETS, yct);
yct_set_mask_attr(YCTATTR_ORIG_BYTES, yct);
yct_set_mask_attr(YCTATTR_REPL_PACKETS, yct);
yct_set_mask_attr(YCTATTR_REPL_BYTES, yct);

#if defined(CONFIG_NF_CONNTRACK_MARK)
yct->connmark = READ_ONCE(ct->mark);
yct_set_mask_attr(YCTATTR_CONNMARK, yct);
#endif


#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
yct->id = nf_ct_get_id(ct);
yct_set_mask_attr(YCTATTR_CONNID, yct);
#endif

#endif /* NO_CONNTRACK */

return pkts;
return 0;
}

/* If this is a Red Hat-based kernel (Red Hat, CentOS, Fedora, etc)... */
Expand Down Expand Up @@ -346,6 +383,7 @@ static int connbytes_pkts(const struct sk_buff *skb) {

static NF_CALLBACK(ykb_nf_hook, skb) {
int ret;
struct packet_data pd = {0};

if ((skb->mark & config.mark) == config.mark)
goto accept;
Expand All @@ -356,16 +394,25 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
if (skb->len > MAX_PACKET_SIZE)
goto accept;

if (config.connbytes_limit != 0 && connbytes_pkts(skb) > config.connbytes_limit)
ret = conntrack_parse(skb, &pd.yct);
if (ret < 0) {
lgtrace("[TRACE] conntrack_parse error code\n");
}

if (config.connbytes_limit != 0 && yct_is_mask_attr(YCTATTR_ORIG_PACKETS, &pd.yct) && pd.yct.orig_packets > config.connbytes_limit)
goto accept;


ret = skb_linearize(skb);
if (ret < 0) {
lgerror(ret, "Cannot linearize");
goto accept;
}

int vrd = process_packet(skb->data, skb->len);
pd.payload = skb->data;
pd.payload_len = skb->len;

int vrd = process_packet(&pd);

switch(vrd) {
case PKT_ACCEPT:
Expand Down Expand Up @@ -397,6 +444,10 @@ static struct nf_hook_ops ykb6_nf_reg __read_mostly = {
};

static int __init ykb_init(void) {
#ifdef NO_CONNTRACK
lgwarning("Conntrack disabled.");
#endif

int ret = 0;
ret = init_config(&config);
if (ret < 0) goto err;
Expand Down
5 changes: 4 additions & 1 deletion src/mangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
#include "linux/inet.h"
#endif

int process_packet(const uint8_t *raw_payload, size_t raw_payload_len) {
int process_packet(const struct packet_data *pd) {
const uint8_t *raw_payload = pd->payload;
uint32_t raw_payload_len = pd->payload_len;

if (raw_payload_len > MAX_PACKET_SIZE) {
return PKT_ACCEPT;
}
Expand Down
3 changes: 2 additions & 1 deletion src/mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "types.h"
#include "tls.h"
#include "config.h"

#define PKT_ACCEPT 0
#define PKT_DROP 1
Expand All @@ -32,7 +33,7 @@
* Processes the packet and returns verdict.
* This is the primary function that traverses the packet.
*/
int process_packet(const uint8_t *packet, size_t packet_len);
int process_packet(const struct packet_data *pd);


/**
Expand Down
Loading
Loading