mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2026-02-01 15:10:34 +03:00
Compare commits
48 Commits
v1.0.0-rc6
...
v1.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
330efb5e63 | ||
|
|
911faa09bd | ||
|
|
27adf8a308 | ||
|
|
4afd4eae5a | ||
|
|
6c17e7d58c | ||
|
|
581364ed9d | ||
|
|
06c3447d5e | ||
|
|
b145d2ae9e | ||
|
|
515d4d4ca6 | ||
|
|
b41fad1fbe | ||
|
|
c9b59f9ce7 | ||
|
|
da650bd09f | ||
|
|
07334c598d | ||
|
|
b35b6ed29c | ||
|
|
2d579d5479 | ||
|
|
473af29c6b | ||
|
|
5c809c893d | ||
|
|
ce859ed9f0 | ||
|
|
23380f7b5c | ||
|
|
65e3613a65 | ||
|
|
d85c723bbe | ||
|
|
71afca37e9 | ||
|
|
6a138324d2 | ||
|
|
6549d0075f | ||
|
|
9e8a2aab36 | ||
|
|
441c5f1fd2 | ||
|
|
8163213602 | ||
|
|
f37c3dd496 | ||
|
|
0cf1035a14 | ||
|
|
7ebaccfa19 | ||
|
|
705da0f4c6 | ||
|
|
df70763b4a | ||
|
|
49304cc111 | ||
|
|
b832541766 | ||
|
|
2884cb72f9 | ||
|
|
34271ece2c | ||
|
|
ad6b84a961 | ||
|
|
5f20220d4e | ||
|
|
6cc23a2991 | ||
|
|
c73885aca3 | ||
|
|
78dd12c526 | ||
|
|
d7489fc08a | ||
|
|
6da6f63541 | ||
|
|
a7b689b320 | ||
|
|
f7d0bed7aa | ||
|
|
d225e673c7 | ||
|
|
d9c360910b | ||
|
|
42917a75fc |
5
.github/workflows/build-ci.yml
vendored
5
.github/workflows/build-ci.yml
vendored
@@ -167,7 +167,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
branch:
|
branch:
|
||||||
- openwrt-23.05
|
- openwrt-24.10
|
||||||
arch:
|
arch:
|
||||||
- aarch64_cortex-a53
|
- aarch64_cortex-a53
|
||||||
- aarch64_cortex-a72
|
- aarch64_cortex-a72
|
||||||
@@ -184,7 +184,6 @@ jobs:
|
|||||||
- arm_cortex-a9_neon
|
- arm_cortex-a9_neon
|
||||||
- arm_cortex-a9_vfpv3-d16
|
- arm_cortex-a9_vfpv3-d16
|
||||||
- arm_fa526
|
- arm_fa526
|
||||||
- arm_mpcore
|
|
||||||
- arm_xscale
|
- arm_xscale
|
||||||
- mips64_octeonplus
|
- mips64_octeonplus
|
||||||
- mips_24kc
|
- mips_24kc
|
||||||
@@ -250,7 +249,7 @@ jobs:
|
|||||||
needs: prepare
|
needs: prepare
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: openwrt/sdk:x86_64-openwrt-23.05
|
image: openwrt/sdk:x86_64-openwrt-24.10
|
||||||
options: --user root
|
options: --user root
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
2
Kbuild
2
Kbuild
@@ -1,3 +1,3 @@
|
|||||||
obj-m := kyoutubeUnblock.o
|
obj-m := kyoutubeUnblock.o
|
||||||
kyoutubeUnblock-objs := src/kytunblock.o src/mangle.o src/quic.o src/quic_crypto.o src/utils.o src/tls.o src/getopt.o src/inet_ntop.o src/args.o deps/cyclone/aes.o deps/cyclone/cpu_endian.o deps/cyclone/ecb.o deps/cyclone/gcm.o deps/cyclone/hkdf.o deps/cyclone/hmac.o deps/cyclone/sha256.o
|
kyoutubeUnblock-objs := src/kytunblock.o src/dpi.o src/mangle.o src/quic.o src/quic_crypto.o src/utils.o src/tls.o src/getopt.o src/inet_ntop.o src/args.o src/trie.o deps/cyclone/aes.o deps/cyclone/cpu_endian.o deps/cyclone/ecb.o deps/cyclone/gcm.o deps/cyclone/hkdf.o deps/cyclone/hmac.o deps/cyclone/sha256.o
|
||||||
ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement -I$(src)/src -I$(src)/deps/cyclone/include
|
ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement -I$(src)/src -I$(src)/deps/cyclone/include
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -1,8 +1,8 @@
|
|||||||
USPACE_TARGETS := default all install uninstall dev run_dev
|
USPACE_TARGETS := default all install uninstall dev run_dev
|
||||||
KMAKE_TARGETS := kmake kload kunload kreload xmod xtclean
|
KMAKE_TARGETS := kmake kload kunload kreload xmod xtclean
|
||||||
|
|
||||||
PKG_VERSION := 1.0.0
|
PKG_VERSION := 1.3.0
|
||||||
PKG_RELEASE := 6
|
PKG_RELEASE := 1
|
||||||
|
|
||||||
PKG_FULLVERSION := $(PKG_VERSION)-$(PKG_RELEASE)
|
PKG_FULLVERSION := $(PKG_VERSION)-$(PKG_RELEASE)
|
||||||
|
|
||||||
|
|||||||
93
README.md
93
README.md
@@ -9,7 +9,8 @@
|
|||||||
- [IPv6](#ipv6)
|
- [IPv6](#ipv6)
|
||||||
- [Check it](#check-it)
|
- [Check it](#check-it)
|
||||||
- [Flags](#flags)
|
- [Flags](#flags)
|
||||||
- [UDP/QUIC/Voice Chats](#udpquicvoice-chats)
|
- [UDP/QUIC](#udpquic)
|
||||||
|
- [Cloudflare](#cloudflare)
|
||||||
- [Troubleshooting](#troubleshooting)
|
- [Troubleshooting](#troubleshooting)
|
||||||
- [TV](#tv)
|
- [TV](#tv)
|
||||||
- [Troubleshooting EPERMS (Operation not permitted)](#troubleshooting-eperms-operation-not-permitted)
|
- [Troubleshooting EPERMS (Operation not permitted)](#troubleshooting-eperms-operation-not-permitted)
|
||||||
@@ -29,10 +30,22 @@
|
|||||||
|
|
||||||
# youtubeUnblock
|
# youtubeUnblock
|
||||||
|
|
||||||
Bypasses Deep Packet Inspection (DPI) systems that relies on SNI. The package is for Linux only. It is also fully compatible with routers running [OpenWRT](https://github.com/openwrt).
|
Bypasses YouTube detection systems that rely on SNI.
|
||||||
|
|
||||||
The program was primarily developed to bypass YouTube Outage in Russia.
|
The program was primarily developed to bypass YouTube Outage in Russia.
|
||||||
|
|
||||||
|
The program should be used **only for the YouTube platform**. It is legal since access to YouTube **is not officially restricted in Russia**. You **MUST NOT** use the program for any other purpose. I respect all Russian laws and do not wish to break any.
|
||||||
|
|
||||||
|
Starting with a YouTube speedup for my laptop, this project grew into a standalone tool that unblocks YouTube on a wide variety of devices. This project has fulfilled my dream of creating a massive, highly reliable, open-source GitHub project that helps people. I value all your feedback, and that is the reason I continue to maintain it. I learned many things while developing it, such as aspects of the Linux kernel networking stack. It is truly rewarding to explore new technologies while developing a project for people. This experience is incomparable to that of working on a mere pet project.
|
||||||
|
|
||||||
|
**So, please use it only for YouTube and only in accordance with the laws of your country.**
|
||||||
|
|
||||||
|
If you have any questions, suggestions, or problems, feel free to open an [issue](https://github.com/Waujito/youtubeUnblock/issues).
|
||||||
|
|
||||||
|
You are also welcome to contact me directly using the links provided in my GitHub profile description; however, please contact me only if you have a special offer. For help with the program, it is preferable to make our conversation public by posting on [GitHub Discussions](https://github.com/Waujito/youtubeUnblock/discussions).
|
||||||
|
|
||||||
|
The program is distributed under the GNU GPL v3 open-source license.
|
||||||
|
|
||||||
```
|
```
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -44,6 +57,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The program is for Linux only. It is also fully compatible with routers running [OpenWRT](https://github.com/openwrt).
|
||||||
|
|
||||||
The program is distributed in two version:
|
The program is distributed in two version:
|
||||||
- A userspace application works on top of nfnetlink queue which requires nfnetlink modules in the kernel and firewall rules. This approach is default and normally should be used but it has some limitations on embedded devices which may have no nfnetlink support. Also this solution may break down the internet speed and CPU load on your device because of jumps between userspace and kernelspace for each packet (this behavior may be fixed with connbytes but it also requires conntrack kernel module).
|
- A userspace application works on top of nfnetlink queue which requires nfnetlink modules in the kernel and firewall rules. This approach is default and normally should be used but it has some limitations on embedded devices which may have no nfnetlink support. Also this solution may break down the internet speed and CPU load on your device because of jumps between userspace and kernelspace for each packet (this behavior may be fixed with connbytes but it also requires conntrack kernel module).
|
||||||
- A kernel module which integrates deeply within the netfilter stack and does not interact with the userspace firewall. The module requires only netfilter kernel support but it definetly present on every device connected to the Internet. The only difficulity is how to build it. I cannot provide modules within Github Actions for each single one kernel, even if we talk only about OpenWRT versions. If you want to learn more about the module, jump on [its section in the README](#kernel-module). Whats the benefits of the kernel module? The benefits come for some specific cases: the kernel module is the fastest thing that allows us to process every single packet sent to the linux network stack, while the normal youtubeUnblock requires connbytes to keep the internet speed. Speaking about connbytes, it also requires conntrack to operate, which may be a limitation on some transit-traffic machines. Also userspace youtubeUnblock requires modules for netlink queue, userspace firewall application and modules for it. The kernel module is much simpler and requires only the linux kernel with netfilter built in.
|
- A kernel module which integrates deeply within the netfilter stack and does not interact with the userspace firewall. The module requires only netfilter kernel support but it definetly present on every device connected to the Internet. The only difficulity is how to build it. I cannot provide modules within Github Actions for each single one kernel, even if we talk only about OpenWRT versions. If you want to learn more about the module, jump on [its section in the README](#kernel-module). Whats the benefits of the kernel module? The benefits come for some specific cases: the kernel module is the fastest thing that allows us to process every single packet sent to the linux network stack, while the normal youtubeUnblock requires connbytes to keep the internet speed. Speaking about connbytes, it also requires conntrack to operate, which may be a limitation on some transit-traffic machines. Also userspace youtubeUnblock requires modules for netlink queue, userspace firewall application and modules for it. The kernel module is much simpler and requires only the linux kernel with netfilter built in.
|
||||||
@@ -52,8 +67,6 @@ The program is compatible with routers based on OpenWRT, Entware(Keenetic/ASUS)
|
|||||||
|
|
||||||
On both OpenWRT and Entware install the program with opkg. If you got read-only filesystem error you may unpack the binary manually or specify opkg path `opkg -o <destdir>`.
|
On both OpenWRT and Entware install the program with opkg. If you got read-only filesystem error you may unpack the binary manually or specify opkg path `opkg -o <destdir>`.
|
||||||
|
|
||||||
For Windows use [GoodbyeDPI by 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).
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### OpenWRT pre configuration
|
### OpenWRT pre configuration
|
||||||
@@ -186,6 +199,11 @@ It should return low speed without **youtubeUnblock** and faster with it. With *
|
|||||||
curl -o/dev/null -k --connect-to ::google.com -k -L -H Host:\ mirror.gcr.io https://mirror.gcr.io/v2/cimg/android/blobs/sha256:6fd8bdac3da660bde7bd0b6f2b6a46e1b686afb74b9a4614def32532b73f5eaa
|
curl -o/dev/null -k --connect-to ::google.com -k -L -H Host:\ mirror.gcr.io https://mirror.gcr.io/v2/cimg/android/blobs/sha256:6fd8bdac3da660bde7bd0b6f2b6a46e1b686afb74b9a4614def32532b73f5eaa
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For ECH check it comes out to be more complicated, since it is still an experimental feature in CURL. If you want to test it, first of all, you should compile curl with ECH support. You can follow [this guide](https://github.com/curl/curl/blob/master/docs/ECH.md). Next, you can check it with
|
||||||
|
```sh
|
||||||
|
LD_LIBRARY_PATH=$HOME/code/openssl $HOME/code/curl/src/curl --ech hard --doh-url https://one.one.one.one/dns-query https://www.opengl.org --ipv4
|
||||||
|
```
|
||||||
|
|
||||||
## Flags
|
## Flags
|
||||||
|
|
||||||
Put flags to the **BINARY**, not an init script. If you are on OpenWRT you should put the flags inside the script: open `/etc/init.d/youtubeUnblock` with any text editor, like vi or nano and put your flags after `procd_set_param command /usr/bin/youtubeUnblock` line.
|
Put flags to the **BINARY**, not an init script. If you are on OpenWRT you should put the flags inside the script: open `/etc/init.d/youtubeUnblock` with any text editor, like vi or nano and put your flags after `procd_set_param command /usr/bin/youtubeUnblock` line.
|
||||||
@@ -226,6 +244,10 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
|
|||||||
|
|
||||||
- `--tls={enabled|disabled}` Set it if you want not to process TLS traffic in current section. May be used if you want to set only UDP-based section. (Here section is a unit between `--fbegin` and `--fend` flags).
|
- `--tls={enabled|disabled}` Set it if you want not to process TLS traffic in current section. May be used if you want to set only UDP-based section. (Here section is a unit between `--fbegin` and `--fend` flags).
|
||||||
|
|
||||||
|
- `--tcp-dport-filter=<5,6,200-500>` Filter the TCP destination ports. Defaults to no ports. Specifie the ports you want to be handled by youtubeUnblock. By default, youtubeUnblock will filter only 443 TLS port. This may disabled by `--no-dport-filter`.
|
||||||
|
|
||||||
|
- `--tcp-match-connpackets` Use this with `--use-conntrack` set. Instead of matching by TLS domains will match packets by OS conntrack connpackets variable (e. g. number of packets sent while connection is alive (SYN is included in the connpackets counter, but anyways will be skipped by youtubeUnblock). You should not set too high number for matching. I recommend something like 4 or 5. If matching happens, youtubeUnblock will send fake and fragement the packet according to fragmentation and faking settings.
|
||||||
|
|
||||||
- `--fake-sni={0|1}` 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 before open an issue refer to [Troubleshooting for EPERMS](#troubleshooting-eperms-operation-not-permitted). Defaults to **1**.
|
- `--fake-sni={0|1}` 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 before open an issue refer to [Troubleshooting for EPERMS](#troubleshooting-eperms-operation-not-permitted). Defaults to **1**.
|
||||||
|
|
||||||
- `--fake-sni-seq-len=<length>` This flag specifies **youtubeUnblock** to build a complicated construction of fake client hello packets. length determines how much fakes will be sent. Defaults to **1**.
|
- `--fake-sni-seq-len=<length>` This flag specifies **youtubeUnblock** to build a complicated construction of fake client hello packets. length determines how much fakes will be sent. Defaults to **1**.
|
||||||
@@ -236,17 +258,20 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
|
|||||||
|
|
||||||
- `--fake-custom-payload-file=<binary file containing TLS message>` Same as `--fake-custom-payload` but binary file instead of hex. The file should contain raw binary TLS message (TCP payload).
|
- `--fake-custom-payload-file=<binary file containing TLS message>` Same as `--fake-custom-payload` but binary file instead of hex. The file should contain raw binary TLS message (TCP payload).
|
||||||
|
|
||||||
- `--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}` This flag determines the strategy of fake packets invalidation. Defaults to `randseq`
|
- `--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum|timestamp}` This flag determines the strategy of fake packets invalidation. The user can specify multiple faking options, so multiple techniques will be applied to the fake packet. Defaults to `tcp_check,timestamp`.
|
||||||
- `randseq` specifies that random sequence/acknowledgment random will be set. This option may be handled by provider which uses *conntrack* with drop on invalid *conntrack* state firewall rule enabled.
|
- `randseq` specifies that random sequence/acknowledgment random will be set. This option may be handled by provider which uses *conntrack* with drop on invalid *conntrack* state firewall rule enabled.
|
||||||
- `ttl` specifies that packet will be invalidated after `--faking-ttl=n` hops. `ttl` is better but may cause issues if unconfigured.
|
- `ttl` specifies that packet will be invalidated after `--faking-ttl=n` hops. `ttl` is better but may cause issues if unconfigured.
|
||||||
- `pastseq` is like `randseq` but sequence number is not random but references the packet sent in the past (before current).
|
- `pastseq` is like `randseq` but sequence number is not random but references the packet sent in the past (before current).
|
||||||
- `tcp_check` will invalidate faking packet with invalid checksum. May be handled and dropped by some providers/TSPUs.
|
- `tcp_check` will invalidate faking packet with invalid checksum. May be handled and dropped by some providers/TSPUs.
|
||||||
- `md5sum` will invalidate faking packet with invalid TCP md5sum. md5sum is a TCP option which is handled by the destination server but may be skipped by TSPU.
|
- `md5sum` will invalidate faking packet with invalid TCP md5sum. md5sum is a TCP option which is handled by the destination server but may be skipped by TSPU.
|
||||||
|
- `timestamp` utilizes TCP Timestamp option. Timestamp TSVal is decreased by `--faking-timestamp-decrease=n` parameter, so it is being rejected by the server.
|
||||||
|
|
||||||
- `--faking-ttl=<ttl>` Tunes the time to live (TTL) of fake SNI messages. TTL is specified like that the packet will go through the DPI system and captured by it, but will not reach the destination server. Defaults to **8**.
|
- `--faking-ttl=<ttl>` Tunes the time to live (TTL) of fake SNI messages. TTL is specified like that the packet will go through the DPI system and captured by it, but will not reach the destination server. Defaults to **8**.
|
||||||
|
|
||||||
- `--fake-seq-offset` Tunes the offset from original sequence number for fake packets. Used by randseq faking strategy. Defaults to 10000. If 0, random sequence number will be set.
|
- `--fake-seq-offset` Tunes the offset from original sequence number for fake packets. Used by randseq faking strategy. Defaults to 10000. If 0, random sequence number will be set.
|
||||||
|
|
||||||
|
- `--faking-timestamp-decrease=<val>` Decreases TSVal parameter of Timestamp option in fake packet by this value. The default is 600000. According to research made in zapret project, this parameter may work in range between 100 and 0x80000000.
|
||||||
|
|
||||||
- `--frag={tcp,ip,none}` Specifies the fragmentation strategy for the packet. tcp is used by default. Ip fragmentation may be blocked by DPI system. None specifies no fragmentation. Probably this won't work, but may be will work for some fake sni strategies.
|
- `--frag={tcp,ip,none}` Specifies the fragmentation strategy for the packet. tcp is used by default. Ip fragmentation may be blocked by DPI system. None specifies no fragmentation. Probably this won't work, but may be will work for some fake sni strategies.
|
||||||
|
|
||||||
- `--frag-sni-reverse={0|1}` Specifies **youtubeUnblock** to send *ClientHello* fragments in the reverse order. Defaults to **1**.
|
- `--frag-sni-reverse={0|1}` Specifies **youtubeUnblock** to send *ClientHello* fragments in the reverse order. Defaults to **1**.
|
||||||
@@ -281,19 +306,21 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
|
|||||||
|
|
||||||
- `--udp-fake-len=<size of udp fake>` Size of udp fake payload (typically payload is zeroes). Defaults to 64.
|
- `--udp-fake-len=<size of udp fake>` Size of udp fake payload (typically payload is zeroes). Defaults to 64.
|
||||||
|
|
||||||
- `--udp-dport-filter=<5,6,200-500>` Filter the UDP destination ports. Defaults to no ports. Specifie the ports you want to be handled by youtubeUnblock.
|
- `--udp-dport-filter=<5,6,200-500>` Filter the UDP destination ports. Defaults to no ports. Specifie the ports you want to be handled by youtubeUnblock. Please note, it may conflict with `--quic-drop` since `--quic-drop` setts `--udp-mode` to drop globally. So, make sure to handle it in a different config section.
|
||||||
|
|
||||||
|
- `--udp-stun-filter` Filter all the UDP STUN request packets. Very useful for voice chats. Please note, it may conflict with `--quic-drop` since `--quic-drop` setts `--udp-mode` to drop globally. So, make sure to handle it in a different config section.
|
||||||
|
|
||||||
- `--udp-faking-strategy={checksum|ttl|none}` Faking strategy for udp. `checksum` will fake UDP checksum, `ttl` won't fake but will make UDP content relatively small, `none` is no faking. Defaults to none.
|
- `--udp-faking-strategy={checksum|ttl|none}` Faking strategy for udp. `checksum` will fake UDP checksum, `ttl` won't fake but will make UDP content relatively small, `none` is no faking. Defaults to none.
|
||||||
|
|
||||||
- `--udp-filter-quic={disabled|all|parse}` Enables QUIC filtering for UDP handler. If disabled, quic won't be processed, if all, all quic initial packets will be handled. `parse` will decrypt and parse QUIC initial message and match it with `--sni-domains`. Defaults to disabled.
|
- `--udp-filter-quic={disabled|all|parse}` Enables QUIC filtering for UDP handler. If disabled, quic won't be processed, if all, all quic initial packets will be handled. `parse` will decrypt and parse QUIC initial message and match it with `--sni-domains`. Defaults to disabled.
|
||||||
|
|
||||||
- `--quic-drop` Drop all QUIC packets which goes to youtubeUnblock. Won't affect any other UDP packets. Just an alias for `--udp-filter-quic=all --udp-mode=drop`.
|
- `--quic-drop` Drop all QUIC packets which goes to youtubeUnblock. Won't affect any other UDP packets. Just an alias for `--udp-filter-quic=all --udp-mode=drop`. Please note, because of `--udp-mode=drop` it may conflict with other filter options. Make sure to use multiple sections.
|
||||||
|
|
||||||
- `--no-dport-filter` By default, youtubeUnblock will filter for TLS and QUIC 443. If you want to disable it, pass this flag. (this does not affect `--udp-dport-filter`)
|
- `--no-dport-filter` By default, youtubeUnblock will filter for TLS and QUIC 443. If you want to disable it, pass this flag. (this does not affect `--udp-dport-filter`)
|
||||||
|
|
||||||
## UDP/QUIC/Voice Chats
|
## UDP/QUIC
|
||||||
|
|
||||||
UDP is another communication protocol. Well-known technologies that use it are DNS, QUIC, voice chats. UDP does not provide reliable connection and its header is much simpler than TCP thus fragmentation is limited. The support provided primarily by faking.
|
UDP is another communication protocol. Well-known technologies that use it are DNS, QUIC. UDP does not provide reliable connection and its header is much simpler than TCP thus fragmentation is limited. The support provided primarily by faking.
|
||||||
|
|
||||||
**For UDP faking in kernel module** Make sure to decrease `--connbytes-limit` up to 5. This will allow not to process additional packets and prevent network flood.
|
**For UDP faking in kernel module** Make sure to decrease `--connbytes-limit` up to 5. This will allow not to process additional packets and prevent network flood.
|
||||||
|
|
||||||
@@ -303,7 +330,30 @@ QUIC is enabled with `--udp-filter-quic` flag. The flag supports two modes: `all
|
|||||||
|
|
||||||
**I recommend to use** `--udp-mode=drop --udp-filter-quic=parse`.
|
**I recommend to use** `--udp-mode=drop --udp-filter-quic=parse`.
|
||||||
|
|
||||||
For **other UDP protocols** I recommend to configure UDP support in the separate section from TCP, like `--fbegin --udp-dport-filter=50000-50099 --tls=disabled`. See more in flags related to udp and [tickets tagged with udp label](https://github.com/Waujito/youtubeUnblock/issues?q=label%3Audp+).
|
For **other UDP protocols** I recommend to configure UDP support in the separate section from TCP, like `--fbegin --udp-dport-filter=50000-50099 --tls=disabled`. **You should not pass `--quic-drop` here unless you are sure what you are doing**
|
||||||
|
|
||||||
|
## Cloudflare
|
||||||
|
|
||||||
|
In Russia, Cloudflare technologies takes special care by RKN.
|
||||||
|
This was caused primarily by ECH technology which allows to easily bypass the TSPU. RKN blocks ECH but alongside with it blocks a lot of harmless network protocols. Currently, the only TLS (and may be HTTP) protocols are allowed on the Cloudflare network. If TSPU could not determine the protocol and Server Name (SNI for TLS), it will drop the connection after 16 KB transferred. This affects not only 443 or 80 ports, but every port on Cloudflare network.
|
||||||
|
|
||||||
|
Because of this, ECH and tons of protocols are unavailable. Tons of various custom servers/utilites/games are down, since custom protocols are being blocked.
|
||||||
|
|
||||||
|
An example: Hypixel Minecraft server relies on Cloudflare and works up on custom Minecraft protocol on port 25565. TSPU can't determine this protocol, so it blocks the connection after 16 KB transferred, so server does not work.
|
||||||
|
|
||||||
|
Note, that the faking here is a key to bypass the TSPU.
|
||||||
|
|
||||||
|
An example of the solution:
|
||||||
|
```sh
|
||||||
|
sudo ./build/youtubeUnblock --use-conntrack --tls=disabled --tcp-match-connpackets=4 --tcp-dport-filter=25565 --frag-sni-pos=1 --fake-sni=1 --faking-strategy=tcp_check,timestamp
|
||||||
|
```
|
||||||
|
|
||||||
|
Also do not forget to add the iptables rule on the custom port:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo iptables -t mangle -A YOUTUBEUNBLOCK -p tcp --dport 25565 -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:19 -j NFQUEUE --queue-num 537 --queue-bypass
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -320,6 +370,10 @@ If your browser is using QUIC it may not work properly. Disable it in Chrome in
|
|||||||
|
|
||||||
It seems like some TSPUs started to block wrongseq packets, so you should play around with faking strategies. I personally recommend to start with `md5sum` faking strategy.
|
It seems like some TSPUs started to block wrongseq packets, so you should play around with faking strategies. I personally recommend to start with `md5sum` faking strategy.
|
||||||
|
|
||||||
|
#### youtube with `--sni-domains=all`
|
||||||
|
|
||||||
|
I know about this issue but it is **basically not an youtubeUnblock problem**. The problem is behind the large `*.googlevideo.com` domain name. All you want is to create a new configuration section for only youtube. It should go after section for all domains. For plain string arguments just `--fbegin` at the end of args list will work. In luci you can create section interactively.
|
||||||
|
|
||||||
### TV
|
### TV
|
||||||
|
|
||||||
Televisions are the biggest headache.
|
Televisions are the biggest headache.
|
||||||
@@ -342,7 +396,7 @@ Where you have to replace 192.168.. with ip of your television.
|
|||||||
|
|
||||||
*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).
|
*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.
|
- **mnl_cb_run** *Operation not permitted* indicates a problem in establishing a netfilter queue. This may occur due to various reasons, but the two most common are: issues with the nfqueue kernel modules and another instance of youtubeUnblock running with the same queue number. For the first issue, check that the kernel modules are installed and running. On OpenWRT, you might have forgotten to install the necessary dependencies [#openwrt-pre-configuration](#openwrt-pre-configuration). For the second issue, check for running youtubeUnblock instances by using the command `ps -e | grep youtubeUnblock`. If you find any, you can terminate them all with the command `killall youtubeUnblock`.
|
||||||
|
|
||||||
- **rawsocket** *Operation not permitted* indicates that the packet is being dropped by nefilter rules. In fact this is a hint from the kernel that something wrong is going on and we should check the firewall rules. Before dive into the problem let's make it clean how the mangled packets are being sent. Nefilter queue provides us with the ability to mangle the packet on fly but that is not suitable for this program because we need to split the packet to at least two independent packets. So we are using [linux raw sockets](https://man7.org/linux/man-pages/man7/raw.7.html) which allows us to send any ipv4 packet. **The packet goes from the OUTPUT chain even when NFQUEUE is set up on FORWARD (suitable for OpenWRT).** So we need to escape packet rejects here.
|
- **rawsocket** *Operation not permitted* indicates that the packet is being dropped by nefilter rules. In fact this is a hint from the kernel that something wrong is going on and we should check the firewall rules. Before dive into the problem let's make it clean how the mangled packets are being sent. Nefilter queue provides us with the ability to mangle the packet on fly but that is not suitable for this program because we need to split the packet to at least two independent packets. So we are using [linux raw sockets](https://man7.org/linux/man-pages/man7/raw.7.html) which allows us to send any ipv4 packet. **The packet goes from the OUTPUT chain even when NFQUEUE is set up on FORWARD (suitable for OpenWRT).** So we need to escape packet rejects here.
|
||||||
* raw_frags_send EPERM: just make sure outgoing traffic is allowed (RELATED,ESTABLISHED should work, if not, go to step 3)
|
* raw_frags_send EPERM: just make sure outgoing traffic is allowed (RELATED,ESTABLISHED should work, if not, go to step 3)
|
||||||
@@ -435,6 +489,12 @@ cat /sys/module/kyoutubeUnblock/parameters/parameters
|
|||||||
|
|
||||||
and check all the parameters configured.
|
and check all the parameters configured.
|
||||||
|
|
||||||
|
You can check up the statistics of youtubeUnblock with
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo cat /proc/kyoutubeUnblock
|
||||||
|
```
|
||||||
|
|
||||||
### Building kernel module
|
### Building kernel module
|
||||||
|
|
||||||
#### Building on host system
|
#### Building on host system
|
||||||
@@ -452,6 +512,12 @@ make kmake KERNEL_BUILDER_MAKEDIR=~/linux
|
|||||||
```
|
```
|
||||||
Note, that the kernel should be already configured and built. See linux kernel building manuals for more information about your specific case.
|
Note, that the kernel should be already configured and built. See linux kernel building manuals for more information about your specific case.
|
||||||
|
|
||||||
|
**If you got a very large module, you can strip it and significiantly decrese the size:**
|
||||||
|
|
||||||
|
```sh
|
||||||
|
strip --strip-debug kyoutubeUnblock.ko
|
||||||
|
```
|
||||||
|
|
||||||
#### Building with openwrt SDK
|
#### Building with openwrt SDK
|
||||||
|
|
||||||
Building with openwrt SDK is not such a hard thing. The only thing you should do is to obtain the sdk. You can find it by looking to your architecture and version of the openwrt currently used. You should use the exactly your version of openwrt since kernels there change often. You can find the sdk in two ways: by downloading it from their site or by using the openwrt sdk docker container (recommended).
|
Building with openwrt SDK is not such a hard thing. The only thing you should do is to obtain the sdk. You can find it by looking to your architecture and version of the openwrt currently used. You should use the exactly your version of openwrt since kernels there change often. You can find the sdk in two ways: by downloading it from their site or by using the openwrt sdk docker container (recommended).
|
||||||
@@ -477,8 +543,3 @@ When the commands finish, the module is ready. Find it with `find bin -name "kmo
|
|||||||
|
|
||||||
## Padavan
|
## Padavan
|
||||||
YoutubeUnblock may also run on Padavan. [Check the manual here\[rus\]](Padavan.md)
|
YoutubeUnblock may also run on Padavan. [Check the manual here\[rus\]](Padavan.md)
|
||||||
|
|
||||||
|
|
||||||
>If you have any questions/suggestions/problems feel free to open an [issue](https://github.com/Waujito/youtubeUnblock/issues).
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
deps/cyclone/include/compiler_port.h
vendored
2
deps/cyclone/include/compiler_port.h
vendored
@@ -157,7 +157,7 @@ typedef unsigned int uint_t;
|
|||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
int strcasecmp(const char *s1, const char *s2);
|
int strcasecmp(const char *s1, const char *s2);
|
||||||
int strncasecmp(const char *s1, const char *s2, size_t n);
|
int strncasecmp(const char *s1, const char *s2, size_t n);
|
||||||
#if !(_SVID_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE)
|
#if !(defined(_SVID_SOURCE) || defined(_BSD_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE))
|
||||||
char *strtok_r(char *s, const char *delim, char **last);
|
char *strtok_r(char *s, const char *delim, char **last);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
331
src/args.c
331
src/args.c
@@ -26,6 +26,7 @@
|
|||||||
#include "getopt.h"
|
#include "getopt.h"
|
||||||
#include "raw_replacements.h"
|
#include "raw_replacements.h"
|
||||||
|
|
||||||
|
struct statistics_data global_stats;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logging definitions
|
* Logging definitions
|
||||||
@@ -61,14 +62,18 @@ static int read_file(const char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = fseek(fd, 0, SEEK_END);
|
ret = fseek(fd, 0, SEEK_END);
|
||||||
if (ret < 0) {
|
if (ret != 0) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto close_file;
|
goto close_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t fsize = ftell(fd);
|
long fsize = ftell(fd);
|
||||||
fseek(fd, 0, SEEK_SET);
|
if (fsize == -1L) {
|
||||||
if (ret < 0) {
|
ret = -errno;
|
||||||
|
goto close_file;
|
||||||
|
}
|
||||||
|
ret = fseek(fd, 0, SEEK_SET);
|
||||||
|
if (ret != 0) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
goto close_file;
|
goto close_file;
|
||||||
}
|
}
|
||||||
@@ -93,10 +98,9 @@ close_file:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int parse_sni_domains(struct domains_list **dlist, const char *domains_str, size_t domains_strlen) {
|
static int parse_sni_domains(struct trie_container *trie, const char *domains_str, size_t domains_strlen) {
|
||||||
// Empty and shouldn't be used
|
int ret;
|
||||||
struct domains_list ndomain = {0};
|
trie_init(trie);
|
||||||
struct domains_list *cdomain = &ndomain;
|
|
||||||
|
|
||||||
unsigned int j = 0;
|
unsigned int j = 0;
|
||||||
for (unsigned int i = 0; i <= domains_strlen; i++) {
|
for (unsigned int i = 0; i <= domains_strlen; i++) {
|
||||||
@@ -118,38 +122,22 @@ static int parse_sni_domains(struct domains_list **dlist, const char *domains_st
|
|||||||
|
|
||||||
unsigned int domain_len = (i - j);
|
unsigned int domain_len = (i - j);
|
||||||
const char *domain_startp = domains_str + j;
|
const char *domain_startp = domains_str + j;
|
||||||
struct domains_list *edomain = malloc(sizeof(struct domains_list));
|
|
||||||
*edomain = (struct domains_list){0};
|
|
||||||
if (edomain == NULL) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
edomain->domain_len = domain_len;
|
ret = trie_add_string(trie, (const uint8_t *)domain_startp, domain_len);
|
||||||
edomain->domain_name = malloc(domain_len + 1);
|
if (ret < 0) {
|
||||||
if (edomain->domain_name == NULL) {
|
lgerror(ret, "trie_add_string");
|
||||||
return -ENOMEM;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(edomain->domain_name, domain_startp, domain_len);
|
|
||||||
edomain->domain_name[domain_len] = '\0';
|
|
||||||
cdomain->next = edomain;
|
|
||||||
cdomain = edomain;
|
|
||||||
|
|
||||||
j = i + 1;
|
j = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*dlist = ndomain.next;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_sni_domains(struct domains_list *dlist) {
|
static void free_sni_domains(struct trie_container *trie) {
|
||||||
for (struct domains_list *ldl = dlist; ldl != NULL;) {
|
trie_destroy(trie);
|
||||||
struct domains_list *ndl = ldl->next;
|
|
||||||
SFREE(ldl->domain_name);
|
|
||||||
SFREE(ldl);
|
|
||||||
ldl = ndl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long parse_numeric_option(const char* value) {
|
static long parse_numeric_option(const char* value) {
|
||||||
@@ -171,7 +159,63 @@ static long parse_numeric_option(const char* value) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_udp_dport_range(char *str, struct udp_dport_range **udpr, int *udpr_len) {
|
static int parse_faking_strategy(char *optarg, int *faking_strategy) {
|
||||||
|
|
||||||
|
*faking_strategy = 0;
|
||||||
|
char *p = optarg;
|
||||||
|
char *ep = p;
|
||||||
|
while (1) {
|
||||||
|
if (*ep == '\0' || *ep == ',') {
|
||||||
|
if (ep == p) {
|
||||||
|
if (*ep == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
p++, ep++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ep_endsym = *ep;
|
||||||
|
*ep = '\0';
|
||||||
|
|
||||||
|
if (strcmp(p, "randseq") == 0) {
|
||||||
|
*faking_strategy |= FAKE_STRAT_RAND_SEQ;
|
||||||
|
} else if (strcmp(p, "ttl") == 0) {
|
||||||
|
*faking_strategy |= FAKE_STRAT_TTL;
|
||||||
|
} else if (strcmp(p, "tcp_check") == 0) {
|
||||||
|
*faking_strategy |= FAKE_STRAT_TCP_CHECK;
|
||||||
|
} else if (strcmp(p, "pastseq") == 0) {
|
||||||
|
*faking_strategy |= FAKE_STRAT_PAST_SEQ;
|
||||||
|
} else if (strcmp(p, "md5sum") == 0) {
|
||||||
|
*faking_strategy |= FAKE_STRAT_TCP_MD5SUM;
|
||||||
|
} else if (strcmp(p, "timestamp") == 0) {
|
||||||
|
*faking_strategy |= FAKE_STRAT_TCP_TS;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ep = ep_endsym;
|
||||||
|
|
||||||
|
if (*ep == '\0') {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
p = ep + 1;
|
||||||
|
ep = p;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ep++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( CHECK_BITFIELD(*faking_strategy, FAKE_STRAT_PAST_SEQ) &&
|
||||||
|
CHECK_BITFIELD(*faking_strategy, FAKE_STRAT_RAND_SEQ)) {
|
||||||
|
lgerr("Strategies pastseq and randseq are incompatible\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_dport_range(char *str, struct dport_range **udpr, int *udpr_len) {
|
||||||
int seclen = 1;
|
int seclen = 1;
|
||||||
const char *p = str;
|
const char *p = str;
|
||||||
while (*p != '\0') {
|
while (*p != '\0') {
|
||||||
@@ -181,14 +225,14 @@ static int parse_udp_dport_range(char *str, struct udp_dport_range **udpr, int *
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef KERNEL_SPACE
|
#ifdef KERNEL_SPACE
|
||||||
struct udp_dport_range *udp_dport_ranges = kmalloc(
|
struct dport_range *dport_ranges = kmalloc(
|
||||||
seclen * sizeof(struct udp_dport_range), GFP_KERNEL);
|
seclen * sizeof(struct dport_range), GFP_KERNEL);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
struct udp_dport_range *udp_dport_ranges = malloc(
|
struct dport_range *dport_ranges = malloc(
|
||||||
seclen * sizeof(struct udp_dport_range));
|
seclen * sizeof(struct dport_range));
|
||||||
#endif
|
#endif
|
||||||
if (udp_dport_ranges == NULL) {
|
if (dport_ranges == NULL) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +279,7 @@ static int parse_udp_dport_range(char *str, struct udp_dport_range **udpr, int *
|
|||||||
)
|
)
|
||||||
goto erret;
|
goto erret;
|
||||||
|
|
||||||
udp_dport_ranges[i] = (struct udp_dport_range){
|
dport_ranges[i] = (struct dport_range){
|
||||||
.start = num1,
|
.start = num1,
|
||||||
.end = num2
|
.end = num2
|
||||||
};
|
};
|
||||||
@@ -253,15 +297,15 @@ static int parse_udp_dport_range(char *str, struct udp_dport_range **udpr, int *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
free(udp_dport_ranges);
|
free(dport_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
*udpr = udp_dport_ranges;
|
*udpr = dport_ranges;
|
||||||
*udpr_len = i;
|
*udpr_len = i;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
erret:
|
erret:
|
||||||
free(udp_dport_ranges);
|
free(dport_ranges);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -284,6 +328,9 @@ static int parse_fake_custom_payload(
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
unsigned char *custom_buf = malloc(custom_len);
|
unsigned char *custom_buf = malloc(custom_len);
|
||||||
|
if (custom_buf == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < custom_len; i++) {
|
for (int i = 0; i < custom_len; i++) {
|
||||||
ret = sscanf(custom_hex_fake + (i << 1), "%2hhx", custom_buf + i);
|
ret = sscanf(custom_hex_fake + (i << 1), "%2hhx", custom_buf + i);
|
||||||
@@ -303,9 +350,11 @@ enum {
|
|||||||
OPT_EXCLUDE_DOMAINS,
|
OPT_EXCLUDE_DOMAINS,
|
||||||
OPT_SNI_DOMAINS_FILE,
|
OPT_SNI_DOMAINS_FILE,
|
||||||
OPT_EXCLUDE_DOMAINS_FILE,
|
OPT_EXCLUDE_DOMAINS_FILE,
|
||||||
|
OPT_TCP_DPORT_FILTER,
|
||||||
OPT_FAKE_SNI,
|
OPT_FAKE_SNI,
|
||||||
OPT_FAKING_TTL,
|
OPT_FAKING_TTL,
|
||||||
OPT_FAKING_STRATEGY,
|
OPT_FAKING_STRATEGY,
|
||||||
|
OPT_FAKING_TIMESTAMP_DECREASE,
|
||||||
OPT_FAKE_SNI_SEQ_LEN,
|
OPT_FAKE_SNI_SEQ_LEN,
|
||||||
OPT_FAKE_SNI_TYPE,
|
OPT_FAKE_SNI_TYPE,
|
||||||
OPT_FAKE_CUSTOM_PAYLOAD,
|
OPT_FAKE_CUSTOM_PAYLOAD,
|
||||||
@@ -342,12 +391,14 @@ enum {
|
|||||||
OPT_UDP_FAKE_PAYLOAD_LEN,
|
OPT_UDP_FAKE_PAYLOAD_LEN,
|
||||||
OPT_UDP_FAKING_STRATEGY,
|
OPT_UDP_FAKING_STRATEGY,
|
||||||
OPT_UDP_DPORT_FILTER,
|
OPT_UDP_DPORT_FILTER,
|
||||||
|
OPT_UDP_STUN_FILTER,
|
||||||
OPT_UDP_FILTER_QUIC,
|
OPT_UDP_FILTER_QUIC,
|
||||||
OPT_TLS_ENABLED,
|
OPT_TLS_ENABLED,
|
||||||
OPT_CLS,
|
OPT_CLS,
|
||||||
OPT_HELP,
|
OPT_HELP,
|
||||||
OPT_VERSION,
|
OPT_VERSION,
|
||||||
OPT_CONNBYTES_LIMIT,
|
OPT_CONNBYTES_LIMIT,
|
||||||
|
OPT_TCP_M_CONNPKTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct option long_opt[] = {
|
static struct option long_opt[] = {
|
||||||
@@ -361,6 +412,7 @@ static struct option long_opt[] = {
|
|||||||
{"synfake", 1, 0, OPT_SYNFAKE},
|
{"synfake", 1, 0, OPT_SYNFAKE},
|
||||||
{"synfake-len", 1, 0, OPT_SYNFAKE_LEN},
|
{"synfake-len", 1, 0, OPT_SYNFAKE_LEN},
|
||||||
{"tls", 1, 0, OPT_TLS_ENABLED},
|
{"tls", 1, 0, OPT_TLS_ENABLED},
|
||||||
|
{"tcp-dport-filter", 1, 0, OPT_TCP_DPORT_FILTER},
|
||||||
{"fake-sni-seq-len", 1, 0, OPT_FAKE_SNI_SEQ_LEN},
|
{"fake-sni-seq-len", 1, 0, OPT_FAKE_SNI_SEQ_LEN},
|
||||||
{"fake-sni-type", 1, 0, OPT_FAKE_SNI_TYPE},
|
{"fake-sni-type", 1, 0, OPT_FAKE_SNI_TYPE},
|
||||||
{"fake-custom-payload", 1, 0, OPT_FAKE_CUSTOM_PAYLOAD},
|
{"fake-custom-payload", 1, 0, OPT_FAKE_CUSTOM_PAYLOAD},
|
||||||
@@ -368,6 +420,7 @@ static struct option long_opt[] = {
|
|||||||
{"faking-strategy", 1, 0, OPT_FAKING_STRATEGY},
|
{"faking-strategy", 1, 0, OPT_FAKING_STRATEGY},
|
||||||
{"fake-seq-offset", 1, 0, OPT_FAKE_SEQ_OFFSET},
|
{"fake-seq-offset", 1, 0, OPT_FAKE_SEQ_OFFSET},
|
||||||
{"faking-ttl", 1, 0, OPT_FAKING_TTL},
|
{"faking-ttl", 1, 0, OPT_FAKING_TTL},
|
||||||
|
{"faking-timestamp-decrease", 1, 0, OPT_FAKING_TIMESTAMP_DECREASE},
|
||||||
{"frag", 1, 0, OPT_FRAG},
|
{"frag", 1, 0, OPT_FRAG},
|
||||||
{"frag-sni-reverse", 1, 0, OPT_FRAG_SNI_REVERSE},
|
{"frag-sni-reverse", 1, 0, OPT_FRAG_SNI_REVERSE},
|
||||||
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
|
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
|
||||||
@@ -382,8 +435,10 @@ static struct option long_opt[] = {
|
|||||||
{"udp-fake-len", 1, 0, OPT_UDP_FAKE_PAYLOAD_LEN},
|
{"udp-fake-len", 1, 0, OPT_UDP_FAKE_PAYLOAD_LEN},
|
||||||
{"udp-faking-strategy", 1, 0, OPT_UDP_FAKING_STRATEGY},
|
{"udp-faking-strategy", 1, 0, OPT_UDP_FAKING_STRATEGY},
|
||||||
{"udp-dport-filter", 1, 0, OPT_UDP_DPORT_FILTER},
|
{"udp-dport-filter", 1, 0, OPT_UDP_DPORT_FILTER},
|
||||||
|
{"udp-stun-filter", 0, 0, OPT_UDP_STUN_FILTER},
|
||||||
{"udp-filter-quic", 1, 0, OPT_UDP_FILTER_QUIC},
|
{"udp-filter-quic", 1, 0, OPT_UDP_FILTER_QUIC},
|
||||||
{"no-dport-filter", 0, 0, OPT_NO_DPORT_FILTER},
|
{"no-dport-filter", 0, 0, OPT_NO_DPORT_FILTER},
|
||||||
|
{"tcp-match-connpackets", 1, 0, OPT_TCP_M_CONNPKTS},
|
||||||
{"threads", 1, 0, OPT_THREADS},
|
{"threads", 1, 0, OPT_THREADS},
|
||||||
{"silent", 0, 0, OPT_SILENT},
|
{"silent", 0, 0, OPT_SILENT},
|
||||||
{"trace", 0, 0, OPT_TRACE},
|
{"trace", 0, 0, OPT_TRACE},
|
||||||
@@ -425,6 +480,7 @@ void print_usage(const char *argv0) {
|
|||||||
printf("\t--sni-domains-file=<file contains comma or new-line separated list>\n");
|
printf("\t--sni-domains-file=<file contains comma or new-line separated list>\n");
|
||||||
printf("\t--exclude-domains-file=<file contains comma or new-line separated list>\n");
|
printf("\t--exclude-domains-file=<file contains comma or new-line separated list>\n");
|
||||||
printf("\t--tls={enabled|disabled}\n");
|
printf("\t--tls={enabled|disabled}\n");
|
||||||
|
printf("\t--tcp-dport-filter=<5,6,200-500>\n");
|
||||||
printf("\t--fake-sni={1|0}\n");
|
printf("\t--fake-sni={1|0}\n");
|
||||||
printf("\t--fake-sni-seq-len=<length>\n");
|
printf("\t--fake-sni-seq-len=<length>\n");
|
||||||
printf("\t--fake-sni-type={default|random|custom}\n");
|
printf("\t--fake-sni-type={default|random|custom}\n");
|
||||||
@@ -432,7 +488,8 @@ void print_usage(const char *argv0) {
|
|||||||
printf("\t--fake-custom-payload-file=<binary file containing TLS message>\n");
|
printf("\t--fake-custom-payload-file=<binary file containing TLS message>\n");
|
||||||
printf("\t--fake-seq-offset=<offset>\n");
|
printf("\t--fake-seq-offset=<offset>\n");
|
||||||
printf("\t--faking-ttl=<ttl>\n");
|
printf("\t--faking-ttl=<ttl>\n");
|
||||||
printf("\t--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}\n");
|
printf("\t--faking-timestamp-decrease=<val>\n");
|
||||||
|
printf("\t--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum|timestamp}\n");
|
||||||
printf("\t--synfake={1|0}\n");
|
printf("\t--synfake={1|0}\n");
|
||||||
printf("\t--synfake-len=<len>\n");
|
printf("\t--synfake-len=<len>\n");
|
||||||
printf("\t--frag={tcp,ip,none}\n");
|
printf("\t--frag={tcp,ip,none}\n");
|
||||||
@@ -449,11 +506,13 @@ void print_usage(const char *argv0) {
|
|||||||
printf("\t--udp-fake-len=<size of upd fake>\n");
|
printf("\t--udp-fake-len=<size of upd fake>\n");
|
||||||
printf("\t--udp-faking-strategy={checksum|ttl|none}\n");
|
printf("\t--udp-faking-strategy={checksum|ttl|none}\n");
|
||||||
printf("\t--udp-dport-filter=<5,6,200-500>\n");
|
printf("\t--udp-dport-filter=<5,6,200-500>\n");
|
||||||
|
printf("\t--udp-stun-filter\n");
|
||||||
printf("\t--udp-filter-quic={disabled|all|parse}\n");
|
printf("\t--udp-filter-quic={disabled|all|parse}\n");
|
||||||
printf("\t--no-dport-filter\n");
|
printf("\t--no-dport-filter\n");
|
||||||
printf("\t--threads=<threads number>\n");
|
printf("\t--threads=<threads number>\n");
|
||||||
printf("\t--packet-mark=<mark>\n");
|
printf("\t--packet-mark=<mark>\n");
|
||||||
printf("\t--connbytes-limit=<pkts>\n");
|
printf("\t--connbytes-limit=<pkts>\n");
|
||||||
|
printf("\t--tcp-match-connpackets=<n of packets in connection>\n");
|
||||||
printf("\t--silent\n");
|
printf("\t--silent\n");
|
||||||
printf("\t--trace\n");
|
printf("\t--trace\n");
|
||||||
printf("\t--instaflush\n");
|
printf("\t--instaflush\n");
|
||||||
@@ -632,7 +691,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case OPT_SNI_DOMAINS:
|
case OPT_SNI_DOMAINS:
|
||||||
free_sni_domains(sect_config->sni_domains);
|
free_sni_domains(§_config->sni_domains);
|
||||||
sect_config->all_domains = 0;
|
sect_config->all_domains = 0;
|
||||||
if (!strcmp(optarg, "all")) {
|
if (!strcmp(optarg, "all")) {
|
||||||
sect_config->all_domains = 1;
|
sect_config->all_domains = 1;
|
||||||
@@ -648,7 +707,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
|||||||
goto error;
|
goto error;
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
free_sni_domains(sect_config->sni_domains);
|
free_sni_domains(§_config->sni_domains);
|
||||||
ret = read_file(optarg);
|
ret = read_file(optarg);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -661,7 +720,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
case OPT_EXCLUDE_DOMAINS:
|
case OPT_EXCLUDE_DOMAINS:
|
||||||
free_sni_domains(sect_config->exclude_sni_domains);
|
free_sni_domains(§_config->exclude_sni_domains);
|
||||||
ret = parse_sni_domains(§_config->exclude_sni_domains, optarg, strlen(optarg));
|
ret = parse_sni_domains(§_config->exclude_sni_domains, optarg, strlen(optarg));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
@@ -673,7 +732,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
|||||||
goto error;
|
goto error;
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
free_sni_domains(sect_config->exclude_sni_domains);
|
free_sni_domains(§_config->exclude_sni_domains);
|
||||||
ret = read_file(optarg);
|
ret = read_file(optarg);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -735,21 +794,28 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
|||||||
|
|
||||||
sect_config->frag_sni_pos = num;
|
sect_config->frag_sni_pos = num;
|
||||||
break;
|
break;
|
||||||
case OPT_FAKING_STRATEGY:
|
case OPT_TCP_DPORT_FILTER:
|
||||||
if (strcmp(optarg, "randseq") == 0) {
|
{
|
||||||
sect_config->faking_strategy = FAKE_STRAT_RAND_SEQ;
|
SFREE(sect_config->tcp_dport_range);
|
||||||
} else if (strcmp(optarg, "ttl") == 0) {
|
if (parse_dport_range(optarg, §_config->tcp_dport_range, §_config->tcp_dport_range_len) < 0) {
|
||||||
sect_config->faking_strategy = FAKE_STRAT_TTL;
|
goto invalid_opt;
|
||||||
} else if (strcmp(optarg, "tcp_check") == 0) {
|
}
|
||||||
sect_config->faking_strategy = FAKE_STRAT_TCP_CHECK;
|
break;
|
||||||
} else if (strcmp(optarg, "pastseq") == 0) {
|
}
|
||||||
sect_config->faking_strategy = FAKE_STRAT_PAST_SEQ;
|
case OPT_TCP_M_CONNPKTS:
|
||||||
} else if (strcmp(optarg, "md5sum") == 0) {
|
num = parse_numeric_option(optarg);
|
||||||
sect_config->faking_strategy = FAKE_STRAT_TCP_MD5SUM;
|
if (errno != 0 || num < 0) {
|
||||||
} else {
|
|
||||||
goto invalid_opt;
|
goto invalid_opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sect_config->tcp_match_connpkts = num;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_FAKING_STRATEGY:
|
||||||
|
if (parse_faking_strategy(
|
||||||
|
optarg, §_config->faking_strategy) < 0) {
|
||||||
|
goto invalid_opt;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_FAKING_TTL:
|
case OPT_FAKING_TTL:
|
||||||
num = parse_numeric_option(optarg);
|
num = parse_numeric_option(optarg);
|
||||||
@@ -759,6 +825,14 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
|||||||
|
|
||||||
sect_config->faking_ttl = num;
|
sect_config->faking_ttl = num;
|
||||||
break;
|
break;
|
||||||
|
case OPT_FAKING_TIMESTAMP_DECREASE:
|
||||||
|
num = parse_numeric_option(optarg);
|
||||||
|
if (errno != 0) {
|
||||||
|
goto invalid_opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
sect_config->faking_timestamp_decrease = num;
|
||||||
|
break;
|
||||||
case OPT_FAKE_SEQ_OFFSET:
|
case OPT_FAKE_SEQ_OFFSET:
|
||||||
num = parse_numeric_option(optarg);
|
num = parse_numeric_option(optarg);
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
@@ -931,11 +1005,14 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
|
|||||||
case OPT_UDP_DPORT_FILTER:
|
case OPT_UDP_DPORT_FILTER:
|
||||||
{
|
{
|
||||||
SFREE(sect_config->udp_dport_range);
|
SFREE(sect_config->udp_dport_range);
|
||||||
if (parse_udp_dport_range(optarg, §_config->udp_dport_range, §_config->udp_dport_range_len) < 0) {
|
if (parse_dport_range(optarg, §_config->udp_dport_range, §_config->udp_dport_range_len) < 0) {
|
||||||
goto invalid_opt;
|
goto invalid_opt;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OPT_UDP_STUN_FILTER:
|
||||||
|
sect_config->udp_stun_filter = 1;
|
||||||
|
break;
|
||||||
case OPT_UDP_FILTER_QUIC:
|
case OPT_UDP_FILTER_QUIC:
|
||||||
if (strcmp(optarg, "disabled") == 0) {
|
if (strcmp(optarg, "disabled") == 0) {
|
||||||
sect_config->udp_filter_quic = UDP_FILTER_QUIC_DISABLED;
|
sect_config->udp_filter_quic = UDP_FILTER_QUIC_DISABLED;
|
||||||
@@ -1001,8 +1078,26 @@ static size_t print_config_section(const struct section_config_t *section, char
|
|||||||
size_t buf_sz = buffer_size;
|
size_t buf_sz = buffer_size;
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
|
||||||
if (section->tls_enabled) {
|
if (section->tcp_dport_range_len != 0) {
|
||||||
print_cnf_buf("--tls=enabled");
|
print_cnf_raw("--tcp-dport-filter=");
|
||||||
|
for (int i = 0; i < section->tcp_dport_range_len; i++) {
|
||||||
|
struct dport_range range = section->tcp_dport_range[i];
|
||||||
|
print_cnf_raw("%d-%d,", range.start, range.end);
|
||||||
|
}
|
||||||
|
print_cnf_raw(" ");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section->tcp_match_connpkts) {
|
||||||
|
print_cnf_buf("--tcp-match-connpackets=%d",
|
||||||
|
section->tcp_match_connpkts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section->tls_enabled || section->tcp_dport_range_len != 0) {
|
||||||
|
if (section->tls_enabled) {
|
||||||
|
print_cnf_buf("--tls=enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch(section->fragmentation_strategy) {
|
switch(section->fragmentation_strategy) {
|
||||||
case FRAG_STRAT_IP:
|
case FRAG_STRAT_IP:
|
||||||
@@ -1038,28 +1133,63 @@ static size_t print_config_section(const struct section_config_t *section, char
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(section->faking_strategy) {
|
print_cnf_buf("--seg2delay=%d", section->seg2_delay);
|
||||||
case FAKE_STRAT_TTL:
|
} else {
|
||||||
print_cnf_buf("--faking-strategy=ttl");
|
print_cnf_buf("--fake-sni=0");
|
||||||
print_cnf_buf("--faking-ttl=%d", section->faking_ttl);
|
}
|
||||||
break;
|
|
||||||
case FAKE_STRAT_RAND_SEQ:
|
|
||||||
print_cnf_buf("--faking-strategy=randseq");
|
|
||||||
break;
|
|
||||||
case FAKE_STRAT_TCP_CHECK:
|
|
||||||
print_cnf_buf("--faking-strategy=tcp_check");
|
|
||||||
break;
|
|
||||||
case FAKE_STRAT_TCP_MD5SUM:
|
|
||||||
print_cnf_buf("--faking-strategy=md5sum");
|
|
||||||
break;
|
|
||||||
case FAKE_STRAT_PAST_SEQ:
|
|
||||||
print_cnf_buf("--faking-strategy=pastseq");
|
|
||||||
print_cnf_buf("--fake-seq-offset=%d", section->fakeseq_offset);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
if (section->fake_sni && section->faking_strategy) {
|
||||||
|
int show_ttl = 0;
|
||||||
|
int show_seq_offset = 0;
|
||||||
|
int show_faking_ts_decr = 0;
|
||||||
|
|
||||||
|
print_cnf_raw("--faking-strategy=");
|
||||||
|
if (CHECK_BITFIELD(section->faking_strategy, FAKE_STRAT_TTL)) {
|
||||||
|
print_cnf_raw("ttl");
|
||||||
|
print_cnf_raw(",");
|
||||||
|
show_ttl = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_cnf_buf("--seg2delay=%d", section->seg2_delay);
|
if (CHECK_BITFIELD(section->faking_strategy, FAKE_STRAT_RAND_SEQ)) {
|
||||||
|
print_cnf_raw("randseq");
|
||||||
|
print_cnf_raw(",");
|
||||||
|
show_ttl = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(section->faking_strategy, FAKE_STRAT_TCP_CHECK)) {
|
||||||
|
print_cnf_raw("tcp_check");
|
||||||
|
print_cnf_raw(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(section->faking_strategy, FAKE_STRAT_TCP_MD5SUM)) {
|
||||||
|
print_cnf_raw("md5sum");
|
||||||
|
print_cnf_raw(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(section->faking_strategy, FAKE_STRAT_TCP_TS)) {
|
||||||
|
print_cnf_raw("timestamp");
|
||||||
|
print_cnf_raw(",");
|
||||||
|
show_faking_ts_decr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(section->faking_strategy, FAKE_STRAT_PAST_SEQ)) {
|
||||||
|
print_cnf_raw("pastseq");
|
||||||
|
print_cnf_raw(",");
|
||||||
|
}
|
||||||
|
// delete comma and write space
|
||||||
|
print_cnf_raw("\b ");
|
||||||
|
|
||||||
|
if (show_ttl) {
|
||||||
|
print_cnf_buf("--faking-ttl=%d", section->faking_ttl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_seq_offset) {
|
||||||
|
print_cnf_buf("--fake-seq-offset=%d", section->fakeseq_offset);
|
||||||
|
}
|
||||||
|
if (show_faking_ts_decr) {
|
||||||
|
print_cnf_buf("--faking-timestamp-decrease=%d",
|
||||||
|
section->faking_timestamp_decrease);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print_cnf_buf("--tls=disabled");
|
print_cnf_buf("--tls=disabled");
|
||||||
@@ -1067,20 +1197,11 @@ static size_t print_config_section(const struct section_config_t *section, char
|
|||||||
|
|
||||||
if (section->all_domains) {
|
if (section->all_domains) {
|
||||||
print_cnf_buf("--sni-domains=all");
|
print_cnf_buf("--sni-domains=all");
|
||||||
} else if (section->sni_domains != NULL) {
|
} else if (section->sni_domains.vx != NULL) {
|
||||||
print_cnf_raw("--sni-domains=");
|
print_cnf_buf("--sni-domains=<trie of %zu vertexes>", section->sni_domains.sz);
|
||||||
|
|
||||||
for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) {
|
|
||||||
print_cnf_raw("%s,", sne->domain_name);
|
|
||||||
}
|
|
||||||
print_cnf_raw(" ");
|
|
||||||
}
|
}
|
||||||
if (section->exclude_sni_domains != NULL) {
|
if (section->exclude_sni_domains.vx != NULL) {
|
||||||
print_cnf_raw("--exclude-domains=");
|
print_cnf_buf("--exclude-domains=<trie of %zu vertexes>", section->sni_domains.sz);
|
||||||
for (struct domains_list *sne = section->exclude_sni_domains; sne != NULL; sne = sne->next) {
|
|
||||||
print_cnf_raw("%s,", sne->domain_name);
|
|
||||||
}
|
|
||||||
print_cnf_raw(" ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(section->sni_detection) {
|
switch(section->sni_detection) {
|
||||||
@@ -1117,11 +1238,15 @@ static size_t print_config_section(const struct section_config_t *section, char
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (section->udp_stun_filter) {
|
||||||
|
print_cnf_buf("--udp-stun-filter");
|
||||||
|
}
|
||||||
|
|
||||||
if (section->udp_dport_range_len != 0) {
|
if (section->udp_dport_range_len != 0) {
|
||||||
|
|
||||||
print_cnf_raw("--udp-dport-filter=");
|
print_cnf_raw("--udp-dport-filter=");
|
||||||
for (int i = 0; i < section->udp_dport_range_len; i++) {
|
for (int i = 0; i < section->udp_dport_range_len; i++) {
|
||||||
struct udp_dport_range range = section->udp_dport_range[i];
|
struct dport_range range = section->udp_dport_range[i];
|
||||||
print_cnf_raw("%d-%d,", range.start, range.end);
|
print_cnf_raw("%d-%d,", range.start, range.end);
|
||||||
}
|
}
|
||||||
print_cnf_raw(" ");
|
print_cnf_raw(" ");
|
||||||
@@ -1241,11 +1366,11 @@ int init_section_config(struct section_config_t **section, struct section_config
|
|||||||
#else
|
#else
|
||||||
def_section = malloc(sizeof(struct section_config_t));
|
def_section = malloc(sizeof(struct section_config_t));
|
||||||
#endif
|
#endif
|
||||||
*def_section = (struct section_config_t)default_section_config;
|
|
||||||
def_section->prev = prev;
|
|
||||||
|
|
||||||
if (def_section == NULL)
|
if (def_section == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
*def_section = (struct section_config_t)default_section_config;
|
||||||
|
|
||||||
|
def_section->prev = prev;
|
||||||
|
|
||||||
ret = parse_sni_domains(&def_section->sni_domains, default_snistr, sizeof(default_snistr));
|
ret = parse_sni_domains(&def_section->sni_domains, default_snistr, sizeof(default_snistr));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -1253,8 +1378,8 @@ int init_section_config(struct section_config_t **section, struct section_config
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
def_section->fake_sni_pkt = fake_sni_old;
|
def_section->fake_sni_pkt = fake_sni;
|
||||||
def_section->fake_sni_pkt_sz = sizeof(fake_sni_old) - 1;
|
def_section->fake_sni_pkt_sz = sizeof(fake_sni) - 1;
|
||||||
|
|
||||||
*section = def_section;
|
*section = def_section;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1280,10 +1405,12 @@ void free_config_section(struct section_config_t *section) {
|
|||||||
SFREE(section->udp_dport_range);
|
SFREE(section->udp_dport_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_sni_domains(section->sni_domains);
|
if (section->tcp_dport_range_len != 0) {
|
||||||
section->sni_domains = NULL;
|
SFREE(section->tcp_dport_range);
|
||||||
free_sni_domains(section->exclude_sni_domains);
|
}
|
||||||
section->exclude_sni_domains = NULL;
|
|
||||||
|
free_sni_domains(§ion->sni_domains);
|
||||||
|
free_sni_domains(§ion->exclude_sni_domains);
|
||||||
|
|
||||||
section->fake_custom_pkt_sz = 0;
|
section->fake_custom_pkt_sz = 0;
|
||||||
SFREE(section->fake_custom_pkt);
|
SFREE(section->fake_custom_pkt);
|
||||||
|
|||||||
44
src/config.h
44
src/config.h
@@ -25,6 +25,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "trie.h"
|
||||||
|
|
||||||
typedef int (*raw_send_t)(const unsigned char *data, size_t data_len);
|
typedef int (*raw_send_t)(const unsigned char *data, size_t data_len);
|
||||||
/**
|
/**
|
||||||
@@ -47,29 +48,27 @@ struct logging_config_t {
|
|||||||
};
|
};
|
||||||
extern struct logging_config_t logging_conf;
|
extern struct logging_config_t logging_conf;
|
||||||
|
|
||||||
struct udp_dport_range {
|
struct dport_range {
|
||||||
uint16_t start;
|
uint16_t start;
|
||||||
uint16_t end;
|
uint16_t end;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct domains_list {
|
|
||||||
char *domain_name;
|
|
||||||
uint16_t domain_len;
|
|
||||||
|
|
||||||
struct domains_list *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct section_config_t {
|
struct section_config_t {
|
||||||
int id;
|
int id;
|
||||||
struct section_config_t *next;
|
struct section_config_t *next;
|
||||||
struct section_config_t *prev;
|
struct section_config_t *prev;
|
||||||
|
|
||||||
struct domains_list *sni_domains;
|
struct trie_container sni_domains;
|
||||||
struct domains_list *exclude_sni_domains;
|
struct trie_container exclude_sni_domains;
|
||||||
unsigned int all_domains;
|
unsigned int all_domains;
|
||||||
|
|
||||||
int tls_enabled;
|
int tls_enabled;
|
||||||
|
|
||||||
|
struct dport_range *tcp_dport_range;
|
||||||
|
int tcp_dport_range_len;
|
||||||
|
|
||||||
|
int tcp_match_connpkts;
|
||||||
|
|
||||||
int fragmentation_strategy;
|
int fragmentation_strategy;
|
||||||
int frag_sni_reverse;
|
int frag_sni_reverse;
|
||||||
int frag_sni_faked;
|
int frag_sni_faked;
|
||||||
@@ -77,6 +76,7 @@ struct section_config_t {
|
|||||||
int frag_middle_sni;
|
int frag_middle_sni;
|
||||||
int frag_sni_pos;
|
int frag_sni_pos;
|
||||||
unsigned char faking_ttl;
|
unsigned char faking_ttl;
|
||||||
|
unsigned int faking_timestamp_decrease;
|
||||||
int fake_sni;
|
int fake_sni;
|
||||||
unsigned int fake_sni_seq_len;
|
unsigned int fake_sni_seq_len;
|
||||||
|
|
||||||
@@ -111,8 +111,9 @@ struct section_config_t {
|
|||||||
unsigned int udp_fake_len;
|
unsigned int udp_fake_len;
|
||||||
int udp_faking_strategy;
|
int udp_faking_strategy;
|
||||||
|
|
||||||
struct udp_dport_range *udp_dport_range;
|
struct dport_range *udp_dport_range;
|
||||||
int udp_dport_range_len;
|
int udp_dport_range_len;
|
||||||
|
int udp_stun_filter;
|
||||||
int udp_filter_quic;
|
int udp_filter_quic;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -181,6 +182,7 @@ for (struct section_config_t *section = (config)->last_section; section != NULL;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FAKE_TTL 8
|
#define FAKE_TTL 8
|
||||||
|
#define FAKING_TIMESTAMP_DECREASE_TTL 600000
|
||||||
|
|
||||||
#define FAKE_STRAT_NONE 0
|
#define FAKE_STRAT_NONE 0
|
||||||
// Will invalidate fake packets by out-of-ack_seq out-of-seq request
|
// Will invalidate fake packets by out-of-ack_seq out-of-seq request
|
||||||
@@ -192,6 +194,7 @@ for (struct section_config_t *section = (config)->last_section; section != NULL;
|
|||||||
#define FAKE_STRAT_TCP_CHECK (1 << 3)
|
#define FAKE_STRAT_TCP_CHECK (1 << 3)
|
||||||
#define FAKE_STRAT_TCP_MD5SUM (1 << 4)
|
#define FAKE_STRAT_TCP_MD5SUM (1 << 4)
|
||||||
#define FAKE_STRAT_UDP_CHECK (1 << 5)
|
#define FAKE_STRAT_UDP_CHECK (1 << 5)
|
||||||
|
#define FAKE_STRAT_TCP_TS (1 << 6)
|
||||||
|
|
||||||
#define FAKE_STRAT_COUNT 6
|
#define FAKE_STRAT_COUNT 6
|
||||||
|
|
||||||
@@ -204,7 +207,7 @@ for (int strategy = 1; strategy <= (1 << FAKE_STRAT_COUNT); strategy <<= 1) \
|
|||||||
if ((fake_bitmask) & strategy)
|
if ((fake_bitmask) & strategy)
|
||||||
|
|
||||||
#ifndef FAKING_STRATEGY
|
#ifndef FAKING_STRATEGY
|
||||||
#define FAKING_STRATEGY FAKE_STRAT_PAST_SEQ
|
#define FAKING_STRATEGY FAKE_STRAT_TCP_CHECK | FAKE_STRAT_TCP_TS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_FAKE_SIZE 1300
|
#define MAX_FAKE_SIZE 1300
|
||||||
@@ -237,15 +240,19 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define default_section_config { \
|
#define default_section_config { \
|
||||||
.sni_domains = NULL, \
|
.sni_domains = {0}, \
|
||||||
.exclude_sni_domains = NULL, \
|
.exclude_sni_domains = {0}, \
|
||||||
.all_domains = 0, \
|
.all_domains = 0, \
|
||||||
|
.tcp_dport_range = NULL, \
|
||||||
|
.tcp_dport_range_len = 0, \
|
||||||
|
.tcp_match_connpkts = 0, \
|
||||||
.tls_enabled = 1, \
|
.tls_enabled = 1, \
|
||||||
.frag_sni_reverse = 1, \
|
.frag_sni_reverse = 1, \
|
||||||
.frag_sni_faked = 0, \
|
.frag_sni_faked = 0, \
|
||||||
.fragmentation_strategy = FRAGMENTATION_STRATEGY, \
|
.fragmentation_strategy = FRAGMENTATION_STRATEGY, \
|
||||||
.faking_strategy = FAKING_STRATEGY, \
|
.faking_strategy = FAKING_STRATEGY, \
|
||||||
.faking_ttl = FAKE_TTL, \
|
.faking_ttl = FAKE_TTL, \
|
||||||
|
.faking_timestamp_decrease = FAKING_TIMESTAMP_DECREASE_TTL, \
|
||||||
.fake_sni = 1, \
|
.fake_sni = 1, \
|
||||||
.fake_sni_seq_len = 1, \
|
.fake_sni_seq_len = 1, \
|
||||||
.fake_sni_type = FAKE_PAYLOAD_DEFAULT, \
|
.fake_sni_type = FAKE_PAYLOAD_DEFAULT, \
|
||||||
@@ -339,4 +346,13 @@ struct packet_data {
|
|||||||
struct ytb_conntrack yct;
|
struct ytb_conntrack yct;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct statistics_data {
|
||||||
|
unsigned long all_packet_counter;
|
||||||
|
unsigned long packet_counter;
|
||||||
|
unsigned long target_counter;
|
||||||
|
unsigned long sent_counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct statistics_data global_stats;
|
||||||
|
|
||||||
#endif /* YTB_CONFIG_H */
|
#endif /* YTB_CONFIG_H */
|
||||||
|
|||||||
509
src/dpi.c
Normal file
509
src/dpi.c
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
/*
|
||||||
|
youtubeUnblock - https://github.com/Waujito/youtubeUnblock
|
||||||
|
|
||||||
|
Copyright (C) 2024-2025 Vadim Vetrov <vetrovvd@gmail.com>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dpi.c - Inspects packets for blocked patterns.
|
||||||
|
* "If you want to bypass the DPI, you should became the DPI"
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include "types.h" // IWYU pragma: keep
|
||||||
|
#ifndef KERNEL_SPACE
|
||||||
|
#include <stdlib.h>
|
||||||
|
#else
|
||||||
|
#include "linux/inet.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dpi.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "quic.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "tls.h"
|
||||||
|
|
||||||
|
#include "mangle.h"
|
||||||
|
|
||||||
|
void log_packet(const struct parsed_packet *pkt);
|
||||||
|
|
||||||
|
#define MAX_FRAGMENTATION_PTS 16
|
||||||
|
|
||||||
|
struct fragmentation_points {
|
||||||
|
size_t payload_points[16];
|
||||||
|
int used_points;
|
||||||
|
};
|
||||||
|
|
||||||
|
int process_packet(const struct config_t *config, const struct packet_data *pd) {
|
||||||
|
assert (config);
|
||||||
|
assert (pd);
|
||||||
|
|
||||||
|
struct parsed_packet pkt = {0};
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
pkt.yct = pd->yct;
|
||||||
|
|
||||||
|
lgtrace_start();
|
||||||
|
|
||||||
|
pkt.raw_payload = pd->payload;
|
||||||
|
pkt.raw_payload_len = pd->payload_len;
|
||||||
|
|
||||||
|
if (pkt.raw_payload_len > MAX_PACKET_SIZE) {
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt.ipver = netproto_version(pkt.raw_payload, pkt.raw_payload_len);
|
||||||
|
|
||||||
|
lgtrace_wr("IPv%d ", pkt.ipver);
|
||||||
|
|
||||||
|
pkt.transport_proto = -1;
|
||||||
|
if (pkt.ipver == IP4VERSION) {
|
||||||
|
ret = ip4_payload_split((uint8_t *)pkt.raw_payload, pkt.raw_payload_len,
|
||||||
|
(struct iphdr **)&pkt.iph, &pkt.iph_len,
|
||||||
|
(uint8_t **)&pkt.ip_payload, &pkt.ip_payload_len);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto accept;
|
||||||
|
|
||||||
|
pkt.transport_proto = pkt.iph->protocol;
|
||||||
|
}
|
||||||
|
#ifndef NO_IPV6
|
||||||
|
else if (pkt.ipver == IP6VERSION && config->use_ipv6) {
|
||||||
|
ret = ip6_payload_split((uint8_t *)pkt.raw_payload, pkt.raw_payload_len,
|
||||||
|
(struct ip6_hdr **)&pkt.ip6h, &pkt.iph_len,
|
||||||
|
(uint8_t **)&pkt.ip_payload, &pkt.ip_payload_len);
|
||||||
|
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto accept;
|
||||||
|
|
||||||
|
pkt.transport_proto = pkt.ip6h->ip6_nxt;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pkt.transport_proto == IPPROTO_TCP) {
|
||||||
|
int ret = tcp_payload_split((uint8_t *)pkt.raw_payload, pkt.raw_payload_len,
|
||||||
|
NULL, NULL,
|
||||||
|
(struct tcphdr **)&pkt.tcph, &pkt.tcph_len,
|
||||||
|
(uint8_t **)&pkt.transport_payload, &pkt.transport_payload_len);
|
||||||
|
if (ret < 0)
|
||||||
|
goto accept;
|
||||||
|
} else if (pkt.transport_proto == IPPROTO_UDP) {
|
||||||
|
int ret = udp_payload_split((uint8_t *)pkt.raw_payload, pkt.raw_payload_len,
|
||||||
|
NULL, NULL,
|
||||||
|
(struct udphdr **)&pkt.udph,
|
||||||
|
(uint8_t **)&pkt.transport_payload, &pkt.transport_payload_len);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_LEVEL >= VERBOSE_TRACE) {
|
||||||
|
log_packet(&pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int verdict = PKT_CONTINUE;
|
||||||
|
|
||||||
|
ITER_CONFIG_SECTIONS(config, section) {
|
||||||
|
lgtrace_wr("Section #%d: ", CONFIG_SECTION_NUMBER(section));
|
||||||
|
|
||||||
|
switch (pkt.transport_proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
verdict = process_tcp_packet(section, &pkt);
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
verdict = process_udp_packet(section, &pkt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verdict == PKT_CONTINUE) {
|
||||||
|
lgtrace_wr("continue_flow");
|
||||||
|
lgtrace_write();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_write();
|
||||||
|
goto ret_verdict;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept:
|
||||||
|
verdict = PKT_ACCEPT;
|
||||||
|
|
||||||
|
ret_verdict:
|
||||||
|
|
||||||
|
switch (verdict) {
|
||||||
|
case PKT_ACCEPT:
|
||||||
|
lgtrace_wr("accept");
|
||||||
|
break;
|
||||||
|
case PKT_DROP:
|
||||||
|
lgtrace_wr("drop");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lgtrace_wr("unknown verdict: %d", verdict);
|
||||||
|
}
|
||||||
|
lgtrace_end();
|
||||||
|
|
||||||
|
return verdict;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum tls_proc_verdict {
|
||||||
|
TLS_NOT_MATCHED,
|
||||||
|
TLS_ERROR,
|
||||||
|
TLS_MATCHED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tls_proc_verdict process_tls_packet(const struct section_config_t *section,
|
||||||
|
const struct parsed_packet *pkt,
|
||||||
|
struct fragmentation_points *frag_pts);
|
||||||
|
|
||||||
|
|
||||||
|
int perform_attack(const struct section_config_t *section,
|
||||||
|
const struct parsed_packet *pkt, const struct fragmentation_points *frag_pts);
|
||||||
|
|
||||||
|
int process_tcp_packet(const struct section_config_t *section, const struct parsed_packet *pkt) {
|
||||||
|
assert (section);
|
||||||
|
assert (pkt);
|
||||||
|
|
||||||
|
assert (pkt->transport_proto == IPPROTO_TCP);
|
||||||
|
|
||||||
|
uint16_t dport = ntohs(pkt->tcph->dest);
|
||||||
|
|
||||||
|
if (section->tcp_dport_range_len) {
|
||||||
|
int is_dport_matched = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < section->tcp_dport_range_len; i++) {
|
||||||
|
struct dport_range crange = section->tcp_dport_range[i];
|
||||||
|
if (dport >= crange.start && dport <= crange.end) {
|
||||||
|
lgtrace_addp("matched to %d-%d", crange.start, crange.end);
|
||||||
|
is_dport_matched = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_dport_matched) {
|
||||||
|
return PKT_CONTINUE;
|
||||||
|
}
|
||||||
|
} else if (section->dport_filter && dport != 443) {
|
||||||
|
return PKT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkt->tcph->syn && section->synfake) {
|
||||||
|
return send_synfake(section, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkt->tcph->syn)
|
||||||
|
return PKT_CONTINUE;
|
||||||
|
|
||||||
|
int is_matched = 0;
|
||||||
|
struct fragmentation_points frag_pts = {0};
|
||||||
|
|
||||||
|
if (!is_matched && section->tls_enabled) {
|
||||||
|
enum tls_proc_verdict vrd = process_tls_packet(section, pkt, &frag_pts);
|
||||||
|
|
||||||
|
if (vrd == TLS_ERROR) {
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vrd == TLS_MATCHED) {
|
||||||
|
is_matched = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_matched && section->tcp_match_connpkts && pkt->yct.orig_packets) {
|
||||||
|
if (pkt->yct.orig_packets <= section->tcp_match_connpkts) {
|
||||||
|
lgtrace_addp("connpackets match: %u <= %d",
|
||||||
|
(uint32_t) pkt->yct.orig_packets, section->tcp_match_connpkts);
|
||||||
|
is_matched = 1;
|
||||||
|
|
||||||
|
frag_pts.used_points = 0;
|
||||||
|
if (section->frag_sni_pos &&
|
||||||
|
pkt->transport_payload_len > section->frag_sni_pos) {
|
||||||
|
frag_pts.payload_points[frag_pts.used_points++] =
|
||||||
|
section->frag_sni_pos;
|
||||||
|
lgtrace_addp("frag set to %d", section->frag_sni_pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_matched) {
|
||||||
|
return perform_attack(section, pkt, &frag_pts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PKT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bubblesort(size_t arr[], size_t n){
|
||||||
|
for (int i = 0; i < n - 1; i++) {
|
||||||
|
for (int j = 0; j < n - 1 - i; j++) {
|
||||||
|
if (arr[j] > arr[j + 1]) {
|
||||||
|
int temp = arr[j];
|
||||||
|
arr[j] = arr[j + 1];
|
||||||
|
arr[j + 1] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum tls_proc_verdict process_tls_packet(const struct section_config_t *section,
|
||||||
|
const struct parsed_packet *pkt,
|
||||||
|
struct fragmentation_points *frag_pts) {
|
||||||
|
assert (section);
|
||||||
|
assert (pkt);
|
||||||
|
|
||||||
|
|
||||||
|
struct tls_verdict vrd = analyze_tls_data(section,
|
||||||
|
pkt->transport_payload, pkt->transport_payload_len);
|
||||||
|
lgtrace_addp("TLS analyzed");
|
||||||
|
|
||||||
|
if (vrd.sni_len != 0) {
|
||||||
|
lgtrace_addp("SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vrd.target_sni) {
|
||||||
|
lgdebug("Target SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
|
||||||
|
size_t target_sni_offset = vrd.target_sni_ptr - pkt->transport_payload;
|
||||||
|
|
||||||
|
size_t ipd_offset = target_sni_offset;
|
||||||
|
size_t mid_offset = ipd_offset + vrd.target_sni_len / 2;
|
||||||
|
|
||||||
|
// hardcode googlevideo.com split
|
||||||
|
// googlevideo domains are very long, so
|
||||||
|
// it is possible for the entire domain to not be
|
||||||
|
// splitted (split goes for subdomain)
|
||||||
|
if (vrd.target_sni_len > 30) {
|
||||||
|
mid_offset = ipd_offset +
|
||||||
|
vrd.target_sni_len - 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
frag_pts->used_points = 0;
|
||||||
|
|
||||||
|
if (section->frag_sni_pos && pkt->transport_payload_len > section->frag_sni_pos) {
|
||||||
|
frag_pts->payload_points[frag_pts->used_points++] = section->frag_sni_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section->frag_middle_sni) {
|
||||||
|
frag_pts->payload_points[frag_pts->used_points++] = mid_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
bubblesort(frag_pts->payload_points, frag_pts->used_points);
|
||||||
|
|
||||||
|
return TLS_MATCHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TLS_NOT_MATCHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int perform_attack(const struct section_config_t *section,
|
||||||
|
const struct parsed_packet *pkt, const struct fragmentation_points *frag_pts) {
|
||||||
|
assert (section);
|
||||||
|
assert (pkt);
|
||||||
|
assert (frag_pts);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
size_t payload_len = pkt->raw_payload_len;
|
||||||
|
uint8_t *payload = malloc(pkt->raw_payload_len);
|
||||||
|
if (payload == NULL) {
|
||||||
|
lgerror(-ENOMEM, "Allocation error");
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(payload, pkt->raw_payload, pkt->raw_payload_len);
|
||||||
|
|
||||||
|
if (pkt->transport_payload_len > AVAILABLE_MTU) {
|
||||||
|
lgdebug("WARNING! Tartget packet is too big and may cause issues!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section->fake_sni) {
|
||||||
|
void *iph;
|
||||||
|
size_t iph_len;
|
||||||
|
struct tcphdr *tcph;
|
||||||
|
size_t tcph_len;
|
||||||
|
uint8_t *data;
|
||||||
|
size_t dlen;
|
||||||
|
|
||||||
|
int ret = tcp_payload_split(payload, payload_len,
|
||||||
|
&iph, &iph_len, &tcph, &tcph_len,
|
||||||
|
&data, &dlen);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "tcp_payload_split in targ_sni");
|
||||||
|
goto accept_lc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section->fk_winsize) {
|
||||||
|
tcph->window = htons(section->fk_winsize);
|
||||||
|
set_tcp_checksum(tcph, iph, iph_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct fake_type f_type = args_default_fake_type(section);
|
||||||
|
post_fake_sni(f_type, iph, iph_len, tcph, tcph_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (frag_pts->used_points > 0) {
|
||||||
|
if (section->fragmentation_strategy == FRAG_STRAT_TCP) {
|
||||||
|
ret = send_tcp_frags(section, payload, payload_len, frag_pts->payload_points,
|
||||||
|
frag_pts->used_points, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "tcp4 send frags");
|
||||||
|
goto accept_lc;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto drop_lc;
|
||||||
|
} else if (section->fragmentation_strategy == FRAG_STRAT_IP && pkt->ipver == IP4VERSION) {
|
||||||
|
ret = send_ip4_frags(section, payload, payload_len, frag_pts->payload_points,
|
||||||
|
frag_pts->used_points, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "tcp4 send frags");
|
||||||
|
goto accept_lc;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto drop_lc;
|
||||||
|
|
||||||
|
} else if (section->fragmentation_strategy == FRAG_STRAT_IP && pkt->ipver != IP4VERSION) {
|
||||||
|
lginfo("WARNING: IP fragmentation is supported only for IPv4");
|
||||||
|
goto accept_lc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
accept_lc:
|
||||||
|
free(payload);
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
drop_lc:
|
||||||
|
free(payload);
|
||||||
|
return PKT_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_udp_packet(const struct section_config_t *section, const struct parsed_packet *pkt) {
|
||||||
|
assert (section);
|
||||||
|
assert (pkt);
|
||||||
|
|
||||||
|
assert (pkt->transport_proto == IPPROTO_UDP);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!detect_udp_filtered(section, pkt->raw_payload, pkt->raw_payload_len))
|
||||||
|
goto continue_flow;
|
||||||
|
|
||||||
|
if (section->udp_mode == UDP_MODE_DROP)
|
||||||
|
goto drop;
|
||||||
|
else if (section->udp_mode == UDP_MODE_FAKE) {
|
||||||
|
for (int i = 0; i < section->udp_fake_seq_len; i++) {
|
||||||
|
uint8_t *fake_udp = NULL;
|
||||||
|
size_t fake_udp_len = 0;
|
||||||
|
|
||||||
|
struct udp_fake_type fake_type = {
|
||||||
|
.fake_len = section->udp_fake_len,
|
||||||
|
.strategy = {
|
||||||
|
.strategy = section->udp_faking_strategy,
|
||||||
|
.faking_ttl = section->faking_ttl,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ret = gen_fake_udp(fake_type, pkt->iph, pkt->iph_len, pkt->udph,
|
||||||
|
&fake_udp, &fake_udp_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "gen_fake_udp");
|
||||||
|
goto erret;
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_addp("post fake udp #%d", i + 1);
|
||||||
|
|
||||||
|
ret = instance_config.send_raw_packet(fake_udp, fake_udp_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "send fake udp");
|
||||||
|
goto erret_lc;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fake_udp);
|
||||||
|
continue;
|
||||||
|
erret_lc:
|
||||||
|
free(fake_udp);
|
||||||
|
erret:
|
||||||
|
goto accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// requeue
|
||||||
|
ret = instance_config.send_raw_packet(pkt->raw_payload, pkt->raw_payload_len);
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue_flow:
|
||||||
|
return PKT_CONTINUE;
|
||||||
|
accept:
|
||||||
|
return PKT_ACCEPT;
|
||||||
|
drop:
|
||||||
|
return PKT_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_packet(const struct parsed_packet *pkt) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
const char *bpt = inet_ntop(
|
||||||
|
pkt->ipver == IP4VERSION ? AF_INET : AF_INET6,
|
||||||
|
pkt->ipver == IP4VERSION ? (void *)(&pkt->iph->saddr) :
|
||||||
|
(void *)(&pkt->ip6h->ip6_src),
|
||||||
|
ylgh_curptr, ylgh_leftbuf);
|
||||||
|
if (bpt != NULL) {
|
||||||
|
ret = strnlen(bpt, ylgh_leftbuf);
|
||||||
|
ylgh_leftbuf -= ret;
|
||||||
|
ylgh_curptr += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_wr(" => ");
|
||||||
|
|
||||||
|
bpt = inet_ntop(
|
||||||
|
pkt->ipver == IP4VERSION ? AF_INET : AF_INET6,
|
||||||
|
pkt->ipver == IP4VERSION ? (void *)(&pkt->iph->daddr) :
|
||||||
|
(void *)(&pkt->ip6h->ip6_dst),
|
||||||
|
ylgh_curptr, ylgh_leftbuf);
|
||||||
|
if (bpt != NULL) {
|
||||||
|
ret = strnlen(bpt, ylgh_leftbuf);
|
||||||
|
ylgh_leftbuf -= ret;
|
||||||
|
ylgh_curptr += ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_wr(" ");
|
||||||
|
int sport = -1, dport = -1;
|
||||||
|
|
||||||
|
if (pkt->transport_proto == IPPROTO_TCP) {
|
||||||
|
lgtrace_wr("TCP ");
|
||||||
|
|
||||||
|
sport = ntohs(pkt->tcph->source);
|
||||||
|
dport = ntohs(pkt->tcph->dest);
|
||||||
|
|
||||||
|
} else if (pkt->transport_proto == IPPROTO_UDP) {
|
||||||
|
lgtrace_wr("UDP ");
|
||||||
|
|
||||||
|
sport = ntohs(pkt->udph->source);
|
||||||
|
dport = ntohs(pkt->udph->dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
lgtrace_wr("%d => %d ", sport, dport);
|
||||||
|
lgtrace_write();
|
||||||
|
|
||||||
|
lgtrace_wr("Transport payload: [ ");
|
||||||
|
for (int i = 0; i < min((int)16, (int)pkt->transport_payload_len); i++) {
|
||||||
|
lgtrace_wr("%02x ", pkt->transport_payload[i]);
|
||||||
|
}
|
||||||
|
lgtrace_wr("]");
|
||||||
|
lgtrace_write();
|
||||||
|
}
|
||||||
87
src/dpi.h
Normal file
87
src/dpi.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
youtubeUnblock - https://github.com/Waujito/youtubeUnblock
|
||||||
|
|
||||||
|
Copyright (C) 2024-2025 Vadim Vetrov <vetrovvd@gmail.com>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef YU_DPI_H
|
||||||
|
#define YU_DPI_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "tls.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define PKT_ACCEPT 0
|
||||||
|
#define PKT_DROP 1
|
||||||
|
// Used for section config
|
||||||
|
#define PKT_CONTINUE 2
|
||||||
|
|
||||||
|
struct parsed_packet {
|
||||||
|
const uint8_t *raw_payload;
|
||||||
|
uint32_t raw_payload_len;
|
||||||
|
|
||||||
|
int ipver;
|
||||||
|
union {
|
||||||
|
void *ipxh;
|
||||||
|
const struct iphdr *iph;
|
||||||
|
|
||||||
|
#ifndef NO_IPV6
|
||||||
|
const struct ip6_hdr *ip6h;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
size_t iph_len;
|
||||||
|
|
||||||
|
const uint8_t *ip_payload;
|
||||||
|
size_t ip_payload_len;
|
||||||
|
|
||||||
|
int transport_proto;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
const struct tcphdr *tcph;
|
||||||
|
size_t tcph_len;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
const struct udphdr *udph;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t *transport_payload;
|
||||||
|
size_t transport_payload_len;
|
||||||
|
|
||||||
|
struct ytb_conntrack yct;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the packet and returns verdict.
|
||||||
|
* This is the primary function that traverses the packet.
|
||||||
|
*/
|
||||||
|
int process_packet(const struct config_t *config, const struct packet_data *pd);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processe the TCP packet.
|
||||||
|
* Returns verdict.
|
||||||
|
*/
|
||||||
|
int process_tcp_packet(const struct section_config_t *section, const struct parsed_packet *pkt);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the UDP packet.
|
||||||
|
* Returns verdict.
|
||||||
|
*/
|
||||||
|
int process_udp_packet(const struct section_config_t *section, const struct parsed_packet *pkt);
|
||||||
|
|
||||||
|
#endif /* DPI_H */
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <linux/net.h>
|
#include <linux/net.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_ipv4.h>
|
#include <linux/netfilter_ipv4.h>
|
||||||
@@ -329,6 +330,8 @@ erret_lc:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++global_stats.sent_counter;
|
||||||
|
|
||||||
int ipvx = netproto_version(pkt, pktlen);
|
int ipvx = netproto_version(pkt, pktlen);
|
||||||
|
|
||||||
if (ipvx == IP4VERSION) {
|
if (ipvx == IP4VERSION) {
|
||||||
@@ -480,8 +483,10 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
|||||||
uint8_t *data_buf = NULL;
|
uint8_t *data_buf = NULL;
|
||||||
int nf_verdict = NF_ACCEPT;
|
int nf_verdict = NF_ACCEPT;
|
||||||
|
|
||||||
|
kref_get(&cur_config->refcount);
|
||||||
struct config_t *config = cur_config;
|
struct config_t *config = cur_config;
|
||||||
kref_get(&config->refcount);
|
|
||||||
|
++global_stats.all_packet_counter;
|
||||||
|
|
||||||
if ((skb->mark & config->mark) == config->mark) {
|
if ((skb->mark & config->mark) == config->mark) {
|
||||||
goto send_verdict;
|
goto send_verdict;
|
||||||
@@ -523,12 +528,14 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
|||||||
pd.payload_len = skb->len;
|
pd.payload_len = skb->len;
|
||||||
|
|
||||||
int vrd = process_packet(config, &pd);
|
int vrd = process_packet(config, &pd);
|
||||||
|
++global_stats.packet_counter;
|
||||||
|
|
||||||
switch(vrd) {
|
switch(vrd) {
|
||||||
case PKT_ACCEPT:
|
case PKT_ACCEPT:
|
||||||
nf_verdict = NF_ACCEPT;
|
nf_verdict = NF_ACCEPT;
|
||||||
break;
|
break;
|
||||||
case PKT_DROP:
|
case PKT_DROP:
|
||||||
|
++global_stats.target_counter;
|
||||||
nf_verdict = NF_STOLEN;
|
nf_verdict = NF_STOLEN;
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
break;
|
break;
|
||||||
@@ -580,6 +587,37 @@ static struct pernet_operations ykb_pernet_ops = {
|
|||||||
};
|
};
|
||||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROC_FS
|
||||||
|
|
||||||
|
static int proc_stats_show(struct seq_file *s, void *v) {
|
||||||
|
seq_printf(s, "youtubeUnblock stats: \n"
|
||||||
|
"\tCatched: %ld packets\n"
|
||||||
|
"\tProcessed: %ld packets\n"
|
||||||
|
"\tTargetted: %ld packets\n"
|
||||||
|
"\tSent over socket %ld packets\n",
|
||||||
|
global_stats.all_packet_counter, global_stats.packet_counter,
|
||||||
|
global_stats.target_counter, global_stats.sent_counter);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0)
|
||||||
|
|
||||||
|
static int proc_stats_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, proc_stats_show, NULL);
|
||||||
|
}
|
||||||
|
static const struct file_operations proc_stats_operations = {
|
||||||
|
.open = proc_stats_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* KERNEL_VERSION */
|
||||||
|
|
||||||
|
#endif /* CONFIG_PROC_FS */
|
||||||
|
|
||||||
static int __init ykb_init(void) {
|
static int __init ykb_init(void) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -615,6 +653,18 @@ static int __init ykb_init(void) {
|
|||||||
}
|
}
|
||||||
#endif /* NO_IPV6 */
|
#endif /* NO_IPV6 */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROC_FS
|
||||||
|
if (!
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
|
||||||
|
proc_create_single("kyoutubeUnblock", 0, NULL, proc_stats_show)
|
||||||
|
#else
|
||||||
|
proc_create("kyoutubeUnblock", 0, NULL, &proc_stats_operations)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
lgwarning("kyoutubeUnblock procfs entry creation failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
|
||||||
ret = register_pernet_subsys(&ykb_pernet_ops);
|
ret = register_pernet_subsys(&ykb_pernet_ops);
|
||||||
#else
|
#else
|
||||||
@@ -651,6 +701,10 @@ static void __exit ykb_destroy(void) {
|
|||||||
close_raw6_socket();
|
close_raw6_socket();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROC_FS
|
||||||
|
remove_proc_entry("kyoutubeUnblock", NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
close_raw_socket();
|
close_raw_socket();
|
||||||
kref_put(&cur_config->refcount, config_release);
|
kref_put(&cur_config->refcount, config_release);
|
||||||
lginfo("youtubeUnblock kernel module destroyed.\n");
|
lginfo("youtubeUnblock kernel module destroyed.\n");
|
||||||
|
|||||||
633
src/mangle.c
633
src/mangle.c
@@ -25,6 +25,7 @@
|
|||||||
#include "quic.h"
|
#include "quic.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
#include "dpi.h"
|
||||||
|
|
||||||
#ifndef KERNEL_SPACE
|
#ifndef KERNEL_SPACE
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -32,488 +33,63 @@
|
|||||||
#include "linux/inet.h"
|
#include "linux/inet.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int process_packet(const struct config_t *config, const struct packet_data *pd) {
|
int send_synfake(const struct section_config_t *section, const struct parsed_packet *pkt) {
|
||||||
const uint8_t *raw_payload = pd->payload;
|
assert (section);
|
||||||
uint32_t raw_payload_len = pd->payload_len;
|
assert (pkt);
|
||||||
|
|
||||||
if (raw_payload_len > MAX_PACKET_SIZE) {
|
assert (pkt->transport_proto == IPPROTO_TCP);
|
||||||
|
assert (pkt->tcph->syn);
|
||||||
|
|
||||||
|
lgtrace_addp("TCP syn alter");
|
||||||
|
|
||||||
|
size_t fake_len = section->fake_sni_pkt_sz;
|
||||||
|
if (section->synfake_len)
|
||||||
|
fake_len = min((int)section->synfake_len, (int)fake_len);
|
||||||
|
|
||||||
|
|
||||||
|
size_t payload_len = pkt->iph_len + pkt->tcph_len + fake_len;
|
||||||
|
uint8_t *payload = malloc(payload_len);
|
||||||
|
if (payload == NULL) {
|
||||||
|
lgerror(-ENOMEM, "Allocation error");
|
||||||
return PKT_ACCEPT;
|
return PKT_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct iphdr *iph;
|
memcpy(payload, pkt->ipxh, pkt->iph_len);
|
||||||
const struct ip6_hdr *ip6h;
|
memcpy(payload + pkt->iph_len, pkt->tcph, pkt->tcph_len);
|
||||||
size_t iph_len;
|
memcpy(payload + pkt->iph_len + pkt->tcph_len, section->fake_sni_pkt, fake_len);
|
||||||
const uint8_t *ip_payload;
|
|
||||||
size_t ip_payload_len;
|
|
||||||
const char *bpt;
|
|
||||||
|
|
||||||
int transport_proto = -1;
|
struct tcphdr *tcph = (struct tcphdr *)(payload + pkt->iph_len);
|
||||||
int ipver = netproto_version(raw_payload, raw_payload_len);
|
if (pkt->ipver == IP4VERSION) {
|
||||||
int ret;
|
struct iphdr *iph = (struct iphdr *)payload;
|
||||||
|
iph->tot_len = htons(pkt->iph_len + pkt->tcph_len + fake_len);
|
||||||
lgtrace_start();
|
set_ip_checksum(payload, pkt->iph_len);
|
||||||
|
set_tcp_checksum(tcph, iph, pkt->iph_len);
|
||||||
lgtrace_wr("IPv%d ", ipver);
|
} else if (pkt->ipver == IP6VERSION) {
|
||||||
|
struct ip6_hdr *ip6h = (struct ip6_hdr *)payload;
|
||||||
if (ipver == IP4VERSION) {
|
ip6h->ip6_plen = ntohs(pkt->tcph_len + fake_len);
|
||||||
ret = ip4_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
set_ip_checksum(ip6h, pkt->iph_len);
|
||||||
(struct iphdr **)&iph, &iph_len,
|
set_tcp_checksum(tcph, ip6h, pkt->iph_len);
|
||||||
(uint8_t **)&ip_payload, &ip_payload_len);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
goto accept;
|
|
||||||
|
|
||||||
transport_proto = iph->protocol;
|
|
||||||
|
|
||||||
}
|
|
||||||
#ifndef NO_IPV6
|
|
||||||
else if (ipver == IP6VERSION && config->use_ipv6) {
|
|
||||||
ret = ip6_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
|
||||||
(struct ip6_hdr **)&ip6h, &iph_len,
|
|
||||||
(uint8_t **)&ip_payload, &ip_payload_len);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
goto accept;
|
|
||||||
|
|
||||||
transport_proto = ip6h->ip6_nxt;
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
lgtrace("Unknown layer 3 protocol version: %d", ipver);
|
|
||||||
goto accept;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG_LEVEL >= VERBOSE_TRACE) {
|
int ret = instance_config.send_raw_packet(payload, payload_len);
|
||||||
bpt = inet_ntop(
|
|
||||||
ipver == IP4VERSION ? AF_INET : AF_INET6,
|
|
||||||
ipver == IP4VERSION ? (void *)(&iph->saddr) :
|
|
||||||
(void *)(&ip6h->ip6_src),
|
|
||||||
ylgh_curptr, ylgh_leftbuf);
|
|
||||||
if (bpt != NULL) {
|
|
||||||
ret = strnlen(bpt, ylgh_leftbuf);
|
|
||||||
ylgh_leftbuf -= ret;
|
|
||||||
ylgh_curptr += ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
lgtrace_wr(" => ");
|
|
||||||
|
|
||||||
bpt = inet_ntop(
|
|
||||||
ipver == IP4VERSION ? AF_INET : AF_INET6,
|
|
||||||
ipver == IP4VERSION ? (void *)(&iph->daddr) :
|
|
||||||
(void *)(&ip6h->ip6_dst),
|
|
||||||
ylgh_curptr, ylgh_leftbuf);
|
|
||||||
if (bpt != NULL) {
|
|
||||||
ret = strnlen(bpt, ylgh_leftbuf);
|
|
||||||
ylgh_leftbuf -= ret;
|
|
||||||
ylgh_curptr += ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
lgtrace_wr(" ");
|
|
||||||
const uint8_t *transport_payload = NULL;
|
|
||||||
size_t transport_payload_len = 0;
|
|
||||||
int sport = -1, dport = -1;
|
|
||||||
|
|
||||||
if (transport_proto == IPPROTO_TCP) {
|
|
||||||
lgtrace_wr("TCP ");
|
|
||||||
const struct tcphdr *tcph;
|
|
||||||
ret = tcp_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
|
||||||
NULL, NULL,
|
|
||||||
(struct tcphdr **)&tcph, NULL,
|
|
||||||
(uint8_t **)&transport_payload, &transport_payload_len);
|
|
||||||
|
|
||||||
if (ret == 0) {
|
|
||||||
sport = ntohs(tcph->source);
|
|
||||||
dport = ntohs(tcph->dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (transport_proto == IPPROTO_UDP) {
|
|
||||||
lgtrace_wr("UDP ");
|
|
||||||
const struct udphdr *udph = ((const struct udphdr *)ip_payload);
|
|
||||||
ret = udp_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
|
||||||
NULL, NULL,
|
|
||||||
(struct udphdr **)&udph,
|
|
||||||
(uint8_t **)&transport_payload, &transport_payload_len);
|
|
||||||
|
|
||||||
if (ret == 0) {
|
|
||||||
sport = ntohs(udph->source);
|
|
||||||
dport = ntohs(udph->dest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lgtrace_wr("%d => %d ", sport, dport);
|
|
||||||
lgtrace_write();
|
|
||||||
|
|
||||||
lgtrace_wr("Transport payload: [ ");
|
|
||||||
for (int i = 0; i < min((int)16, (int)transport_payload_len); i++) {
|
|
||||||
lgtrace_wr("%02x ", transport_payload[i]);
|
|
||||||
}
|
|
||||||
lgtrace_wr("]");
|
|
||||||
lgtrace_write();
|
|
||||||
}
|
|
||||||
|
|
||||||
int verdict = PKT_CONTINUE;
|
|
||||||
|
|
||||||
ITER_CONFIG_SECTIONS(config, section) {
|
|
||||||
lgtrace_wr("Section #%d: ", CONFIG_SECTION_NUMBER(section));
|
|
||||||
|
|
||||||
switch (transport_proto) {
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
verdict = process_tcp_packet(section, raw_payload, raw_payload_len);
|
|
||||||
break;
|
|
||||||
case IPPROTO_UDP:
|
|
||||||
verdict = process_udp_packet(section, raw_payload, raw_payload_len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verdict == PKT_CONTINUE) {
|
|
||||||
lgtrace_wr("continue_flow");
|
|
||||||
lgtrace_write();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lgtrace_write();
|
|
||||||
goto ret_verdict;
|
|
||||||
}
|
|
||||||
|
|
||||||
accept:
|
|
||||||
verdict = PKT_ACCEPT;
|
|
||||||
|
|
||||||
ret_verdict:
|
|
||||||
|
|
||||||
switch (verdict) {
|
|
||||||
case PKT_ACCEPT:
|
|
||||||
lgtrace_wr("accept");
|
|
||||||
break;
|
|
||||||
case PKT_DROP:
|
|
||||||
lgtrace_wr("drop");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lgtrace_wr("unknown verdict: %d", verdict);
|
|
||||||
}
|
|
||||||
lgtrace_end();
|
|
||||||
|
|
||||||
return verdict;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_tcp_packet(const struct section_config_t *section, const uint8_t *raw_payload, size_t raw_payload_len) {
|
|
||||||
const void *ipxh;
|
|
||||||
size_t iph_len;
|
|
||||||
const struct tcphdr *tcph;
|
|
||||||
size_t tcph_len;
|
|
||||||
const uint8_t *data;
|
|
||||||
size_t dlen;
|
|
||||||
|
|
||||||
|
|
||||||
int ipxv = netproto_version(raw_payload, raw_payload_len);
|
|
||||||
|
|
||||||
int ret = tcp_payload_split((uint8_t *)raw_payload, raw_payload_len,
|
|
||||||
(void *)&ipxh, &iph_len,
|
|
||||||
(struct tcphdr **)&tcph, &tcph_len,
|
|
||||||
(uint8_t **)&data, &dlen);
|
|
||||||
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "send_syn_altered");
|
||||||
|
|
||||||
|
free(payload);
|
||||||
return PKT_ACCEPT;
|
return PKT_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// As defined by TLS standard.
|
free(payload);
|
||||||
if (section->dport_filter && ntohs(tcph->dest) != 443) {
|
|
||||||
return PKT_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tcph->syn && section->synfake) {
|
|
||||||
lgtrace_addp("TCP syn alter");
|
|
||||||
|
|
||||||
size_t fake_len = section->fake_sni_pkt_sz;
|
|
||||||
if (section->synfake_len)
|
|
||||||
fake_len = min((int)section->synfake_len, (int)fake_len);
|
|
||||||
|
|
||||||
|
|
||||||
size_t payload_len = iph_len + tcph_len + fake_len;
|
|
||||||
uint8_t *payload = malloc(payload_len);
|
|
||||||
if (payload == NULL) {
|
|
||||||
lgerror(-ENOMEM, "Allocation error");
|
|
||||||
return PKT_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(payload, ipxh, iph_len);
|
|
||||||
memcpy(payload + iph_len, tcph, tcph_len);
|
|
||||||
memcpy(payload + iph_len + tcph_len, section->fake_sni_pkt, fake_len);
|
|
||||||
|
|
||||||
struct tcphdr *tcph = (struct tcphdr *)(payload + iph_len);
|
|
||||||
if (ipxv == IP4VERSION) {
|
|
||||||
struct iphdr *iph = (struct iphdr *)payload;
|
|
||||||
iph->tot_len = htons(iph_len + tcph_len + fake_len);
|
|
||||||
set_ip_checksum(payload, iph_len);
|
|
||||||
set_tcp_checksum(tcph, iph, iph_len);
|
|
||||||
} else if (ipxv == IP6VERSION) {
|
|
||||||
struct ip6_hdr *ip6h = (struct ip6_hdr *)payload;
|
|
||||||
ip6h->ip6_plen = ntohs(tcph_len + fake_len);
|
|
||||||
set_ip_checksum(ip6h, iph_len);
|
|
||||||
set_tcp_checksum(tcph, ip6h, iph_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ret = instance_config.send_raw_packet(payload, payload_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "send_syn_altered");
|
|
||||||
|
|
||||||
free(payload);
|
|
||||||
return PKT_ACCEPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(payload);
|
|
||||||
return PKT_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tcph->syn)
|
|
||||||
return PKT_CONTINUE;
|
|
||||||
|
|
||||||
if (!section->tls_enabled)
|
|
||||||
return PKT_CONTINUE;
|
|
||||||
|
|
||||||
struct tls_verdict vrd = analyze_tls_data(section, data, dlen);
|
|
||||||
lgtrace_addp("TLS analyzed");
|
|
||||||
|
|
||||||
if (vrd.sni_len != 0) {
|
|
||||||
lgtrace_addp("SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vrd.target_sni) {
|
|
||||||
lgdebug("Target SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
|
|
||||||
size_t target_sni_offset = vrd.target_sni_ptr - data;
|
|
||||||
|
|
||||||
|
|
||||||
size_t payload_len = raw_payload_len;
|
|
||||||
uint8_t *payload = malloc(raw_payload_len);
|
|
||||||
if (payload == NULL) {
|
|
||||||
lgerror(-ENOMEM, "Allocation error");
|
|
||||||
return PKT_ACCEPT;
|
|
||||||
}
|
|
||||||
memcpy(payload, raw_payload, raw_payload_len);
|
|
||||||
|
|
||||||
void *iph;
|
|
||||||
size_t iph_len;
|
|
||||||
struct tcphdr *tcph;
|
|
||||||
size_t tcph_len;
|
|
||||||
uint8_t *data;
|
|
||||||
size_t dlen;
|
|
||||||
|
|
||||||
int ret = tcp_payload_split(payload, payload_len,
|
|
||||||
&iph, &iph_len, &tcph, &tcph_len,
|
|
||||||
&data, &dlen);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "tcp_payload_split in targ_sni");
|
|
||||||
goto accept_lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section->fk_winsize) {
|
|
||||||
tcph->window = htons(section->fk_winsize);
|
|
||||||
set_tcp_checksum(tcph, iph, iph_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (0) {
|
|
||||||
int delta = 2;
|
|
||||||
ret = seqovl_packet(payload, &payload_len, delta);
|
|
||||||
int ret = tcp_payload_split(payload, payload_len,
|
|
||||||
&iph, &iph_len, &tcph, &tcph_len,
|
|
||||||
&data, &dlen);
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "seqovl_packet delta %d", delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (dlen > AVAILABLE_MTU) {
|
|
||||||
lgdebug("WARNING! Client Hello packet is too big and may cause issues!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section->fake_sni) {
|
|
||||||
post_fake_sni(args_default_fake_type(section), iph, iph_len, tcph, tcph_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ipd_offset;
|
|
||||||
size_t mid_offset;
|
|
||||||
|
|
||||||
switch (section->fragmentation_strategy) {
|
|
||||||
case FRAG_STRAT_TCP:
|
|
||||||
{
|
|
||||||
ipd_offset = target_sni_offset;
|
|
||||||
mid_offset = ipd_offset + vrd.target_sni_len / 2;
|
|
||||||
|
|
||||||
size_t poses[2];
|
|
||||||
int cnt = 0;
|
|
||||||
|
|
||||||
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
|
|
||||||
poses[cnt++] = section->frag_sni_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section->frag_middle_sni) {
|
|
||||||
poses[cnt++] = mid_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt > 1 && poses[0] > poses[1]) {
|
|
||||||
size_t tmp = poses[0];
|
|
||||||
poses[0] = poses[1];
|
|
||||||
poses[1] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = send_tcp_frags(section, payload, payload_len, poses, cnt, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "tcp4 send frags");
|
|
||||||
goto accept_lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto drop_lc;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FRAG_STRAT_IP:
|
|
||||||
if (ipxv == IP4VERSION) {
|
|
||||||
ipd_offset = ((char *)data - (char *)tcph) + target_sni_offset;
|
|
||||||
mid_offset = ipd_offset + vrd.target_sni_len / 2;
|
|
||||||
mid_offset += 8 - mid_offset % 8;
|
|
||||||
|
|
||||||
size_t poses[2];
|
|
||||||
int cnt = 0;
|
|
||||||
|
|
||||||
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
|
|
||||||
poses[cnt] = section->frag_sni_pos + ((char *)data - (char *)tcph);
|
|
||||||
poses[cnt] += 8 - poses[cnt] % 8;
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (section->frag_middle_sni) {
|
|
||||||
poses[cnt++] = mid_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt > 1 && poses[0] > poses[1]) {
|
|
||||||
size_t tmp = poses[0];
|
|
||||||
poses[0] = poses[1];
|
|
||||||
poses[1] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = send_ip4_frags(section, payload, payload_len, poses, cnt, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "ip4 send frags");
|
|
||||||
goto accept_lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto drop_lc;
|
|
||||||
} else {
|
|
||||||
lginfo("WARNING: IP fragmentation is supported only for IPv4");
|
|
||||||
goto default_send;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_send:
|
|
||||||
ret = instance_config.send_raw_packet(payload, payload_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "raw pack send");
|
|
||||||
goto accept_lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto drop_lc;
|
|
||||||
|
|
||||||
accept_lc:
|
|
||||||
free(payload);
|
|
||||||
return PKT_ACCEPT;
|
|
||||||
drop_lc:
|
|
||||||
free(payload);
|
|
||||||
return PKT_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PKT_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, size_t pktlen) {
|
|
||||||
const void *iph;
|
|
||||||
size_t iph_len;
|
|
||||||
const struct udphdr *udph;
|
|
||||||
const uint8_t *data;
|
|
||||||
size_t dlen;
|
|
||||||
|
|
||||||
int ret = udp_payload_split((uint8_t *)pkt, pktlen,
|
|
||||||
(void **)&iph, &iph_len,
|
|
||||||
(struct udphdr **)&udph,
|
|
||||||
(uint8_t **)&data, &dlen);
|
|
||||||
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
lgtrace_addp("undefined");
|
|
||||||
goto accept;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!detect_udp_filtered(section, pkt, pktlen))
|
|
||||||
goto continue_flow;
|
|
||||||
|
|
||||||
if (section->udp_mode == UDP_MODE_DROP)
|
|
||||||
goto drop;
|
|
||||||
else if (section->udp_mode == UDP_MODE_FAKE) {
|
|
||||||
for (int i = 0; i < section->udp_fake_seq_len; i++) {
|
|
||||||
uint8_t *fake_udp;
|
|
||||||
size_t fake_udp_len;
|
|
||||||
|
|
||||||
struct udp_fake_type fake_type = {
|
|
||||||
.fake_len = section->udp_fake_len,
|
|
||||||
.strategy = {
|
|
||||||
.strategy = section->udp_faking_strategy,
|
|
||||||
.faking_ttl = section->faking_ttl,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
ret = gen_fake_udp(fake_type, iph, iph_len, udph, &fake_udp, &fake_udp_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "gen_fake_udp");
|
|
||||||
goto erret;
|
|
||||||
}
|
|
||||||
|
|
||||||
lgtrace_addp("post fake udp #%d", i + 1);
|
|
||||||
|
|
||||||
ret = instance_config.send_raw_packet(fake_udp, fake_udp_len);
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "send fake udp");
|
|
||||||
goto erret_lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(fake_udp);
|
|
||||||
continue;
|
|
||||||
erret_lc:
|
|
||||||
free(fake_udp);
|
|
||||||
erret:
|
|
||||||
goto accept;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ret = instance_config.send_raw_packet(pkt, pktlen);
|
|
||||||
goto drop;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue_flow:
|
|
||||||
return PKT_CONTINUE;
|
|
||||||
accept:
|
|
||||||
return PKT_ACCEPT;
|
|
||||||
drop:
|
|
||||||
return PKT_DROP;
|
return PKT_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
int send_ip4_frags(const struct section_config_t *section, const uint8_t *packet, size_t pktlen, const size_t *poses, size_t poses_sz, size_t dvs) {
|
int send_ip4_frags(const struct section_config_t *section, const uint8_t *packet, size_t pktlen, const size_t *poses, size_t poses_sz, size_t dvs) {
|
||||||
if (poses_sz == 0) {
|
if (poses_sz == 0) {
|
||||||
|
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
|
||||||
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
|
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
|
||||||
if (!instance_config.send_delayed_packet) {
|
return instance_config.send_delayed_packet(
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
lgtrace_addp("Sent %zu delayed for %d", pktlen, section->seg2_delay);
|
|
||||||
instance_config.send_delayed_packet(
|
|
||||||
packet, pktlen, section->seg2_delay);
|
packet, pktlen, section->seg2_delay);
|
||||||
|
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
lgtrace_addp("Sent %zu bytes", pktlen);
|
|
||||||
return instance_config.send_raw_packet(
|
return instance_config.send_raw_packet(
|
||||||
packet, pktlen);
|
packet, pktlen);
|
||||||
}
|
}
|
||||||
@@ -588,18 +164,11 @@ out:
|
|||||||
|
|
||||||
int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet, size_t pktlen, const size_t *poses, size_t poses_sz, size_t dvs) {
|
int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet, size_t pktlen, const size_t *poses, size_t poses_sz, size_t dvs) {
|
||||||
if (poses_sz == 0) {
|
if (poses_sz == 0) {
|
||||||
|
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
|
||||||
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
|
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
|
||||||
if (!instance_config.send_delayed_packet) {
|
return instance_config.send_delayed_packet(
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance_config.send_delayed_packet(
|
|
||||||
packet, pktlen, section->seg2_delay);
|
packet, pktlen, section->seg2_delay);
|
||||||
|
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
|
|
||||||
|
|
||||||
return instance_config.send_raw_packet(
|
return instance_config.send_raw_packet(
|
||||||
packet, pktlen);
|
packet, pktlen);
|
||||||
}
|
}
|
||||||
@@ -658,6 +227,7 @@ send_fake:
|
|||||||
struct tcphdr *tcph;
|
struct tcphdr *tcph;
|
||||||
ret = tcp_payload_split(frag2, f2len, &iph, &iphfl, &tcph, &tcphfl, NULL, NULL);
|
ret = tcp_payload_split(frag2, f2len, &iph, &iphfl, &tcph, &tcphfl, NULL, NULL);
|
||||||
struct fake_type f_type = args_default_fake_type(section);
|
struct fake_type f_type = args_default_fake_type(section);
|
||||||
|
|
||||||
if ((f_type.strategy.strategy & FAKE_STRAT_PAST_SEQ) == FAKE_STRAT_PAST_SEQ) {
|
if ((f_type.strategy.strategy & FAKE_STRAT_PAST_SEQ) == FAKE_STRAT_PAST_SEQ) {
|
||||||
f_type.strategy.strategy ^= FAKE_STRAT_PAST_SEQ;
|
f_type.strategy.strategy ^= FAKE_STRAT_PAST_SEQ;
|
||||||
f_type.strategy.strategy |= FAKE_STRAT_RAND_SEQ;
|
f_type.strategy.strategy |= FAKE_STRAT_RAND_SEQ;
|
||||||
@@ -709,71 +279,68 @@ int post_fake_sni(struct fake_type f_type,
|
|||||||
void *fsiph = (void *)rfsiph;
|
void *fsiph = (void *)rfsiph;
|
||||||
struct tcphdr *fstcph = (void *)rfstcph;
|
struct tcphdr *fstcph = (void *)rfstcph;
|
||||||
|
|
||||||
ITER_FAKE_STRAT(f_type.strategy.strategy, strategy) {
|
struct fake_type fake_seq_type = f_type;
|
||||||
struct fake_type fake_seq_type = f_type;
|
|
||||||
fake_seq_type.strategy.strategy = strategy;
|
|
||||||
|
|
||||||
// one goes for default fake
|
// one goes for default fake
|
||||||
for (int i = 0; i < fake_seq_type.sequence_len; i++) {
|
for (int i = 0; i < fake_seq_type.sequence_len; i++) {
|
||||||
uint8_t *fake_sni;
|
uint8_t *fake_sni;
|
||||||
size_t fake_sni_len;
|
size_t fake_sni_len;
|
||||||
|
|
||||||
ret = gen_fake_sni(
|
ret = gen_fake_sni(
|
||||||
fake_seq_type,
|
fake_seq_type,
|
||||||
fsiph, iph_len, fstcph, tcph_len,
|
fsiph, iph_len, fstcph, tcph_len,
|
||||||
&fake_sni, &fake_sni_len);
|
&fake_sni, &fake_sni_len);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
lgerror(ret, "gen_fake_sni");
|
lgerror(ret, "gen_fake_sni");
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
lgtrace_addp("post fake sni #%d", i + 1);
|
|
||||||
|
|
||||||
if (f_type.seg2delay) {
|
|
||||||
ret = instance_config.send_delayed_packet(fake_sni, fake_sni_len, f_type.seg2delay);
|
|
||||||
} else {
|
|
||||||
ret = instance_config.send_raw_packet(fake_sni, fake_sni_len);
|
|
||||||
}
|
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "send fake sni");
|
|
||||||
goto erret_lc;
|
|
||||||
}
|
|
||||||
size_t iph_len;
|
|
||||||
size_t tcph_len;
|
|
||||||
size_t plen;
|
|
||||||
ret = tcp_payload_split(
|
|
||||||
fake_sni, fake_sni_len,
|
|
||||||
&fsiph, &iph_len,
|
|
||||||
&fstcph, &tcph_len,
|
|
||||||
NULL, &plen);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
lgtrace_addp("continue fake seq");
|
|
||||||
goto erret_lc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!(strategy == FAKE_STRAT_PAST_SEQ ||
|
|
||||||
strategy == FAKE_STRAT_RAND_SEQ)) {
|
|
||||||
fstcph->seq = htonl(ntohl(fstcph->seq) + plen);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ipxv == IP4VERSION) {
|
|
||||||
((struct iphdr *)fsiph)->id = htons(ntohs(((struct iphdr *)fsiph)->id) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(rfsiph, fsiph, iph_len);
|
|
||||||
|
|
||||||
memcpy(rfstcph, fstcph, tcph_len);
|
|
||||||
fsiph = (void *)rfsiph;
|
|
||||||
fstcph = (void *)rfstcph;
|
|
||||||
|
|
||||||
free(fake_sni);
|
|
||||||
continue;
|
|
||||||
erret_lc:
|
|
||||||
free(fake_sni);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lgtrace_addp("post fake sni #%d", i + 1);
|
||||||
|
|
||||||
|
if (f_type.seg2delay) {
|
||||||
|
ret = instance_config.send_delayed_packet(fake_sni, fake_sni_len, f_type.seg2delay);
|
||||||
|
} else {
|
||||||
|
ret = instance_config.send_raw_packet(fake_sni, fake_sni_len);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "send fake sni");
|
||||||
|
goto erret_lc;
|
||||||
|
}
|
||||||
|
size_t iph_len;
|
||||||
|
size_t tcph_len;
|
||||||
|
size_t plen;
|
||||||
|
ret = tcp_payload_split(
|
||||||
|
fake_sni, fake_sni_len,
|
||||||
|
&fsiph, &iph_len,
|
||||||
|
&fstcph, &tcph_len,
|
||||||
|
NULL, &plen);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
lgtrace_addp("continue fake seq");
|
||||||
|
goto erret_lc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!(CHECK_BITFIELD(f_type.strategy.strategy, FAKE_STRAT_PAST_SEQ) ||
|
||||||
|
CHECK_BITFIELD(f_type.strategy.strategy, FAKE_STRAT_RAND_SEQ))) {
|
||||||
|
fstcph->seq = htonl(ntohl(fstcph->seq) + plen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipxv == IP4VERSION) {
|
||||||
|
((struct iphdr *)fsiph)->id = htons(ntohs(((struct iphdr *)fsiph)->id) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(rfsiph, fsiph, iph_len);
|
||||||
|
|
||||||
|
memcpy(rfstcph, fstcph, tcph_len);
|
||||||
|
fsiph = (void *)rfsiph;
|
||||||
|
fstcph = (void *)rfstcph;
|
||||||
|
|
||||||
|
free(fake_sni);
|
||||||
|
continue;
|
||||||
|
erret_lc:
|
||||||
|
free(fake_sni);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
20
src/mangle.h
20
src/mangle.h
@@ -23,32 +23,18 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "dpi.h"
|
||||||
|
|
||||||
#define PKT_ACCEPT 0
|
#define PKT_ACCEPT 0
|
||||||
#define PKT_DROP 1
|
#define PKT_DROP 1
|
||||||
// Used for section config
|
// Used for section config
|
||||||
#define PKT_CONTINUE 2
|
#define PKT_CONTINUE 2
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes the packet and returns verdict.
|
|
||||||
* This is the primary function that traverses the packet.
|
|
||||||
*/
|
|
||||||
int process_packet(const struct config_t *config, const struct packet_data *pd);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processe the TCP packet.
|
* Sends synfake message
|
||||||
* Returns verdict.
|
|
||||||
*/
|
*/
|
||||||
int process_tcp_packet(const struct section_config_t *section, const uint8_t *raw_payload, size_t raw_payload_len);
|
int send_synfake(const struct section_config_t *section, const struct parsed_packet *pkt);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes the UDP packet.
|
|
||||||
* Returns verdict.
|
|
||||||
*/
|
|
||||||
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, size_t pktlen);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
51
src/quic.c
51
src/quic.c
@@ -71,7 +71,7 @@ int quic_check_is_initial(const struct quic_lhdr *qch) {
|
|||||||
uint32_t qversion;
|
uint32_t qversion;
|
||||||
int ret;
|
int ret;
|
||||||
ret = quic_get_version(&qversion, qch);
|
ret = quic_get_version(&qversion, qch);
|
||||||
if (qversion < 0) return 0;
|
if (ret < 0) return 0;
|
||||||
|
|
||||||
uint8_t qtype = qch->type;
|
uint8_t qtype = qch->type;
|
||||||
|
|
||||||
@@ -426,6 +426,48 @@ out:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_stun_message(const uint8_t *data, size_t dlen) {
|
||||||
|
size_t left_len = dlen;
|
||||||
|
const uint8_t *data_ptr = data;
|
||||||
|
uint16_t message_type;
|
||||||
|
uint16_t message_length;
|
||||||
|
|
||||||
|
if (left_len < 2 + 2 + 4 + 12) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
message_type = *(uint16_t *)data_ptr;
|
||||||
|
data_ptr += 2;
|
||||||
|
left_len -= 2;
|
||||||
|
|
||||||
|
message_length = *(uint16_t *)data_ptr;
|
||||||
|
data_ptr += 2;
|
||||||
|
left_len -= 2;
|
||||||
|
|
||||||
|
data_ptr += 4;
|
||||||
|
left_len -= 4;
|
||||||
|
data_ptr += 12;
|
||||||
|
left_len -= 12;
|
||||||
|
|
||||||
|
message_type = ntohs(message_type);
|
||||||
|
message_length = ntohs(message_length);
|
||||||
|
|
||||||
|
if (left_len != message_length) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((message_type & (1 << 15)) || (message_type & (1 << 14))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter request only
|
||||||
|
if ((message_type & (1 << 4)) || (message_type & (1 << 8))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int detect_udp_filtered(const struct section_config_t *section,
|
int detect_udp_filtered(const struct section_config_t *section,
|
||||||
const uint8_t *payload, size_t plen) {
|
const uint8_t *payload, size_t plen) {
|
||||||
const void *iph;
|
const void *iph;
|
||||||
@@ -537,13 +579,18 @@ int detect_udp_filtered(const struct section_config_t *section,
|
|||||||
match_port:
|
match_port:
|
||||||
|
|
||||||
for (int i = 0; i < section->udp_dport_range_len; i++) {
|
for (int i = 0; i < section->udp_dport_range_len; i++) {
|
||||||
struct udp_dport_range crange = section->udp_dport_range[i];
|
struct dport_range crange = section->udp_dport_range[i];
|
||||||
if (udp_dport >= crange.start && udp_dport <= crange.end) {
|
if (udp_dport >= crange.start && udp_dport <= crange.end) {
|
||||||
lgtrace_addp("matched to %d-%d", crange.start, crange.end);
|
lgtrace_addp("matched to %d-%d", crange.start, crange.end);
|
||||||
goto approve;
|
goto approve;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (section->udp_stun_filter && is_stun_message(data, dlen)) {
|
||||||
|
lgtrace_addp("STUN protocol detected");
|
||||||
|
goto approve;
|
||||||
|
}
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
return 0;
|
return 0;
|
||||||
approve:
|
approve:
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ int quic_parse_initial_message(
|
|||||||
ret = quic_parse_data(quic_payload, quic_plen,
|
ret = quic_parse_data(quic_payload, quic_plen,
|
||||||
&qch, &qch_len, &qci, &inpayload, &inplen
|
&qch, &qch_len, &qci, &inpayload, &inplen
|
||||||
);
|
);
|
||||||
|
if (ret < 0) {
|
||||||
|
lgerror(ret, "quic_parse_data");
|
||||||
|
goto error_nfr;
|
||||||
|
}
|
||||||
|
|
||||||
ret = quic_get_version(&qversion, qch);
|
ret = quic_get_version(&qversion, qch);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -117,10 +121,6 @@ int quic_parse_initial_message(
|
|||||||
}
|
}
|
||||||
|
|
||||||
quic_header_len = inpayload - quic_payload;
|
quic_header_len = inpayload - quic_payload;
|
||||||
if (ret < 0) {
|
|
||||||
lgerror(ret, "quic_parse_data");
|
|
||||||
goto error_nfr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = quic_parse_initial_header(inpayload, inplen, &qich);
|
ret = quic_parse_initial_header(inpayload, inplen, &qich);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
@@ -5,6 +5,5 @@
|
|||||||
|
|
||||||
static const char fake_sni[] = "\026\003\001\002\000\001\000\001\374\003\003\323[\345\201f\362\200:B\356Uq\355X\315i\235*\021\367\331\272\a>\233\254\355\307/\342\372\265 \275\2459l&r\222\313\361\3729`\376\256\233\333O\001\373\33050\r\260f,\231\035 \324^\000>\023\002\023\003\023\001\300,\3000\000\237\314\251\314\250\314\252\300+\300/\000\236\300$\300(\000k\300#\300'\000g\300\n\300\024\0009\300\t\300\023\0003\000\235\000\234\000=\000<\0005\000/\000\377\001\000\001u\000\000\000\023\000\021\000\000\016www.google.com\000\v\000\004\003\000\001\002\000\n\000\026\000\024\000\035\000\027\000\036\000\031\000\030\001\000\001\001\001\002\001\003\001\004\000\020\000\016\000\f\002h2\bhttp/1.1\000\026\000\000\000\027\000\000\0001\000\000\000\r\0000\000.\004\003\005\003\006\003\b\a\b\b\b\032\b\033\b\034\b\t\b\n\b\v\b\004\b\005\b\006\004\001\005\001\006\001\003\003\003\001\003\002\004\002\005\002\006\002\000+\000\005\004\003\004\003\003\000-\000\002\001\001\0003\000&\000$\000\035\000 \004\224\206\021\256\f\222\266\3435\216\202\342\2573\341\3503\2107\341\023\016\240r|6\000^K\310s\000\025\000\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
static const char fake_sni[] = "\026\003\001\002\000\001\000\001\374\003\003\323[\345\201f\362\200:B\356Uq\355X\315i\235*\021\367\331\272\a>\233\254\355\307/\342\372\265 \275\2459l&r\222\313\361\3729`\376\256\233\333O\001\373\33050\r\260f,\231\035 \324^\000>\023\002\023\003\023\001\300,\3000\000\237\314\251\314\250\314\252\300+\300/\000\236\300$\300(\000k\300#\300'\000g\300\n\300\024\0009\300\t\300\023\0003\000\235\000\234\000=\000<\0005\000/\000\377\001\000\001u\000\000\000\023\000\021\000\000\016www.google.com\000\v\000\004\003\000\001\002\000\n\000\026\000\024\000\035\000\027\000\036\000\031\000\030\001\000\001\001\001\002\001\003\001\004\000\020\000\016\000\f\002h2\bhttp/1.1\000\026\000\000\000\027\000\000\0001\000\000\000\r\0000\000.\004\003\005\003\006\003\b\a\b\b\b\032\b\033\b\034\b\t\b\n\b\v\b\004\b\005\b\006\004\001\005\001\006\001\003\003\003\001\003\002\004\002\005\002\006\002\000+\000\005\004\003\004\003\003\000-\000\002\001\001\0003\000&\000$\000\035\000 \004\224\206\021\256\f\222\266\3435\216\202\342\2573\341\3503\2107\341\023\016\240r|6\000^K\310s\000\025\000\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
|
||||||
|
|
||||||
static const char fake_sni_old[] = "\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*/
|
#endif /*RAW_REPLACEMENTS_H*/
|
||||||
|
|||||||
94
src/tls.c
94
src/tls.c
@@ -33,6 +33,8 @@ int bruteforce_analyze_sni_str(
|
|||||||
const uint8_t *data, size_t dlen,
|
const uint8_t *data, size_t dlen,
|
||||||
struct tls_verdict *vrd
|
struct tls_verdict *vrd
|
||||||
) {
|
) {
|
||||||
|
size_t offset, offlen;
|
||||||
|
int ret;
|
||||||
*vrd = (struct tls_verdict){0};
|
*vrd = (struct tls_verdict){0};
|
||||||
|
|
||||||
if (dlen <= 1) {
|
if (dlen <= 1) {
|
||||||
@@ -47,50 +49,17 @@ int bruteforce_analyze_sni_str(
|
|||||||
vrd->target_sni_len = vrd->sni_len;
|
vrd->target_sni_len = vrd->sni_len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int max_domain_len = 0;
|
|
||||||
|
|
||||||
for (struct domains_list *sne = section->sni_domains; sne != NULL;
|
// It is safe for multithreading, so dp mutability is ok
|
||||||
sne = sne->next) {
|
ret = trie_process_str((struct trie_container *)§ion->sni_domains, data, dlen, 0, &offset, &offlen);
|
||||||
max_domain_len = max((int)sne->domain_len, max_domain_len);
|
if (ret) {
|
||||||
|
vrd->target_sni = 1;
|
||||||
|
vrd->sni_len = offlen;
|
||||||
|
vrd->sni_ptr = data + offset;
|
||||||
|
vrd->target_sni_ptr = vrd->sni_ptr;
|
||||||
|
vrd->target_sni_len = vrd->sni_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t buf_size = max_domain_len + dlen + 1;
|
|
||||||
uint8_t *buf = malloc(buf_size);
|
|
||||||
if (buf == NULL) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
int *nzbuf = malloc(buf_size * sizeof(int));
|
|
||||||
if (nzbuf == NULL) {
|
|
||||||
free(buf);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) {
|
|
||||||
const char *domain_startp = sne->domain_name;
|
|
||||||
int domain_len = sne->domain_len;
|
|
||||||
|
|
||||||
int *zbuf = (void *)nzbuf;
|
|
||||||
|
|
||||||
memcpy(buf, domain_startp, domain_len);
|
|
||||||
memcpy(buf + domain_len, "#", 1);
|
|
||||||
memcpy(buf + domain_len + 1, data, dlen);
|
|
||||||
|
|
||||||
z_function((char *)buf, zbuf, domain_len + 1 + dlen);
|
|
||||||
|
|
||||||
for (size_t k = 0; k < domain_len + 1 + dlen; k++) {
|
|
||||||
if (zbuf[k] == domain_len) {
|
|
||||||
vrd->target_sni = 1;
|
|
||||||
vrd->sni_len = domain_len;
|
|
||||||
vrd->sni_ptr = data + (k - domain_len - 1);
|
|
||||||
vrd->target_sni_ptr = vrd->sni_ptr;
|
|
||||||
vrd->target_sni_len = vrd->sni_len;
|
|
||||||
goto return_vrd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return_vrd:
|
|
||||||
free(buf);
|
|
||||||
free(nzbuf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static int analyze_sni_str(
|
static int analyze_sni_str(
|
||||||
@@ -98,42 +67,33 @@ static int analyze_sni_str(
|
|||||||
const char *sni_name, int sni_len,
|
const char *sni_name, int sni_len,
|
||||||
struct tls_verdict *vrd
|
struct tls_verdict *vrd
|
||||||
) {
|
) {
|
||||||
|
int ret;
|
||||||
|
size_t offset, offlen;
|
||||||
|
|
||||||
if (section->all_domains) {
|
if (section->all_domains) {
|
||||||
vrd->target_sni = 1;
|
vrd->target_sni = 1;
|
||||||
goto check_domain;
|
goto check_domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (struct domains_list *sne = section->sni_domains; sne != NULL; sne = sne->next) {
|
// It is safe for multithreading, so dp mutability is ok
|
||||||
const char *sni_startp = sni_name + sni_len - sne->domain_len;
|
ret = trie_process_str((struct trie_container *)§ion->sni_domains,
|
||||||
const char *domain_startp = sne->domain_name;
|
(const uint8_t *)sni_name, sni_len, TRIE_OPT_MAP_TO_END, &offset, &offlen);
|
||||||
|
if (ret) {
|
||||||
if (sni_len >= sne->domain_len &&
|
vrd->target_sni = 1;
|
||||||
sni_len < 128 &&
|
vrd->target_sni_ptr = (const uint8_t *)sni_name + offset;
|
||||||
!strncmp(sni_startp,
|
vrd->target_sni_len = offlen;
|
||||||
domain_startp,
|
|
||||||
sne->domain_len)) {
|
|
||||||
vrd->target_sni = 1;
|
|
||||||
vrd->target_sni_ptr = (const uint8_t *)sni_startp;
|
|
||||||
vrd->target_sni_len = sne->domain_len;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_domain:
|
check_domain:
|
||||||
if (vrd->target_sni == 1) {
|
if (vrd->target_sni == 1) {
|
||||||
for (struct domains_list *sne = section->exclude_sni_domains; sne != NULL; sne = sne->next) {
|
|
||||||
const char *sni_startp = sni_name + sni_len - sne->domain_len;
|
|
||||||
const char *domain_startp = sne->domain_name;
|
|
||||||
|
|
||||||
if (sni_len >= sne->domain_len &&
|
// It is safe for multithreading, so dp mutability is ok
|
||||||
sni_len < 128 &&
|
ret = trie_process_str((struct trie_container *)§ion->exclude_sni_domains,
|
||||||
!strncmp(sni_startp,
|
(const uint8_t *)sni_name, sni_len, TRIE_OPT_MAP_TO_END, &offset, &offlen);
|
||||||
domain_startp,
|
if (ret) {
|
||||||
sne->domain_len)) {
|
vrd->target_sni = 0;
|
||||||
vrd->target_sni = 0;
|
lgdebug("Excluded SNI: %.*s",
|
||||||
lgdebug("Excluded SNI: %.*s",
|
vrd->sni_len, vrd->sni_ptr);
|
||||||
vrd->sni_len, vrd->sni_ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
197
src/trie.c
Normal file
197
src/trie.c
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
youtubeUnblock - https://github.com/Waujito/youtubeUnblock
|
||||||
|
|
||||||
|
Copyright (C) 2024-2025 Vadim Vetrov <vetrovvd@gmail.com>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is slightly optimized Aho-Corasick implementation
|
||||||
|
*
|
||||||
|
* Big thanks to e-maxx http://e-maxx.ru/algo/aho_corasick
|
||||||
|
* for the best description and reference code samples
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "trie.h"
|
||||||
|
|
||||||
|
int trie_init(struct trie_container *trie) {
|
||||||
|
void *vx = malloc(sizeof(struct trie_vertex) * TRIE_STARTSZ);
|
||||||
|
if (vx == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
trie->vx = vx;
|
||||||
|
trie->arrsz = TRIE_STARTSZ;
|
||||||
|
trie->sz = 1;
|
||||||
|
|
||||||
|
struct trie_vertex *trx = trie->vx;
|
||||||
|
trx->p = trx->link = -1;
|
||||||
|
trx->leaf = 0;
|
||||||
|
trx->depth = 0;
|
||||||
|
trx->pch = 0;
|
||||||
|
memset(trx->go, 0xff, sizeof(trie->vx[0].go));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trie_destroy(struct trie_container *trie) {
|
||||||
|
trie->arrsz = 0;
|
||||||
|
trie->sz = 0;
|
||||||
|
free(trie->vx);
|
||||||
|
trie->vx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Increases trie vertex container size.
|
||||||
|
* Returns new vertex index or ret < 0 on error
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int trie_push_vertex(struct trie_container *trie) {
|
||||||
|
if (trie->sz == NMAX - 1) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trie->arrsz == trie->sz) { // realloc
|
||||||
|
void *pt = realloc(trie->vx,
|
||||||
|
sizeof(struct trie_vertex) * trie->arrsz * 2);
|
||||||
|
if (pt == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
trie->arrsz *= 2;
|
||||||
|
trie->vx = pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trie->sz++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int trie_add_string(struct trie_container *trie,
|
||||||
|
const uint8_t *str, size_t strlen) {
|
||||||
|
if (trie == NULL || trie->vx == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v = 0;
|
||||||
|
int nv;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < strlen; ++i) {
|
||||||
|
uint8_t c = str[i];
|
||||||
|
if (c >= TRIE_ALPHABET) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trie->vx[v].go[c] == -1) {
|
||||||
|
nv = trie_push_vertex(trie);
|
||||||
|
if (nv < 0) {
|
||||||
|
return nv;
|
||||||
|
}
|
||||||
|
struct trie_vertex *tvx = trie->vx + nv;
|
||||||
|
|
||||||
|
memset(tvx->go, 0xff, sizeof(tvx->go));
|
||||||
|
tvx->link = -1;
|
||||||
|
tvx->p = v;
|
||||||
|
tvx->depth = trie->vx[v].depth + 1;
|
||||||
|
tvx->leaf = 0;
|
||||||
|
tvx->pch = c;
|
||||||
|
trie->vx[v].go[c] = nv;
|
||||||
|
}
|
||||||
|
v = trie->vx[v].go[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v != 0) {
|
||||||
|
trie->vx[v].leaf = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trie_go(struct trie_container *trie,
|
||||||
|
int v, uint8_t c);
|
||||||
|
|
||||||
|
static int trie_get_link(struct trie_container *trie,
|
||||||
|
int v) {
|
||||||
|
struct trie_vertex *tvx = trie->vx + v;
|
||||||
|
|
||||||
|
if (tvx->link == -1) {
|
||||||
|
if (v == 0 || tvx->p == 0) {
|
||||||
|
tvx->link = 0;
|
||||||
|
} else {
|
||||||
|
tvx->link = trie_go(trie,
|
||||||
|
trie_get_link(trie, tvx->p), tvx->pch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tvx->link;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trie_go(struct trie_container *trie, int v, uint8_t c) {
|
||||||
|
struct trie_vertex *tvx = trie->vx + v;
|
||||||
|
|
||||||
|
if (tvx->go[c] == -1) {
|
||||||
|
tvx->go[c] = v == 0 ? 0 :
|
||||||
|
trie_go(trie, trie_get_link(trie, v), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tvx->go[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int trie_process_str(
|
||||||
|
struct trie_container *trie,
|
||||||
|
const uint8_t *str, size_t strlen,
|
||||||
|
int flags,
|
||||||
|
size_t *offset, size_t *offlen
|
||||||
|
) {
|
||||||
|
if (trie == NULL || trie->vx == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
uint8_t c;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
for (; i < strlen; ++i) {
|
||||||
|
c = str[i];
|
||||||
|
if (c >= TRIE_ALPHABET) {
|
||||||
|
v = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = trie->vx[v].go[c] != -1 ? trie->vx[v].go[c] :
|
||||||
|
trie_go(trie, v, str[i]);
|
||||||
|
|
||||||
|
if (trie->vx[v].leaf &&
|
||||||
|
((flags & TRIE_OPT_MAP_TO_END) != TRIE_OPT_MAP_TO_END ||
|
||||||
|
i == strlen - 1)
|
||||||
|
) {
|
||||||
|
++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = trie->vx[v].depth;
|
||||||
|
if ( trie->vx[v].leaf &&
|
||||||
|
i >= len
|
||||||
|
) {
|
||||||
|
size_t sp = i - len;
|
||||||
|
*offset = sp;
|
||||||
|
*offlen = len;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
92
src/trie.h
Normal file
92
src/trie.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
youtubeUnblock - https://github.com/Waujito/youtubeUnblock
|
||||||
|
|
||||||
|
Copyright (C) 2024-2025 Vadim Vetrov <vetrovvd@gmail.com>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is slightly optimized Aho-Corasick implementation
|
||||||
|
*
|
||||||
|
* Big thanks to e-maxx http://e-maxx.ru/algo/aho_corasick
|
||||||
|
* for the best description and reference code samples
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This algorithm allows us to search inside the string
|
||||||
|
* for a list of patterns in the linear time.
|
||||||
|
*
|
||||||
|
* The algorithm will lazily initialize itself while
|
||||||
|
* youtubeUnblock works. Lazy initializations considered
|
||||||
|
* safe for multithreading and operate without atomicity
|
||||||
|
* or synchronization primitives.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TRIE_H
|
||||||
|
#define TRIE_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
// ASCII alphabet
|
||||||
|
#define TRIE_ALPHABET 128
|
||||||
|
// Maximum of vertexes in the trie
|
||||||
|
#define NMAX ((1 << 15) - 1)
|
||||||
|
|
||||||
|
struct trie_vertex {
|
||||||
|
int leaf; // boolean flag
|
||||||
|
int depth; // depth of tree (length of substring)
|
||||||
|
int p; // parent
|
||||||
|
uint8_t pch; // vertex char
|
||||||
|
int link; // sufflink
|
||||||
|
int16_t go[TRIE_ALPHABET]; // dynamically filled pushes
|
||||||
|
};
|
||||||
|
|
||||||
|
struct trie_container {
|
||||||
|
struct trie_vertex *vx;
|
||||||
|
size_t arrsz;
|
||||||
|
size_t sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TRIE_STARTSZ 32
|
||||||
|
int trie_init(struct trie_container *trie);
|
||||||
|
void trie_destroy(struct trie_container *trie);
|
||||||
|
|
||||||
|
int trie_add_string(struct trie_container *trie,
|
||||||
|
const uint8_t *str, size_t strlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aligns the pattern to the end
|
||||||
|
*/
|
||||||
|
#define TRIE_OPT_MAP_TO_END (1 << 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the string for the patterns.
|
||||||
|
* flags is TRIE_OPT binary mask with options for search.
|
||||||
|
* offset, offlen are destination variables with
|
||||||
|
* offset of the given string and length of target.
|
||||||
|
*
|
||||||
|
* returns 1 if target found, 0 otherwise
|
||||||
|
*/
|
||||||
|
int trie_process_str(
|
||||||
|
struct trie_container *trie,
|
||||||
|
const uint8_t *str, size_t strlen,
|
||||||
|
int flags,
|
||||||
|
size_t *offset, size_t *offlen
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -22,6 +22,12 @@
|
|||||||
#define TYPES_H
|
#define TYPES_H
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
|
|
||||||
|
#ifndef KERNEL_SPACE
|
||||||
|
#include <assert.h>
|
||||||
|
#else
|
||||||
|
#define assert(...) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef KERNEL_SPACE
|
#ifdef KERNEL_SPACE
|
||||||
#include <linux/errno.h> // IWYU pragma: export
|
#include <linux/errno.h> // IWYU pragma: export
|
||||||
#include <linux/string.h> // IWYU pragma: export
|
#include <linux/string.h> // IWYU pragma: export
|
||||||
@@ -68,6 +74,7 @@ typedef __s16 int_least16_t; /* integer of >= 16 bits */
|
|||||||
|
|
||||||
#define free kfree
|
#define free kfree
|
||||||
#define malloc(size) kmalloc((size), GFP_KERNEL)
|
#define malloc(size) kmalloc((size), GFP_KERNEL)
|
||||||
|
#define realloc(pt, size) krealloc((pt), (size), GFP_KERNEL)
|
||||||
#define calloc(n, size) kcalloc((n), (size), GFP_KERNEL)
|
#define calloc(n, size) kcalloc((n), (size), GFP_KERNEL)
|
||||||
|
|
||||||
#define ip6_hdr ipv6hdr
|
#define ip6_hdr ipv6hdr
|
||||||
@@ -126,6 +133,8 @@ free((item)); \
|
|||||||
|
|
||||||
#endif /* not a KERNEL_SPACE */
|
#endif /* not a KERNEL_SPACE */
|
||||||
|
|
||||||
|
#define CHECK_BITFIELD(value, field) (((value) & (field)) == (field))
|
||||||
|
|
||||||
static inline int randint(void) {
|
static inline int randint(void) {
|
||||||
int rnd;
|
int rnd;
|
||||||
|
|
||||||
|
|||||||
78
src/utils.c
78
src/utils.c
@@ -616,6 +616,15 @@ struct tcp_md5sig_opt {
|
|||||||
// Real length of the option, with NOOP fillers
|
// Real length of the option, with NOOP fillers
|
||||||
#define TCP_MD5SIG_OPT_RLEN 20
|
#define TCP_MD5SIG_OPT_RLEN 20
|
||||||
|
|
||||||
|
#define TCP_TS_OPT_KIND 0x08
|
||||||
|
struct tcp_ts_opt {
|
||||||
|
uint8_t kind;
|
||||||
|
uint8_t len;
|
||||||
|
uint32_t ts_val;
|
||||||
|
uint32_t ts_echo;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen, size_t avail_buflen) {
|
int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen, size_t avail_buflen) {
|
||||||
void *iph;
|
void *iph;
|
||||||
size_t iph_len;
|
size_t iph_len;
|
||||||
@@ -636,18 +645,22 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (strategy.strategy == FAKE_STRAT_RAND_SEQ) {
|
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_RAND_SEQ)) {
|
||||||
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
|
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
|
||||||
|
|
||||||
tcph->seq = htonl(ntohl(tcph->seq) - (strategy.randseq_offset + dlen));
|
tcph->seq = htonl(ntohl(tcph->seq) - (strategy.randseq_offset + dlen));
|
||||||
|
|
||||||
lgtrace_addp("%u", ntohl(tcph->seq));
|
lgtrace_addp("%u", ntohl(tcph->seq));
|
||||||
} else if (strategy.strategy == FAKE_STRAT_PAST_SEQ) {
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_PAST_SEQ)) {
|
||||||
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
|
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
|
||||||
tcph->seq = htonl(ntohl(tcph->seq) - dlen);
|
tcph->seq = htonl(ntohl(tcph->seq) - dlen);
|
||||||
lgtrace_addp("%u", ntohl(tcph->seq));
|
lgtrace_addp("%u", ntohl(tcph->seq));
|
||||||
|
|
||||||
} else if (strategy.strategy == FAKE_STRAT_TTL) {
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_TTL)) {
|
||||||
lgtrace_addp("set fake ttl to %d", strategy.faking_ttl);
|
lgtrace_addp("set fake ttl to %d", strategy.faking_ttl);
|
||||||
|
|
||||||
if (ipxv == IP4VERSION) {
|
if (ipxv == IP4VERSION) {
|
||||||
@@ -658,7 +671,9 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
|
|||||||
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
|
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
} else if (strategy.strategy == FAKE_STRAT_TCP_MD5SUM) {
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_TCP_MD5SUM)) {
|
||||||
int optp_len = tcph_len - sizeof(struct tcphdr);
|
int optp_len = tcph_len - sizeof(struct tcphdr);
|
||||||
int delta = TCP_MD5SIG_OPT_RLEN - optp_len;
|
int delta = TCP_MD5SIG_OPT_RLEN - optp_len;
|
||||||
lgtrace_addp("Incr delta %d: %d -> %d", delta, optp_len, optp_len + delta);
|
lgtrace_addp("Incr delta %d: %d -> %d", delta, optp_len, optp_len + delta);
|
||||||
@@ -673,9 +688,11 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
|
|||||||
tcph_len = tcph_len + delta;
|
tcph_len = tcph_len + delta;
|
||||||
tcph->doff = tcph_len >> 2;
|
tcph->doff = tcph_len >> 2;
|
||||||
if (ipxv == IP4VERSION) {
|
if (ipxv == IP4VERSION) {
|
||||||
((struct iphdr *)iph)->tot_len = htons(ntohs(((struct iphdr *)iph)->tot_len) + delta);
|
((struct iphdr *)iph)->tot_len =
|
||||||
|
htons(ntohs(((struct iphdr *)iph)->tot_len) + delta);
|
||||||
} else if (ipxv == IP6VERSION) {
|
} else if (ipxv == IP6VERSION) {
|
||||||
((struct ip6_hdr *)iph)->ip6_plen = htons(ntohs(((struct ip6_hdr *)iph)->ip6_plen) + delta);
|
((struct ip6_hdr *)iph)->ip6_plen =
|
||||||
|
htons(ntohs(((struct ip6_hdr *)iph)->ip6_plen) + delta);
|
||||||
} else {
|
} else {
|
||||||
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
|
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -697,6 +714,53 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_TCP_TS)) {
|
||||||
|
int optp_len = tcph_len - sizeof(struct tcphdr);
|
||||||
|
uint8_t *optp = (uint8_t *)tcph + sizeof(struct tcphdr);
|
||||||
|
|
||||||
|
uint8_t *tcp_ts = NULL;
|
||||||
|
|
||||||
|
while (optp_len && *optp != 0x00) {
|
||||||
|
if (*optp == 0x01) {
|
||||||
|
optp_len--;
|
||||||
|
optp++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optp_len < 2) {
|
||||||
|
lgerr("Tcp option parsing failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t len = optp[1];
|
||||||
|
if (len > optp_len) {
|
||||||
|
lgerr("Tcp option parsing failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*optp == 0x08) {
|
||||||
|
tcp_ts = optp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
optp_len -= len;
|
||||||
|
optp += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_ts) {
|
||||||
|
struct tcp_ts_opt *ts_opt = (void *)tcp_ts;
|
||||||
|
uint32_t old_ts = ntohl(ts_opt->ts_val);
|
||||||
|
ts_opt->ts_val = htonl(ntohl(ts_opt->ts_val) -
|
||||||
|
strategy.faking_timestamp_decrease);
|
||||||
|
uint32_t new_ts = ntohl(ts_opt->ts_val);
|
||||||
|
|
||||||
|
lgtrace_addp( "Fake TCP TimeStamp %u -> %u", old_ts, new_ts);
|
||||||
|
} else {
|
||||||
|
lgtrace_addp( "Fake TCP TimeStamp was not fullfilled: "
|
||||||
|
"the option does not present");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ipxv == IP4VERSION) {
|
if (ipxv == IP4VERSION) {
|
||||||
((struct iphdr *)iph)->frag_off = 0;
|
((struct iphdr *)iph)->frag_off = 0;
|
||||||
}
|
}
|
||||||
@@ -705,7 +769,7 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
|
|||||||
set_ip_checksum(iph, iph_len);
|
set_ip_checksum(iph, iph_len);
|
||||||
set_tcp_checksum(tcph, iph, iph_len);
|
set_tcp_checksum(tcph, iph, iph_len);
|
||||||
|
|
||||||
if (strategy.strategy == FAKE_STRAT_TCP_CHECK) {
|
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_TCP_CHECK)) {
|
||||||
lgtrace_addp("break fake tcp checksum");
|
lgtrace_addp("break fake tcp checksum");
|
||||||
tcph->check += 1;
|
tcph->check += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ void shift_data(uint8_t *data, size_t dlen, size_t delta);
|
|||||||
struct failing_strategy {
|
struct failing_strategy {
|
||||||
unsigned int strategy;
|
unsigned int strategy;
|
||||||
uint8_t faking_ttl;
|
uint8_t faking_ttl;
|
||||||
|
uint32_t faking_timestamp_decrease;
|
||||||
size_t randseq_offset;
|
size_t randseq_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -197,7 +198,8 @@ static inline struct failing_strategy args_default_failing_strategy(const struct
|
|||||||
struct failing_strategy fl_strat = {
|
struct failing_strategy fl_strat = {
|
||||||
.strategy = (unsigned int)section->faking_strategy,
|
.strategy = (unsigned int)section->faking_strategy,
|
||||||
.faking_ttl = section->faking_ttl,
|
.faking_ttl = section->faking_ttl,
|
||||||
.randseq_offset = (size_t)section->fakeseq_offset
|
.faking_timestamp_decrease = section->faking_timestamp_decrease,
|
||||||
|
.randseq_offset = (size_t)section->fakeseq_offset,
|
||||||
};
|
};
|
||||||
return fl_strat;
|
return fl_strat;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,9 +46,10 @@
|
|||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "mangle.h"
|
#include "dpi.h"
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
@@ -62,8 +63,9 @@ int raw6socket = -2;
|
|||||||
static struct config_t *cur_config = NULL;
|
static struct config_t *cur_config = NULL;
|
||||||
|
|
||||||
static int open_socket(struct mnl_socket **_nl) {
|
static int open_socket(struct mnl_socket **_nl) {
|
||||||
struct mnl_socket *nl = NULL;
|
assert (_nl);
|
||||||
nl = mnl_socket_open(NETLINK_NETFILTER);
|
|
||||||
|
struct mnl_socket *nl = mnl_socket_open(NETLINK_NETFILTER);
|
||||||
|
|
||||||
if (nl == NULL) {
|
if (nl == NULL) {
|
||||||
lgerror(-errno, "mnl_socket_open");
|
lgerror(-errno, "mnl_socket_open");
|
||||||
@@ -82,15 +84,15 @@ static int open_socket(struct mnl_socket **_nl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int close_socket(struct mnl_socket **_nl) {
|
static int close_socket(struct mnl_socket **nl) {
|
||||||
struct mnl_socket *nl = *_nl;
|
assert (nl);
|
||||||
if (nl == NULL) return 1;
|
|
||||||
if (mnl_socket_close(nl) < 0) {
|
if (*nl && mnl_socket_close(*nl) < 0) {
|
||||||
lgerror(-errno, "mnl_socket_close");
|
lgerror(-errno, "mnl_socket_close");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*_nl = NULL;
|
*nl = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -198,231 +200,6 @@ static int close_raw6_socket(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* libnetfilter_conntrack
|
|
||||||
* (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum ctattr_counters {
|
|
||||||
CTA_COUNTERS_UNSPEC,
|
|
||||||
CTA_COUNTERS_PACKETS, /* 64bit counters */
|
|
||||||
CTA_COUNTERS_BYTES, /* 64bit counters */
|
|
||||||
CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */
|
|
||||||
CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */
|
|
||||||
CTA_COUNTERS_PAD,
|
|
||||||
__CTA_COUNTERS_MAX
|
|
||||||
};
|
|
||||||
#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
|
|
||||||
|
|
||||||
enum ctattr_type {
|
|
||||||
CTA_UNSPEC,
|
|
||||||
CTA_TUPLE_ORIG,
|
|
||||||
CTA_TUPLE_REPLY,
|
|
||||||
CTA_STATUS,
|
|
||||||
CTA_PROTOINFO,
|
|
||||||
CTA_HELP,
|
|
||||||
CTA_NAT_SRC,
|
|
||||||
#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */
|
|
||||||
CTA_TIMEOUT,
|
|
||||||
CTA_MARK,
|
|
||||||
CTA_COUNTERS_ORIG,
|
|
||||||
CTA_COUNTERS_REPLY,
|
|
||||||
CTA_USE,
|
|
||||||
CTA_ID,
|
|
||||||
CTA_NAT_DST,
|
|
||||||
CTA_TUPLE_MASTER,
|
|
||||||
CTA_SEQ_ADJ_ORIG,
|
|
||||||
CTA_NAT_SEQ_ADJ_ORIG = CTA_SEQ_ADJ_ORIG,
|
|
||||||
CTA_SEQ_ADJ_REPLY,
|
|
||||||
CTA_NAT_SEQ_ADJ_REPLY = CTA_SEQ_ADJ_REPLY,
|
|
||||||
CTA_SECMARK, /* obsolete */
|
|
||||||
CTA_ZONE,
|
|
||||||
CTA_SECCTX,
|
|
||||||
CTA_TIMESTAMP,
|
|
||||||
CTA_MARK_MASK,
|
|
||||||
CTA_LABELS,
|
|
||||||
CTA_LABELS_MASK,
|
|
||||||
CTA_SYNPROXY,
|
|
||||||
CTA_FILTER,
|
|
||||||
CTA_STATUS_MASK,
|
|
||||||
__CTA_MAX
|
|
||||||
};
|
|
||||||
#define CTA_MAX (__CTA_MAX - 1)
|
|
||||||
|
|
||||||
enum {
|
|
||||||
__DIR_ORIG,
|
|
||||||
__DIR_REPL
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
yct_parse_counters_attr_cb(const struct nlattr *attr, void *data)
|
|
||||||
{
|
|
||||||
const struct nlattr **tb = data;
|
|
||||||
int type = mnl_attr_get_type(attr);
|
|
||||||
|
|
||||||
if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0)
|
|
||||||
return MNL_CB_OK;
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case CTA_COUNTERS_PACKETS:
|
|
||||||
case CTA_COUNTERS_BYTES:
|
|
||||||
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
|
|
||||||
return MNL_CB_ERROR;
|
|
||||||
break;
|
|
||||||
case CTA_COUNTERS32_PACKETS:
|
|
||||||
case CTA_COUNTERS32_BYTES:
|
|
||||||
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
|
|
||||||
return MNL_CB_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tb[type] = attr;
|
|
||||||
return MNL_CB_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
yct_parse_counters(const struct nlattr *attr, struct ytb_conntrack *yct,
|
|
||||||
int dir)
|
|
||||||
{
|
|
||||||
struct nlattr *tb[CTA_COUNTERS_MAX+1] = {0};
|
|
||||||
|
|
||||||
if (mnl_attr_parse_nested(attr, yct_parse_counters_attr_cb, tb) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (tb[CTA_COUNTERS_PACKETS] || tb[CTA_COUNTERS32_PACKETS]) {
|
|
||||||
uint64_t packets_counter;
|
|
||||||
if (tb[CTA_COUNTERS32_PACKETS]) {
|
|
||||||
packets_counter =
|
|
||||||
ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_PACKETS]));
|
|
||||||
}
|
|
||||||
if (tb[CTA_COUNTERS_PACKETS]) {
|
|
||||||
packets_counter =
|
|
||||||
be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS]));
|
|
||||||
}
|
|
||||||
switch(dir) {
|
|
||||||
case __DIR_ORIG:
|
|
||||||
yct->orig_packets = packets_counter;
|
|
||||||
yct_set_mask_attr(YCTATTR_ORIG_PACKETS, yct);
|
|
||||||
break;
|
|
||||||
case __DIR_REPL:
|
|
||||||
yct->repl_packets = packets_counter;
|
|
||||||
yct_set_mask_attr(YCTATTR_REPL_PACKETS, yct);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tb[CTA_COUNTERS_BYTES] || tb[CTA_COUNTERS32_BYTES]) {
|
|
||||||
uint64_t bytes_counter;
|
|
||||||
if (tb[CTA_COUNTERS32_BYTES]) {
|
|
||||||
bytes_counter =
|
|
||||||
ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_BYTES]));
|
|
||||||
}
|
|
||||||
if (tb[CTA_COUNTERS_BYTES]) {
|
|
||||||
bytes_counter =
|
|
||||||
be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES]));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(dir) {
|
|
||||||
case __DIR_ORIG:
|
|
||||||
yct->orig_bytes = bytes_counter;
|
|
||||||
yct_set_mask_attr(YCTATTR_ORIG_BYTES, yct);
|
|
||||||
break;
|
|
||||||
case __DIR_REPL:
|
|
||||||
yct->repl_bytes = bytes_counter;
|
|
||||||
yct_set_mask_attr(YCTATTR_REPL_BYTES, yct);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
yct_parse_conntrack_attr_cb(const struct nlattr *attr, void *data){
|
|
||||||
const struct nlattr **tb = data;
|
|
||||||
int type = mnl_attr_get_type(attr);
|
|
||||||
|
|
||||||
if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
|
|
||||||
return MNL_CB_OK;
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case CTA_TUPLE_ORIG:
|
|
||||||
case CTA_TUPLE_REPLY:
|
|
||||||
case CTA_TUPLE_MASTER:
|
|
||||||
case CTA_NAT_SEQ_ADJ_ORIG:
|
|
||||||
case CTA_NAT_SEQ_ADJ_REPLY:
|
|
||||||
case CTA_PROTOINFO:
|
|
||||||
case CTA_COUNTERS_ORIG:
|
|
||||||
case CTA_COUNTERS_REPLY:
|
|
||||||
case CTA_HELP:
|
|
||||||
case CTA_SECCTX:
|
|
||||||
case CTA_TIMESTAMP:
|
|
||||||
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
|
|
||||||
return MNL_CB_ERROR;
|
|
||||||
break;
|
|
||||||
case CTA_STATUS:
|
|
||||||
case CTA_TIMEOUT:
|
|
||||||
case CTA_MARK:
|
|
||||||
case CTA_SECMARK:
|
|
||||||
case CTA_USE:
|
|
||||||
case CTA_ID:
|
|
||||||
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
|
|
||||||
return MNL_CB_ERROR;
|
|
||||||
break;
|
|
||||||
case CTA_ZONE:
|
|
||||||
if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
|
|
||||||
return MNL_CB_ERROR;
|
|
||||||
break;
|
|
||||||
case CTA_NAT_SRC:
|
|
||||||
case CTA_NAT_DST:
|
|
||||||
/* deprecated */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tb[type] = attr;
|
|
||||||
return MNL_CB_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
yct_payload_parse(const void *payload, size_t payload_len,
|
|
||||||
uint16_t l3num, struct ytb_conntrack *yct)
|
|
||||||
{
|
|
||||||
struct nlattr *tb[CTA_MAX+1] = {0};
|
|
||||||
|
|
||||||
if (mnl_attr_parse_payload(payload, payload_len,
|
|
||||||
yct_parse_conntrack_attr_cb, tb) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (tb[CTA_MARK]) {
|
|
||||||
yct->connmark = ntohl(mnl_attr_get_u32(tb[CTA_MARK]));
|
|
||||||
yct_set_mask_attr(YCTATTR_CONNMARK, yct);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (tb[CTA_COUNTERS_ORIG]) {
|
|
||||||
if (yct_parse_counters(tb[CTA_COUNTERS_ORIG],
|
|
||||||
yct, __DIR_ORIG) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[CTA_ID]) {
|
|
||||||
yct->id = ntohl(mnl_attr_get_u32(tb[CTA_ID]));
|
|
||||||
yct_set_mask_attr(YCTATTR_CONNID, yct);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[CTA_COUNTERS_REPLY]) {
|
|
||||||
if (yct_parse_counters(tb[CTA_COUNTERS_REPLY],
|
|
||||||
yct, __DIR_REPL) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int send_raw_ipv4(const uint8_t *pkt, size_t pktlen) {
|
static int send_raw_ipv4(const uint8_t *pkt, size_t pktlen) {
|
||||||
int ret;
|
int ret;
|
||||||
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
|
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
|
||||||
@@ -546,6 +323,7 @@ erret_lc:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++global_stats.sent_counter;
|
||||||
int ipvx = netproto_version(pkt, pktlen);
|
int ipvx = netproto_version(pkt, pktlen);
|
||||||
|
|
||||||
if (ipvx == IP4VERSION) {
|
if (ipvx == IP4VERSION) {
|
||||||
@@ -561,6 +339,227 @@ erret_lc:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libnetfilter_conntrack
|
||||||
|
* (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ctattr_counters {
|
||||||
|
CTA_COUNTERS_UNSPEC,
|
||||||
|
CTA_COUNTERS_PACKETS, /* 64bit counters */
|
||||||
|
CTA_COUNTERS_BYTES, /* 64bit counters */
|
||||||
|
CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */
|
||||||
|
CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */
|
||||||
|
CTA_COUNTERS_PAD,
|
||||||
|
__CTA_COUNTERS_MAX
|
||||||
|
};
|
||||||
|
#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
|
||||||
|
|
||||||
|
enum ctattr_type {
|
||||||
|
CTA_UNSPEC,
|
||||||
|
CTA_TUPLE_ORIG,
|
||||||
|
CTA_TUPLE_REPLY,
|
||||||
|
CTA_STATUS,
|
||||||
|
CTA_PROTOINFO,
|
||||||
|
CTA_HELP,
|
||||||
|
CTA_NAT_SRC,
|
||||||
|
#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */
|
||||||
|
CTA_TIMEOUT,
|
||||||
|
CTA_MARK,
|
||||||
|
CTA_COUNTERS_ORIG,
|
||||||
|
CTA_COUNTERS_REPLY,
|
||||||
|
CTA_USE,
|
||||||
|
CTA_ID,
|
||||||
|
CTA_NAT_DST,
|
||||||
|
CTA_TUPLE_MASTER,
|
||||||
|
CTA_SEQ_ADJ_ORIG,
|
||||||
|
CTA_NAT_SEQ_ADJ_ORIG = CTA_SEQ_ADJ_ORIG,
|
||||||
|
CTA_SEQ_ADJ_REPLY,
|
||||||
|
CTA_NAT_SEQ_ADJ_REPLY = CTA_SEQ_ADJ_REPLY,
|
||||||
|
CTA_SECMARK, /* obsolete */
|
||||||
|
CTA_ZONE,
|
||||||
|
CTA_SECCTX,
|
||||||
|
CTA_TIMESTAMP,
|
||||||
|
CTA_MARK_MASK,
|
||||||
|
CTA_LABELS,
|
||||||
|
CTA_LABELS_MASK,
|
||||||
|
CTA_SYNPROXY,
|
||||||
|
CTA_FILTER,
|
||||||
|
CTA_STATUS_MASK,
|
||||||
|
__CTA_MAX
|
||||||
|
};
|
||||||
|
#define CTA_MAX (__CTA_MAX - 1)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
__DIR_ORIG,
|
||||||
|
__DIR_REPL
|
||||||
|
};
|
||||||
|
|
||||||
|
static int yct_parse_counters_attr_cb(const struct nlattr *attr,
|
||||||
|
void *data) {
|
||||||
|
const struct nlattr **tb = data;
|
||||||
|
int type = mnl_attr_get_type(attr);
|
||||||
|
|
||||||
|
if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0)
|
||||||
|
return MNL_CB_OK;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case CTA_COUNTERS_PACKETS:
|
||||||
|
case CTA_COUNTERS_BYTES:
|
||||||
|
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
|
||||||
|
return MNL_CB_ERROR;
|
||||||
|
break;
|
||||||
|
case CTA_COUNTERS32_PACKETS:
|
||||||
|
case CTA_COUNTERS32_BYTES:
|
||||||
|
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
|
||||||
|
return MNL_CB_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tb[type] = attr;
|
||||||
|
return MNL_CB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yct_parse_counters(const struct nlattr *attr,
|
||||||
|
struct ytb_conntrack *yct, int dir) {
|
||||||
|
struct nlattr *tb[CTA_COUNTERS_MAX+1] = {0};
|
||||||
|
|
||||||
|
if (mnl_attr_parse_nested(attr, yct_parse_counters_attr_cb, tb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (tb[CTA_COUNTERS_PACKETS] || tb[CTA_COUNTERS32_PACKETS]) {
|
||||||
|
uint64_t packets_counter;
|
||||||
|
if (tb[CTA_COUNTERS32_PACKETS]) {
|
||||||
|
packets_counter =
|
||||||
|
ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_PACKETS]));
|
||||||
|
}
|
||||||
|
if (tb[CTA_COUNTERS_PACKETS]) {
|
||||||
|
packets_counter =
|
||||||
|
be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS]));
|
||||||
|
}
|
||||||
|
switch(dir) {
|
||||||
|
case __DIR_ORIG:
|
||||||
|
yct->orig_packets = packets_counter;
|
||||||
|
yct_set_mask_attr(YCTATTR_ORIG_PACKETS, yct);
|
||||||
|
break;
|
||||||
|
case __DIR_REPL:
|
||||||
|
yct->repl_packets = packets_counter;
|
||||||
|
yct_set_mask_attr(YCTATTR_REPL_PACKETS, yct);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tb[CTA_COUNTERS_BYTES] || tb[CTA_COUNTERS32_BYTES]) {
|
||||||
|
uint64_t bytes_counter;
|
||||||
|
if (tb[CTA_COUNTERS32_BYTES]) {
|
||||||
|
bytes_counter =
|
||||||
|
ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_BYTES]));
|
||||||
|
}
|
||||||
|
if (tb[CTA_COUNTERS_BYTES]) {
|
||||||
|
bytes_counter =
|
||||||
|
be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES]));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(dir) {
|
||||||
|
case __DIR_ORIG:
|
||||||
|
yct->orig_bytes = bytes_counter;
|
||||||
|
yct_set_mask_attr(YCTATTR_ORIG_BYTES, yct);
|
||||||
|
break;
|
||||||
|
case __DIR_REPL:
|
||||||
|
yct->repl_bytes = bytes_counter;
|
||||||
|
yct_set_mask_attr(YCTATTR_REPL_BYTES, yct);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yct_parse_conntrack_attr_cb(const struct nlattr *attr,
|
||||||
|
void *data) {
|
||||||
|
const struct nlattr **tb = data;
|
||||||
|
int type = mnl_attr_get_type(attr);
|
||||||
|
|
||||||
|
if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
|
||||||
|
return MNL_CB_OK;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case CTA_TUPLE_ORIG:
|
||||||
|
case CTA_TUPLE_REPLY:
|
||||||
|
case CTA_TUPLE_MASTER:
|
||||||
|
case CTA_NAT_SEQ_ADJ_ORIG:
|
||||||
|
case CTA_NAT_SEQ_ADJ_REPLY:
|
||||||
|
case CTA_PROTOINFO:
|
||||||
|
case CTA_COUNTERS_ORIG:
|
||||||
|
case CTA_COUNTERS_REPLY:
|
||||||
|
case CTA_HELP:
|
||||||
|
case CTA_SECCTX:
|
||||||
|
case CTA_TIMESTAMP:
|
||||||
|
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
|
||||||
|
return MNL_CB_ERROR;
|
||||||
|
break;
|
||||||
|
case CTA_STATUS:
|
||||||
|
case CTA_TIMEOUT:
|
||||||
|
case CTA_MARK:
|
||||||
|
case CTA_SECMARK:
|
||||||
|
case CTA_USE:
|
||||||
|
case CTA_ID:
|
||||||
|
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
|
||||||
|
return MNL_CB_ERROR;
|
||||||
|
break;
|
||||||
|
case CTA_ZONE:
|
||||||
|
if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
|
||||||
|
return MNL_CB_ERROR;
|
||||||
|
break;
|
||||||
|
case CTA_NAT_SRC:
|
||||||
|
case CTA_NAT_DST:
|
||||||
|
/* deprecated */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tb[type] = attr;
|
||||||
|
return MNL_CB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yct_payload_parse(const void *payload,
|
||||||
|
size_t payload_len, uint16_t l3num,
|
||||||
|
struct ytb_conntrack *yct) {
|
||||||
|
struct nlattr *tb[CTA_MAX+1] = {0};
|
||||||
|
|
||||||
|
if (mnl_attr_parse_payload(payload, payload_len,
|
||||||
|
yct_parse_conntrack_attr_cb, tb) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (tb[CTA_MARK]) {
|
||||||
|
yct->connmark = ntohl(mnl_attr_get_u32(tb[CTA_MARK]));
|
||||||
|
yct_set_mask_attr(YCTATTR_CONNMARK, yct);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (tb[CTA_COUNTERS_ORIG]) {
|
||||||
|
if (yct_parse_counters(tb[CTA_COUNTERS_ORIG],
|
||||||
|
yct, __DIR_ORIG) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tb[CTA_ID]) {
|
||||||
|
yct->id = ntohl(mnl_attr_get_u32(tb[CTA_ID]));
|
||||||
|
yct_set_mask_attr(YCTATTR_CONNID, yct);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tb[CTA_COUNTERS_REPLY]) {
|
||||||
|
if (yct_parse_counters(tb[CTA_COUNTERS_REPLY],
|
||||||
|
yct, __DIR_REPL) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Per-queue data. Passed to queue_cb.
|
// Per-queue data. Passed to queue_cb.
|
||||||
struct queue_data {
|
struct queue_data {
|
||||||
@@ -612,14 +611,33 @@ void *delay_packet_send_fn(void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int delay_packet_send(const unsigned char *data, size_t data_len, unsigned int delay_ms) {
|
int delay_packet_send(const unsigned char *data, size_t data_len, unsigned int delay_ms) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
|
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
|
||||||
|
if (dpdt == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
*dpdt = (struct dps_t){0};
|
||||||
|
|
||||||
dpdt->pkt = malloc(data_len);
|
dpdt->pkt = malloc(data_len);
|
||||||
|
if (dpdt->pkt == NULL) {
|
||||||
|
free(dpdt);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
memcpy(dpdt->pkt, data, data_len);
|
memcpy(dpdt->pkt, data, data_len);
|
||||||
|
|
||||||
dpdt->pktlen = data_len;
|
dpdt->pktlen = data_len;
|
||||||
dpdt->timer = delay_ms;
|
dpdt->timer = delay_ms;
|
||||||
pthread_t thr;
|
pthread_t thr = {0};
|
||||||
pthread_create(&thr, NULL, delay_packet_send_fn, dpdt);
|
ret = pthread_create(&thr, NULL, delay_packet_send_fn, dpdt);
|
||||||
pthread_detach(thr);
|
if (ret != 0) {
|
||||||
|
free(dpdt->pkt);
|
||||||
|
free(dpdt);
|
||||||
|
return -ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pthread_detach(thr);
|
||||||
|
|
||||||
lgtrace_addp("Scheduled packet send after %d ms", delay_ms);
|
lgtrace_addp("Scheduled packet send after %d ms", delay_ms);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -640,6 +658,8 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
|||||||
uint16_t l3num;
|
uint16_t l3num;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|
||||||
|
++global_stats.all_packet_counter;
|
||||||
|
|
||||||
if (nfq_nlmsg_parse(nlh, attr) < 0) {
|
if (nfq_nlmsg_parse(nlh, attr) < 0) {
|
||||||
lgerror(-errno, "Attr parse");
|
lgerror(-errno, "Attr parse");
|
||||||
return MNL_CB_ERROR;
|
return MNL_CB_ERROR;
|
||||||
@@ -661,15 +681,16 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
|
|||||||
packet.payload_len = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]);
|
packet.payload_len = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]);
|
||||||
packet.payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]);
|
packet.payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]);
|
||||||
|
|
||||||
if (attr[NFQA_CAP_LEN] != NULL && ntohl(mnl_attr_get_u32(attr[NFQA_CAP_LEN])) != packet.payload_len) {
|
if (attr[NFQA_CAP_LEN] != NULL &&
|
||||||
|
ntohl(mnl_attr_get_u32(attr[NFQA_CAP_LEN])) != packet.payload_len) {
|
||||||
lgerr("The packet was truncated! Skip!");
|
lgerr("The packet was truncated! Skip!");
|
||||||
return fallback_accept_packet(id, *qdata);
|
return fallback_accept_packet(id, *qdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attr[NFQA_MARK] != NULL) {
|
if (attr[NFQA_MARK] != NULL) {
|
||||||
// Skip packets sent by rawsocket to escape infinity loop.
|
// Skip packets sent by rawsocket to escape infinity loop.
|
||||||
if ((ntohl(mnl_attr_get_u32(attr[NFQA_MARK])) & cur_config->mark) ==
|
if (CHECK_BITFIELD(ntohl(mnl_attr_get_u32(attr[NFQA_MARK])),
|
||||||
cur_config->mark) {
|
cur_config->mark)) {
|
||||||
return fallback_accept_packet(id, *qdata);
|
return fallback_accept_packet(id, *qdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -694,8 +715,11 @@ ct_out:
|
|||||||
|
|
||||||
ret = process_packet(cur_config, &packet);
|
ret = process_packet(cur_config, &packet);
|
||||||
|
|
||||||
|
++global_stats.packet_counter;
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case PKT_DROP:
|
case PKT_DROP:
|
||||||
|
++global_stats.target_counter;
|
||||||
nfq_nlmsg_verdict_put(verdnlh, id, NF_DROP);
|
nfq_nlmsg_verdict_put(verdnlh, id, NF_DROP);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -875,6 +899,16 @@ struct instance_config_t instance_config = {
|
|||||||
.send_delayed_packet = delay_packet_send,
|
.send_delayed_packet = delay_packet_send,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void sigint_handler(int s) {
|
||||||
|
lginfo("youtubeUnblock stats: catched %ld packets, "
|
||||||
|
"processed %ld packets, "
|
||||||
|
"targetted %ld packets, sent over socket %ld packets",
|
||||||
|
global_stats.all_packet_counter, global_stats.packet_counter,
|
||||||
|
global_stats.target_counter, global_stats.sent_counter);
|
||||||
|
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int ret;
|
int ret;
|
||||||
struct config_t config;
|
struct config_t config;
|
||||||
@@ -893,6 +927,8 @@ int main(int argc, char *argv[]) {
|
|||||||
parse_global_lgconf(&config);
|
parse_global_lgconf(&config);
|
||||||
cur_config = &config;
|
cur_config = &config;
|
||||||
|
|
||||||
|
signal(SIGINT, sigint_handler);
|
||||||
|
signal(SIGTERM, sigint_handler);
|
||||||
|
|
||||||
if (open_raw_socket() < 0) {
|
if (open_raw_socket() < 0) {
|
||||||
lgerror(-errno, "Unable to open raw socket");
|
lgerror(-errno, "Unable to open raw socket");
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ static void RunAllTests(void)
|
|||||||
{
|
{
|
||||||
RUN_TEST_GROUP(TLSTest)
|
RUN_TEST_GROUP(TLSTest)
|
||||||
RUN_TEST_GROUP(QuicTest);
|
RUN_TEST_GROUP(QuicTest);
|
||||||
|
RUN_TEST_GROUP(TrieTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char * argv[])
|
int main(int argc, const char * argv[])
|
||||||
|
|||||||
15
test/tls.c
15
test/tls.c
@@ -36,22 +36,21 @@ TEST(TLSTest, Test_CHLO_message_detect)
|
|||||||
TEST(TLSTest, Test_Bruteforce_detects)
|
TEST(TLSTest, Test_Bruteforce_detects)
|
||||||
{
|
{
|
||||||
struct tls_verdict tlsv;
|
struct tls_verdict tlsv;
|
||||||
struct domains_list dmns = {
|
struct trie_container trie;
|
||||||
.domain_name = "youtube.com",
|
int ret;
|
||||||
.domain_len = 11,
|
ret = trie_init(&trie);
|
||||||
.next = NULL
|
ret = trie_add_string(&trie, (uint8_t *)"youtube.com", 11);
|
||||||
};
|
sconf.sni_domains = trie;
|
||||||
sconf.sni_domains = &dmns;
|
|
||||||
|
|
||||||
int ret = bruteforce_analyze_sni_str(&sconf, (const uint8_t *)tls_bruteforce_message, sizeof(tls_bruteforce_message) - 1, &tlsv);
|
ret = bruteforce_analyze_sni_str(&sconf, (const uint8_t *)tls_bruteforce_message, sizeof(tls_bruteforce_message) - 1, &tlsv);
|
||||||
TEST_ASSERT_EQUAL(0, ret);
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
TEST_ASSERT_EQUAL(11, tlsv.sni_len);
|
TEST_ASSERT_EQUAL(11, tlsv.sni_len);
|
||||||
TEST_ASSERT_EQUAL_STRING_LEN("youtube.com", tlsv.sni_ptr, 11);
|
TEST_ASSERT_EQUAL_STRING_LEN("youtube.com", tlsv.sni_ptr, 11);
|
||||||
TEST_ASSERT_EQUAL_PTR(tls_bruteforce_message +
|
TEST_ASSERT_EQUAL_PTR(tls_bruteforce_message +
|
||||||
sizeof(tls_bruteforce_message) - 12, tlsv.sni_ptr);
|
sizeof(tls_bruteforce_message) - 12, tlsv.sni_ptr);
|
||||||
|
trie_destroy(&trie);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_GROUP_RUNNER(TLSTest)
|
TEST_GROUP_RUNNER(TLSTest)
|
||||||
{
|
{
|
||||||
RUN_TEST_CASE(TLSTest, Test_CHLO_message_detect);
|
RUN_TEST_CASE(TLSTest, Test_CHLO_message_detect);
|
||||||
|
|||||||
147
test/trie.c
Normal file
147
test/trie.c
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#include "unity.h"
|
||||||
|
#include "unity_fixture.h"
|
||||||
|
|
||||||
|
#include "trie.h"
|
||||||
|
|
||||||
|
TEST_GROUP(TrieTest);
|
||||||
|
|
||||||
|
TEST_SETUP(TrieTest)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_TEAR_DOWN(TrieTest)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char ASTR[] = "abacaba";
|
||||||
|
const char BSTR[] = "BABABABA";
|
||||||
|
const char CSTR[] = "abracadabra";
|
||||||
|
|
||||||
|
const char tstr[] = "aBABABABDADAabacabracadabraabbbabacabaaaaaabacaba";
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TrieTest, Trie_string_adds)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t offset;
|
||||||
|
size_t offlen;
|
||||||
|
struct trie_container trie;
|
||||||
|
|
||||||
|
ret = trie_init(&trie);
|
||||||
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||||
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
|
||||||
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
|
||||||
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(25, trie.sz);
|
||||||
|
|
||||||
|
trie_destroy(&trie);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TrieTest, Trie_string_finds)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t offset;
|
||||||
|
size_t offlen;
|
||||||
|
struct trie_container trie;
|
||||||
|
|
||||||
|
ret = trie_init(&trie);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
|
||||||
|
|
||||||
|
ret = trie_process_str(&trie,
|
||||||
|
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||||
|
0, &offset, &offlen
|
||||||
|
);
|
||||||
|
TEST_ASSERT_EQUAL(1, ret);
|
||||||
|
TEST_ASSERT_EQUAL(11, offlen);
|
||||||
|
TEST_ASSERT_EQUAL_STRING_LEN("abracadabra", tstr + offset, offlen);
|
||||||
|
|
||||||
|
trie_destroy(&trie);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TrieTest, Trie_string_finds_opt_end)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t offset;
|
||||||
|
size_t offlen;
|
||||||
|
struct trie_container trie;
|
||||||
|
|
||||||
|
ret = trie_init(&trie);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
|
||||||
|
|
||||||
|
ret = trie_process_str(&trie,
|
||||||
|
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||||
|
TRIE_OPT_MAP_TO_END,
|
||||||
|
&offset, &offlen
|
||||||
|
);
|
||||||
|
TEST_ASSERT_EQUAL(1, ret);
|
||||||
|
TEST_ASSERT_EQUAL(7, offlen);
|
||||||
|
TEST_ASSERT_EQUAL_STRING_LEN("abacaba", tstr + offset, offlen);
|
||||||
|
|
||||||
|
ret = trie_process_str(&trie,
|
||||||
|
(uint8_t *)tstr, sizeof(tstr),
|
||||||
|
TRIE_OPT_MAP_TO_END,
|
||||||
|
&offset, &offlen
|
||||||
|
);
|
||||||
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
|
|
||||||
|
trie_destroy(&trie);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TrieTest, Trie_single_vertex)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t offset;
|
||||||
|
size_t offlen;
|
||||||
|
struct trie_container trie;
|
||||||
|
|
||||||
|
ret = trie_init(&trie);
|
||||||
|
|
||||||
|
ret = trie_process_str(&trie,
|
||||||
|
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||||
|
0,
|
||||||
|
&offset, &offlen
|
||||||
|
);
|
||||||
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
|
|
||||||
|
trie_destroy(&trie);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TrieTest, Trie_uninitialized)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t offset;
|
||||||
|
size_t offlen;
|
||||||
|
struct trie_container trie = {0};
|
||||||
|
|
||||||
|
// ret = trie_init(&trie);
|
||||||
|
|
||||||
|
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
|
||||||
|
TEST_ASSERT_EQUAL(-EINVAL, ret);
|
||||||
|
|
||||||
|
ret = trie_process_str(&trie,
|
||||||
|
(uint8_t *)tstr, sizeof(tstr) - 1,
|
||||||
|
0,
|
||||||
|
&offset, &offlen
|
||||||
|
);
|
||||||
|
TEST_ASSERT_EQUAL(0, ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_GROUP_RUNNER(TrieTest)
|
||||||
|
{
|
||||||
|
RUN_TEST_CASE(TrieTest, Trie_string_adds);
|
||||||
|
RUN_TEST_CASE(TrieTest, Trie_string_finds);
|
||||||
|
RUN_TEST_CASE(TrieTest, Trie_string_finds_opt_end);
|
||||||
|
RUN_TEST_CASE(TrieTest, Trie_single_vertex);
|
||||||
|
RUN_TEST_CASE(TrieTest, Trie_uninitialized);
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@ export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CF
|
|||||||
APP:=$(BUILD_DIR)/youtubeUnblock
|
APP:=$(BUILD_DIR)/youtubeUnblock
|
||||||
TEST_APP:=$(BUILD_DIR)/testYoutubeUnblock
|
TEST_APP:=$(BUILD_DIR)/testYoutubeUnblock
|
||||||
|
|
||||||
SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c
|
SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c trie.c dpi.c
|
||||||
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
|
||||||
APP_EXEC := youtubeUnblock.c
|
APP_EXEC := youtubeUnblock.c
|
||||||
APP_OBJ := $(APP_EXEC:%.c=$(BUILD_DIR)/%.o)
|
APP_OBJ := $(APP_EXEC:%.c=$(BUILD_DIR)/%.o)
|
||||||
@@ -109,7 +109,10 @@ $(BUILD_DIR)/test/%.o: test/%.c $(REQ) $(INCLUDE_DIR)/config.h
|
|||||||
@echo 'CC $@'
|
@echo 'CC $@'
|
||||||
$(CC) -c $(CFLAGS) $(LDFLAGS) $(TEST_CFLAGS) $< -o $@
|
$(CC) -c $(CFLAGS) $(LDFLAGS) $(TEST_CFLAGS) $< -o $@
|
||||||
|
|
||||||
install: all
|
install:
|
||||||
|
ifeq (,$(wildcard $(APP)))
|
||||||
|
$(error Make the binary first)
|
||||||
|
endif
|
||||||
install -d $(DESTDIR)$(PREFIX)/bin/
|
install -d $(DESTDIR)$(PREFIX)/bin/
|
||||||
install -m 755 $(APP) $(DESTDIR)$(PREFIX)/bin/
|
install -m 755 $(APP) $(DESTDIR)$(PREFIX)/bin/
|
||||||
install -d $(DESTDIR)$(PREFIX)/lib/systemd/system/
|
install -d $(DESTDIR)$(PREFIX)/lib/systemd/system/
|
||||||
|
|||||||
Reference in New Issue
Block a user