mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2024-12-22 06:15:31 +00:00
Merge pull request #9 from Waujito/kern_mod
This PR brings more modular application and better APIs. Kernel module itself is not complete yet.
This commit is contained in:
commit
9101d8bd63
6
.editorconfig
Normal file
6
.editorconfig
Normal file
@ -0,0 +1,6 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
tab_width = 8
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -4,3 +4,12 @@ build
|
||||
|
||||
configure~
|
||||
|
||||
# Kernel module files
|
||||
*.o
|
||||
.*
|
||||
*.mod.*
|
||||
*.mod
|
||||
modules.order
|
||||
Module.symvers
|
||||
*.so
|
||||
*.ko
|
||||
|
3
Kbuild
Normal file
3
Kbuild
Normal file
@ -0,0 +1,3 @@
|
||||
obj-m := ipt_YTUNBLOCK.o
|
||||
ipt_YTUNBLOCK-objs := iptk_YTUNBLOCK.o mangle.o
|
||||
ccflags-y := -std=gnu11 -Wno-unused-variable -DKERNEL_SPACE -DDEBUG
|
97
Makefile
97
Makefile
@ -1,91 +1,14 @@
|
||||
BUILD_DIR := $(CURDIR)/build
|
||||
DEPSDIR := $(BUILD_DIR)/deps
|
||||
USPACE_TARGETS := default all install uninstall dev run_dev
|
||||
KMAKE_TARGETS := kmake kload kunload kreload xmod xtclean
|
||||
|
||||
CC:=gcc
|
||||
CCLD:=$(CC)
|
||||
LD:=ld
|
||||
override CFLAGS += -Wall -Wpedantic -Wno-unused-variable -I$(DEPSDIR)/include
|
||||
override LDFLAGS += -L$(DEPSDIR)/lib
|
||||
.PHONY: $(USPACE_TARGETS) $(KMAKE_TARGETS) clean
|
||||
$(USPACE_TARGETS):
|
||||
@$(MAKE) -f uspace.mk $@
|
||||
|
||||
LIBNFNETLINK_CFLAGS := -I$(DEPSDIR)/include
|
||||
LIBNFNETLINK_LIBS := -L$(DEPSDIR)/lib
|
||||
LIBMNL_CFLAGS := -I$(DEPSDIR)/include
|
||||
LIBMNL_LIBS := -L$(DEPSDIR)/lib
|
||||
|
||||
# PREFIX is environment variable, if not set default to /usr/local
|
||||
ifeq ($(PREFIX),)
|
||||
PREFIX := /usr/local
|
||||
else
|
||||
PREFIX := $(DESTDIR)
|
||||
endif
|
||||
|
||||
export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CFLAGS LIBMNL_LIBS
|
||||
|
||||
APP:=$(BUILD_DIR)/youtubeUnblock
|
||||
|
||||
SRCS := youtubeUnblock.c
|
||||
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
||||
|
||||
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a
|
||||
LIBMNL := $(DEPSDIR)/lib/libmnl.a
|
||||
LIBNETFILTER_QUEUE := $(DEPSDIR)/lib/libnetfilter_queue.a
|
||||
|
||||
|
||||
.PHONY: default all dev dev_attrs prepare_dirs
|
||||
default: all
|
||||
|
||||
run_dev: dev
|
||||
bash -c "sudo $(APP) 537"
|
||||
|
||||
dev: dev_attrs all
|
||||
|
||||
dev_attrs:
|
||||
$(eval CFLAGS := $(CFLAGS) -DDEBUG -ggdb -g3)
|
||||
|
||||
all: prepare_dirs $(APP)
|
||||
|
||||
prepare_dirs:
|
||||
mkdir -p $(BUILD_DIR)
|
||||
mkdir -p $(DEPSDIR)
|
||||
|
||||
$(LIBNFNETLINK):
|
||||
cd deps/libnfnetlink && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
|
||||
$(MAKE) -C deps/libnfnetlink
|
||||
$(MAKE) install -C deps/libnfnetlink
|
||||
|
||||
$(LIBMNL):
|
||||
cd deps/libmnl && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
|
||||
$(MAKE) -C deps/libmnl
|
||||
$(MAKE) install -C deps/libmnl
|
||||
|
||||
$(LIBNETFILTER_QUEUE): $(LIBNFNETLINK) $(LIBMNL)
|
||||
cd deps/libnetfilter_queue && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
|
||||
$(MAKE) -C deps/libnetfilter_queue
|
||||
$(MAKE) install -C deps/libnetfilter_queue
|
||||
|
||||
$(APP): $(OBJS) $(LIBNETFILTER_QUEUE) $(LIBMNL)
|
||||
@echo 'CCLD $(APP)'
|
||||
$(CCLD) $(OBJS) -o $(APP) $(LDFLAGS) -lmnl -lnetfilter_queue
|
||||
|
||||
$(BUILD_DIR)/%.o: %.c $(LIBNETFILTER_QUEUE) $(LIBMNL)
|
||||
@echo 'CC $@'
|
||||
$(CC) -c $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||
|
||||
install: all
|
||||
install -d $(PREFIX)/bin/
|
||||
install -m 755 $(APP) $(PREFIX)/bin/
|
||||
install -d $(PREFIX)/lib/systemd/system/
|
||||
@cp youtubeUnblock.service $(BUILD_DIR)
|
||||
@sed -i 's/$$(PREFIX)/$(subst /,\/,$(PREFIX))/g' $(BUILD_DIR)/youtubeUnblock.service
|
||||
install -m 644 $(BUILD_DIR)/youtubeUnblock.service $(PREFIX)/lib/systemd/system/
|
||||
|
||||
uninstall:
|
||||
rm $(PREFIX)/bin/youtubeUnblock
|
||||
rm $(PREFIX)/lib/systemd/system/youtubeUnblock.service
|
||||
-systemctl disable youtubeUnblock.service
|
||||
$(KMAKE_TARGETS):
|
||||
@$(MAKE) -f kmake.mk $@
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
$(MAKE) distclean -C deps/libnetfilter_queue || true
|
||||
$(MAKE) distclean -C deps/libmnl || true
|
||||
$(MAKE) distclean -C deps/libnfnetlink || true
|
||||
-@$(MAKE) -f kmake.mk kclean
|
||||
@$(MAKE) -f uspace.mk clean
|
||||
|
||||
|
15
README.md
15
README.md
@ -34,12 +34,15 @@ If you don't want youtubeUnblock to log on each googlevideo request pass -DSILEN
|
||||
|
||||
Also DNS over HTTPS (DOH) is preferred for additional anonimity.
|
||||
|
||||
## Troubleshooting
|
||||
If you have any troubles with youtubeUnblock, here are some options to tune. If them don't work in your case, please, open an issue. You can pass these options in make CFLAGS (`make CFLAGS=...`) or edit CFLAGS variable in Makefile.
|
||||
## Flags
|
||||
Available flags:
|
||||
- -DUSE_SEG2_DELAY This flag forces youtubeUnblock to wait little bit before send the 2nd part of the split packet. You can tune the amount of time in `#define SEG2_DELAY 100` where 100 stands for milliseconds.
|
||||
- -DNO_FAKE_SNI This flag disables -DFAKE_SNI which forces youtubeUnblock to send at least three packets instead of one with TLS ClientHello: Fake ClientHello, 1st part of original ClientHello, 2nd part of original ClientHello. This flag may be related to some Operation not permitted error messages, so befor open an issue refer to FAQ for EPERMS.
|
||||
- -DNOUSE_GSO This flag disables fix for Google Chrome fat ClientHello. The GSO is well tested now, so this flag probably won't fix anything.
|
||||
- `--seg2delay=<delay>` - This flag forces youtubeUnblock to wait little bit before send the 2nd part of the split packet.
|
||||
- `--fake-sni={ack,ttl, none}` This flag enables fake-sni which forces youtubeUnblock to send at least three packets instead of one with TLS ClientHello: Fake ClientHello, 1st part of original ClientHello, 2nd part of original ClientHello. This flag may be related to some Operation not permitted error messages, so befor open an issue refer to FAQ for EPERMS. Note, that this flag is set to `ack` by default. You may disable fake sni by setting it to `none`. Note, that your ISP may have conntrack drop on invalid state enabled, so this flag won't work. Use `ttl` to escape that.
|
||||
- `--fake-sni-ttl=<ttl>` Tunes the time to live of fake sni messages. TTL is specified like that the packet will go through the TSPU and captured by it, but will not reach the destination server. Defaults to 8.
|
||||
- `--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.
|
||||
- `--threads=<threads number>` Specifies the amount of threads you want to be running for your program. This defaults to 1 and shouldn't be edited for normal use. If you have performance issues, consult [performance chaptr](https://github.com/Waujito/youtubeUnblock?tab=readme-ov-file#performance)
|
||||
- `--silent` - Disables Google video detected debug logs.
|
||||
- `--frag={tcp,ip,none}` Specifies the fragmentation strategy for the packet. tcp is used by default. Ip fragmentation may be blocked by TSPU. None specifies no fragmentation. Probably this won't work, but may be will work for some fake sni strategies.
|
||||
|
||||
If you are on Chromium you may have to disable kyber (the feature that makes the TLS ClientHello very fat). I've got the problem with it on router, so to escape possibly errors it is better to just disable it: in chrome://flags search for kyber and switch it to disabled state.
|
||||
|
||||
@ -55,9 +58,9 @@ EPERM may occur in a lot of places but generally here are two: mnl_cb_run and wh
|
||||
If you have bad performance you can queue to youtubeUnblock only first, say, 20 packets from the connection. To do so, use nftables conntrack packets counter: `nft add rule inet fw4 mangle_forward tcp dport 443 ct original "packets < 20" counter queue num 537 bypass`. For my 1 CPU core device it worked pretty well. This works because we do care about only first packets with ClientHello. We don't need to process others.
|
||||
|
||||
The same behavior is also possible in iptables: `iptables -t mangle -A FORWARD -p tcp -m tcp --dport 443 -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:19 -j NFQUEUE --queue-num 537 --queue-bypass`. (The package iptables-mod-conntrack-extra is required for connbytes on OpenWRT)
|
||||
|
||||
For hosts change FORWARD to OUTPUT.
|
||||
|
||||
You can use `--queue-balance` with multiple instances of youtubeUnblock. This behavior is supported via multithreading. Just pass -DTHREADS_NUM=n where n stands for an amount of threads you want to be enabled. The n defaults to 1. The maximum threads defaults to 16 but may be altered programatically. Note, that if you are about to increase it, here is 100% chance that you are on the wrong way.
|
||||
|
||||
## OpenWRT case
|
||||
The package is also compatible with routers. The router should be running by linux-based system such as [OpenWRT](https://openwrt.org/).
|
||||
|
68
config.h
Normal file
68
config.h
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
struct config_t {
|
||||
unsigned int queue_start_num;
|
||||
int rawsocket;
|
||||
int threads;
|
||||
int use_gso;
|
||||
int fragmentation_strategy;
|
||||
unsigned char fake_sni_ttl;
|
||||
int fake_sni_strategy;
|
||||
int verbose;
|
||||
unsigned int seg2_delay;
|
||||
};
|
||||
extern struct config_t config;
|
||||
|
||||
#define MAX_THREADS 16
|
||||
|
||||
#ifndef THREADS_NUM
|
||||
#define THREADS_NUM 1
|
||||
#endif
|
||||
|
||||
#if THREADS_NUM > MAX_THREADS
|
||||
#error "Too much threads"
|
||||
#endif
|
||||
|
||||
#ifndef NOUSE_GSO
|
||||
#define USE_GSO
|
||||
#endif
|
||||
|
||||
#define FRAG_STRAT_TCP 0
|
||||
#define FRAG_STRAT_IP 1
|
||||
#define FRAG_STRAT_NONE 2
|
||||
|
||||
#ifndef FRAGMENTATION_STRATEGY
|
||||
#define FRAGMENTATION_STRATEGY FRAG_STRAT_TCP
|
||||
#endif
|
||||
|
||||
#define RAWSOCKET_MARK (1 << 15)
|
||||
|
||||
#ifdef USE_SEG2_DELAY
|
||||
#define SEG2_DELAY 100
|
||||
#endif
|
||||
|
||||
#define FAKE_SNI_TTL 8
|
||||
|
||||
// No fake SNI
|
||||
#define FKSN_STRAT_NONE 0
|
||||
// Will invalidate fake client hello by out-of-ack_seq out-of-seq request
|
||||
#define FKSN_STRAT_ACK_SEQ 1
|
||||
// Will assume that GGC server is located further than FAKE_SNI_TTL
|
||||
// Thus, Fake Client Hello will be eliminated automatically.
|
||||
#define FKSN_STRAT_TTL 2
|
||||
|
||||
|
||||
#ifdef NO_FAKE_SNI
|
||||
#define FAKE_SNI_STRATEGY FKSN_STRAT_NONE
|
||||
#endif
|
||||
|
||||
#ifndef FAKE_SNI_STRATEGY
|
||||
#define FAKE_SNI_STRATEGY FKSN_STRAT_ACK_SEQ
|
||||
#endif
|
||||
|
||||
#if !defined(SILENT) && !defined(KERNEL_SPACE)
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
// The Maximum Transmission Unit size for rawsocket
|
||||
// Larger packets will be fragmented. Applicable for Chrome's kyber.
|
||||
#define AVAILABLE_MTU 1384
|
1
deps/libnfnetlink/.gitignore
vendored
1
deps/libnfnetlink/.gitignore
vendored
@ -15,3 +15,4 @@ Makefile.in
|
||||
/stamp-h1
|
||||
|
||||
/*.pc
|
||||
doxygen.cfg
|
||||
|
180
deps/libnfnetlink/doxygen.cfg
vendored
180
deps/libnfnetlink/doxygen.cfg
vendored
@ -1,180 +0,0 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = libnfnetlink
|
||||
PROJECT_NUMBER = 1.0.2
|
||||
OUTPUT_DIRECTORY = doxygen
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF =
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
EXTRACT_ALL = NO
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
INPUT = .
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c libnfnetlink.h
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = */.git/* .*.d
|
||||
EXCLUDE_SYMBOLS = EXPORT_SYMBOL
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_STYLESHEET =
|
||||
GENERATE_HTMLHELP = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
GENERATE_MAN = YES
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = YES
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
SEARCHENGINE = NO
|
6
ipt_YTUNBLOCK.h
Normal file
6
ipt_YTUNBLOCK.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef IPT_YTUNBLOCK_H
|
||||
#define IPT_YTUNBLOCK_H
|
||||
|
||||
struct xt_ytunblock_tginfo {};
|
||||
|
||||
#endif /* IPT_YTUNBLOCK_H */
|
341
iptk_YTUNBLOCK.c
Normal file
341
iptk_YTUNBLOCK.c
Normal file
@ -0,0 +1,341 @@
|
||||
#define _GNU_SOURCE
|
||||
// Kernel module for youtubeUnblock.
|
||||
// Make with make kmake && sudo iptables -t mangle -D OUTPUT 1 && sudo make kreload && sudo iptables -t mangle -I OUTPUT -p tcp -j YTUNBLOCK
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "ipt_YTUNBLOCK.h"
|
||||
|
||||
#include "mangle.h"
|
||||
#include "config.h"
|
||||
#include "raw_replacements.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_AUTHOR("Vadim Vetrov <vetrovvd@gmail.com>");
|
||||
MODULE_DESCRIPTION("Linux kernel module for youtube unblock");
|
||||
|
||||
static int rsfd;
|
||||
static struct socket *rawsocket;
|
||||
DEFINE_MUTEX(rslock);
|
||||
|
||||
static int open_raw_socket(void) {
|
||||
int ret = 0;
|
||||
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_alert("Unable to create raw socket\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
sockptr_t optval = {
|
||||
.kernel = NULL,
|
||||
.is_kernel = 1
|
||||
};
|
||||
|
||||
int mark = RAWSOCKET_MARK;
|
||||
optval.kernel = &mark;
|
||||
ret = sock_setsockopt(rawsocket, SOL_SOCKET, SO_MARK, optval, sizeof(mark));
|
||||
if (ret < 0)
|
||||
{
|
||||
pr_alert("setsockopt(SO_MARK, %d) failed\n", mark);
|
||||
goto sr_err;
|
||||
}
|
||||
int one = 1;
|
||||
optval.kernel = &one;
|
||||
|
||||
return 0;
|
||||
sr_err:
|
||||
sock_release(rawsocket);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void close_raw_socket(void) {
|
||||
sock_release(rawsocket);
|
||||
}
|
||||
|
||||
#define AVAILABLE_MTU 1384
|
||||
|
||||
static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
|
||||
|
||||
if (pktlen > AVAILABLE_MTU) {
|
||||
pr_warn("The packet is too big and may cause issues!");
|
||||
|
||||
__u32 buff1_size = pktlen;
|
||||
__u32 buff2_size = pktlen;
|
||||
__u8 *buff1 = kmalloc(pktlen, GFP_ATOMIC);
|
||||
if (buff1 == NULL) return -1;
|
||||
__u8 *buff2 = kmalloc(pktlen, GFP_ATOMIC);
|
||||
if (buff2 == NULL) {
|
||||
kfree(buff1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
#if defined(USE_TCP_SEGMENTATION) || defined(RAWSOCK_TCP_FSTRAT)
|
||||
if ((ret = tcp4_frag(pkt, pktlen, AVAILABLE_MTU-128,
|
||||
buff1, &buff1_size, buff2, &buff2_size)) < 0)
|
||||
return ret;
|
||||
#elif defined(USE_IP_FRAGMENTATION) || defined(RAWSOCK_IP_FSTRAT)
|
||||
if ((ret = ip4_frag(pkt, pktlen, AVAILABLE_MTU-128,
|
||||
buff1, &buff1_size, buff2, &buff2_size)) < 0)
|
||||
return ret;
|
||||
#else
|
||||
pr_warn("send_raw_socket: Packet is too big but fragmentation is disabled! "
|
||||
"Pass -DRAWSOCK_TCP_FSTRAT or -DRAWSOCK_IP_FSTRAT as CFLAGS "
|
||||
"To enable it only for raw socket\n");
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
int sent = 0;
|
||||
ret = send_raw_socket(buff1, buff1_size);
|
||||
|
||||
if (ret >= 0) sent += ret;
|
||||
else {
|
||||
kfree(buff1);
|
||||
kfree(buff2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
kfree(buff1);
|
||||
|
||||
ret = send_raw_socket(buff2, buff2_size);
|
||||
if (ret >= 0) sent += ret;
|
||||
else {
|
||||
kfree(buff2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
kfree(buff2);
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
struct iphdr *iph;
|
||||
|
||||
int ret;
|
||||
if ((ret = ip4_payload_split(
|
||||
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sockaddr_in daddr = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = 0,
|
||||
.sin_addr = {
|
||||
.s_addr = iph->daddr
|
||||
}
|
||||
};
|
||||
|
||||
struct msghdr msg;
|
||||
struct kvec iov;
|
||||
iov.iov_base = (__u8 *)pkt;
|
||||
iov.iov_len = pktlen;
|
||||
iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, 1);
|
||||
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_name = &daddr;
|
||||
msg.msg_namelen = sizeof(struct sockaddr_in);
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
|
||||
mutex_lock(&rslock);
|
||||
ret = kernel_sendmsg(rawsocket, &msg, &iov, 1, pktlen);
|
||||
mutex_unlock(&rslock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static unsigned int ykb_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
if ((skb->mark & RAWSOCKET_MARK) == RAWSOCKET_MARK)
|
||||
return XT_CONTINUE;
|
||||
|
||||
if (skb->head == NULL) return XT_CONTINUE;
|
||||
|
||||
// TODO: Mallocs are bad!
|
||||
uint32_t buflen = skb->len;
|
||||
__u8 *buf = kmalloc(skb->len, GFP_ATOMIC);
|
||||
if (buf == NULL) {
|
||||
pr_err("Cannot alloc enough buffer space");
|
||||
goto accept;
|
||||
}
|
||||
if (skb_copy_bits(skb, 0, buf, skb->len) < 0) {
|
||||
pr_err("Unable copy bits\n");
|
||||
goto ac_fkb;
|
||||
}
|
||||
struct iphdr *iph;
|
||||
uint32_t iph_len;
|
||||
struct tcphdr *tcph;
|
||||
uint32_t tcph_len;
|
||||
__u8 *payload;
|
||||
uint32_t plen;
|
||||
|
||||
int ret = tcp4_payload_split(buf, buflen, &iph, &iph_len,
|
||||
&tcph, &tcph_len, &payload, &plen);
|
||||
|
||||
if (ret < 0)
|
||||
goto ac_fkb;
|
||||
|
||||
struct verdict vrd = analyze_tls_data(payload, plen);
|
||||
|
||||
if (vrd.gvideo_hello) {
|
||||
int ret;
|
||||
pr_info("Googlevideo detected\n");
|
||||
|
||||
ip4_set_checksum(iph);
|
||||
tcp4_set_checksum(tcph, iph);
|
||||
|
||||
uint32_t f1len = skb->len;
|
||||
uint32_t f2len = skb->len;
|
||||
__u8 *frag1 = kmalloc(f1len, GFP_ATOMIC);
|
||||
if (!frag1) {
|
||||
pr_err("Cannot alloc enough gv frag1 buffer space");
|
||||
goto ac_fkb;
|
||||
}
|
||||
__u8 *frag2 = kmalloc(f2len, GFP_ATOMIC);
|
||||
if (!frag2) {
|
||||
pr_err("Cannot alloc enough gv frag1 buffer space");
|
||||
kfree(frag1);
|
||||
goto ac_fkb;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FAKE_SNI
|
||||
uint32_t fksn_len = FAKE_SNI_MAXLEN;
|
||||
__u8 *fksn_buf = kmalloc(fksn_len, GFP_ATOMIC);
|
||||
if (!fksn_buf) {
|
||||
pr_err("Cannot alloc enough gksn buffer space");
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
ret = gen_fake_sni(iph, tcph, fksn_buf, &fksn_len);
|
||||
if (ret < 0) {
|
||||
pr_err("Cannot alloc enough gksn buffer space");
|
||||
goto fksn_fb;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_TCP_SEGMENTATION)
|
||||
size_t ipd_offset = vrd.sni_offset;
|
||||
size_t mid_offset = ipd_offset + vrd.sni_len / 2;
|
||||
|
||||
|
||||
if ((ret = tcp4_frag(buf, skb->len,
|
||||
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
|
||||
pr_err("tcp4_frag: %d", ret);
|
||||
goto fksn_fb;
|
||||
}
|
||||
#elif defined(USE_IP_FRAGMENTATION)
|
||||
size_t ipd_offset = tcph_len + vrd.sni_offset;
|
||||
size_t mid_offset = ipd_offset + vrd.sni_len / 2;
|
||||
mid_offset += 8 - mid_offset % 8;
|
||||
|
||||
if ((ret = ip4_frag(buf, skb->len,
|
||||
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
|
||||
pr_err("ip4_frag: %d", ret);
|
||||
goto fksn_fb;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FAKE_SNI
|
||||
ret = send_raw_socket(fksn_buf, fksn_len);
|
||||
if (ret < 0) {
|
||||
pr_err("fksn_send: %d", ret);
|
||||
goto fksn_fb;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_NO_FRAGMENTATION)
|
||||
#ifdef SEG2_DELAY
|
||||
#error "SEG2_DELAY is incompatible with NO FRAGMENTATION"
|
||||
#endif
|
||||
ret = send_raw_socket(buf, buflen);
|
||||
if (ret < 0) {
|
||||
pr_err("nofrag_send: %d", ret);
|
||||
}
|
||||
goto fksn_fb;
|
||||
#endif
|
||||
|
||||
ret = send_raw_socket(frag2, f2len);
|
||||
if (ret < 0) {
|
||||
pr_err("raw frag2 send: %d", ret);
|
||||
goto fksn_fb;
|
||||
}
|
||||
|
||||
#ifdef SEG2_DELAY
|
||||
#error "Seg2 delay is unsupported yet for kmod"
|
||||
#else
|
||||
ret = send_raw_socket(frag1, f1len);
|
||||
if (ret < 0) {
|
||||
pr_err("raw frag1 send: %d", ret);
|
||||
goto fksn_fb;
|
||||
}
|
||||
#endif
|
||||
|
||||
fksn_fb:
|
||||
#ifdef FAKE_SNI
|
||||
kfree(fksn_buf);
|
||||
#endif
|
||||
fallback:
|
||||
#ifndef SEG2_DELAY
|
||||
kfree(frag1);
|
||||
#endif
|
||||
kfree(frag2);
|
||||
kfree(buf);
|
||||
kfree_skb(skb);
|
||||
return NF_STOLEN;
|
||||
}
|
||||
ac_fkb:
|
||||
kfree(buf);
|
||||
accept:
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int ykb_chk(const struct xt_tgchk_param *par) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct xt_target ykb_tg_reg __read_mostly = {
|
||||
.name = "YTUNBLOCK",
|
||||
.target = ykb_tg,
|
||||
.table = "mangle",
|
||||
.hooks = (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_FORWARD),
|
||||
.targetsize = sizeof(struct xt_ytunblock_tginfo),
|
||||
.proto = IPPROTO_TCP,
|
||||
.family = NFPROTO_IPV4,
|
||||
.checkentry = ykb_chk,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init ykb_init(void) {
|
||||
int ret = 0;
|
||||
|
||||
ret = open_raw_socket();
|
||||
if (ret < 0) goto err;
|
||||
|
||||
ret = xt_register_target(&ykb_tg_reg);
|
||||
if (ret < 0) goto close_rawsocket;
|
||||
|
||||
pr_info("youtubeUnblock kernel module started.\n");
|
||||
return 0;
|
||||
close_rawsocket:
|
||||
close_raw_socket();
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ykb_destroy(void) {
|
||||
xt_unregister_target(&ykb_tg_reg);
|
||||
close_raw_socket();
|
||||
pr_info("youtubeUnblock kernel module destroyed.\n");
|
||||
}
|
||||
|
||||
module_init(ykb_init);
|
||||
module_exit(ykb_destroy);
|
42
kmake.mk
Normal file
42
kmake.mk
Normal file
@ -0,0 +1,42 @@
|
||||
#Kernel module makes here
|
||||
PWD := $(CURDIR)
|
||||
|
||||
CC := gcc
|
||||
CCLD := $(CC)
|
||||
LD := ld
|
||||
CFLAGS :=
|
||||
LDFLAGS :=
|
||||
|
||||
IPT_CFLAGS := -Wall -Wpedantic -O2
|
||||
|
||||
.PHONY: kmake kload kunload kreload kclean kmclean xclean
|
||||
kmake: kmod xmod
|
||||
|
||||
kmod:
|
||||
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
|
||||
xmod: libipt_YTUNBLOCK.so
|
||||
|
||||
libipt_YTUNBLOCK.so: libipt_YTUNBLOCK.o
|
||||
$(CCLD) -shared -fPIC ${IPT_CFLAGS} -o $@ $^;
|
||||
|
||||
libipt_YTUNBLOCK.o: libipt_YTUNBLOCK.c
|
||||
$(CC) ${IPT_CFLAGS} -D_INIT=lib$*_init -fPIC -c -o $@ $<;
|
||||
|
||||
kload:
|
||||
insmod ipt_YTUNBLOCK.ko
|
||||
cp ./libipt_YTUNBLOCK.so /usr/lib/xtables/
|
||||
|
||||
kunload:
|
||||
-rmmod ipt_YTUNBLOCK
|
||||
-/bin/rm /usr/lib/xtables/libipt_YTUNBLOCK.so
|
||||
|
||||
kreload: kunload kload
|
||||
|
||||
kclean: xtclean kmclean
|
||||
|
||||
kmclean:
|
||||
-$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
||||
|
||||
xtclean:
|
||||
-/bin/rm -f libipt_YTUNBLOCK.so libipt_YTUNBLOCK.o
|
26
libipt_YTUNBLOCK.c
Normal file
26
libipt_YTUNBLOCK.c
Normal file
@ -0,0 +1,26 @@
|
||||
// Used to register target in iptables
|
||||
#include <stdio.h>
|
||||
#include <xtables.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ipt_YTUNBLOCK.h"
|
||||
|
||||
#define _init __attribute__((constructor)) _INIT
|
||||
#define __maybe_unused __attribute__((__unused__))
|
||||
|
||||
static void YTKB_help(void) {
|
||||
printf("Youtube Unblock - bypass youtube slowdown DPI in Russia\n");
|
||||
}
|
||||
|
||||
static struct xtables_target ykb_tg_reg = {
|
||||
.name = "YTUNBLOCK",
|
||||
.version = XTABLES_VERSION,
|
||||
.family = NFPROTO_IPV4,
|
||||
.size = XT_ALIGN(sizeof(struct xt_ytunblock_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_ytunblock_tginfo)),
|
||||
.help = YTKB_help,
|
||||
};
|
||||
|
||||
void _init(void) {
|
||||
xtables_register_target(&ykb_tg_reg);
|
||||
}
|
473
mangle.c
Normal file
473
mangle.c
Normal file
@ -0,0 +1,473 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "mangle.h"
|
||||
#include "raw_replacements.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
#include <linux/printk.h>
|
||||
#include <linux/ip.h>
|
||||
|
||||
#define printf pr_info
|
||||
#define perror pr_err
|
||||
#define lgerror(msg, ret) (pr_err(msg ": %d\n", ret))
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
|
||||
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
|
||||
|
||||
typedef uint8_t __u8;
|
||||
typedef uint32_t __u32;
|
||||
typedef uint16_t __u16;
|
||||
|
||||
#define lgerror(msg, ret) __extension__ ({errno = -ret; perror(msg);})
|
||||
#endif
|
||||
|
||||
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
|
||||
{
|
||||
#ifdef KERNEL_SPACE
|
||||
uint32_t tcp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
|
||||
tcph->check = 0;
|
||||
tcph->check = csum_tcpudp_magic(
|
||||
iph->saddr, iph->daddr, tcp_packet_len,
|
||||
IPPROTO_TCP,
|
||||
csum_partial(tcph, tcp_packet_len, 0));
|
||||
#else
|
||||
nfq_tcp_compute_checksum_ipv4(tcph, iph);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ip4_set_checksum(struct iphdr *iph)
|
||||
{
|
||||
#ifdef KERNEL_SPACE
|
||||
iph->check = 0;
|
||||
iph->check = ip_fast_csum(iph, iph->ihl);
|
||||
#else
|
||||
nfq_ip_set_checksum(iph);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int ip4_payload_split(__u8 *pkt, __u32 buflen,
|
||||
struct iphdr **iph, __u32 *iph_len,
|
||||
__u8 **payload, __u32 *plen) {
|
||||
if (pkt == NULL || buflen < sizeof(struct iphdr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct iphdr *hdr = (struct iphdr *)pkt;
|
||||
if (hdr->version != IPVERSION) return -EINVAL;
|
||||
|
||||
__u32 hdr_len = hdr->ihl * 4;
|
||||
__u32 pktlen = ntohs(hdr->tot_len);
|
||||
if (buflen < pktlen || hdr_len > pktlen) return -EINVAL;
|
||||
|
||||
if (iph)
|
||||
*iph = hdr;
|
||||
if (iph_len)
|
||||
*iph_len = hdr_len;
|
||||
if (payload)
|
||||
*payload = pkt + hdr_len;
|
||||
if (plen)
|
||||
*plen = pktlen - hdr_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tcp4_payload_split(__u8 *pkt, __u32 buflen,
|
||||
struct iphdr **iph, __u32 *iph_len,
|
||||
struct tcphdr **tcph, __u32 *tcph_len,
|
||||
__u8 **payload, __u32 *plen) {
|
||||
struct iphdr *hdr;
|
||||
__u32 hdr_len;
|
||||
struct tcphdr *thdr;
|
||||
__u32 thdr_len;
|
||||
|
||||
__u8 *tcph_pl;
|
||||
__u32 tcph_plen;
|
||||
|
||||
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
|
||||
&tcph_pl, &tcph_plen)){
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
hdr->protocol != IPPROTO_TCP ||
|
||||
tcph_plen < sizeof(struct tcphdr)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
thdr = (struct tcphdr *)(tcph_pl);
|
||||
thdr_len = thdr->doff * 4;
|
||||
|
||||
if (thdr_len > tcph_plen) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iph) *iph = hdr;
|
||||
if (iph_len) *iph_len = hdr_len;
|
||||
if (tcph) *tcph = thdr;
|
||||
if (tcph_len) *tcph_len = thdr_len;
|
||||
if (payload) *payload = tcph_pl + thdr_len;
|
||||
if (plen) *plen = tcph_plen - thdr_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// split packet to two ipv4 fragments.
|
||||
int ip4_frag(const __u8 *pkt, __u32 buflen, __u32 payload_offset,
|
||||
__u8 *frag1, __u32 *f1len,
|
||||
__u8 *frag2, __u32 *f2len) {
|
||||
|
||||
struct iphdr *hdr;
|
||||
const __u8 *payload;
|
||||
__u32 plen;
|
||||
__u32 hdr_len;
|
||||
int ret;
|
||||
|
||||
if (!frag1 || !f1len || !frag2 || !f2len)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ret = ip4_payload_split(
|
||||
(__u8 *)pkt, buflen,
|
||||
&hdr, &hdr_len, (__u8 **)&payload, &plen)) < 0) {
|
||||
lgerror("ipv4_frag: TCP Header extract error", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (plen <= payload_offset) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (payload_offset & ((1 << 3) - 1)) {
|
||||
lgerror("ipv4_frag: Payload offset MUST be a multiply of 8!", -EINVAL);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__u32 f1_plen = payload_offset;
|
||||
__u32 f1_dlen = f1_plen + hdr_len;
|
||||
|
||||
__u32 f2_plen = plen - payload_offset;
|
||||
__u32 f2_dlen = f2_plen + hdr_len;
|
||||
|
||||
if (*f1len < f1_dlen || *f2len < f2_dlen) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
*f1len = f1_dlen;
|
||||
*f2len = f2_dlen;
|
||||
|
||||
memcpy(frag1, hdr, hdr_len);
|
||||
memcpy(frag2, hdr, hdr_len);
|
||||
|
||||
memcpy(frag1 + hdr_len, payload, f1_plen);
|
||||
memcpy(frag2 + hdr_len, payload + payload_offset, f2_plen);
|
||||
|
||||
struct iphdr *f1_hdr = (void *)frag1;
|
||||
struct iphdr *f2_hdr = (void *)frag2;
|
||||
|
||||
__u16 f1_frag_off = ntohs(f1_hdr->frag_off);
|
||||
__u16 f2_frag_off = ntohs(f2_hdr->frag_off);
|
||||
|
||||
f1_frag_off &= IP_OFFMASK;
|
||||
f1_frag_off |= IP_MF;
|
||||
|
||||
if ((f2_frag_off & ~IP_OFFMASK) == IP_MF) {
|
||||
f2_frag_off &= IP_OFFMASK;
|
||||
f2_frag_off |= IP_MF;
|
||||
} else {
|
||||
f2_frag_off &= IP_OFFMASK;
|
||||
}
|
||||
|
||||
f2_frag_off += (__u16)payload_offset / 8;
|
||||
|
||||
f1_hdr->frag_off = htons(f1_frag_off);
|
||||
f1_hdr->tot_len = htons(f1_dlen);
|
||||
|
||||
f2_hdr->frag_off = htons(f2_frag_off);
|
||||
f2_hdr->tot_len = htons(f2_dlen);
|
||||
|
||||
|
||||
if (config.verbose)
|
||||
printf("Packet split in portion %u %u\n", f1_plen, f2_plen);
|
||||
|
||||
ip4_set_checksum(f1_hdr);
|
||||
ip4_set_checksum(f2_hdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// split packet to two tcp-on-ipv4 segments.
|
||||
int tcp4_frag(const __u8 *pkt, __u32 buflen, __u32 payload_offset,
|
||||
__u8 *seg1, __u32 *s1len,
|
||||
__u8 *seg2, __u32 *s2len) {
|
||||
|
||||
struct iphdr *hdr;
|
||||
__u32 hdr_len;
|
||||
struct tcphdr *tcph;
|
||||
__u32 tcph_len;
|
||||
__u32 plen;
|
||||
const __u8 *payload;
|
||||
int ret;
|
||||
|
||||
if (!seg1 || !s1len || !seg2 || !s2len)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ret = tcp4_payload_split((__u8 *)pkt, buflen,
|
||||
&hdr, &hdr_len,
|
||||
&tcph, &tcph_len,
|
||||
(__u8 **)&payload, &plen)) < 0) {
|
||||
lgerror("tcp4_frag: tcp4_payload_split", ret);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
ntohs(hdr->frag_off) & IP_MF ||
|
||||
ntohs(hdr->frag_off) & IP_OFFMASK) {
|
||||
printf("tcp4_frag: frag value: %d\n",
|
||||
ntohs(hdr->frag_off));
|
||||
lgerror("tcp4_frag: ip fragmentation is set", -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (plen <= payload_offset) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__u32 s1_plen = payload_offset;
|
||||
__u32 s1_dlen = s1_plen + hdr_len + tcph_len;
|
||||
|
||||
__u32 s2_plen = plen - payload_offset;
|
||||
__u32 s2_dlen = s2_plen + hdr_len + tcph_len;
|
||||
|
||||
if (*s1len < s1_dlen || *s2len < s2_dlen)
|
||||
return -ENOMEM;
|
||||
|
||||
*s1len = s1_dlen;
|
||||
*s2len = s2_dlen;
|
||||
|
||||
memcpy(seg1, hdr, hdr_len);
|
||||
memcpy(seg2, hdr, hdr_len);
|
||||
|
||||
memcpy(seg1 + hdr_len, tcph, tcph_len);
|
||||
memcpy(seg2 + hdr_len, tcph, tcph_len);
|
||||
|
||||
memcpy(seg1 + hdr_len + tcph_len, payload, s1_plen);
|
||||
memcpy(seg2 + hdr_len + tcph_len, payload + payload_offset, s2_plen);
|
||||
|
||||
struct iphdr *s1_hdr = (void *)seg1;
|
||||
struct iphdr *s2_hdr = (void *)seg2;
|
||||
|
||||
struct tcphdr *s1_tcph = (void *)(seg1 + hdr_len);
|
||||
struct tcphdr *s2_tcph = (void *)(seg2 + hdr_len);
|
||||
|
||||
s1_hdr->tot_len = htons(s1_dlen);
|
||||
s2_hdr->tot_len = htons(s2_dlen);
|
||||
|
||||
s2_tcph->seq = htonl(ntohl(s2_tcph->seq) + payload_offset);
|
||||
|
||||
if (config.verbose)
|
||||
printf("Packet split in portion %u %u\n", s1_plen, s2_plen);
|
||||
|
||||
tcp4_set_checksum(s1_tcph, s1_hdr);
|
||||
tcp4_set_checksum(s2_tcph, s2_hdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
|
||||
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
|
||||
#define TLS_EXTENSION_SNI 0x0000
|
||||
#define TLS_EXTENSION_CLIENT_HELLO_ENCRYPTED 0xfe0d
|
||||
|
||||
const char googlevideo_ending[] = "googlevideo.com";
|
||||
const int googlevideo_len = 15;
|
||||
|
||||
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u32 uint32_t;
|
||||
typedef __u16 uint16_t;
|
||||
|
||||
/**
|
||||
* Processes tls payload of the tcp request.
|
||||
*
|
||||
* data Payload data of TCP.
|
||||
* dlen Length of `data`.
|
||||
*/
|
||||
struct verdict analyze_tls_data(
|
||||
const uint8_t *data,
|
||||
uint32_t dlen)
|
||||
{
|
||||
struct verdict vrd = {0};
|
||||
|
||||
size_t i = 0;
|
||||
const uint8_t *data_end = data + dlen;
|
||||
|
||||
while (i + 4 < dlen) {
|
||||
const uint8_t *msgData = data + i;
|
||||
|
||||
uint8_t tls_content_type = *msgData;
|
||||
uint8_t tls_vmajor = *(msgData + 1);
|
||||
uint8_t tls_vminor = *(msgData + 2);
|
||||
uint16_t message_length = ntohs(*(uint16_t *)(msgData + 3));
|
||||
const uint8_t *message_length_ptr = msgData + 3;
|
||||
|
||||
|
||||
if (i + 5 + message_length > dlen) break;
|
||||
|
||||
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
|
||||
goto nextMessage;
|
||||
|
||||
|
||||
const uint8_t *handshakeProto = msgData + 5;
|
||||
|
||||
if (handshakeProto + 1 >= data_end) break;
|
||||
|
||||
uint8_t handshakeType = *handshakeProto;
|
||||
|
||||
if (handshakeType != TLS_HANDSHAKE_TYPE_CLIENT_HELLO)
|
||||
goto nextMessage;
|
||||
|
||||
const uint8_t *msgPtr = handshakeProto;
|
||||
msgPtr += 1;
|
||||
const uint8_t *handshakeProto_length_ptr = msgPtr + 1;
|
||||
msgPtr += 3 + 2 + 32;
|
||||
|
||||
if (msgPtr + 1 >= data_end) break;
|
||||
uint8_t sessionIdLength = *msgPtr;
|
||||
msgPtr++;
|
||||
msgPtr += sessionIdLength;
|
||||
|
||||
if (msgPtr + 2 >= data_end) break;
|
||||
uint16_t ciphersLength = ntohs(*(uint16_t *)msgPtr);
|
||||
msgPtr += 2;
|
||||
msgPtr += ciphersLength;
|
||||
|
||||
if (msgPtr + 1 >= data_end) break;
|
||||
uint8_t compMethodsLen = *msgPtr;
|
||||
msgPtr++;
|
||||
msgPtr += compMethodsLen;
|
||||
|
||||
if (msgPtr + 2 >= data_end) break;
|
||||
uint16_t extensionsLen = ntohs(*(uint16_t *)msgPtr);
|
||||
const uint8_t *extensionsLen_ptr = msgPtr;
|
||||
msgPtr += 2;
|
||||
|
||||
const uint8_t *extensionsPtr = msgPtr;
|
||||
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
|
||||
if (extensions_end > data_end) break;
|
||||
|
||||
while (extensionsPtr < extensions_end) {
|
||||
const uint8_t *extensionPtr = extensionsPtr;
|
||||
if (extensionPtr + 4 >= extensions_end) break;
|
||||
|
||||
uint16_t extensionType =
|
||||
ntohs(*(uint16_t *)extensionPtr);
|
||||
extensionPtr += 2;
|
||||
|
||||
uint16_t extensionLen =
|
||||
ntohs(*(uint16_t *)extensionPtr);
|
||||
const uint8_t *extensionLen_ptr = extensionPtr;
|
||||
extensionPtr += 2;
|
||||
|
||||
|
||||
if (extensionPtr + extensionLen > extensions_end)
|
||||
break;
|
||||
|
||||
if (extensionType != TLS_EXTENSION_SNI)
|
||||
goto nextExtension;
|
||||
|
||||
const uint8_t *sni_ext_ptr = extensionPtr;
|
||||
|
||||
if (sni_ext_ptr + 2 >= extensions_end) break;
|
||||
uint16_t sni_ext_dlen = ntohs(*(uint16_t *)sni_ext_ptr);
|
||||
|
||||
const uint8_t *sni_ext_dlen_ptr = sni_ext_ptr;
|
||||
sni_ext_ptr += 2;
|
||||
|
||||
const uint8_t *sni_ext_end = sni_ext_ptr + sni_ext_dlen;
|
||||
if (sni_ext_end >= extensions_end) break;
|
||||
|
||||
if (sni_ext_ptr + 3 >= sni_ext_end) break;
|
||||
uint8_t sni_type = *sni_ext_ptr++;
|
||||
uint16_t sni_len = ntohs(*(uint16_t *)sni_ext_ptr);
|
||||
sni_ext_ptr += 2;
|
||||
|
||||
if (sni_ext_ptr + sni_len > sni_ext_end) break;
|
||||
|
||||
char *sni_name = (char *)sni_ext_ptr;
|
||||
// sni_len
|
||||
|
||||
vrd.sni_offset = (uint8_t *)sni_name - data;
|
||||
vrd.sni_len = sni_len;
|
||||
|
||||
char *gv_startp = sni_name + sni_len - googlevideo_len;
|
||||
if (sni_len >= googlevideo_len &&
|
||||
sni_len < 128 &&
|
||||
!strncmp(gv_startp,
|
||||
googlevideo_ending,
|
||||
googlevideo_len)) {
|
||||
|
||||
vrd.gvideo_hello = 1;
|
||||
}
|
||||
|
||||
nextExtension:
|
||||
extensionsPtr += 2 + 2 + extensionLen;
|
||||
}
|
||||
nextMessage:
|
||||
i += 5 + message_length;
|
||||
}
|
||||
|
||||
return vrd;
|
||||
}
|
||||
|
||||
int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
|
||||
uint8_t *buf, uint32_t *buflen) {
|
||||
|
||||
if (!iph || !tcph || !buf || !buflen)
|
||||
return -EINVAL;
|
||||
|
||||
int ip_len = iph->ihl * 4;
|
||||
size_t data_len = sizeof(fake_sni);
|
||||
|
||||
size_t dlen = data_len + ip_len;
|
||||
|
||||
if (*buflen < dlen)
|
||||
return -ENOMEM;
|
||||
*buflen = dlen;
|
||||
|
||||
memcpy(buf, iph, ip_len);
|
||||
memcpy(buf + ip_len, fake_sni, data_len);
|
||||
struct iphdr *niph = (struct iphdr *)buf;
|
||||
|
||||
niph->protocol = IPPROTO_TCP;
|
||||
niph->tot_len = htons(dlen);
|
||||
|
||||
int ret = 0;
|
||||
struct tcphdr *ntcph = (struct tcphdr *)(buf + ip_len);
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
ntcph->dest = tcph->dest;
|
||||
ntcph->source = tcph->source;
|
||||
#else
|
||||
ntcph->th_dport = tcph->th_dport;
|
||||
ntcph->th_sport = tcph->th_sport;
|
||||
|
||||
#if FAKE_SNI_STRATEGY == FKSN_STRAT_TTL
|
||||
ntcph->ack = tcph->ack;
|
||||
ntcph->ack_seq = tcph->ack_seq;
|
||||
niph->ttl = FAKE_SNI_TTL;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
ip4_set_checksum(niph);
|
||||
tcp4_set_checksum(ntcph, niph);
|
||||
|
||||
return 0;
|
||||
}
|
66
mangle.h
Normal file
66
mangle.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef YU_MANGLE_H
|
||||
#define YU_MANGLE_H
|
||||
|
||||
#ifdef KERNEL_SPACE
|
||||
#include <linux/types.h>
|
||||
typedef __u8 uint8_t;
|
||||
typedef __u32 uint32_t;
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/* from <netinet/ip.h> */
|
||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
||||
#define IP_DF 0x4000 /* dont fragment flag */
|
||||
#define IP_MF 0x2000 /* more fragments flag */
|
||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||
#else
|
||||
#define USER_SPACE
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
struct verdict {
|
||||
int gvideo_hello; /* google video hello packet */
|
||||
int sni_offset; /* offset from start of tcp _payload_ */
|
||||
int sni_len;
|
||||
};
|
||||
|
||||
struct verdict analyze_tls_data(const uint8_t *data, uint32_t dlen);
|
||||
|
||||
int ip4_frag(const uint8_t *pkt, uint32_t pktlen,
|
||||
uint32_t payload_offset,
|
||||
uint8_t *frag1, uint32_t *f1len,
|
||||
uint8_t *frag2, uint32_t *f2len);
|
||||
|
||||
int tcp4_frag(const uint8_t *pkt, uint32_t pktlen,
|
||||
uint32_t payload_offset,
|
||||
uint8_t *seg1, uint32_t *s1len,
|
||||
uint8_t *seg2, uint32_t *s2len);
|
||||
|
||||
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||
struct iphdr **iph, uint32_t *iph_len,
|
||||
uint8_t **payload, uint32_t *plen);
|
||||
|
||||
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
|
||||
struct iphdr **iph, uint32_t *iph_len,
|
||||
struct tcphdr **tcph, uint32_t *tcph_len,
|
||||
uint8_t **payload, uint32_t *plen);
|
||||
|
||||
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph);
|
||||
void ip4_set_checksum(struct iphdr *iph);
|
||||
|
||||
int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
|
||||
uint8_t *buf, uint32_t *buflen);
|
||||
#endif /* YU_MANGLE_H */
|
@ -1,6 +1,9 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
USE_PROCD=1
|
||||
|
||||
START=50
|
||||
STOP=50
|
||||
|
||||
# Openwrt procd script: https://openwrt.org/docs/guide-developer/procd-init-script-example
|
||||
# The program should be put into /usr/bin/
|
||||
# This file should be put into /etc/init.d/
|
||||
|
@ -1,6 +1,9 @@
|
||||
#ifndef RAW_REPLACEMENTS_H
|
||||
#define RAW_REPLACEMENTS_H
|
||||
|
||||
const char fake_sni[] = "\276(\001\273\366\234|\335\213\222\023\330\200\030\001\366\350e\000\000\001\001\b\n}\355\267Hm/\217\347\026\003\001\004\316\001\000\004\312\003\003K+\272\314\340\306\374>dw%\f\223\346\225\270\270~\335\027\f\264\341H\267\357\303\216T\322[\371 \245\320\212V6\374\3706\232\0216B\325\273P\b\300>\0332>\362\323\033\322\301\204\022f8\223\214\000\"\023\001\023\003\023\002\300+\300/\314\251\314\250\300,\3000\300\n\300\t\300\023\300\024\000\234\000\235\000/\0005\001\000\004_\000\000\000\023\000\021\000\000\016www.google.com\000\027\000\000\377\001\000\001\000\000\n\000\016\000\f\000\035\000\027\000\030\000\031\001\000\001\001\000\v\000\002\001\000\000\020\000\v\000\t\bhttp/1.1\000\005\000\005\001\000\000\000\000\000\"\000\n\000\b\004\003\005\003\006\003\002\003\0003\000k\000i\000\035\000 \333C\212\234-\t\237#\202\\\231\311\022]\333\341t(\t\276U\373u\234\316J~,^|*Z\000\027\000A\004k\n\255\254\376X\226t\001;n~\033\034.\245\027\024\3762_\352$\374\346^f\fF,\201\275\263\336O\231\001\032\200\357dI\266y\031\323\311vR\232\004\r\366FT\004\335\326\356\256\230B\t\313\000*\000\000\000+\000\005\004\003\004\003\003\000\r\000\030\000\026\004\003\005\003\006\003\b\004\b\005\b\006\004\001\005\001\006\001\002\003\002\001\000-\000\002\001\001\000\034\000\002@\001\376\r\0029\000\000\001\000\003\344\000 \337\306\243\332Y\033\a\252\352\025\365Z\035\223\226\304\255\363\215G\356g\344%}7\217\033n\211^\201\002\017g\267\334\326OD}\336\341ZC\230\226'\225\313\357\211\\\242\273\030k\216\377U\315\206\2410\200\203\332Z\223\005\370\b\304\370f\017\200\023\241\223~?\270{\037b\312\001\270\227\366\356\352\002\314\351\006\237\241q\226\300\314\321o\247{\201\317\230}B\005T\3660\335\320\332r?S\217\tq\036\031\326I|\237]\311 c\f\024r\031\310W\373\257\314q)q\030\237\261\227\217Kd?\257'G\320\020\340\256ND\247\005\341\324\024OP>\370\350\270b\311wAj\t\311\213\365i\203\230x\207\354\245<\274\202\230c\v0Y\263\364\022\303a\200\022\031\314\271rl=\327\336\001\327\264\267\342\353\352=\354[u\224\260\257\034\004\232\023\226}\227\030e\221\"\350\207\027dId\324\305\362N:\035\307`\204\337\201;\221\320\266b\362hrH\345e\206\246%\006\020a4\3430\036\225\215\274\275\360Q&\271\237)\222uK\362\017o\220\226W\357\267#\357\v\023\354\213\2629\331\ad\005/~6k\000[\247\301\270\310qJ\004\303|m5\363\376Y\002\243}6\251x\024\331)GH\335\205rI\032\f\210\a\212\347]\271\030\347.\021\213\365\026\030\340/Ny\r\332\3577\3203\026iX}>\2507\327&XRXU!\017\270I\313\352\350^?\352Uss\017\266pF\222NI\245\307_\305#\361\352\243+-\266\317Q\036s\243\277\355{S&\023>\275\360\215\032V\237XOY\345u>\002\305\252T\354\035\327v{P\352M\233\366\221\270\377\251\261f+rF\201wL2W\266X\252\242X\2536I\337c\205uZ\254Fe\305h\t\371\376\216r\336Y\327h\347*\331\257-ZQ{(\336\226\206\017\037\036\021\341\027z\033\254\235\252\227\224\004?p\243\351\\\263\352\205\327#W\345\255\256\375\267bP\3047\363!*K\003t\212(\306\214P\215\3506j\025\375\213e\254s\000)\001\034\000\367\000\361\002\276W%\232?\326\223\277\211v\017\a\361\347\312N\226\024L\260v\210\271j\324[|\270\344\3773\321-\313b>~\310\253XIR\324)&;\033{g;)\344\255\226\370\347I\\y\020\324\360\211vC\310\226s\267|\273$\341\332\2045qh\245w\2255\214\316\030\255\301\326C\343\304=\245\231h`yd\000#s\002\370\374Z\0336\245\361\226\222\306\032k\2457\016h\314(R;\326T~EHH\352\307\023^\247\363\321`V\340\253Z\233\357\227I\373\337z\177\nv\261\252\371\017\226\223\345\005\315y4\b\236N0\2630\017\215c\305&L\260\346J\237\203Q(\335W\027|>\3553\275j\307?W5\3463kc\350\262C\361 \037w!\371}\214\"I\377|\331@a;\342\3566\312\272Z\327u7\204'\215YBLL\235\236\242\345\215\245T\211a\312\263\342\000! \221\202X$\302\317\203\246\207c{\231\330\264\324\\k\271\272\336\356\002|\261O\207\030+\367P\317\356";
|
||||
#define FAKE_SNI_MAXLEN 1500
|
||||
|
||||
static const char fake_sni[] = "\276(\001\273\366\234|\335\213\222\023\330\200\030\001\366\350e\000\000\001\001\b\n}\355\267Hm/\217\347\026\003\001\004\316\001\000\004\312\003\003K+\272\314\340\306\374>dw%\f\223\346\225\270\270~\335\027\f\264\341H\267\357\303\216T\322[\371 \245\320\212V6\374\3706\232\0216B\325\273P\b\300>\0332>\362\323\033\322\301\204\022f8\223\214\000\"\023\001\023\003\023\002\300+\300/\314\251\314\250\300,\3000\300\n\300\t\300\023\300\024\000\234\000\235\000/\0005\001\000\004_\000\000\000\023\000\021\000\000\016www.google.com\000\027\000\000\377\001\000\001\000\000\n\000\016\000\f\000\035\000\027\000\030\000\031\001\000\001\001\000\v\000\002\001\000\000\020\000\v\000\t\bhttp/1.1\000\005\000\005\001\000\000\000\000\000\"\000\n\000\b\004\003\005\003\006\003\002\003\0003\000k\000i\000\035\000 \333C\212\234-\t\237#\202\\\231\311\022]\333\341t(\t\276U\373u\234\316J~,^|*Z\000\027\000A\004k\n\255\254\376X\226t\001;n~\033\034.\245\027\024\3762_\352$\374\346^f\fF,\201\275\263\336O\231\001\032\200\357dI\266y\031\323\311vR\232\004\r\366FT\004\335\326\356\256\230B\t\313\000*\000\000\000+\000\005\004\003\004\003\003\000\r\000\030\000\026\004\003\005\003\006\003\b\004\b\005\b\006\004\001\005\001\006\001\002\003\002\001\000-\000\002\001\001\000\034\000\002@\001\376\r\0029\000\000\001\000\003\344\000 \337\306\243\332Y\033\a\252\352\025\365Z\035\223\226\304\255\363\215G\356g\344%}7\217\033n\211^\201\002\017g\267\334\326OD}\336\341ZC\230\226'\225\313\357\211\\\242\273\030k\216\377U\315\206\2410\200\203\332Z\223\005\370\b\304\370f\017\200\023\241\223~?\270{\037b\312\001\270\227\366\356\352\002\314\351\006\237\241q\226\300\314\321o\247{\201\317\230}B\005T\3660\335\320\332r?S\217\tq\036\031\326I|\237]\311 c\f\024r\031\310W\373\257\314q)q\030\237\261\227\217Kd?\257'G\320\020\340\256ND\247\005\341\324\024OP>\370\350\270b\311wAj\t\311\213\365i\203\230x\207\354\245<\274\202\230c\v0Y\263\364\022\303a\200\022\031\314\271rl=\327\336\001\327\264\267\342\353\352=\354[u\224\260\257\034\004\232\023\226}\227\030e\221\"\350\207\027dId\324\305\362N:\035\307`\204\337\201;\221\320\266b\362hrH\345e\206\246%\006\020a4\3430\036\225\215\274\275\360Q&\271\237)\222uK\362\017o\220\226W\357\267#\357\v\023\354\213\2629\331\ad\005/~6k\000[\247\301\270\310qJ\004\303|m5\363\376Y\002\243}6\251x\024\331)GH\335\205rI\032\f\210\a\212\347]\271\030\347.\021\213\365\026\030\340/Ny\r\332\3577\3203\026iX}>\2507\327&XRXU!\017\270I\313\352\350^?\352Uss\017\266pF\222NI\245\307_\305#\361\352\243+-\266\317Q\036s\243\277\355{S&\023>\275\360\215\032V\237XOY\345u>\002\305\252T\354\035\327v{P\352M\233\366\221\270\377\251\261f+rF\201wL2W\266X\252\242X\2536I\337c\205uZ\254Fe\305h\t\371\376\216r\336Y\327h\347*\331\257-ZQ{(\336\226\206\017\037\036\021\341\027z\033\254\235\252\227\224\004?p\243\351\\\263\352\205\327#W\345\255\256\375\267bP\3047\363!*K\003t\212(\306\214P\215\3506j\025\375\213e\254s\000)\001\034\000\367\000\361\002\276W%\232?\326\223\277\211v\017\a\361\347\312N\226\024L\260v\210\271j\324[|\270\344\3773\321-\313b>~\310\253XIR\324)&;\033{g;)\344\255\226\370\347I\\y\020\324\360\211vC\310\226s\267|\273$\341\332\2045qh\245w\2255\214\316\030\255\301\326C\343\304=\245\231h`yd\000#s\002\370\374Z\0336\245\361\226\222\306\032k\2457\016h\314(R;\326T~EHH\352\307\023^\247\363\321`V\340\253Z\233\357\227I\373\337z\177\nv\261\252\371\017\226\223\345\005\315y4\b\236N0\2630\017\215c\305&L\260\346J\237\203Q(\335W\027|>\3553\275j\307?W5\3463kc\350\262C\361 \037w!\371}\214\"I\377|\331@a;\342\3566\312\272Z\327u7\204'\215YBLL\235\236\242\345\215\245T\211a\312\263\342\000! \221\202X$\302\317\203\246\207c{\231\330\264\324\\k\271\272\336\356\002|\261O\207\030+\367P\317\356";
|
||||
|
||||
|
||||
#endif /*RAW_REPLACEMENTS_H*/
|
||||
|
94
uspace.mk
Normal file
94
uspace.mk
Normal file
@ -0,0 +1,94 @@
|
||||
#Userspace app makes here
|
||||
BUILD_DIR := $(CURDIR)/build
|
||||
DEPSDIR := $(BUILD_DIR)/deps
|
||||
|
||||
CC:=gcc
|
||||
CCLD:=$(CC)
|
||||
LD:=ld
|
||||
override CFLAGS += -Wall -Wpedantic -Wno-unused-variable -I$(DEPSDIR)/include
|
||||
override LDFLAGS += -L$(DEPSDIR)/lib
|
||||
|
||||
LIBNFNETLINK_CFLAGS := -I$(DEPSDIR)/include
|
||||
LIBNFNETLINK_LIBS := -L$(DEPSDIR)/lib
|
||||
LIBMNL_CFLAGS := -I$(DEPSDIR)/include
|
||||
LIBMNL_LIBS := -L$(DEPSDIR)/lib
|
||||
|
||||
# PREFIX is environment variable, if not set default to /usr/local
|
||||
ifeq ($(PREFIX),)
|
||||
PREFIX := /usr/local
|
||||
else
|
||||
PREFIX := $(DESTDIR)
|
||||
endif
|
||||
|
||||
export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CFLAGS LIBMNL_LIBS
|
||||
|
||||
APP:=$(BUILD_DIR)/youtubeUnblock
|
||||
|
||||
SRCS := youtubeUnblock.c mangle.c
|
||||
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
||||
|
||||
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a
|
||||
LIBMNL := $(DEPSDIR)/lib/libmnl.a
|
||||
LIBNETFILTER_QUEUE := $(DEPSDIR)/lib/libnetfilter_queue.a
|
||||
|
||||
|
||||
.PHONY: default all dev dev_attrs prepare_dirs
|
||||
default: all
|
||||
|
||||
run_dev: dev
|
||||
bash -c "sudo $(APP) 537"
|
||||
|
||||
dev: dev_attrs all
|
||||
|
||||
dev_attrs:
|
||||
$(eval CFLAGS := $(CFLAGS) -DDEBUG -ggdb -g3)
|
||||
|
||||
all: prepare_dirs $(APP)
|
||||
|
||||
prepare_dirs:
|
||||
mkdir -p $(BUILD_DIR)
|
||||
mkdir -p $(DEPSDIR)
|
||||
|
||||
$(LIBNFNETLINK):
|
||||
cd deps/libnfnetlink && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
|
||||
$(MAKE) -C deps/libnfnetlink
|
||||
$(MAKE) install -C deps/libnfnetlink
|
||||
|
||||
$(LIBMNL):
|
||||
cd deps/libmnl && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
|
||||
$(MAKE) -C deps/libmnl
|
||||
$(MAKE) install -C deps/libmnl
|
||||
|
||||
$(LIBNETFILTER_QUEUE): $(LIBNFNETLINK) $(LIBMNL)
|
||||
cd deps/libnetfilter_queue && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
|
||||
$(MAKE) -C deps/libnetfilter_queue
|
||||
$(MAKE) install -C deps/libnetfilter_queue
|
||||
|
||||
$(APP): $(OBJS) $(LIBNETFILTER_QUEUE) $(LIBMNL)
|
||||
@echo 'CCLD $(APP)'
|
||||
$(CCLD) $(OBJS) -o $(APP) $(LDFLAGS) -lmnl -lnetfilter_queue
|
||||
|
||||
$(BUILD_DIR)/%.o: %.c $(LIBNETFILTER_QUEUE) $(LIBMNL) config.h
|
||||
@echo 'CC $@'
|
||||
$(CC) -c $(CFLAGS) $(LDFLAGS) $< -o $@
|
||||
|
||||
install: all
|
||||
install -d $(PREFIX)/bin/
|
||||
install -m 755 $(APP) $(PREFIX)/bin/
|
||||
install -d $(PREFIX)/lib/systemd/system/
|
||||
@cp youtubeUnblock.service $(BUILD_DIR)
|
||||
@sed -i 's/$$(PREFIX)/$(subst /,\/,$(PREFIX))/g' $(BUILD_DIR)/youtubeUnblock.service
|
||||
install -m 644 $(BUILD_DIR)/youtubeUnblock.service $(PREFIX)/lib/systemd/system/
|
||||
|
||||
uninstall:
|
||||
rm $(PREFIX)/bin/youtubeUnblock
|
||||
rm $(PREFIX)/lib/systemd/system/youtubeUnblock.service
|
||||
-systemctl disable youtubeUnblock.service
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR)
|
||||
$(MAKE) distclean -C deps/libnetfilter_queue || true
|
||||
$(MAKE) distclean -C deps/libmnl || true
|
||||
$(MAKE) distclean -C deps/libnfnetlink || true
|
||||
|
||||
|
1235
youtubeUnblock.c
1235
youtubeUnblock.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user