4 Commits

Author SHA1 Message Date
Vadim Vetrov
883346b808 Add luci builder for apk 2025-12-28 13:42:49 +03:00
Vadim Vetrov
28d24c80ef Update documentation for 24.10 2025-12-28 13:42:49 +03:00
Vadim Vetrov
4761034802 Update workflow for openwrt 24.10 2025-12-28 13:42:49 +03:00
Vadim Vetrov
6c3ed7e5e9 Add signing public key
The key used primarily for OpenWRT apk
2025-12-28 13:42:48 +03:00
18 changed files with 904 additions and 1272 deletions

View File

@@ -167,7 +167,14 @@ jobs:
strategy:
matrix:
branch:
- openwrt-24.10
- openwrt-23.05
- SNAPSHOT
include:
- branch: SNAPSHOT
package_extension: apk
- branch: openwrt-23.05
package_extension: ipk
arch:
- aarch64_cortex-a53
- aarch64_cortex-a72
@@ -184,6 +191,7 @@ jobs:
- arm_cortex-a9_neon
- arm_cortex-a9_vfpv3-d16
- arm_fa526
- arm_mpcore
- arm_xscale
- mips64_octeonplus
- mips_24kc
@@ -194,6 +202,9 @@ jobs:
- mipsel_74kc
- mipsel_mips32
- x86_64
exclude:
- branch: SNAPSHOT
arch: arm_mpcore
container:
image: openwrt/sdk:${{ matrix.arch }}-${{ matrix.branch }}
options: --user root
@@ -209,7 +220,8 @@ jobs:
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION-$RELEASE-$SHA/" youtubeUnblock/Makefile
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION/;s/PKG_RELEASE:=.*$/PKG_RELEASE:=$RELEASE/;" youtubeUnblock/Makefile
- name: Initilalize SDK
id: init_sdk
@@ -221,6 +233,15 @@ jobs:
run: |
HOME=/builder ./setup.sh
- name: Add signing key
if: matrix.package_extension == 'apk'
id: signing_key
env:
SIGNING_KEY: ${{ secrets.EC_PRIVATE_KEY }}
working-directory: /builder
run: |
([ -n "$SIGNING_KEY" ] && echo "$SIGNING_KEY" > private-key.pem) || true
- name: Build packages
id: build
env:
@@ -235,21 +256,33 @@ jobs:
./scripts/feeds install -a -p youtubeUnblock
make defconfig
make package/youtubeUnblock/compile V=s
mv $(find ./bin -type f -name 'youtubeUnblock*.ipk') ./youtubeUnblock-$VERSION-$RELEASE-$SHA-${{ matrix.arch }}-${{ matrix.branch }}.ipk
mv $(find ./bin -type f -name "youtubeUnblock*.${{ matrix.package_extension }}") ./youtubeUnblock-$VERSION-$RELEASE-$SHA-${{ matrix.arch }}-${{ matrix.branch }}.${{ matrix.package_extension }}
- name: Upload packages
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: youtubeUnblock-${{ matrix.branch }}-${{ matrix.arch }}
path: /builder/youtubeUnblock*.ipk
path: /builder/youtubeUnblock*.${{ matrix.package_extension }}
if-no-files-found: error
build-openwrt-luci:
needs: prepare
runs-on: ubuntu-latest
strategy:
matrix:
branch:
- openwrt-23.05
- SNAPSHOT
arch:
- x86_64
include:
- branch: SNAPSHOT
package_extension: apk
- branch: openwrt-23.05
package_extension: ipk
container:
image: openwrt/sdk:x86_64-openwrt-24.10
image: openwrt/sdk:${{ matrix.arch }}-${{ matrix.branch }}
options: --user root
steps:
- name: Checkout
@@ -257,14 +290,6 @@ jobs:
with:
ref: 'openwrt'
- name: Prepare build
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION-$RELEASE-$SHA/" youtubeUnblock/Makefile
- name: Initilalize SDK
id: init_sdk
env:
@@ -275,6 +300,15 @@ jobs:
run: |
HOME=/builder ./setup.sh
- name: Add signing key
if: matrix.package_extension == 'apk'
id: signing_key
env:
SIGNING_KEY: ${{ secrets.EC_PRIVATE_KEY }}
working-directory: /builder
run: |
([ -n "$SIGNING_KEY" ] && echo "$SIGNING_KEY" > private-key.pem) || true
- name: Build packages
id: build
env:
@@ -289,14 +323,14 @@ jobs:
./scripts/feeds install -a -p youtubeUnblock
make defconfig
make package/luci-app-youtubeUnblock/compile V=s
mv $(find ./bin -type f -name 'luci-app-youtubeUnblock*.ipk') ./luci-app-youtubeUnblock-$VERSION-$RELEASE-$SHA.ipk
mv $(find ./bin -type f -name 'luci-app-youtubeUnblock*.${{ matrix.package_extension }}') ./luci-app-youtubeUnblock-$VERSION-$RELEASE-$SHA.${{ matrix.package_extension }}
- name: Upload packages
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: luci-app-youtubeUnblock
path: /builder/luci-app-youtubeUnblock*.ipk
name: luci-app-youtubeUnblock-${{ matrix.branch }}
path: /builder/luci-app-youtubeUnblock*.${{ matrix.package_extension }}
if-no-files-found: error
build-entware:
@@ -327,7 +361,7 @@ jobs:
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION-$RELEASE-$SHA/" youtubeUnblockEntware/Makefile
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION/;s/PKG_RELEASE:=.*$/PKG_RELEASE:=$RELEASE/;" youtubeUnblockEntware/Makefile
- name: Build packages
id: build
@@ -374,5 +408,7 @@ jobs:
title: 'Development build'
files: |
./**/youtubeUnblock*.ipk
./**/youtubeUnblock*.apk
./**/youtubeUnblock*.tar.gz
./**/luci-app-youtubeUnblock*.ipk
./**/luci-app-youtubeUnblock*.apk

2
Kbuild
View File

@@ -1,3 +1,3 @@
obj-m := kyoutubeUnblock.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
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 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

View File

@@ -1,7 +1,7 @@
USPACE_TARGETS := default all install uninstall dev run_dev
KMAKE_TARGETS := kmake kload kunload kreload xmod xtclean
PKG_VERSION := 1.3.0
PKG_VERSION := 1.1.1
PKG_RELEASE := 1
PKG_FULLVERSION := $(PKG_VERSION)-$(PKG_RELEASE)

View File

@@ -10,7 +10,6 @@
- [Check it](#check-it)
- [Flags](#flags)
- [UDP/QUIC](#udpquic)
- [Cloudflare](#cloudflare)
- [Troubleshooting](#troubleshooting)
- [TV](#tv)
- [Troubleshooting EPERMS (Operation not permitted)](#troubleshooting-eperms-operation-not-permitted)
@@ -73,7 +72,7 @@ On both OpenWRT and Entware install the program with opkg. If you got read-only
When you got the release package, you should install it. Go to your router interface, to *System->Software*, do *Update lists* and install youtubeUnblock via *install_package* button. Then, you should go to *System-Startup* menu and reload the firewall (You may also do it within *Services->youtubeUnblock* menu).
Since OpenWRT **main** branch switched to apk instead of opkg, but this is not released yet, here is not deploys for apk in **Releases**. But **apk is supported** in PR #196.
Since OpenWRT **main** branch switched to apk instead of opkg, but this is not released yet, here is not deploys for apk in **Releases**. But **apk is supported** in PR #196. Note, that if you are on **24.10** you will get **UNTRUSTED SIGNATURE** error. Put youtubeUnblock.pem to `/etc/apk/keys/` or install youtubeUnblock with `--allow-untrusted` flag `apk add youtubeUnblock*.apk --allow-untrusted`.
To make it work you should register an iptables rule and install required kernel modules. The list of modules depends on the version of OpenWRT and which firewall do you use (iptables or nftables). For most modern versions of OpenWRT (v23.x, v22.x) you should use nftables rules, for older ones it depends, but typically iptables.
@@ -199,11 +198,6 @@ 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
```
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
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.
@@ -244,10 +238,6 @@ 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).
- `--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-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**.
@@ -258,20 +248,17 @@ 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).
- `--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`.
- `--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}` This flag determines the strategy of fake packets invalidation. Defaults to `randseq`
- `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.
- `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.
- `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**.
- `--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-sni-reverse={0|1}` Specifies **youtubeUnblock** to send *ClientHello* fragments in the reverse order. Defaults to **1**.
@@ -332,29 +319,6 @@ QUIC is enabled with `--udp-filter-quic` flag. The flag supports two modes: `all
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
Check up [this issue](https://github.com/Waujito/youtubeUnblock/issues/148) for useful configs.

View File

@@ -159,63 +159,7 @@ static long parse_numeric_option(const char* value) {
return result;
}
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) {
static int parse_udp_dport_range(char *str, struct udp_dport_range **udpr, int *udpr_len) {
int seclen = 1;
const char *p = str;
while (*p != '\0') {
@@ -225,14 +169,14 @@ static int parse_dport_range(char *str, struct dport_range **udpr, int *udpr_len
}
#ifdef KERNEL_SPACE
struct dport_range *dport_ranges = kmalloc(
seclen * sizeof(struct dport_range), GFP_KERNEL);
struct udp_dport_range *udp_dport_ranges = kmalloc(
seclen * sizeof(struct udp_dport_range), GFP_KERNEL);
#else
struct dport_range *dport_ranges = malloc(
seclen * sizeof(struct dport_range));
struct udp_dport_range *udp_dport_ranges = malloc(
seclen * sizeof(struct udp_dport_range));
#endif
if (dport_ranges == NULL) {
if (udp_dport_ranges == NULL) {
return -ENOMEM;
}
@@ -279,7 +223,7 @@ static int parse_dport_range(char *str, struct dport_range **udpr, int *udpr_len
)
goto erret;
dport_ranges[i] = (struct dport_range){
udp_dport_ranges[i] = (struct udp_dport_range){
.start = num1,
.end = num2
};
@@ -297,15 +241,15 @@ static int parse_dport_range(char *str, struct dport_range **udpr, int *udpr_len
}
if (i == 0) {
free(dport_ranges);
free(udp_dport_ranges);
}
*udpr = dport_ranges;
*udpr = udp_dport_ranges;
*udpr_len = i;
return 0;
erret:
free(dport_ranges);
free(udp_dport_ranges);
return -1;
}
@@ -350,11 +294,9 @@ enum {
OPT_EXCLUDE_DOMAINS,
OPT_SNI_DOMAINS_FILE,
OPT_EXCLUDE_DOMAINS_FILE,
OPT_TCP_DPORT_FILTER,
OPT_FAKE_SNI,
OPT_FAKING_TTL,
OPT_FAKING_STRATEGY,
OPT_FAKING_TIMESTAMP_DECREASE,
OPT_FAKE_SNI_SEQ_LEN,
OPT_FAKE_SNI_TYPE,
OPT_FAKE_CUSTOM_PAYLOAD,
@@ -398,7 +340,6 @@ enum {
OPT_HELP,
OPT_VERSION,
OPT_CONNBYTES_LIMIT,
OPT_TCP_M_CONNPKTS,
};
static struct option long_opt[] = {
@@ -412,7 +353,6 @@ static struct option long_opt[] = {
{"synfake", 1, 0, OPT_SYNFAKE},
{"synfake-len", 1, 0, OPT_SYNFAKE_LEN},
{"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-type", 1, 0, OPT_FAKE_SNI_TYPE},
{"fake-custom-payload", 1, 0, OPT_FAKE_CUSTOM_PAYLOAD},
@@ -420,7 +360,6 @@ static struct option long_opt[] = {
{"faking-strategy", 1, 0, OPT_FAKING_STRATEGY},
{"fake-seq-offset", 1, 0, OPT_FAKE_SEQ_OFFSET},
{"faking-ttl", 1, 0, OPT_FAKING_TTL},
{"faking-timestamp-decrease", 1, 0, OPT_FAKING_TIMESTAMP_DECREASE},
{"frag", 1, 0, OPT_FRAG},
{"frag-sni-reverse", 1, 0, OPT_FRAG_SNI_REVERSE},
{"frag-sni-faked", 1, 0, OPT_FRAG_SNI_FAKED},
@@ -438,7 +377,6 @@ static struct option long_opt[] = {
{"udp-stun-filter", 0, 0, OPT_UDP_STUN_FILTER},
{"udp-filter-quic", 1, 0, OPT_UDP_FILTER_QUIC},
{"no-dport-filter", 0, 0, OPT_NO_DPORT_FILTER},
{"tcp-match-connpackets", 1, 0, OPT_TCP_M_CONNPKTS},
{"threads", 1, 0, OPT_THREADS},
{"silent", 0, 0, OPT_SILENT},
{"trace", 0, 0, OPT_TRACE},
@@ -480,7 +418,6 @@ void print_usage(const char *argv0) {
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--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-seq-len=<length>\n");
printf("\t--fake-sni-type={default|random|custom}\n");
@@ -488,8 +425,7 @@ void print_usage(const char *argv0) {
printf("\t--fake-custom-payload-file=<binary file containing TLS message>\n");
printf("\t--fake-seq-offset=<offset>\n");
printf("\t--faking-ttl=<ttl>\n");
printf("\t--faking-timestamp-decrease=<val>\n");
printf("\t--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum|timestamp}\n");
printf("\t--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}\n");
printf("\t--synfake={1|0}\n");
printf("\t--synfake-len=<len>\n");
printf("\t--frag={tcp,ip,none}\n");
@@ -512,7 +448,6 @@ void print_usage(const char *argv0) {
printf("\t--threads=<threads number>\n");
printf("\t--packet-mark=<mark>\n");
printf("\t--connbytes-limit=<pkts>\n");
printf("\t--tcp-match-connpackets=<n of packets in connection>\n");
printf("\t--silent\n");
printf("\t--trace\n");
printf("\t--instaflush\n");
@@ -794,28 +729,21 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
sect_config->frag_sni_pos = num;
break;
case OPT_TCP_DPORT_FILTER:
{
SFREE(sect_config->tcp_dport_range);
if (parse_dport_range(optarg, &sect_config->tcp_dport_range, &sect_config->tcp_dport_range_len) < 0) {
goto invalid_opt;
}
break;
}
case OPT_TCP_M_CONNPKTS:
num = parse_numeric_option(optarg);
if (errno != 0 || num < 0) {
goto invalid_opt;
}
sect_config->tcp_match_connpkts = num;
break;
case OPT_FAKING_STRATEGY:
if (parse_faking_strategy(
optarg, &sect_config->faking_strategy) < 0) {
if (strcmp(optarg, "randseq") == 0) {
sect_config->faking_strategy = FAKE_STRAT_RAND_SEQ;
} else if (strcmp(optarg, "ttl") == 0) {
sect_config->faking_strategy = FAKE_STRAT_TTL;
} else if (strcmp(optarg, "tcp_check") == 0) {
sect_config->faking_strategy = FAKE_STRAT_TCP_CHECK;
} else if (strcmp(optarg, "pastseq") == 0) {
sect_config->faking_strategy = FAKE_STRAT_PAST_SEQ;
} else if (strcmp(optarg, "md5sum") == 0) {
sect_config->faking_strategy = FAKE_STRAT_TCP_MD5SUM;
} else {
goto invalid_opt;
}
break;
case OPT_FAKING_TTL:
num = parse_numeric_option(optarg);
@@ -825,14 +753,6 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
sect_config->faking_ttl = num;
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:
num = parse_numeric_option(optarg);
if (errno != 0) {
@@ -1005,7 +925,7 @@ int yparse_args(struct config_t *config, int argc, char *argv[]) {
case OPT_UDP_DPORT_FILTER:
{
SFREE(sect_config->udp_dport_range);
if (parse_dport_range(optarg, &sect_config->udp_dport_range, &sect_config->udp_dport_range_len) < 0) {
if (parse_udp_dport_range(optarg, &sect_config->udp_dport_range, &sect_config->udp_dport_range_len) < 0) {
goto invalid_opt;
}
break;
@@ -1078,26 +998,8 @@ static size_t print_config_section(const struct section_config_t *section, char
size_t buf_sz = buffer_size;
size_t sz;
if (section->tcp_dport_range_len != 0) {
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) {
case FRAG_STRAT_IP:
@@ -1133,64 +1035,31 @@ static size_t print_config_section(const struct section_config_t *section, char
break;
}
switch(section->faking_strategy) {
case FAKE_STRAT_TTL:
print_cnf_buf("--faking-strategy=ttl");
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;
}
print_cnf_buf("--seg2delay=%d", section->seg2_delay);
} else {
print_cnf_buf("--fake-sni=0");
}
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;
}
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 {
print_cnf_buf("--tls=disabled");
}
@@ -1246,7 +1115,7 @@ static size_t print_config_section(const struct section_config_t *section, char
print_cnf_raw("--udp-dport-filter=");
for (int i = 0; i < section->udp_dport_range_len; i++) {
struct dport_range range = section->udp_dport_range[i];
struct udp_dport_range range = section->udp_dport_range[i];
print_cnf_raw("%d-%d,", range.start, range.end);
}
print_cnf_raw(" ");
@@ -1378,8 +1247,8 @@ int init_section_config(struct section_config_t **section, struct section_config
return ret;
}
def_section->fake_sni_pkt = fake_sni;
def_section->fake_sni_pkt_sz = sizeof(fake_sni) - 1;
def_section->fake_sni_pkt = fake_sni_old;
def_section->fake_sni_pkt_sz = sizeof(fake_sni_old) - 1;
*section = def_section;
return 0;
@@ -1405,10 +1274,6 @@ void free_config_section(struct section_config_t *section) {
SFREE(section->udp_dport_range);
}
if (section->tcp_dport_range_len != 0) {
SFREE(section->tcp_dport_range);
}
free_sni_domains(&section->sni_domains);
free_sni_domains(&section->exclude_sni_domains);

View File

@@ -48,7 +48,7 @@ struct logging_config_t {
};
extern struct logging_config_t logging_conf;
struct dport_range {
struct udp_dport_range {
uint16_t start;
uint16_t end;
};
@@ -64,11 +64,6 @@ struct section_config_t {
int tls_enabled;
struct dport_range *tcp_dport_range;
int tcp_dport_range_len;
int tcp_match_connpkts;
int fragmentation_strategy;
int frag_sni_reverse;
int frag_sni_faked;
@@ -76,7 +71,6 @@ struct section_config_t {
int frag_middle_sni;
int frag_sni_pos;
unsigned char faking_ttl;
unsigned int faking_timestamp_decrease;
int fake_sni;
unsigned int fake_sni_seq_len;
@@ -111,7 +105,7 @@ struct section_config_t {
unsigned int udp_fake_len;
int udp_faking_strategy;
struct dport_range *udp_dport_range;
struct udp_dport_range *udp_dport_range;
int udp_dport_range_len;
int udp_stun_filter;
int udp_filter_quic;
@@ -182,7 +176,6 @@ for (struct section_config_t *section = (config)->last_section; section != NULL;
#endif
#define FAKE_TTL 8
#define FAKING_TIMESTAMP_DECREASE_TTL 600000
#define FAKE_STRAT_NONE 0
// Will invalidate fake packets by out-of-ack_seq out-of-seq request
@@ -194,7 +187,6 @@ for (struct section_config_t *section = (config)->last_section; section != NULL;
#define FAKE_STRAT_TCP_CHECK (1 << 3)
#define FAKE_STRAT_TCP_MD5SUM (1 << 4)
#define FAKE_STRAT_UDP_CHECK (1 << 5)
#define FAKE_STRAT_TCP_TS (1 << 6)
#define FAKE_STRAT_COUNT 6
@@ -207,7 +199,7 @@ for (int strategy = 1; strategy <= (1 << FAKE_STRAT_COUNT); strategy <<= 1) \
if ((fake_bitmask) & strategy)
#ifndef FAKING_STRATEGY
#define FAKING_STRATEGY FAKE_STRAT_TCP_CHECK | FAKE_STRAT_TCP_TS
#define FAKING_STRATEGY FAKE_STRAT_PAST_SEQ
#endif
#define MAX_FAKE_SIZE 1300
@@ -243,17 +235,13 @@ enum {
.sni_domains = {0}, \
.exclude_sni_domains = {0}, \
.all_domains = 0, \
.tcp_dport_range = NULL, \
.tcp_dport_range_len = 0, \
.tcp_match_connpkts = 0, \
.tls_enabled = 1, \
.frag_sni_reverse = 1, \
.frag_sni_faked = 0, \
.fragmentation_strategy = FRAGMENTATION_STRATEGY, \
.faking_strategy = FAKING_STRATEGY, \
.faking_ttl = FAKE_TTL, \
.faking_timestamp_decrease = FAKING_TIMESTAMP_DECREASE_TTL, \
.fake_sni = 1, \
.fake_sni = 0, \
.fake_sni_seq_len = 1, \
.fake_sni_type = FAKE_PAYLOAD_DEFAULT, \
.fake_custom_pkt = NULL, \

509
src/dpi.c
View File

@@ -1,509 +0,0 @@
/*
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();
}

View File

@@ -1,87 +0,0 @@
/*
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 */

View File

@@ -25,7 +25,6 @@
#include "quic.h"
#include "logging.h"
#include "tls.h"
#include "dpi.h"
#ifndef KERNEL_SPACE
#include <stdlib.h>
@@ -33,13 +32,198 @@
#include "linux/inet.h"
#endif
int send_synfake(const struct section_config_t *section, const struct parsed_packet *pkt) {
assert (section);
assert (pkt);
int process_packet(const struct config_t *config, const struct packet_data *pd) {
const uint8_t *raw_payload = pd->payload;
uint32_t raw_payload_len = pd->payload_len;
assert (pkt->transport_proto == IPPROTO_TCP);
assert (pkt->tcph->syn);
if (raw_payload_len > MAX_PACKET_SIZE) {
return PKT_ACCEPT;
}
const struct iphdr *iph;
const struct ip6_hdr *ip6h;
size_t iph_len;
const uint8_t *ip_payload;
size_t ip_payload_len;
const char *bpt;
int transport_proto = -1;
int ipver = netproto_version(raw_payload, raw_payload_len);
int ret;
lgtrace_start();
lgtrace_wr("IPv%d ", ipver);
if (ipver == IP4VERSION) {
ret = ip4_payload_split((uint8_t *)raw_payload, raw_payload_len,
(struct iphdr **)&iph, &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) {
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) {
return PKT_ACCEPT;
}
// As defined by TLS standard.
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;
@@ -47,31 +231,32 @@ int send_synfake(const struct section_config_t *section, const struct parsed_pac
fake_len = min((int)section->synfake_len, (int)fake_len);
size_t payload_len = pkt->iph_len + pkt->tcph_len + 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, pkt->ipxh, pkt->iph_len);
memcpy(payload + pkt->iph_len, pkt->tcph, pkt->tcph_len);
memcpy(payload + pkt->iph_len + pkt->tcph_len, section->fake_sni_pkt, fake_len);
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 + pkt->iph_len);
if (pkt->ipver == IP4VERSION) {
struct tcphdr *tcph = (struct tcphdr *)(payload + iph_len);
if (ipxv == IP4VERSION) {
struct iphdr *iph = (struct iphdr *)payload;
iph->tot_len = htons(pkt->iph_len + pkt->tcph_len + fake_len);
set_ip_checksum(payload, pkt->iph_len);
set_tcp_checksum(tcph, iph, pkt->iph_len);
} else if (pkt->ipver == IP6VERSION) {
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(pkt->tcph_len + fake_len);
set_ip_checksum(ip6h, pkt->iph_len);
set_tcp_checksum(tcph, ip6h, pkt->iph_len);
ip6h->ip6_plen = ntohs(tcph_len + fake_len);
set_ip_checksum(ip6h, iph_len);
set_tcp_checksum(tcph, ip6h, iph_len);
}
int ret = instance_config.send_raw_packet(payload, payload_len);
ret = instance_config.send_raw_packet(payload, payload_len);
if (ret < 0) {
lgerror(ret, "send_syn_altered");
@@ -81,6 +266,247 @@ int send_synfake(const struct section_config_t *section, const struct parsed_pac
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;
// 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;
}
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;
}
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) {
@@ -227,7 +653,6 @@ send_fake:
struct tcphdr *tcph;
ret = tcp_payload_split(frag2, f2len, &iph, &iphfl, &tcph, &tcphfl, NULL, NULL);
struct fake_type f_type = args_default_fake_type(section);
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_RAND_SEQ;
@@ -279,7 +704,9 @@ int post_fake_sni(struct fake_type f_type,
void *fsiph = (void *)rfsiph;
struct tcphdr *fstcph = (void *)rfstcph;
ITER_FAKE_STRAT(f_type.strategy.strategy, strategy) {
struct fake_type fake_seq_type = f_type;
fake_seq_type.strategy.strategy = strategy;
// one goes for default fake
for (int i = 0; i < fake_seq_type.sequence_len; i++) {
@@ -321,8 +748,8 @@ int post_fake_sni(struct fake_type f_type,
}
if (!(CHECK_BITFIELD(f_type.strategy.strategy, FAKE_STRAT_PAST_SEQ) ||
CHECK_BITFIELD(f_type.strategy.strategy, FAKE_STRAT_RAND_SEQ))) {
if (!(strategy == FAKE_STRAT_PAST_SEQ ||
strategy == FAKE_STRAT_RAND_SEQ)) {
fstcph->seq = htonl(ntohl(fstcph->seq) + plen);
}
@@ -342,6 +769,7 @@ erret_lc:
free(fake_sni);
return ret;
}
}
return 0;
}

View File

@@ -23,18 +23,32 @@
#include "types.h"
#include "tls.h"
#include "config.h"
#include "dpi.h"
#define PKT_ACCEPT 0
#define PKT_DROP 1
// Used for section config
#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);
/**
* Sends synfake message
* Processe the TCP packet.
* Returns verdict.
*/
int send_synfake(const struct section_config_t *section, const struct parsed_packet *pkt);
int process_tcp_packet(const struct section_config_t *section, const uint8_t *raw_payload, size_t raw_payload_len);
/**
* Processes the UDP packet.
* Returns verdict.
*/
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, size_t pktlen);
/**

View File

@@ -579,7 +579,7 @@ int detect_udp_filtered(const struct section_config_t *section,
match_port:
for (int i = 0; i < section->udp_dport_range_len; i++) {
struct dport_range crange = section->udp_dport_range[i];
struct udp_dport_range crange = section->udp_dport_range[i];
if (udp_dport >= crange.start && udp_dport <= crange.end) {
lgtrace_addp("matched to %d-%d", crange.start, crange.end);
goto approve;

View File

@@ -5,5 +5,6 @@
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*/

View File

@@ -22,12 +22,6 @@
#define TYPES_H
#include <asm/byteorder.h>
#ifndef KERNEL_SPACE
#include <assert.h>
#else
#define assert(...) ;
#endif
#ifdef KERNEL_SPACE
#include <linux/errno.h> // IWYU pragma: export
#include <linux/string.h> // IWYU pragma: export
@@ -133,8 +127,6 @@ free((item)); \
#endif /* not a KERNEL_SPACE */
#define CHECK_BITFIELD(value, field) (((value) & (field)) == (field))
static inline int randint(void) {
int rnd;

View File

@@ -616,15 +616,6 @@ struct tcp_md5sig_opt {
// Real length of the option, with NOOP fillers
#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) {
void *iph;
size_t iph_len;
@@ -645,22 +636,18 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
}
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_RAND_SEQ)) {
if (strategy.strategy == FAKE_STRAT_RAND_SEQ) {
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
tcph->seq = htonl(ntohl(tcph->seq) - (strategy.randseq_offset + dlen));
lgtrace_addp("%u", ntohl(tcph->seq));
}
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_PAST_SEQ)) {
} else if (strategy.strategy == FAKE_STRAT_PAST_SEQ) {
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
tcph->seq = htonl(ntohl(tcph->seq) - dlen);
lgtrace_addp("%u", ntohl(tcph->seq));
}
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_TTL)) {
} else if (strategy.strategy == FAKE_STRAT_TTL) {
lgtrace_addp("set fake ttl to %d", strategy.faking_ttl);
if (ipxv == IP4VERSION) {
@@ -671,9 +658,7 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
return -EINVAL;
}
}
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_TCP_MD5SUM)) {
} else if (strategy.strategy == FAKE_STRAT_TCP_MD5SUM) {
int optp_len = tcph_len - sizeof(struct tcphdr);
int delta = TCP_MD5SIG_OPT_RLEN - optp_len;
lgtrace_addp("Incr delta %d: %d -> %d", delta, optp_len, optp_len + delta);
@@ -688,11 +673,9 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
tcph_len = tcph_len + delta;
tcph->doff = tcph_len >> 2;
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) {
((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 {
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
return -EINVAL;
@@ -714,53 +697,6 @@ 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) {
((struct iphdr *)iph)->frag_off = 0;
}
@@ -769,7 +705,7 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen
set_ip_checksum(iph, iph_len);
set_tcp_checksum(tcph, iph, iph_len);
if (CHECK_BITFIELD(strategy.strategy, FAKE_STRAT_TCP_CHECK)) {
if (strategy.strategy == FAKE_STRAT_TCP_CHECK) {
lgtrace_addp("break fake tcp checksum");
tcph->check += 1;
}

View File

@@ -133,7 +133,6 @@ void shift_data(uint8_t *data, size_t dlen, size_t delta);
struct failing_strategy {
unsigned int strategy;
uint8_t faking_ttl;
uint32_t faking_timestamp_decrease;
size_t randseq_offset;
};
@@ -198,8 +197,7 @@ static inline struct failing_strategy args_default_failing_strategy(const struct
struct failing_strategy fl_strat = {
.strategy = (unsigned int)section->faking_strategy,
.faking_ttl = section->faking_ttl,
.faking_timestamp_decrease = section->faking_timestamp_decrease,
.randseq_offset = (size_t)section->fakeseq_offset,
.randseq_offset = (size_t)section->fakeseq_offset
};
return fl_strat;
}

View File

@@ -49,7 +49,7 @@
#include <signal.h>
#include "config.h"
#include "dpi.h"
#include "mangle.h"
#include "args.h"
#include "utils.h"
#include "logging.h"
@@ -63,9 +63,8 @@ int raw6socket = -2;
static struct config_t *cur_config = NULL;
static int open_socket(struct mnl_socket **_nl) {
assert (_nl);
struct mnl_socket *nl = mnl_socket_open(NETLINK_NETFILTER);
struct mnl_socket *nl = NULL;
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
lgerror(-errno, "mnl_socket_open");
@@ -84,15 +83,15 @@ static int open_socket(struct mnl_socket **_nl) {
}
static int close_socket(struct mnl_socket **nl) {
assert (nl);
if (*nl && mnl_socket_close(*nl) < 0) {
static int close_socket(struct mnl_socket **_nl) {
struct mnl_socket *nl = *_nl;
if (nl == NULL) return 1;
if (mnl_socket_close(nl) < 0) {
lgerror(-errno, "mnl_socket_close");
return -1;
}
*nl = NULL;
*_nl = NULL;
return 0;
}
@@ -200,6 +199,231 @@ static int close_raw6_socket(void) {
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) {
int ret;
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
@@ -339,227 +563,6 @@ erret_lc:
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.
struct queue_data {
@@ -681,16 +684,15 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
packet.payload_len = mnl_attr_get_payload_len(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!");
return fallback_accept_packet(id, *qdata);
}
if (attr[NFQA_MARK] != NULL) {
// Skip packets sent by rawsocket to escape infinity loop.
if (CHECK_BITFIELD(ntohl(mnl_attr_get_u32(attr[NFQA_MARK])),
cur_config->mark)) {
if ((ntohl(mnl_attr_get_u32(attr[NFQA_MARK])) & cur_config->mark) ==
cur_config->mark) {
return fallback_accept_packet(id, *qdata);
}
}

View File

@@ -34,7 +34,7 @@ export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CF
APP:=$(BUILD_DIR)/youtubeUnblock
TEST_APP:=$(BUILD_DIR)/testYoutubeUnblock
SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c trie.c dpi.c
SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c trie.c
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
APP_EXEC := youtubeUnblock.c
APP_OBJ := $(APP_EXEC:%.c=$(BUILD_DIR)/%.o)

4
youtubeUnblock.pem Normal file
View File

@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoeHyI7xqf2Y5weRscJxUy/BRoKqT
2dE9xFsZ2HKBTd2UMMkOwca+/BDXRZlxWGvcVNhDyLY9VGnZniF2JaH+Fw==
-----END PUBLIC KEY-----