39 Commits

Author SHA1 Message Date
Vadim Vetrov
d42ecb2b82 Fix #40 (finally) 2024-08-08 16:18:50 +03:00
Vadim Vetrov
15619afcdf Merge pull request #41 from Masha/mawa
Makefiles correction for destdir/prefix support
2024-08-08 05:34:06 -07:00
Vadim Vetrov
fb47d80543 Fix #40 2024-08-08 15:29:04 +03:00
Miezhiko
13bafac036 fix destdir support
Signed-off-by: Miezhiko <Miezhiko@gmail.com>
2024-08-08 14:58:47 +04:00
Vadim Vetrov
22573b7d12 Update README.md 2024-08-08 10:54:59 +03:00
Vadim Vetrov
9101d8bd63 Merge pull request #9 from Waujito/kern_mod
This PR brings more modular application and better APIs. 
Kernel module itself is not complete yet.
2024-08-07 12:29:22 -07:00
Vadim Vetrov
768a29baec Document flags in readme 2024-08-07 22:28:03 +03:00
Vadim Vetrov
eac78de701 Merge pull request #37 from zabbius/kern_mod
Commandline options
2024-08-07 10:37:10 -07:00
Sergey Zabodalov
0a66da7014 Merge pull request #1 from Waujito/zabbius-kern_mod
Zabbius kern mod
2024-08-07 20:31:58 +03:00
Vadim Vetrov
84541e8eae Merge branch 'kern_mod' into zabbius-kern_mod 2024-08-07 13:52:40 +03:00
Vadim Vetrov
66906dbe0c Code cleanup 2024-08-07 13:32:01 +03:00
Vadim Vetrov
c9949a3605 Fix tcp4 frag error caused by enabled IP fragmentation
If the packet is fragmented here is no way to deal with it, but we don't
care about DF flag in real
2024-08-07 11:38:26 +03:00
Vadim Vetrov
477304ab53 Fix #38 2024-08-07 10:14:42 +03:00
zabbius
6eca2cb77c minor 2024-08-07 04:00:48 +03:00
zabbius
69955d5237 commandline options 2024-08-07 03:31:10 +03:00
zabbius
255371cbaa start-stop priority in rc script - now service can be enabled 2024-08-07 02:22:33 +03:00
Vadim Vetrov
1b8d3a0e66 Code cleanup 2024-08-07 00:22:52 +03:00
Vadim Vetrov
7ef3290f41 Merge branch 'main' into kern_mod 2024-08-06 23:56:17 +03:00
Vadim Vetrov
8a9348d97c Update README.md 2024-08-06 23:55:19 +03:00
Vadim Vetrov
0860d5c576 Update README.md 2024-08-06 23:54:52 +03:00
Vadim Vetrov
511efcc785 Fix service and README for iptables to use connbytes 2024-08-06 01:00:50 +03:00
Vadim Vetrov
458780d8a2 Add definitions guards 2024-08-05 23:37:45 +03:00
Vadim Vetrov
3f1e8d3f01 Suuport for fake sni elimination strategy - TTL 2024-08-05 23:13:35 +03:00
Vadim Vetrov
7829012aa3 Merge branch 'main' into kern_mod 2024-08-05 22:53:44 +03:00
Vadim Vetrov
6c9f9d0e96 Update README.md 2024-08-05 18:36:55 +03:00
Vadim Vetrov
cda9ea9b9c Update README.md 2024-08-05 16:57:04 +03:00
Vadim Vetrov
4078ff061b Update README.md 2024-08-05 16:44:49 +03:00
Vadim Vetrov
82d65b8f96 Support for openWRT SDK build system 2024-08-05 16:41:35 +03:00
Vadim Vetrov
1e36a55d9d Userspace compilation for openwrt
\#define _GNU_SOURCE specified explicitly
2024-08-05 00:07:34 +03:00
Vadim Vetrov
8bb2bb28d2 Module for kernel works now on local machine.
SEG2_DELAY is not implemented yet.
2024-08-04 16:06:13 +03:00
Vadim Vetrov
62a5627c50 Update userspace interactions 2024-08-04 12:57:16 +03:00
Vadim Vetrov
97ee3f1e72 Merge branch 'main' into kern_mod 2024-08-04 02:20:09 +03:00
Vadim Vetrov
66191b10f7 Implement packet send 2024-08-04 01:29:57 +03:00
Vadim Vetrov
be40bc91e7 Add distinct fragmentation strategies
Fix ip4_frag, implement no fragmentation strategy. Related to #24
2024-08-04 00:32:16 +03:00
Vadim Vetrov
457911abfa Implement googlevideo packet handling
Mangling itself is in TODO state.
2024-08-01 02:40:58 +03:00
Vadim Vetrov
b14abda600 Add skeleton for module and userspace iptables management
Special thanks to https://github.com/drivenets/iptables_extensions
repository with detailed explanations of iptables userspace interaction
with the kernel module.
2024-07-31 22:13:06 +03:00
Vadim Vetrov
79d592a0ca Makesystem for kernel module 2024-07-31 02:12:59 +03:00
Vadim Vetrov
7490658708 Carry split and detection functions to separate file
This needed to escape code duplication in further development of kernel
module. Also this cleanups the code.
2024-07-30 23:10:00 +03:00
Vadim Vetrov
460c727dea Support for multithreading. Cleanup code 2024-07-30 15:01:58 +03:00
19 changed files with 1750 additions and 956 deletions

6
.editorconfig Normal file
View File

@@ -0,0 +1,6 @@
root = true
[*]
indent_style = tab
indent_size = 8
tab_width = 8

9
.gitignore vendored
View File

@@ -4,3 +4,12 @@ build
configure~
# Kernel module files
*.o
.*
*.mod.*
*.mod
modules.order
Module.symvers
*.so
*.ko

3
Kbuild Normal file
View 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

View File

@@ -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
CFLAGS:=-Wall -Wpedantic -Wno-unused-variable -I$(DEPSDIR)/include -Os
LDFLAGS:=-L$(DEPSDIR)/lib -static
.PHONY: $(USPACE_TARGETS) $(KMAKE_TARGETS) clean
$(USPACE_TARGETS):
@$(MAKE) -ef 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) -L$(DEPSDIR)/lib -lmnl -lnetfilter_queue
$(BUILD_DIR)/%.o: %.c $(LIBNETFILTER_QUEUE) $(LIBMNL)
@echo 'CC $@'
@$(CC) -c $(CFLAGS) $^ -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) -ef 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) -ef kmake.mk kclean
@$(MAKE) -ef uspace.mk clean

View File

@@ -1,5 +1,5 @@
# youtubeUnblock
Bypasses Googlevideo detection systems that relies on SNI. The package is for Linux only.
Bypasses Googlevideo detection systems that relies on SNI. The package is for Linux only. The package is fully compatible with routers running OpenWRT. To learn how to build the package on OpenWRT, consult [this chapter](https://github.com/Waujito/youtubeUnblock?tab=readme-ov-file#openwrt-case).
For Windows use [GoodbyeDPI from ValdikSS](https://github.com/ValdikSS/GoodbyeDPI) (you can find how to use it for YouTube [here](https://github.com/ValdikSS/GoodbyeDPI/issues/378)) The same behavior is also implemented in [zapret package for linux](https://github.com/bol-van/zapret).
@@ -34,15 +34,21 @@ 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.
- `--sni-domains=<comma separated domain list>|all` - List of domains you want to be handled by sni. Use this string if you want to change default domains. Defaults to `googlevideo.com,youtube.com,ggpht.com,ytimg.com`. You can pass all if you want for every Client Hello to be handled.
- `--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.
If your browser is using quic it may not work properly. Disable it in chrome in chrome://flags and in Firefox network.http.http{2,3}.enable(d) in about:config
### Troubleshooting EPERMS (Operation not permitted)
EPERM may occur in a lot of places but generally here are two: mnl_cb_run and when sending the packet via rawsocket (raw_frags_send and send fake sni).
- mnl_cb_run Operation not permitted indicates that another instance of youtubeUnblock is running on the specified queue-num.
@@ -51,20 +57,34 @@ EPERM may occur in a lot of places but generally here are two: mnl_cb_run and wh
* 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`.
## Performance
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 free opensource linux-based system such as [OpenWRT](https://openwrt.org/). You should cross-compile it under your host machine. Be ready for compilation errors and a lot of googling about it. It is not such a trivial process! You can get crosscompilation toolsuite compatible with your router from OpenWRT repositories. For example, I have ramips/mt76x8 based router so for me the toolsuite is on https://downloads.openwrt.org/releases/23.05.3/targets/ramips/mt76x8/ and called `openwrt-toolchain-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64.tar.xz`. You can find out more about your router model on it's openwrt page. When you download the toolsuite, untar it somewhere. Now we are ready for compilation. My cross gcc asked me to create a staging dir for it and pass it as an environment variable. Also you should notice toolsuite packages and replace my make command with yours. ```STAGING_DIR=temp make CC=/usr/bin/mipsel-openwrt-linux-gcc LD=/usr/bin/mipsel-openwrt-linux-ld AR=/usr/bin/mipsel-openwrt-linux-ar OBJDUMP=/usr/bin/mipsel-openwrt-linux-objdump NM=/usr/bin/mipsel-openwrt-linux-nm STRIP=/usr/bin/mipsel-openwrt-linux-strip CROSS_COMPILE_PLATFORM=mipsel-buildroot-linux-gnu```. Take a look at `CROSS_COMPILE_PLATFORM` It is required by autotools but I think it is not necessary. Anyways I put `mipsel-buildroot-linux-gnu` in here. For your model may be an [automake cross-compile manual](https://www.gnu.org/software/automake/manual/html_node/Cross_002dCompilation.html) will be helpful. When compilation is done, the binary file will be in build directory. Copy it to your router. Note that an ssh access is likely to be required to proceed. sshfs don't work on my model so I injected the application to the router via Software Upload Package page. It has given me an error, but also a `/tmp/upload.ipk` file which I copied in root directory, `chmod +x`-ed and run.
The package is also compatible with routers. The router should be running by linux-based system such as [OpenWRT](https://openwrt.org/).
You can build under openwrt with two options: first - through the SDK, which is preferred way and second is cross-compile manually with openwrt toolchain.
Now let's talk about a router configuration. I installed a normal iptables user-space app: `xtables-legacy iptables-zz-legacy` and kernel/iptables nfqueue extensions: `iptables-mod-nfqueue kmod-ipt-nfqueue` and add `iptables -t mangle -A FORWARD -p tcp -m tcp --dport 443 -j NFQUEUE --queue-num 537 --queue-bypass` rule.
### Building OpenWRT .ipk package
OpenWRT provides a high-level SDK for the package builds.
First step is to download or compile OpenWRT SDK for your specific platform. The SDK can be compiled according to [this tutorial](https://openwrt.org/docs/guide-developer/toolchain/using_the_sdk). Beside of raw source code of SDK, OpenWRT also offers precompiled SDKs for your router. You can find it on the router page. For example, I have ramips/mt76x8 based router so for me the sdk is on https://downloads.openwrt.org/releases/23.05.3/targets/ramips/mt76x8/ and called `openwrt-sdk-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64`. You will need to [install sdk requirements on your system](https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem) If you have any problems, use docker ubuntu:24.04 image. Make sure to be a non-root user since some makesystem fails with it. Next, untar the SDK and cd into it. Do `echo "src-git youtubeUnblock https://github.com/Waujito/youtubeUnblock.git;openwrt" >> feeds.conf`, `./scripts/feeds update youtubeUnblock`, `./scripts/feeds install -a -p youtubeUnblock`, `make package/youtubeUnblock/compile`. Now the packet is built and you can import it to the router. Find it in `bin/packages/<target>/youtubeUnblock/youtubeUnblock-<version>.ipk`. Go to your router interface and put it in via System-Software-install_package. Now the package is on the router. Goto System-Startup, restart firewall and start youtubeUnblock. You are done!
If you prefer nftables, this should work: `nft add rule inet fw4 mangle_forward tcp dport 443 counter queue num 537 bypass`. Note that kmod-nft-queue should be installed.
### Building with toolchain
The precompiled toolchain located near the SDK. For me it is called `openwrt-toolchain-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64.tar.xz`. When you download the toolchain, untar it somewhere. Now we are ready for compilation. My cross gcc asked me to create a staging dir for it and pass it as an environment variable. Also you should notice toolsuite packages and replace my make command with yours. ```STAGING_DIR=temp make CC=/usr/bin/mipsel-openwrt-linux-gcc LD=/usr/bin/mipsel-openwrt-linux-ld AR=/usr/bin/mipsel-openwrt-linux-ar OBJDUMP=/usr/bin/mipsel-openwrt-linux-objdump NM=/usr/bin/mipsel-openwrt-linux-nm STRIP=/usr/bin/mipsel-openwrt-linux-strip CROSS_COMPILE_PLATFORM=mipsel-buildroot-linux-gnu```. Take a look at `CROSS_COMPILE_PLATFORM` It is required by autotools but I think it is not necessary. Anyways I put `mipsel-buildroot-linux-gnu` in here. For your model may be an [automake cross-compile manual](https://www.gnu.org/software/automake/manual/html_node/Cross_002dCompilation.html) will be helpful. When compilation is done, the binary file will be in build directory. Copy it to your router. Note that an ssh access is likely to be required to proceed. sshfs don't work on my model so I injected the application to the router via Software Upload Package page. It has given me an error, but also a `/tmp/upload.ipk` file which I copied in root directory, `chmod +x`-ed and run.
### Configuration
If you compiled the package via the SDK everything is preinstalled. But if you got any issues (suitable for routers with iptables instead of nftables), ssh into the router and check up everything manually.
For iptables: install a normal iptables user-space app: `xtables-legacy iptables-zz-legacy` and kernel/iptables nfqueue extensions: `iptables-mod-nfqueue kmod-ipt-nfqueue` and add `iptables -t mangle -A FORWARD -p tcp -m tcp --dport 443 -j NFQUEUE --queue-num 537 --queue-bypass` rule.
If you prefer nftables, this should work: `nft add rule inet fw4 mangle_forward tcp dport 443 counter queue num 537 bypass`. Note that `kmod-nft-queue` should be installed.
Also you can copy `owrt/537-youtubeUnblock.nft` to `/usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft` and run `/etc/init.d/firewall reload`. This will reload the nftables ruleset and automatically link 537-youtubeUnblock.nft with it.
Next step is to daemonize the application in openwrt. Copy `owrt/youtubeUnblock.owrt` to `/etc/init.d/youtubeUnblock` and put the program into /usr/bin/. (Don't forget to `chmod +x` both). Now run `/etc/init.d/youtubeUnblock start`. You can alo run `/etc/init.d/youtubeUnblock enable` to force OpenWRT autostart the program on boot, but I don't recommend this since if the packet has bug you may lose access to the router (I think you will be able to reset it with reset settings tricks documented for your router).
## Performance
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)
## If you have any questions/suggestions/problems feel free to open an issue.

73
config.h Normal file
View File

@@ -0,0 +1,73 @@
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;
const char *domains_str;
unsigned int domains_strlen;
unsigned int all_domains;
};
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
static const char defaul_snistr[] = "googlevideo.com,ggpht.com,ytimg.com,l.google.com,youtube.com,play.google.com";

View File

@@ -15,3 +15,4 @@ Makefile.in
/stamp-h1
/*.pc
doxygen.cfg

View File

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

484
mangle.c Normal file
View File

@@ -0,0 +1,484 @@
#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
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;
vrd.sni_offset = (uint8_t *)sni_name - data;
vrd.sni_len = sni_len;
if (config.all_domains) {
vrd.target_sni = 1;
goto out;
}
unsigned int j = 0;
for (unsigned int i = 0; i < config.domains_strlen; i++) {
if (config.domains_str[i] == ',' || config.domains_str[i] == '\n') {
unsigned int domain_len = (i - j);
const char *sni_startp = sni_name + sni_len - domain_len;
const char *domain_startp = config.domains_str + j;
if (sni_len >= domain_len &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
domain_len)) {
vrd.target_sni = 1;
}
j = i + 1;
}
}
nextExtension:
extensionsPtr += 2 + 2 + extensionLen;
}
nextMessage:
i += 5 + message_length;
}
out:
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
View 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 target_sni; /* 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 */

3
owrt/youtubeUnblock.owrt Normal file → Executable file
View File

@@ -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/

View File

@@ -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*/

91
uspace.mk Normal file
View File

@@ -0,0 +1,91 @@
#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
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 $(DESTDIR)$(PREFIX)/bin/
install -m 755 $(APP) $(DESTDIR)$(PREFIX)/bin/
install -d $(DESTDIR)$(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 $(DESTDIR)$(PREFIX)/lib/systemd/system/
uninstall:
rm $(DESTDIR)$(PREFIX)/bin/youtubeUnblock
rm $(DESTDIR)$(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

File diff suppressed because it is too large Load Diff

View File

@@ -5,9 +5,9 @@ Description=youtubeUnblock
StandardError=journal
StandardOutput=journal
StandardInput=null
ExecStartPre=iptables -t mangle -A OUTPUT -p tcp --dport 443 -j NFQUEUE --queue-num 537 --queue-bypass
ExecStartPre=iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 443 -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:19 -j NFQUEUE --queue-num 537 --queue-bypass
ExecStart=$(PREFIX)/bin/youtubeUnblock 537
ExecStop=iptables -t mangle -D OUTPUT -p tcp --dport 443 -j NFQUEUE --queue-num 537 --queue-bypass
ExecStop=iptables -t mangle -D OUTPUT -p tcp -m tcp --dport 443 -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:19 -j NFQUEUE --queue-num 537 --queue-bypass
[Install]
WantedBy=multi-user.target