Merge branch 'dev'

This commit is contained in:
Vadim Vetrov
2025-01-18 23:21:54 +03:00
70 changed files with 14590 additions and 2637 deletions

View File

@@ -32,11 +32,12 @@ jobs:
run: |
echo "version=$(cat Makefile | grep "PKG_VERSION :=" | sed 's/PKG_VERSION := //')" >> $GITHUB_OUTPUT
echo "release=$(cat Makefile | grep "PKG_RELEASE :=" | sed 's/PKG_RELEASE := //')" >> $GITHUB_OUTPUT
if [[ "${{ github.event_name }}" != "pull_request" ]]; then
echo "sha=$(echo ${GITHUB_SHA::7})" >> $GITHUB_OUTPUT
else
echo "sha=$(gh api repos/$REPO/commits/main --jq '.sha[:7]')" >> $GITHUB_OUTPUT
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
GITHUB_SHA=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.head.sha)
fi
echo "sha=$(echo ${GITHUB_SHA::7})" >> $GITHUB_OUTPUT
cat $GITHUB_OUTPUT
build-static:
needs: prepare

View File

@@ -70,6 +70,29 @@ jobs:
name: static-youtubeUnblock-${{ matrix.arch }}
path: ./**/static-youtubeUnblock*.tar.gz
test:
needs: prepare
name: test
runs-on: ubuntu-latest
strategy:
matrix:
arch: [x86_64]
branch: [latest-stable]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
id: build
shell: bash
run: |
make build_test -j$(nproc)
- name: Test
id: test
run:
./build/testYoutubeUnblock
build-kmod:
needs: prepare
name: build-kmod ${{ matrix.kernel_version }}

1
.gitignore vendored
View File

@@ -13,5 +13,6 @@ modules.order
Module.symvers
*.so
*.ko
*.a
!/.github

4
Kbuild
View File

@@ -1,3 +1,3 @@
obj-m := kyoutubeUnblock.o
kyoutubeUnblock-objs := kytunblock.o mangle.o quic.o utils.o kargs.o tls.o getopt.o args.o
ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement
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
ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement -I$(src)/src -I$(src)/deps/cyclone/include

View File

@@ -8,13 +8,19 @@ PKG_FULLVERSION := $(PKG_VERSION)-$(PKG_RELEASE)
export PKG_VERSION PKG_RELEASE PKG_FULLVERSION
.PHONY: $(USPACE_TARGETS) $(KMAKE_TARGETS) clean
.PHONY: $(USPACE_TARGETS) $(KMAKE_TARGETS) test build_test clean distclean kclean
$(USPACE_TARGETS):
@$(MAKE) -f uspace.mk $@
$(KMAKE_TARGETS):
@$(MAKE) -f kmake.mk $@
build_test:
-@$(MAKE) -f uspace.mk build_test
test:
-@$(MAKE) -f uspace.mk test
clean:
-@$(MAKE) -f uspace.mk clean

View File

@@ -9,7 +9,7 @@
- [IPv6](#ipv6)
- [Check it](#check-it)
- [Flags](#flags)
- [UDP](#udp)
- [UDP/QUIC](#udp/quic)
- [Troubleshooting](#troubleshooting)
- [TV](#tv)
- [Troubleshooting EPERMS (Operation not permitted)](#troubleshooting-eperms-operation-not-permitted)
@@ -198,7 +198,11 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
- `--trace` Maximum verbosity for debugging purposes.
- `--no-gso` Disables support for Google Chrome fat packets which uses GSO. This feature is well tested now, so this flag probably won't fix anything.
- `--instaflush` Used with tracing. Flushes the buffer instantly, without waiting for explicit new line. Highly useful for debugging crushes.
- `--no-gso` Disables support for TCP fat packets which uses GSO. This feature is well tested now, so this flag probably won't fix anything.
- `--no-conntrack` Disables support for conntrack in youtubeUnblock.
- `--no-ipv6` Disables support for ipv6. May be useful if you don't want for ipv6 socket to be opened.
@@ -272,13 +276,23 @@ Flags that do not scoped to a specific section, used over all the youtubeUnblock
- `--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}` Enables QUIC filtering for UDP handler. If disabled, quic won't be processed, if all, all quic initial packets will be handled. 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`.
## UDP
- `--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 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. For QUIC faking may not work well, so use `--quic-drop` if you want to drop all quic traffic. For other technologies 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 [issues tagged with udp label](https://github.com/Waujito/youtubeUnblock/issues?q=label%3Audp+).
## 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.
Right now, QUIC faking may not work well, so use `--udp-mode=drop` option.
QUIC is enabled with `--udp-filter-quic` flag. The flag supports two modes: `all` will handle all the QUIC initial messages and `parse` will decrypt and parse the QUIC initial message, and then compare it with `--sni-domains` flag.
**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+).
## Troubleshooting
@@ -324,6 +338,11 @@ Where you have to replace 192.168.. with ip of your television.
* send fake sni EPERM: Fake SNI is out-of-state thing and will likely corrupt the connection (the behavior is expected). conntrack considers it as an invalid packet. By default OpenWRT set up to drop outgoing packets like this one. You may delete nftables/iptables rule that drops packets with invalid conntrack state, but I don't recommend to do this. The step 3 is better solution.
* Step 3, ultimate solution. Use mark (don't confuse with connmark). The youtubeUnblock uses mark internally to avoid infinity packet loops (when the packet is sent by youtubeUnblock but on next step handled by itself). Currently it uses mark (1 << 15) = 32768. You should put iptables/nftables that ultimately accepts such marks at the very start of the filter OUTPUT chain: `iptables -I OUTPUT -m mark --mark 32768/32768 -j ACCEPT` or `nft insert rule inet fw4 output mark and 0x8000 == 0x8000 counter accept`.
### Conntrack
youtubeUnblock *optionally* depends on conntrack.
For kernel module, if conntrack breaks dependencies, compile it with `make kmake EXTRA_CFLAGS="-DNO_CONNTRACK"` to disable it completly.
## Compilation
Before compilation make sure `gcc`, `make`, `autoconf`, `automake`, `pkg-config` and `libtool` is installed. For Fedora `glibc-static` should be installed as well.

23
args.h
View File

@@ -1,23 +0,0 @@
#ifndef ARGS_H
#define ARGS_H
#include "types.h"
#include "config.h"
void print_version(void);
void print_usage(const char *argv0);
int yparse_args(int argc, char *argv[]);
size_t print_config(char *buffer, size_t buffer_size);
// Initializes configuration storage.
int init_config(struct config_t *config);
// Allocates and initializes configuration section.
int init_section_config(struct section_config_t **section, struct section_config_t *prev);
// Frees configuration section
void free_config_section(struct section_config_t *config);
// Frees sections under config
void free_config(struct config_t config);
/* Prints starting messages */
void print_welcome(void);
#endif /* ARGS_H */

24
deps/cyclone/Makefile vendored Normal file
View File

@@ -0,0 +1,24 @@
SRCS := $(shell find -name "*.c")
OBJS := $(SRCS:%.c=build/%.o)
override CFLAGS += -Iinclude -Wno-pedantic
LIBNAME := libcyclone.a
CC := gcc
run: $(OBJS)
@echo "AR $(LIBNAME)"
@ar rcs libcyclone.a $(OBJS)
prep_dirs:
mkdir -p build
build/%.o: %.c prep_dirs
$(CC) $(CFLAGS) -c -o $@ $<
clean:
@rm $(OBJS) || true
@rm libcyclone.a || true
@rm -rf build || true

577
deps/cyclone/aes.c vendored Normal file
View File

@@ -0,0 +1,577 @@
/**
* @file aes.c
* @brief AES (Advanced Encryption Standard)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @section Description
*
* AES is an encryption standard based on Rijndael algorithm, a symmetric block
* cipher that can process data blocks of 128 bits, using cipher keys with
* lengths of 128, 192, and 256 bits. Refer to FIPS 197 for more details
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL
//Dependencies
#include "core/crypto.h"
#include "cipher/aes.h"
//Check crypto library configuration
#if (AES_SUPPORT == ENABLED)
//Substitution table used by encryption algorithm (S-box)
static const uint8_t sbox[256] =
{
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
//Substitution table used by decryption algorithm (inverse S-box)
static const uint8_t isbox[256] =
{
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};
//Precalculated table (encryption)
static const uint32_t te[256] =
{
0xA56363C6, 0x847C7CF8, 0x997777EE, 0x8D7B7BF6, 0x0DF2F2FF, 0xBD6B6BD6, 0xB16F6FDE, 0x54C5C591,
0x50303060, 0x03010102, 0xA96767CE, 0x7D2B2B56, 0x19FEFEE7, 0x62D7D7B5, 0xE6ABAB4D, 0x9A7676EC,
0x45CACA8F, 0x9D82821F, 0x40C9C989, 0x877D7DFA, 0x15FAFAEF, 0xEB5959B2, 0xC947478E, 0x0BF0F0FB,
0xECADAD41, 0x67D4D4B3, 0xFDA2A25F, 0xEAAFAF45, 0xBF9C9C23, 0xF7A4A453, 0x967272E4, 0x5BC0C09B,
0xC2B7B775, 0x1CFDFDE1, 0xAE93933D, 0x6A26264C, 0x5A36366C, 0x413F3F7E, 0x02F7F7F5, 0x4FCCCC83,
0x5C343468, 0xF4A5A551, 0x34E5E5D1, 0x08F1F1F9, 0x937171E2, 0x73D8D8AB, 0x53313162, 0x3F15152A,
0x0C040408, 0x52C7C795, 0x65232346, 0x5EC3C39D, 0x28181830, 0xA1969637, 0x0F05050A, 0xB59A9A2F,
0x0907070E, 0x36121224, 0x9B80801B, 0x3DE2E2DF, 0x26EBEBCD, 0x6927274E, 0xCDB2B27F, 0x9F7575EA,
0x1B090912, 0x9E83831D, 0x742C2C58, 0x2E1A1A34, 0x2D1B1B36, 0xB26E6EDC, 0xEE5A5AB4, 0xFBA0A05B,
0xF65252A4, 0x4D3B3B76, 0x61D6D6B7, 0xCEB3B37D, 0x7B292952, 0x3EE3E3DD, 0x712F2F5E, 0x97848413,
0xF55353A6, 0x68D1D1B9, 0x00000000, 0x2CEDEDC1, 0x60202040, 0x1FFCFCE3, 0xC8B1B179, 0xED5B5BB6,
0xBE6A6AD4, 0x46CBCB8D, 0xD9BEBE67, 0x4B393972, 0xDE4A4A94, 0xD44C4C98, 0xE85858B0, 0x4ACFCF85,
0x6BD0D0BB, 0x2AEFEFC5, 0xE5AAAA4F, 0x16FBFBED, 0xC5434386, 0xD74D4D9A, 0x55333366, 0x94858511,
0xCF45458A, 0x10F9F9E9, 0x06020204, 0x817F7FFE, 0xF05050A0, 0x443C3C78, 0xBA9F9F25, 0xE3A8A84B,
0xF35151A2, 0xFEA3A35D, 0xC0404080, 0x8A8F8F05, 0xAD92923F, 0xBC9D9D21, 0x48383870, 0x04F5F5F1,
0xDFBCBC63, 0xC1B6B677, 0x75DADAAF, 0x63212142, 0x30101020, 0x1AFFFFE5, 0x0EF3F3FD, 0x6DD2D2BF,
0x4CCDCD81, 0x140C0C18, 0x35131326, 0x2FECECC3, 0xE15F5FBE, 0xA2979735, 0xCC444488, 0x3917172E,
0x57C4C493, 0xF2A7A755, 0x827E7EFC, 0x473D3D7A, 0xAC6464C8, 0xE75D5DBA, 0x2B191932, 0x957373E6,
0xA06060C0, 0x98818119, 0xD14F4F9E, 0x7FDCDCA3, 0x66222244, 0x7E2A2A54, 0xAB90903B, 0x8388880B,
0xCA46468C, 0x29EEEEC7, 0xD3B8B86B, 0x3C141428, 0x79DEDEA7, 0xE25E5EBC, 0x1D0B0B16, 0x76DBDBAD,
0x3BE0E0DB, 0x56323264, 0x4E3A3A74, 0x1E0A0A14, 0xDB494992, 0x0A06060C, 0x6C242448, 0xE45C5CB8,
0x5DC2C29F, 0x6ED3D3BD, 0xEFACAC43, 0xA66262C4, 0xA8919139, 0xA4959531, 0x37E4E4D3, 0x8B7979F2,
0x32E7E7D5, 0x43C8C88B, 0x5937376E, 0xB76D6DDA, 0x8C8D8D01, 0x64D5D5B1, 0xD24E4E9C, 0xE0A9A949,
0xB46C6CD8, 0xFA5656AC, 0x07F4F4F3, 0x25EAEACF, 0xAF6565CA, 0x8E7A7AF4, 0xE9AEAE47, 0x18080810,
0xD5BABA6F, 0x887878F0, 0x6F25254A, 0x722E2E5C, 0x241C1C38, 0xF1A6A657, 0xC7B4B473, 0x51C6C697,
0x23E8E8CB, 0x7CDDDDA1, 0x9C7474E8, 0x211F1F3E, 0xDD4B4B96, 0xDCBDBD61, 0x868B8B0D, 0x858A8A0F,
0x907070E0, 0x423E3E7C, 0xC4B5B571, 0xAA6666CC, 0xD8484890, 0x05030306, 0x01F6F6F7, 0x120E0E1C,
0xA36161C2, 0x5F35356A, 0xF95757AE, 0xD0B9B969, 0x91868617, 0x58C1C199, 0x271D1D3A, 0xB99E9E27,
0x38E1E1D9, 0x13F8F8EB, 0xB398982B, 0x33111122, 0xBB6969D2, 0x70D9D9A9, 0x898E8E07, 0xA7949433,
0xB69B9B2D, 0x221E1E3C, 0x92878715, 0x20E9E9C9, 0x49CECE87, 0xFF5555AA, 0x78282850, 0x7ADFDFA5,
0x8F8C8C03, 0xF8A1A159, 0x80898909, 0x170D0D1A, 0xDABFBF65, 0x31E6E6D7, 0xC6424284, 0xB86868D0,
0xC3414182, 0xB0999929, 0x772D2D5A, 0x110F0F1E, 0xCBB0B07B, 0xFC5454A8, 0xD6BBBB6D, 0x3A16162C
};
//Precalculated table (decryption)
static const uint32_t td[256] =
{
0x50A7F451, 0x5365417E, 0xC3A4171A, 0x965E273A, 0xCB6BAB3B, 0xF1459D1F, 0xAB58FAAC, 0x9303E34B,
0x55FA3020, 0xF66D76AD, 0x9176CC88, 0x254C02F5, 0xFCD7E54F, 0xD7CB2AC5, 0x80443526, 0x8FA362B5,
0x495AB1DE, 0x671BBA25, 0x980EEA45, 0xE1C0FE5D, 0x02752FC3, 0x12F04C81, 0xA397468D, 0xC6F9D36B,
0xE75F8F03, 0x959C9215, 0xEB7A6DBF, 0xDA595295, 0x2D83BED4, 0xD3217458, 0x2969E049, 0x44C8C98E,
0x6A89C275, 0x78798EF4, 0x6B3E5899, 0xDD71B927, 0xB64FE1BE, 0x17AD88F0, 0x66AC20C9, 0xB43ACE7D,
0x184ADF63, 0x82311AE5, 0x60335197, 0x457F5362, 0xE07764B1, 0x84AE6BBB, 0x1CA081FE, 0x942B08F9,
0x58684870, 0x19FD458F, 0x876CDE94, 0xB7F87B52, 0x23D373AB, 0xE2024B72, 0x578F1FE3, 0x2AAB5566,
0x0728EBB2, 0x03C2B52F, 0x9A7BC586, 0xA50837D3, 0xF2872830, 0xB2A5BF23, 0xBA6A0302, 0x5C8216ED,
0x2B1CCF8A, 0x92B479A7, 0xF0F207F3, 0xA1E2694E, 0xCDF4DA65, 0xD5BE0506, 0x1F6234D1, 0x8AFEA6C4,
0x9D532E34, 0xA055F3A2, 0x32E18A05, 0x75EBF6A4, 0x39EC830B, 0xAAEF6040, 0x069F715E, 0x51106EBD,
0xF98A213E, 0x3D06DD96, 0xAE053EDD, 0x46BDE64D, 0xB58D5491, 0x055DC471, 0x6FD40604, 0xFF155060,
0x24FB9819, 0x97E9BDD6, 0xCC434089, 0x779ED967, 0xBD42E8B0, 0x888B8907, 0x385B19E7, 0xDBEEC879,
0x470A7CA1, 0xE90F427C, 0xC91E84F8, 0x00000000, 0x83868009, 0x48ED2B32, 0xAC70111E, 0x4E725A6C,
0xFBFF0EFD, 0x5638850F, 0x1ED5AE3D, 0x27392D36, 0x64D90F0A, 0x21A65C68, 0xD1545B9B, 0x3A2E3624,
0xB1670A0C, 0x0FE75793, 0xD296EEB4, 0x9E919B1B, 0x4FC5C080, 0xA220DC61, 0x694B775A, 0x161A121C,
0x0ABA93E2, 0xE52AA0C0, 0x43E0223C, 0x1D171B12, 0x0B0D090E, 0xADC78BF2, 0xB9A8B62D, 0xC8A91E14,
0x8519F157, 0x4C0775AF, 0xBBDD99EE, 0xFD607FA3, 0x9F2601F7, 0xBCF5725C, 0xC53B6644, 0x347EFB5B,
0x7629438B, 0xDCC623CB, 0x68FCEDB6, 0x63F1E4B8, 0xCADC31D7, 0x10856342, 0x40229713, 0x2011C684,
0x7D244A85, 0xF83DBBD2, 0x1132F9AE, 0x6DA129C7, 0x4B2F9E1D, 0xF330B2DC, 0xEC52860D, 0xD0E3C177,
0x6C16B32B, 0x99B970A9, 0xFA489411, 0x2264E947, 0xC48CFCA8, 0x1A3FF0A0, 0xD82C7D56, 0xEF903322,
0xC74E4987, 0xC1D138D9, 0xFEA2CA8C, 0x360BD498, 0xCF81F5A6, 0x28DE7AA5, 0x268EB7DA, 0xA4BFAD3F,
0xE49D3A2C, 0x0D927850, 0x9BCC5F6A, 0x62467E54, 0xC2138DF6, 0xE8B8D890, 0x5EF7392E, 0xF5AFC382,
0xBE805D9F, 0x7C93D069, 0xA92DD56F, 0xB31225CF, 0x3B99ACC8, 0xA77D1810, 0x6E639CE8, 0x7BBB3BDB,
0x097826CD, 0xF418596E, 0x01B79AEC, 0xA89A4F83, 0x656E95E6, 0x7EE6FFAA, 0x08CFBC21, 0xE6E815EF,
0xD99BE7BA, 0xCE366F4A, 0xD4099FEA, 0xD67CB029, 0xAFB2A431, 0x31233F2A, 0x3094A5C6, 0xC066A235,
0x37BC4E74, 0xA6CA82FC, 0xB0D090E0, 0x15D8A733, 0x4A9804F1, 0xF7DAEC41, 0x0E50CD7F, 0x2FF69117,
0x8DD64D76, 0x4DB0EF43, 0x544DAACC, 0xDF0496E4, 0xE3B5D19E, 0x1B886A4C, 0xB81F2CC1, 0x7F516546,
0x04EA5E9D, 0x5D358C01, 0x737487FA, 0x2E410BFB, 0x5A1D67B3, 0x52D2DB92, 0x335610E9, 0x1347D66D,
0x8C61D79A, 0x7A0CA137, 0x8E14F859, 0x893C13EB, 0xEE27A9CE, 0x35C961B7, 0xEDE51CE1, 0x3CB1477A,
0x59DFD29C, 0x3F73F255, 0x79CE1418, 0xBF37C773, 0xEACDF753, 0x5BAAFD5F, 0x146F3DDF, 0x86DB4478,
0x81F3AFCA, 0x3EC468B9, 0x2C342438, 0x5F40A3C2, 0x72C31D16, 0x0C25E2BC, 0x8B493C28, 0x41950DFF,
0x7101A839, 0xDEB30C08, 0x9CE4B4D8, 0x90C15664, 0x6184CB7B, 0x70B632D5, 0x745C6C48, 0x4257B8D0
};
//Round constant word array
static const uint32_t rcon[11] =
{
0x00000000,
0x00000001,
0x00000002,
0x00000004,
0x00000008,
0x00000010,
0x00000020,
0x00000040,
0x00000080,
0x0000001B,
0x00000036
};
//AES128-ECB OID (2.16.840.1.101.3.4.1.1)
const uint8_t AES128_ECB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x01};
//AES128-CBC OID (2.16.840.1.101.3.4.1.2)
const uint8_t AES128_CBC_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02};
//AES128-OFB OID (2.16.840.1.101.3.4.1.3)
const uint8_t AES128_OFB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x03};
//AES128-CFB OID (2.16.840.1.101.3.4.1.4)
const uint8_t AES128_CFB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x04};
//AES128-GCM OID (2.16.840.1.101.3.4.1.6)
const uint8_t AES128_GCM_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x06};
//AES128-CCM OID (2.16.840.1.101.3.4.1.7)
const uint8_t AES128_CCM_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x07};
//AES192-ECB OID (2.16.840.1.101.3.4.1.21)
const uint8_t AES192_ECB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x15};
//AES192-CBC OID (2.16.840.1.101.3.4.1.22)
const uint8_t AES192_CBC_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16};
//AES192-OFB OID (2.16.840.1.101.3.4.1.23)
const uint8_t AES192_OFB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x17};
//AES192-CFB OID (2.16.840.1.101.3.4.1.24)
const uint8_t AES192_CFB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x18};
//AES192-GCM OID (2.16.840.1.101.3.4.1.26)
const uint8_t AES192_GCM_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x1A};
//AES192-CCM OID (2.16.840.1.101.3.4.1.27)
const uint8_t AES192_CCM_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x1B};
//AES256-ECB OID (2.16.840.1.101.3.4.1.41)
const uint8_t AES256_ECB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x29};
//AES256-CBC OID (2.16.840.1.101.3.4.1.42)
const uint8_t AES256_CBC_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2A};
//AES256-OFB OID (2.16.840.1.101.3.4.1.43)
const uint8_t AES256_OFB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2B};
//AES256-CFB OID (2.16.840.1.101.3.4.1.44)
const uint8_t AES256_CFB_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2C};
//AES256-GCM OID (2.16.840.1.101.3.4.1.46)
const uint8_t AES256_GCM_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2E};
//AES256-CCM OID (2.16.840.1.101.3.4.1.47)
const uint8_t AES256_CCM_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2F};
//Common interface for encryption algorithms
const CipherAlgo aesCipherAlgo =
{
"AES",
sizeof(AesContext),
CIPHER_ALGO_TYPE_BLOCK,
AES_BLOCK_SIZE,
(CipherAlgoInit) aesInit,
NULL,
NULL,
(CipherAlgoEncryptBlock) aesEncryptBlock,
(CipherAlgoDecryptBlock) aesDecryptBlock,
(CipherAlgoDeinit) aesDeinit
};
/**
* @brief Key expansion
* @param[in] context Pointer to the AES context to initialize
* @param[in] key Pointer to the key
* @param[in] keyLen Length of the key
* @return Error code
**/
__weak_func error_t aesInit(AesContext *context, const uint8_t *key,
size_t keyLen)
{
uint_t i;
uint32_t temp;
size_t keyScheduleSize;
//Check parameters
if(context == NULL || key == NULL)
return ERROR_INVALID_PARAMETER;
//Check the length of the key
if(keyLen == 16)
{
//10 rounds are required for 128-bit key
context->nr = 10;
}
else if(keyLen == 24)
{
//12 rounds are required for 192-bit key
context->nr = 12;
}
else if(keyLen == 32)
{
//14 rounds are required for 256-bit key
context->nr = 14;
}
else
{
//Report an error
return ERROR_INVALID_KEY_LENGTH;
}
//Determine the number of 32-bit words in the key
keyLen /= 4;
//Copy the original key
for(i = 0; i < keyLen; i++)
{
context->ek[i] = LOAD32LE(key + (i * 4));
}
//The size of the key schedule depends on the number of rounds
keyScheduleSize = 4 * (context->nr + 1);
//Generate the key schedule (encryption)
for(i = keyLen; i < keyScheduleSize; i++)
{
//Save previous word
temp = context->ek[i - 1];
//Apply transformation
if((i % keyLen) == 0)
{
context->ek[i] = sbox[(temp >> 8) & 0xFF];
context->ek[i] |= (sbox[(temp >> 16) & 0xFF] << 8);
context->ek[i] |= (sbox[(temp >> 24) & 0xFF] << 16);
context->ek[i] |= (sbox[temp & 0xFF] << 24);
context->ek[i] ^= rcon[i / keyLen];
}
else if(keyLen > 6 && (i % keyLen) == 4)
{
context->ek[i] = sbox[temp & 0xFF];
context->ek[i] |= (sbox[(temp >> 8) & 0xFF] << 8);
context->ek[i] |= (sbox[(temp >> 16) & 0xFF] << 16);
context->ek[i] |= (sbox[(temp >> 24) & 0xFF] << 24);
}
else
{
context->ek[i] = temp;
}
//Update the key schedule
context->ek[i] ^= context->ek[i - keyLen];
}
//Generate the key schedule (decryption)
for(i = 0; i < keyScheduleSize; i++)
{
//Apply the InvMixColumns transformation to all round keys but the first
//and the last
if(i < 4 || i >= (keyScheduleSize - 4))
{
context->dk[i] = context->ek[i];
}
else
{
context->dk[i] = td[sbox[context->ek[i] & 0xFF]];
temp = td[sbox[(context->ek[i] >> 8) & 0xFF]];
context->dk[i] ^= ROL32(temp, 8);
temp = td[sbox[(context->ek[i] >> 16) & 0xFF]];
context->dk[i] ^= ROL32(temp, 16);
temp = td[sbox[(context->ek[i] >> 24) & 0xFF]];
context->dk[i] ^= ROL32(temp, 24);
}
}
//No error to report
return NO_ERROR;
}
/**
* @brief Encrypt a 16-byte block using AES algorithm
* @param[in] context Pointer to the AES context
* @param[in] input Plaintext block to encrypt
* @param[out] output Ciphertext block resulting from encryption
**/
__weak_func void aesEncryptBlock(AesContext *context, const uint8_t *input,
uint8_t *output)
{
uint_t i;
uint32_t s0;
uint32_t s1;
uint32_t s2;
uint32_t s3;
uint32_t t0;
uint32_t t1;
uint32_t t2;
uint32_t t3;
uint32_t temp;
//Copy the plaintext to the state array
s0 = LOAD32LE(input + 0);
s1 = LOAD32LE(input + 4);
s2 = LOAD32LE(input + 8);
s3 = LOAD32LE(input + 12);
//Initial round key addition
s0 ^= context->ek[0];
s1 ^= context->ek[1];
s2 ^= context->ek[2];
s3 ^= context->ek[3];
//The number of rounds depends on the key length
for(i = 1; i < context->nr; i++)
{
//Apply round function
t0 = te[s0 & 0xFF];
temp = te[(s1 >> 8) & 0xFF];
t0 ^= ROL32(temp, 8);
temp = te[(s2 >> 16) & 0xFF];
t0 ^= ROL32(temp, 16);
temp = te[(s3 >> 24) & 0xFF];
t0 ^= ROL32(temp, 24);
t1 = te[s1 & 0xFF];
temp = te[(s2 >> 8) & 0xFF];
t1 ^= ROL32(temp, 8);
temp = te[(s3 >> 16) & 0xFF];
t1 ^= ROL32(temp, 16);
temp = te[(s0 >> 24) & 0xFF];
t1 ^= ROL32(temp, 24);
t2 = te[s2 & 0xFF];
temp = te[(s3 >> 8) & 0xFF];
t2 ^= ROL32(temp, 8);
temp = te[(s0 >> 16) & 0xFF];
t2 ^= ROL32(temp, 16);
temp = te[(s1 >> 24) & 0xFF];
t2 ^= ROL32(temp, 24);
t3 = te[s3 & 0xFF];
temp = te[(s0 >> 8) & 0xFF];
t3 ^= ROL32(temp, 8);
temp = te[(s1 >> 16) & 0xFF];
t3 ^= ROL32(temp, 16);
temp = te[(s2 >> 24) & 0xFF];
t3 ^= ROL32(temp, 24);
//Round key addition
s0 = t0 ^ context->ek[i * 4];
s1 = t1 ^ context->ek[i * 4 + 1];
s2 = t2 ^ context->ek[i * 4 + 2];
s3 = t3 ^ context->ek[i * 4 + 3];
}
//The last round differs slightly from the first rounds
t0 = sbox[s0 & 0xFF];
t0 |= sbox[(s1 >> 8) & 0xFF] << 8;
t0 |= sbox[(s2 >> 16) & 0xFF] << 16;
t0 |= sbox[(s3 >> 24) & 0xFF] << 24;
t1 = sbox[s1 & 0xFF];
t1 |= sbox[(s2 >> 8) & 0xFF] << 8;
t1 |= sbox[(s3 >> 16) & 0xFF] << 16;
t1 |= sbox[(s0 >> 24) & 0xFF] << 24;
t2 = sbox[s2 & 0xFF];
t2 |= sbox[(s3 >> 8) & 0xFF] << 8;
t2 |= sbox[(s0 >> 16) & 0xFF] << 16;
t2 |= sbox[(s1 >> 24) & 0xFF] << 24;
t3 = sbox[s3 & 0xFF];
t3 |= sbox[(s0 >> 8) & 0xFF] << 8;
t3 |= sbox[(s1 >> 16) & 0xFF] << 16;
t3 |= sbox[(s2 >> 24) & 0xFF] << 24;
//Last round key addition
s0 = t0 ^ context->ek[context->nr * 4];
s1 = t1 ^ context->ek[context->nr * 4 + 1];
s2 = t2 ^ context->ek[context->nr * 4 + 2];
s3 = t3 ^ context->ek[context->nr * 4 + 3];
//The final state is then copied to the output
STORE32LE(s0, output + 0);
STORE32LE(s1, output + 4);
STORE32LE(s2, output + 8);
STORE32LE(s3, output + 12);
}
/**
* @brief Decrypt a 16-byte block using AES algorithm
* @param[in] context Pointer to the AES context
* @param[in] input Ciphertext block to decrypt
* @param[out] output Plaintext block resulting from decryption
**/
__weak_func void aesDecryptBlock(AesContext *context, const uint8_t *input,
uint8_t *output)
{
uint_t i;
uint32_t s0;
uint32_t s1;
uint32_t s2;
uint32_t s3;
uint32_t t0;
uint32_t t1;
uint32_t t2;
uint32_t t3;
uint32_t temp;
//Copy the ciphertext to the state array
s0 = LOAD32LE(input + 0);
s1 = LOAD32LE(input + 4);
s2 = LOAD32LE(input + 8);
s3 = LOAD32LE(input + 12);
//Initial round key addition
s0 ^= context->dk[context->nr * 4];
s1 ^= context->dk[context->nr * 4 + 1];
s2 ^= context->dk[context->nr * 4 + 2];
s3 ^= context->dk[context->nr * 4 + 3];
//The number of rounds depends on the key length
for(i = context->nr - 1; i >= 1; i--)
{
//Apply round function
t0 = td[s0 & 0xFF];
temp = td[(s3 >> 8) & 0xFF];
t0 ^= ROL32(temp, 8);
temp = td[(s2 >> 16) & 0xFF];
t0 ^= ROL32(temp, 16);
temp = td[(s1 >> 24) & 0xFF];
t0 ^= ROL32(temp, 24);
t1 = td[s1 & 0xFF];
temp = td[(s0 >> 8) & 0xFF];
t1 ^= ROL32(temp, 8);
temp = td[(s3 >> 16) & 0xFF];
t1 ^= ROL32(temp, 16);
temp = td[(s2 >> 24) & 0xFF];
t1 ^= ROL32(temp, 24);
t2 = td[s2 & 0xFF];
temp = td[(s1 >> 8) & 0xFF];
t2 ^= ROL32(temp, 8);
temp = td[(s0 >> 16) & 0xFF];
t2 ^= ROL32(temp, 16);
temp = td[(s3 >> 24) & 0xFF];
t2 ^= ROL32(temp, 24);
t3 = td[s3 & 0xFF];
temp = td[(s2 >> 8) & 0xFF];
t3 ^= ROL32(temp, 8);
temp = td[(s1 >> 16) & 0xFF];
t3 ^= ROL32(temp, 16);
temp = td[(s0 >> 24) & 0xFF];
t3 ^= ROL32(temp, 24);
//Round key addition
s0 = t0 ^ context->dk[i * 4];
s1 = t1 ^ context->dk[i * 4 + 1];
s2 = t2 ^ context->dk[i * 4 + 2];
s3 = t3 ^ context->dk[i * 4 + 3];
}
//The last round differs slightly from the first rounds
t0 = isbox[s0 & 0xFF];
t0 |= isbox[(s3 >> 8) & 0xFF] << 8;
t0 |= isbox[(s2 >> 16) & 0xFF] << 16;
t0 |= isbox[(s1 >> 24) & 0xFF] << 24;
t1 = isbox[s1 & 0xFF];
t1 |= isbox[(s0 >> 8) & 0xFF] << 8;
t1 |= isbox[(s3 >> 16) & 0xFF] << 16;
t1 |= isbox[(s2 >> 24) & 0xFF] << 24;
t2 = isbox[s2 & 0xFF];
t2 |= isbox[(s1 >> 8) & 0xFF] << 8;
t2 |= isbox[(s0 >> 16) & 0xFF] << 16;
t2 |= isbox[(s3 >> 24) & 0xFF] << 24;
t3 = isbox[s3 & 0xFF];
t3 |= isbox[(s2 >> 8) & 0xFF] << 8;
t3 |= isbox[(s1 >> 16) & 0xFF] << 16;
t3 |= isbox[(s0 >> 24) & 0xFF] << 24;
//Last round key addition
s0 = t0 ^ context->dk[0];
s1 = t1 ^ context->dk[1];
s2 = t2 ^ context->dk[2];
s3 = t3 ^ context->dk[3];
//The final state is then copied to the output
STORE32LE(s0, output + 0);
STORE32LE(s1, output + 4);
STORE32LE(s2, output + 8);
STORE32LE(s3, output + 12);
}
/**
* @brief Release AES context
* @param[in] context Pointer to the AES context
**/
__weak_func void aesDeinit(AesContext *context)
{
//Clear AES context
osMemset(context, 0, sizeof(AesContext));
}
#endif

151
deps/cyclone/cpu_endian.c vendored Normal file
View File

@@ -0,0 +1,151 @@
/**
* @file cpu_endian.c
* @brief Byte order conversion
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Dependencies
#include "cpu_endian.h"
/**
* @brief Reverse the byte order of a 16-bit word
* @param[in] value 16-bit value
* @return 16-bit value with byte order swapped
**/
uint16_t swapInt16(uint16_t value)
{
return SWAPINT16(value);
}
/**
* @brief Reverse the byte order of a 32-bit word
* @param[in] value 32-bit value
* @return 32-bit value with byte order swapped
**/
uint32_t swapInt32(uint32_t value)
{
return SWAPINT32(value);
}
/**
* @brief Reverse the byte order of a 64-bit word
* @param[in] value 64-bit value
* @return 64-bit value with byte order swapped
**/
uint64_t swapInt64(uint64_t value)
{
return SWAPINT64(value);
}
/**
* @brief Reverse bit order in a 4-bit word
* @param[in] value 4-bit value
* @return 4-bit value with bit order reversed
**/
uint8_t reverseInt4(uint8_t value)
{
value = ((value & 0x0C) >> 2) | ((value & 0x03) << 2);
value = ((value & 0x0A) >> 1) | ((value & 0x05) << 1);
return value;
}
/**
* @brief Reverse bit order in a byte
* @param[in] value 8-bit value
* @return 8-bit value with bit order reversed
**/
uint8_t reverseInt8(uint8_t value)
{
value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4);
value = ((value & 0xCC) >> 2) | ((value & 0x33) << 2);
value = ((value & 0xAA) >> 1) | ((value & 0x55) << 1);
return value;
}
/**
* @brief Reverse bit order in a 16-bit word
* @param[in] value 16-bit value
* @return 16-bit value with bit order reversed
**/
uint16_t reverseInt16(uint16_t value)
{
value = ((value & 0xFF00) >> 8) | ((value & 0x00FF) << 8);
value = ((value & 0xF0F0) >> 4) | ((value & 0x0F0F) << 4);
value = ((value & 0xCCCC) >> 2) | ((value & 0x3333) << 2);
value = ((value & 0xAAAA) >> 1) | ((value & 0x5555) << 1);
return value;
}
/**
* @brief Reverse bit order in a 32-bit word
* @param[in] value 32-bit value
* @return 32-bit value with bit order reversed
**/
uint32_t reverseInt32(uint32_t value)
{
value = ((value & 0xFFFF0000UL) >> 16) | ((value & 0x0000FFFFUL) << 16);
value = ((value & 0xFF00FF00UL) >> 8) | ((value & 0x00FF00FFUL) << 8);
value = ((value & 0xF0F0F0F0UL) >> 4) | ((value & 0x0F0F0F0FUL) << 4);
value = ((value & 0xCCCCCCCCUL) >> 2) | ((value & 0x33333333UL) << 2);
value = ((value & 0xAAAAAAAAUL) >> 1) | ((value & 0x55555555UL) << 1);
return value;
}
/**
* @brief Reverse bit order in a 64-bit word
* @param[in] value 64-bit value
* @return 64-bit value with bit order reversed
**/
uint64_t reverseInt64(uint64_t value)
{
value = ((value & 0xFFFFFFFF00000000ULL) >> 32) | ((value & 0x00000000FFFFFFFFULL) << 32);
value = ((value & 0xFFFF0000FFFF0000ULL) >> 16) | ((value & 0x0000FFFF0000FFFFULL) << 16);
value = ((value & 0xFF00FF00FF00FF00ULL) >> 8) | ((value & 0x00FF00FF00FF00FFULL) << 8);
value = ((value & 0xF0F0F0F0F0F0F0F0ULL) >> 4) | ((value & 0x0F0F0F0F0F0F0F0FULL) << 4);
value = ((value & 0xCCCCCCCCCCCCCCCCULL) >> 2) | ((value & 0x3333333333333333ULL) << 2);
value = ((value & 0xAAAAAAAAAAAAAAAAULL) >> 1) | ((value & 0x5555555555555555ULL) << 1);
return value;
}

116
deps/cyclone/ecb.c vendored Normal file
View File

@@ -0,0 +1,116 @@
/**
* @file ecb.c
* @brief Electronic Codebook (ECB) mode
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @section Description
*
* The Electronic Codebook (ECB) mode is a confidentiality mode that features,
* for a given key, the assignment of a fixed ciphertext block to each
* plaintext block, analogous to the assignment of code words in a codebook.
* Refer to SP 800-38A for more details
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL
//Dependencies
#include "core/crypto.h"
#include "cipher_modes/ecb.h"
//Check crypto library configuration
#if (ECB_SUPPORT == ENABLED)
/**
* @brief ECB encryption
* @param[in] cipher Cipher algorithm
* @param[in] context Cipher algorithm context
* @param[in] p Plaintext to be encrypted
* @param[out] c Ciphertext resulting from the encryption
* @param[in] length Total number of data bytes to be encrypted
* @return Error code
**/
__weak_func error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
const uint8_t *p, uint8_t *c, size_t length)
{
//ECB mode operates in a block-by-block fashion
while(length >= cipher->blockSize)
{
//Encrypt current block
cipher->encryptBlock(context, p, c);
//Next block
p += cipher->blockSize;
c += cipher->blockSize;
length -= cipher->blockSize;
}
//The plaintext must be a multiple of the block size
if(length != 0)
return ERROR_INVALID_LENGTH;
//Successful encryption
return NO_ERROR;
}
/**
* @brief ECB decryption
* @param[in] cipher Cipher algorithm
* @param[in] context Cipher algorithm context
* @param[in] c Ciphertext to be decrypted
* @param[out] p Plaintext resulting from the decryption
* @param[in] length Total number of data bytes to be decrypted
* @return Error code
**/
__weak_func error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
const uint8_t *c, uint8_t *p, size_t length)
{
//ECB mode operates in a block-by-block fashion
while(length >= cipher->blockSize)
{
//Decrypt current block
cipher->decryptBlock(context, c, p);
//Next block
c += cipher->blockSize;
p += cipher->blockSize;
length -= cipher->blockSize;
}
//The ciphertext must be a multiple of the block size
if(length != 0)
return ERROR_INVALID_LENGTH;
//Successful encryption
return NO_ERROR;
}
#endif

629
deps/cyclone/gcm.c vendored Normal file
View File

@@ -0,0 +1,629 @@
/**
* @file gcm.c
* @brief Galois/Counter Mode (GCM)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @section Description
*
* The Galois/Counter Mode (GCM) is an authenticated encryption algorithm
* designed to provide both data authenticity (integrity) and confidentiality.
* Refer to SP 800-38D for more details
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL
//Dependencies
#include "core/crypto.h"
#include "aead/gcm.h"
//Check crypto library configuration
#if (GCM_SUPPORT == ENABLED)
//Reduction table
static const uint32_t r[GCM_TABLE_N] =
{
#if (GCM_TABLE_W == 4)
0x00000000, 0x1C200000, 0x38400000, 0x24600000, 0x70800000, 0x6CA00000, 0x48C00000, 0x54E00000,
0xE1000000, 0xFD200000, 0xD9400000, 0xC5600000, 0x91800000, 0x8DA00000, 0xA9C00000, 0xB5E00000
#else
0x00000000, 0x01C20000, 0x03840000, 0x02460000, 0x07080000, 0x06CA0000, 0x048C0000, 0x054E0000,
0x0E100000, 0x0FD20000, 0x0D940000, 0x0C560000, 0x09180000, 0x08DA0000, 0x0A9C0000, 0x0B5E0000,
0x1C200000, 0x1DE20000, 0x1FA40000, 0x1E660000, 0x1B280000, 0x1AEA0000, 0x18AC0000, 0x196E0000,
0x12300000, 0x13F20000, 0x11B40000, 0x10760000, 0x15380000, 0x14FA0000, 0x16BC0000, 0x177E0000,
0x38400000, 0x39820000, 0x3BC40000, 0x3A060000, 0x3F480000, 0x3E8A0000, 0x3CCC0000, 0x3D0E0000,
0x36500000, 0x37920000, 0x35D40000, 0x34160000, 0x31580000, 0x309A0000, 0x32DC0000, 0x331E0000,
0x24600000, 0x25A20000, 0x27E40000, 0x26260000, 0x23680000, 0x22AA0000, 0x20EC0000, 0x212E0000,
0x2A700000, 0x2BB20000, 0x29F40000, 0x28360000, 0x2D780000, 0x2CBA0000, 0x2EFC0000, 0x2F3E0000,
0x70800000, 0x71420000, 0x73040000, 0x72C60000, 0x77880000, 0x764A0000, 0x740C0000, 0x75CE0000,
0x7E900000, 0x7F520000, 0x7D140000, 0x7CD60000, 0x79980000, 0x785A0000, 0x7A1C0000, 0x7BDE0000,
0x6CA00000, 0x6D620000, 0x6F240000, 0x6EE60000, 0x6BA80000, 0x6A6A0000, 0x682C0000, 0x69EE0000,
0x62B00000, 0x63720000, 0x61340000, 0x60F60000, 0x65B80000, 0x647A0000, 0x663C0000, 0x67FE0000,
0x48C00000, 0x49020000, 0x4B440000, 0x4A860000, 0x4FC80000, 0x4E0A0000, 0x4C4C0000, 0x4D8E0000,
0x46D00000, 0x47120000, 0x45540000, 0x44960000, 0x41D80000, 0x401A0000, 0x425C0000, 0x439E0000,
0x54E00000, 0x55220000, 0x57640000, 0x56A60000, 0x53E80000, 0x522A0000, 0x506C0000, 0x51AE0000,
0x5AF00000, 0x5B320000, 0x59740000, 0x58B60000, 0x5DF80000, 0x5C3A0000, 0x5E7C0000, 0x5FBE0000,
0xE1000000, 0xE0C20000, 0xE2840000, 0xE3460000, 0xE6080000, 0xE7CA0000, 0xE58C0000, 0xE44E0000,
0xEF100000, 0xEED20000, 0xEC940000, 0xED560000, 0xE8180000, 0xE9DA0000, 0xEB9C0000, 0xEA5E0000,
0xFD200000, 0xFCE20000, 0xFEA40000, 0xFF660000, 0xFA280000, 0xFBEA0000, 0xF9AC0000, 0xF86E0000,
0xF3300000, 0xF2F20000, 0xF0B40000, 0xF1760000, 0xF4380000, 0xF5FA0000, 0xF7BC0000, 0xF67E0000,
0xD9400000, 0xD8820000, 0xDAC40000, 0xDB060000, 0xDE480000, 0xDF8A0000, 0xDDCC0000, 0xDC0E0000,
0xD7500000, 0xD6920000, 0xD4D40000, 0xD5160000, 0xD0580000, 0xD19A0000, 0xD3DC0000, 0xD21E0000,
0xC5600000, 0xC4A20000, 0xC6E40000, 0xC7260000, 0xC2680000, 0xC3AA0000, 0xC1EC0000, 0xC02E0000,
0xCB700000, 0xCAB20000, 0xC8F40000, 0xC9360000, 0xCC780000, 0xCDBA0000, 0xCFFC0000, 0xCE3E0000,
0x91800000, 0x90420000, 0x92040000, 0x93C60000, 0x96880000, 0x974A0000, 0x950C0000, 0x94CE0000,
0x9F900000, 0x9E520000, 0x9C140000, 0x9DD60000, 0x98980000, 0x995A0000, 0x9B1C0000, 0x9ADE0000,
0x8DA00000, 0x8C620000, 0x8E240000, 0x8FE60000, 0x8AA80000, 0x8B6A0000, 0x892C0000, 0x88EE0000,
0x83B00000, 0x82720000, 0x80340000, 0x81F60000, 0x84B80000, 0x857A0000, 0x873C0000, 0x86FE0000,
0xA9C00000, 0xA8020000, 0xAA440000, 0xAB860000, 0xAEC80000, 0xAF0A0000, 0xAD4C0000, 0xAC8E0000,
0xA7D00000, 0xA6120000, 0xA4540000, 0xA5960000, 0xA0D80000, 0xA11A0000, 0xA35C0000, 0xA29E0000,
0xB5E00000, 0xB4220000, 0xB6640000, 0xB7A60000, 0xB2E80000, 0xB32A0000, 0xB16C0000, 0xB0AE0000,
0xBBF00000, 0xBA320000, 0xB8740000, 0xB9B60000, 0xBCF80000, 0xBD3A0000, 0xBF7C0000, 0xBEBE0000
#endif
};
/**
* @brief Initialize GCM context
* @param[in] context Pointer to the GCM context
* @param[in] cipherAlgo Cipher algorithm
* @param[in] cipherContext Pointer to the cipher algorithm context
* @return Error code
**/
__weak_func error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo,
void *cipherContext)
{
uint_t i;
uint_t j;
uint32_t c;
uint32_t h[4];
//Check parameters
if(context == NULL || cipherAlgo == NULL || cipherContext == NULL)
return ERROR_INVALID_PARAMETER;
//GCM supports only symmetric block ciphers whose block size is 128 bits
if(cipherAlgo->type != CIPHER_ALGO_TYPE_BLOCK || cipherAlgo->blockSize != 16)
return ERROR_INVALID_PARAMETER;
//Save cipher algorithm context
context->cipherAlgo = cipherAlgo;
context->cipherContext = cipherContext;
//Let H = 0
h[0] = 0;
h[1] = 0;
h[2] = 0;
h[3] = 0;
//Generate the hash subkey H
context->cipherAlgo->encryptBlock(context->cipherContext, (uint8_t *) h,
(uint8_t *) h);
//Pre-compute M(0) = H * 0
j = GCM_REVERSE_BITS(0);
context->m[j][0] = 0;
context->m[j][1] = 0;
context->m[j][2] = 0;
context->m[j][3] = 0;
//Pre-compute M(1) = H * 1
j = GCM_REVERSE_BITS(1);
context->m[j][0] = betoh32(h[3]);
context->m[j][1] = betoh32(h[2]);
context->m[j][2] = betoh32(h[1]);
context->m[j][3] = betoh32(h[0]);
//Pre-compute all multiples of H (Shoup's method)
for(i = 2; i < GCM_TABLE_N; i++)
{
//Odd value?
if((i & 1) != 0)
{
//Compute M(i) = M(i - 1) + H
j = GCM_REVERSE_BITS(i - 1);
h[0] = context->m[j][0];
h[1] = context->m[j][1];
h[2] = context->m[j][2];
h[3] = context->m[j][3];
//An addition in GF(2^128) is identical to a bitwise exclusive-OR
//operation
j = GCM_REVERSE_BITS(1);
h[0] ^= context->m[j][0];
h[1] ^= context->m[j][1];
h[2] ^= context->m[j][2];
h[3] ^= context->m[j][3];
}
else
{
//Compute M(i) = M(i / 2) * x
j = GCM_REVERSE_BITS(i / 2);
h[0] = context->m[j][0];
h[1] = context->m[j][1];
h[2] = context->m[j][2];
h[3] = context->m[j][3];
//The multiplication of a polynomial by x in GF(2^128) corresponds
//to a shift of indices
c = h[0] & 0x01;
h[0] = (h[0] >> 1) | (h[1] << 31);
h[1] = (h[1] >> 1) | (h[2] << 31);
h[2] = (h[2] >> 1) | (h[3] << 31);
h[3] >>= 1;
//If the highest term of the result is equal to one, then perform
//reduction
h[3] ^= r[GCM_REVERSE_BITS(1)] & ~(c - 1);
}
//Save M(i)
j = GCM_REVERSE_BITS(i);
context->m[j][0] = h[0];
context->m[j][1] = h[1];
context->m[j][2] = h[2];
context->m[j][3] = h[3];
}
//Successful initialization
return NO_ERROR;
}
/**
* @brief Authenticated encryption using GCM
* @param[in] context Pointer to the GCM context
* @param[in] iv Initialization vector
* @param[in] ivLen Length of the initialization vector
* @param[in] a Additional authenticated data
* @param[in] aLen Length of the additional data
* @param[in] p Plaintext to be encrypted
* @param[out] c Ciphertext resulting from the encryption
* @param[in] length Total number of data bytes to be encrypted
* @param[out] t Authentication tag
* @param[in] tLen Length of the authentication tag
* @return Error code
**/
__weak_func error_t gcmEncrypt(GcmContext *context, const uint8_t *iv,
size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p,
uint8_t *c, size_t length, uint8_t *t, size_t tLen)
{
size_t k;
size_t n;
uint8_t b[16];
uint8_t j[16];
uint8_t s[16];
//Make sure the GCM context is valid
if(context == NULL)
return ERROR_INVALID_PARAMETER;
//The length of the IV shall meet SP 800-38D requirements
if(ivLen < 1)
return ERROR_INVALID_LENGTH;
//Check the length of the authentication tag
if(tLen < 4 || tLen > 16)
return ERROR_INVALID_LENGTH;
//Check whether the length of the IV is 96 bits
if(ivLen == 12)
{
//When the length of the IV is 96 bits, the padding string is appended
//to the IV to form the pre-counter block
osMemcpy(j, iv, 12);
STORE32BE(1, j + 12);
}
else
{
//Initialize GHASH calculation
osMemset(j, 0, 16);
//Length of the IV
n = ivLen;
//Process the initialization vector
while(n > 0)
{
//The IV is processed in a block-by-block fashion
k = MIN(n, 16);
//Apply GHASH function
gcmXorBlock(j, j, iv, k);
gcmMul(context, j);
//Next block
iv += k;
n -= k;
}
//The string is appended with 64 additional 0 bits, followed by the
//64-bit representation of the length of the IV
osMemset(b, 0, 8);
STORE64BE(ivLen * 8, b + 8);
//The GHASH function is applied to the resulting string to form the
//pre-counter block
gcmXorBlock(j, j, b, 16);
gcmMul(context, j);
}
//Compute MSB(CIPH(J(0)))
context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
osMemcpy(t, b, tLen);
//Initialize GHASH calculation
osMemset(s, 0, 16);
//Length of the AAD
n = aLen;
//Process AAD
while(n > 0)
{
//Additional data are processed in a block-by-block fashion
k = MIN(n, 16);
//Apply GHASH function
gcmXorBlock(s, s, a, k);
gcmMul(context, s);
//Next block
a += k;
n -= k;
}
//Length of the plaintext
n = length;
//Process plaintext
while(n > 0)
{
//The encryption operates in a block-by-block fashion
k = MIN(n, 16);
//Increment counter
gcmIncCounter(j);
//Encrypt plaintext
context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
gcmXorBlock(c, p, b, k);
//Apply GHASH function
gcmXorBlock(s, s, c, k);
gcmMul(context, s);
//Next block
p += k;
c += k;
n -= k;
}
//Append the 64-bit representation of the length of the AAD and the
//ciphertext
STORE64BE(aLen * 8, b);
STORE64BE(length * 8, b + 8);
//The GHASH function is applied to the result to produce a single output
//block S
gcmXorBlock(s, s, b, 16);
gcmMul(context, s);
//Let T = MSB(GCTR(J(0), S)
gcmXorBlock(t, t, s, tLen);
//Successful encryption
return NO_ERROR;
}
/**
* @brief Authenticated decryption using GCM
* @param[in] context Pointer to the GCM context
* @param[in] iv Initialization vector
* @param[in] ivLen Length of the initialization vector
* @param[in] a Additional authenticated data
* @param[in] aLen Length of the additional data
* @param[in] c Ciphertext to be decrypted
* @param[out] p Plaintext resulting from the decryption
* @param[in] length Total number of data bytes to be decrypted
* @param[in] t Authentication tag
* @param[in] tLen Length of the authentication tag
* @return Error code
**/
__weak_func error_t gcmDecrypt(GcmContext *context, const uint8_t *iv,
size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c,
uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
{
uint8_t mask;
size_t k;
size_t n;
uint8_t b[16];
uint8_t j[16];
uint8_t r[16];
uint8_t s[16];
//Make sure the GCM context is valid
if(context == NULL)
return ERROR_INVALID_PARAMETER;
//The length of the IV shall meet SP 800-38D requirements
if(ivLen < 1)
return ERROR_INVALID_LENGTH;
//Check the length of the authentication tag
if(tLen < 4 || tLen > 16)
return ERROR_INVALID_LENGTH;
//Check whether the length of the IV is 96 bits
if(ivLen == 12)
{
//When the length of the IV is 96 bits, the padding string is appended
//to the IV to form the pre-counter block
osMemcpy(j, iv, 12);
STORE32BE(1, j + 12);
}
else
{
//Initialize GHASH calculation
osMemset(j, 0, 16);
//Length of the IV
n = ivLen;
//Process the initialization vector
while(n > 0)
{
//The IV is processed in a block-by-block fashion
k = MIN(n, 16);
//Apply GHASH function
gcmXorBlock(j, j, iv, k);
gcmMul(context, j);
//Next block
iv += k;
n -= k;
}
//The string is appended with 64 additional 0 bits, followed by the
//64-bit representation of the length of the IV
osMemset(b, 0, 8);
STORE64BE(ivLen * 8, b + 8);
//The GHASH function is applied to the resulting string to form the
//pre-counter block
gcmXorBlock(j, j, b, 16);
gcmMul(context, j);
}
//Compute MSB(CIPH(J(0)))
context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
osMemcpy(r, b, tLen);
//Initialize GHASH calculation
osMemset(s, 0, 16);
//Length of the AAD
n = aLen;
//Process AAD
while(n > 0)
{
//Additional data are processed in a block-by-block fashion
k = MIN(n, 16);
//Apply GHASH function
gcmXorBlock(s, s, a, k);
gcmMul(context, s);
//Next block
a += k;
n -= k;
}
//Length of the ciphertext
n = length;
//Process ciphertext
while(n > 0)
{
//The decryption operates in a block-by-block fashion
k = MIN(n, 16);
//Apply GHASH function
gcmXorBlock(s, s, c, k);
gcmMul(context, s);
//Increment counter
gcmIncCounter(j);
//Decrypt ciphertext
context->cipherAlgo->encryptBlock(context->cipherContext, j, b);
gcmXorBlock(p, c, b, k);
//Next block
c += k;
p += k;
n -= k;
}
//Append the 64-bit representation of the length of the AAD and the
//ciphertext
STORE64BE(aLen * 8, b);
STORE64BE(length * 8, b + 8);
//The GHASH function is applied to the result to produce a single output
//block S
gcmXorBlock(s, s, b, 16);
gcmMul(context, s);
//Let R = MSB(GCTR(J(0), S))
gcmXorBlock(r, r, s, tLen);
//The calculated tag is bitwise compared to the received tag. The message
//is authenticated if and only if the tags match
for(mask = 0, n = 0; n < tLen; n++)
{
mask |= r[n] ^ t[n];
}
//Return status code
return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
}
/**
* @brief Multiplication operation in GF(2^128)
* @param[in] context Pointer to the GCM context
* @param[in, out] x 16-byte block to be multiplied by H
**/
__weak_func void gcmMul(GcmContext *context, uint8_t *x)
{
int_t i;
uint8_t b;
uint8_t c;
uint32_t z[4];
//Let Z = 0
z[0] = 0;
z[1] = 0;
z[2] = 0;
z[3] = 0;
//Fast table-driven implementation (Shoup's method)
for(i = 15; i >= 0; i--)
{
#if (GCM_TABLE_W == 4)
//Get the lower nibble
b = x[i] & 0x0F;
//Multiply 4 bits at a time
c = z[0] & 0x0F;
z[0] = (z[0] >> 4) | (z[1] << 28);
z[1] = (z[1] >> 4) | (z[2] << 28);
z[2] = (z[2] >> 4) | (z[3] << 28);
z[3] >>= 4;
z[0] ^= context->m[b][0];
z[1] ^= context->m[b][1];
z[2] ^= context->m[b][2];
z[3] ^= context->m[b][3];
//Perform reduction
z[3] ^= r[c];
//Get the upper nibble
b = (x[i] >> 4) & 0x0F;
//Multiply 4 bits at a time
c = z[0] & 0x0F;
z[0] = (z[0] >> 4) | (z[1] << 28);
z[1] = (z[1] >> 4) | (z[2] << 28);
z[2] = (z[2] >> 4) | (z[3] << 28);
z[3] >>= 4;
z[0] ^= context->m[b][0];
z[1] ^= context->m[b][1];
z[2] ^= context->m[b][2];
z[3] ^= context->m[b][3];
//Perform reduction
z[3] ^= r[c];
#else
//Get current byte
b = x[i];
//Multiply 8 bits at a time
c = z[0] & 0xFF;
z[0] = (z[0] >> 8) | (z[1] << 24);
z[1] = (z[1] >> 8) | (z[2] << 24);
z[2] = (z[2] >> 8) | (z[3] << 24);
z[3] >>= 8;
z[0] ^= context->m[b][0];
z[1] ^= context->m[b][1];
z[2] ^= context->m[b][2];
z[3] ^= context->m[b][3];
//Perform reduction
z[3] ^= r[c];
#endif
}
//Save the result
STORE32BE(z[3], x);
STORE32BE(z[2], x + 4);
STORE32BE(z[1], x + 8);
STORE32BE(z[0], x + 12);
}
/**
* @brief XOR operation
* @param[out] x Block resulting from the XOR operation
* @param[in] a First block
* @param[in] b Second block
* @param[in] n Size of the block
**/
void gcmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
{
size_t i;
//Perform XOR operation
for(i = 0; i < n; i++)
{
x[i] = a[i] ^ b[i];
}
}
/**
* @brief Increment counter block
* @param[in,out] ctr Pointer to the counter block
**/
void gcmIncCounter(uint8_t *ctr)
{
uint16_t temp;
//The function increments the right-most 32 bits of the block. The remaining
//left-most 96 bits remain unchanged
temp = ctr[15] + 1;
ctr[15] = temp & 0xFF;
temp = (temp >> 8) + ctr[14];
ctr[14] = temp & 0xFF;
temp = (temp >> 8) + ctr[13];
ctr[13] = temp & 0xFF;
temp = (temp >> 8) + ctr[12];
ctr[12] = temp & 0xFF;
}
#endif

226
deps/cyclone/hkdf.c vendored Normal file
View File

@@ -0,0 +1,226 @@
/**
* @file hkdf.c
* @brief HKDF (HMAC-based Key Derivation Function)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @section Description
*
* HKDF is a simple HMAC-based key derivation function which can be used as a
* building block in various protocols and applications. Refer to RFC 5869 for
* more details
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL
//Dependencies
#include "core/crypto.h"
#include "kdf/hkdf.h"
#include "mac/hmac.h"
//Check crypto library configuration
#if (HKDF_SUPPORT == ENABLED)
/**
* @brief HKDF key derivation function
* @param[in] hash Underlying hash function
* @param[in] ikm input keying material
* @param[in] ikmLen Length in the input keying material
* @param[in] salt Optional salt value (a non-secret random value)
* @param[in] saltLen Length of the salt
* @param[in] info Optional application specific information
* @param[in] infoLen Length of the application specific information
* @param[out] okm output keying material
* @param[in] okmLen Length of the output keying material
* @return Error code
**/
error_t hkdf(const HashAlgo *hash, const uint8_t *ikm, size_t ikmLen,
const uint8_t *salt, size_t saltLen, const uint8_t *info, size_t infoLen,
uint8_t *okm, size_t okmLen)
{
error_t error;
uint8_t prk[MAX_HASH_DIGEST_SIZE];
//Perform HKDF extract step
error = hkdfExtract(hash, ikm, ikmLen, salt, saltLen, prk);
//Check status code
if(!error)
{
//Perform HKDF expand step
error = hkdfExpand(hash, prk, hash->digestSize, info, infoLen,
okm, okmLen);
}
//Return status code
return error;
}
/**
* @brief HKDF extract step
* @param[in] hash Underlying hash function
* @param[in] ikm input keying material
* @param[in] ikmLen Length in the input keying material
* @param[in] salt Optional salt value (a non-secret random value)
* @param[in] saltLen Length of the salt
* @param[out] prk Pseudorandom key
* @return Error code
**/
error_t hkdfExtract(const HashAlgo *hash, const uint8_t *ikm, size_t ikmLen,
const uint8_t *salt, size_t saltLen, uint8_t *prk)
{
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
HmacContext *hmacContext;
#else
HmacContext hmacContext[1];
#endif
//Check parameters
if(hash == NULL || ikm == NULL || prk == NULL)
return ERROR_INVALID_PARAMETER;
//The salt parameter is optional
if(salt == NULL && saltLen != 0)
return ERROR_INVALID_PARAMETER;
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Allocate a memory buffer to hold the HMAC context
hmacContext = cryptoAllocMem(sizeof(HmacContext));
//Failed to allocate memory?
if(hmacContext == NULL)
return ERROR_OUT_OF_MEMORY;
#endif
//The salt parameter is optional
if(salt == NULL)
{
//If the salt is not provided, it is set to a string of HashLen zeros
osMemset(hmacContext->digest, 0, hash->digestSize);
salt = hmacContext->digest;
saltLen = hash->digestSize;
}
//Compute PRK = HMAC-Hash(salt, IKM)
hmacInit(hmacContext, hash, salt, saltLen);
hmacUpdate(hmacContext, ikm, ikmLen);
hmacFinal(hmacContext, prk);
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Free previously allocated memory
cryptoFreeMem(hmacContext);
#endif
//Successful processing
return NO_ERROR;
}
/**
* @brief HKDF expand step
* @param[in] hash Underlying hash function
* @param[in] prk Pseudorandom key
* @param[in] prkLen Length of the pseudorandom key
* @param[in] info Optional application specific information
* @param[in] infoLen Length of the application specific information
* @param[out] okm output keying material
* @param[in] okmLen Length of the output keying material
* @return Error code
**/
error_t hkdfExpand(const HashAlgo *hash, const uint8_t *prk, size_t prkLen,
const uint8_t *info, size_t infoLen, uint8_t *okm, size_t okmLen)
{
uint8_t i;
size_t tLen;
uint8_t t[MAX_HASH_DIGEST_SIZE];
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
HmacContext *hmacContext;
#else
HmacContext hmacContext[1];
#endif
//Check parameters
if(hash == NULL || prk == NULL || okm == NULL)
return ERROR_INVALID_PARAMETER;
//The application specific information parameter is optional
if(info == NULL && infoLen != 0)
return ERROR_INVALID_PARAMETER;
//PRK must be at least HashLen octets
if(prkLen < hash->digestSize)
return ERROR_INVALID_LENGTH;
//Check the length of the output keying material
if(okmLen > (255 * hash->digestSize))
return ERROR_INVALID_LENGTH;
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Allocate a memory buffer to hold the HMAC context
hmacContext = cryptoAllocMem(sizeof(HmacContext));
//Failed to allocate memory?
if(hmacContext == NULL)
return ERROR_OUT_OF_MEMORY;
#endif
//T(0) is an empty string (zero length)
tLen = 0;
//Iterate as many times as required
for(i = 1; okmLen > 0; i++)
{
//Compute T(i) = HMAC-Hash(PRK, T(i-1) | info | i)
hmacInit(hmacContext, hash, prk, prkLen);
hmacUpdate(hmacContext, t, tLen);
hmacUpdate(hmacContext, info, infoLen);
hmacUpdate(hmacContext, &i, sizeof(i));
hmacFinal(hmacContext, t);
//Number of octets in the current block
tLen = MIN(okmLen, hash->digestSize);
//Save the resulting block
osMemcpy(okm, t, tLen);
//Point to the next block
okm += tLen;
okmLen -= tLen;
}
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Free previously allocated memory
cryptoFreeMem(hmacContext);
#endif
//Successful processing
return NO_ERROR;
}
#endif

303
deps/cyclone/hmac.c vendored Normal file
View File

@@ -0,0 +1,303 @@
/**
* @file hmac.c
* @brief HMAC (Keyed-Hashing for Message Authentication)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @section Description
*
* HMAC is a mechanism for message authentication using cryptographic hash
* functions. HMAC can be used with any iterative cryptographic hash
* function (MD5, SHA-1 or SHA-256) in combination with a secret shared
* key. Refer to RFC 2104 for more details
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL
//Dependencies
#include "core/crypto.h"
#include "mac/hmac.h"
//Check crypto library configuration
#if (HMAC_SUPPORT == ENABLED)
//HMAC with MD5 OID (1.3.6.1.5.5.8.1.1)
const uint8_t HMAC_WITH_MD5_OID[8] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x01};
//HMAC with Tiger OID (1.3.6.1.5.5.8.1.3)
const uint8_t HMAC_WITH_TIGER_OID[8] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x03};
//HMAC with RIPEMD-160 OID (1.3.6.1.5.5.8.1.4)
const uint8_t HMAC_WITH_RIPEMD160_OID[8] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x04};
//HMAC with SHA-1 OID (1.2.840.113549.2.7)
const uint8_t HMAC_WITH_SHA1_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07};
//HMAC with SHA-224 OID (1.2.840.113549.2.8)
const uint8_t HMAC_WITH_SHA224_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x08};
//HMAC with SHA-256 OID (1.2.840.113549.2.9)
const uint8_t HMAC_WITH_SHA256_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x09};
//HMAC with SHA-384 OID (1.2.840.113549.2.10)
const uint8_t HMAC_WITH_SHA384_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0A};
//HMAC with SHA-512 OID (1.2.840.113549.2.11)
const uint8_t HMAC_WITH_SHA512_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0B};
//HMAC with SHA-512/224 OID (1.2.840.113549.2.12)
const uint8_t HMAC_WITH_SHA512_224_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0C};
//HMAC with SHA-512/256 OID (1.2.840.113549.2.13)
const uint8_t HMAC_WITH_SHA512_256_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0D};
//HMAC with SHA-3-224 OID (2.16.840.1.101.3.4.2.13)
const uint8_t HMAC_WITH_SHA3_224_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0D};
//HMAC with SHA-3-256 OID (2.16.840.1.101.3.4.2.14)
const uint8_t HMAC_WITH_SHA3_256_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0E};
//HMAC with SHA-3-384 OID (2.16.840.1.101.3.4.2.15)
const uint8_t HMAC_WITH_SHA3_384_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0F};
//HMAC with SHA-3-512 OID (2.16.840.1.101.3.4.2.16)
const uint8_t HMAC_WITH_SHA3_512_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x10};
//HMAC with SM3 OID (1.2.156.10197.1.401.3.1)
const uint8_t HMAC_WITH_SM3_OID[10] = {0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x82, 0x91, 0x03, 0x01};
/**
* @brief Compute HMAC using the specified hash function
* @param[in] hash Hash algorithm used to compute HMAC
* @param[in] key Key to use in the hash algorithm
* @param[in] keyLen Length of the key
* @param[in] data The input data for which to compute the hash code
* @param[in] dataLen Length of the input data
* @param[out] digest The computed HMAC value
* @return Error code
**/
__weak_func error_t hmacCompute(const HashAlgo *hash, const void *key, size_t keyLen,
const void *data, size_t dataLen, uint8_t *digest)
{
error_t error;
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
HmacContext *context;
#else
HmacContext context[1];
#endif
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Allocate a memory buffer to hold the HMAC context
context = cryptoAllocMem(sizeof(HmacContext));
//Failed to allocate memory?
if(context == NULL)
return ERROR_OUT_OF_MEMORY;
#endif
//Initialize the HMAC context
error = hmacInit(context, hash, key, keyLen);
//Check status code
if(!error)
{
//Digest the message
hmacUpdate(context, data, dataLen);
//Finalize the HMAC computation
hmacFinal(context, digest);
}
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Free previously allocated memory
cryptoFreeMem(context);
#endif
//Return status code
return error;
}
/**
* @brief Initialize HMAC calculation
* @param[in] context Pointer to the HMAC context to initialize
* @param[in] hash Hash algorithm used to compute HMAC
* @param[in] key Key to use in the hash algorithm
* @param[in] keyLen Length of the key
* @return Error code
**/
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash,
const void *key, size_t keyLen)
{
uint_t i;
//Check parameters
if(context == NULL || hash == NULL)
return ERROR_INVALID_PARAMETER;
//Make sure the supplied key is valid
if(key == NULL && keyLen != 0)
return ERROR_INVALID_PARAMETER;
//Hash algorithm used to compute HMAC
context->hash = hash;
//The key is longer than the block size?
if(keyLen > hash->blockSize)
{
//Initialize the hash function context
hash->init(&context->hashContext);
//Digest the original key
hash->update(&context->hashContext, key, keyLen);
//Finalize the message digest computation
hash->final(&context->hashContext, context->key);
//Key is padded to the right with extra zeros
osMemset(context->key + hash->digestSize, 0,
hash->blockSize - hash->digestSize);
}
else
{
//Copy the key
osMemcpy(context->key, key, keyLen);
//Key is padded to the right with extra zeros
osMemset(context->key + keyLen, 0, hash->blockSize - keyLen);
}
//XOR the resulting key with ipad
for(i = 0; i < hash->blockSize; i++)
{
context->key[i] ^= HMAC_IPAD;
}
//Initialize context for the first pass
hash->init(&context->hashContext);
//Start with the inner pad
hash->update(&context->hashContext, context->key, hash->blockSize);
//Successful initialization
return NO_ERROR;
}
/**
* @brief Update the HMAC context with a portion of the message being hashed
* @param[in] context Pointer to the HMAC context
* @param[in] data Pointer to the buffer being hashed
* @param[in] length Length of the buffer
**/
__weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
{
const HashAlgo *hash;
//Hash algorithm used to compute HMAC
hash = context->hash;
//Digest the message (first pass)
hash->update(&context->hashContext, data, length);
}
/**
* @brief Finish the HMAC calculation
* @param[in] context Pointer to the HMAC context
* @param[out] digest Calculated HMAC value (optional parameter)
**/
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
{
uint_t i;
const HashAlgo *hash;
//Hash algorithm used to compute HMAC
hash = context->hash;
//Finish the first pass
hash->final(&context->hashContext, context->digest);
//XOR the original key with opad
for(i = 0; i < hash->blockSize; i++)
{
context->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
}
//Initialize context for the second pass
hash->init(&context->hashContext);
//Start with outer pad
hash->update(&context->hashContext, context->key, hash->blockSize);
//Then digest the result of the first hash
hash->update(&context->hashContext, context->digest, hash->digestSize);
//Finish the second pass
hash->final(&context->hashContext, context->digest);
//Copy the resulting HMAC value
if(digest != NULL)
{
osMemcpy(digest, context->digest, hash->digestSize);
}
}
/**
* @brief Release HMAC context
* @param[in] context Pointer to the HMAC context
**/
void hmacDeinit(HmacContext *context)
{
//Make sure the HMAC context is valid
if(context != NULL)
{
//Clear HMAC context
osMemset(context, 0, sizeof(HmacContext));
}
}
/**
* @brief Finish the HMAC calculation (no padding added)
* @param[in] context Pointer to the HMAC context
* @param[out] digest Calculated HMAC value (optional parameter)
**/
void hmacFinalRaw(HmacContext *context, uint8_t *digest)
{
uint_t i;
const HashAlgo *hash;
//Hash algorithm used to compute HMAC
hash = context->hash;
//XOR the original key with opad
for(i = 0; i < hash->blockSize; i++)
{
context->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
}
//Initialize context for the second pass
hash->init(&context->hashContext);
//Start with outer pad
hash->update(&context->hashContext, context->key, hash->blockSize);
//Then digest the result of the first hash
hash->update(&context->hashContext, context->digest, hash->digestSize);
//Finish the second pass
hash->final(&context->hashContext, context->digest);
//Copy the resulting HMAC value
if(digest != NULL)
{
osMemcpy(digest, context->digest, hash->digestSize);
}
}
#endif

92
deps/cyclone/include/aead/gcm.h vendored Normal file
View File

@@ -0,0 +1,92 @@
/**
* @file gcm.h
* @brief Galois/Counter Mode (GCM)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _GCM_H
#define _GCM_H
//Dependencies
#include "core/crypto.h"
//Precalculated table width, in bits
#ifndef GCM_TABLE_W
#define GCM_TABLE_W 4
#elif (GCM_TABLE_W != 4 && GCM_TABLE_W != 8)
#error GCM_TABLE_W parameter is not valid
#endif
//4-bit or 8-bit precalculated table?
#if (GCM_TABLE_W == 4)
#define GCM_TABLE_N 16
#define GCM_REVERSE_BITS(n) reverseInt4(n)
#else
#define GCM_TABLE_N 256
#define GCM_REVERSE_BITS(n) reverseInt8(n)
#endif
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief GCM context
**/
typedef struct
{
const CipherAlgo *cipherAlgo; ///<Cipher algorithm
void *cipherContext; ///<Cipher algorithm context
uint32_t m[GCM_TABLE_N][4]; ///<Precalculated table
} GcmContext;
//GCM related functions
error_t gcmInit(GcmContext *context, const CipherAlgo *cipherAlgo,
void *cipherContext);
error_t gcmEncrypt(GcmContext *context, const uint8_t *iv,
size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *p,
uint8_t *c, size_t length, uint8_t *t, size_t tLen);
error_t gcmDecrypt(GcmContext *context, const uint8_t *iv,
size_t ivLen, const uint8_t *a, size_t aLen, const uint8_t *c,
uint8_t *p, size_t length, const uint8_t *t, size_t tLen);
void gcmMul(GcmContext *context, uint8_t *x);
void gcmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n);
void gcmIncCounter(uint8_t *ctr);
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

103
deps/cyclone/include/cipher/aes.h vendored Normal file
View File

@@ -0,0 +1,103 @@
/**
* @file aes.h
* @brief AES (Advanced Encryption Standard)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _AES_H
#define _AES_H
//Dependencies
#include "core/crypto.h"
//Application specific context
#ifndef AES_PRIVATE_CONTEXT
#define AES_PRIVATE_CONTEXT
#endif
//AES block size
#define AES_BLOCK_SIZE 16
//Common interface for encryption algorithms
#define AES_CIPHER_ALGO (&aesCipherAlgo)
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief AES algorithm context
**/
typedef struct
{
uint_t nr;
uint32_t ek[60];
uint32_t dk[60];
AES_PRIVATE_CONTEXT
} AesContext;
//AES related constants
extern const uint8_t AES128_ECB_OID[9];
extern const uint8_t AES128_CBC_OID[9];
extern const uint8_t AES128_OFB_OID[9];
extern const uint8_t AES128_CFB_OID[9];
extern const uint8_t AES128_GCM_OID[9];
extern const uint8_t AES128_CCM_OID[9];
extern const uint8_t AES192_ECB_OID[9];
extern const uint8_t AES192_CBC_OID[9];
extern const uint8_t AES192_OFB_OID[9];
extern const uint8_t AES192_CFB_OID[9];
extern const uint8_t AES192_GCM_OID[9];
extern const uint8_t AES192_CCM_OID[9];
extern const uint8_t AES256_ECB_OID[9];
extern const uint8_t AES256_CBC_OID[9];
extern const uint8_t AES256_OFB_OID[9];
extern const uint8_t AES256_CFB_OID[9];
extern const uint8_t AES256_GCM_OID[9];
extern const uint8_t AES256_CCM_OID[9];
extern const CipherAlgo aesCipherAlgo;
//AES related functions
error_t aesInit(AesContext *context, const uint8_t *key, size_t keyLen);
void aesEncryptBlock(AesContext *context, const uint8_t *input,
uint8_t *output);
void aesDecryptBlock(AesContext *context, const uint8_t *input,
uint8_t *output);
void aesDeinit(AesContext *context);
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

54
deps/cyclone/include/cipher_modes/ecb.h vendored Normal file
View File

@@ -0,0 +1,54 @@
/**
* @file ecb.h
* @brief Electronic Codebook (ECB) mode
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _ECB_H
#define _ECB_H
//Dependencies
#include "core/crypto.h"
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
//ECB encryption and decryption routines
error_t ecbEncrypt(const CipherAlgo *cipher, void *context,
const uint8_t *p, uint8_t *c, size_t length);
error_t ecbDecrypt(const CipherAlgo *cipher, void *context,
const uint8_t *c, uint8_t *p, size_t length);
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

283
deps/cyclone/include/compiler_port.h vendored Normal file
View File

@@ -0,0 +1,283 @@
/**
* @file compiler_port.h
* @brief Compiler specific definitions
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _COMPILER_PORT_H
#define _COMPILER_PORT_H
//Dependencies
#include "types.h"
//ARM compiler V6?
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include <stdarg.h>
#endif
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
//Types
typedef char char_t;
typedef signed int int_t;
typedef unsigned int uint_t;
#if !defined(R_TYPEDEFS_H) && !defined(USE_CHIBIOS_2)
typedef int bool_t;
#endif
//ARM compiler?
#if defined(__CC_ARM)
#undef PRIu8
#undef PRIu16
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIuSIZE "u"
#define PRIXSIZE "X"
#define PRIuTIME "lu"
//Microchip XC32 compiler?
#elif defined(__XC32)
#if defined(__C32_LEGACY_LIBC__)
#define PRIuSIZE "lu"
#define PRIXSIZE "lX"
#define PRIuTIME "lu"
#else
#define PRIuSIZE "u"
#define PRIXSIZE "X"
#define PRIuTIME "u"
#endif
//NXP MCUXpresso compiler?
#elif defined(__MCUXPRESSO)
#undef PRIu64
#define PRIu64 "llu"
#define PRIuSIZE "u"
#define PRIXSIZE "X"
#define PRIuTIME "lu"
//NXP CodeWarrior compiler?
#elif defined(__CWCC__)
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIu32 "u"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIx32 "x"
#define PRIX8 "X"
#define PRIX16 "X"
#define PRIX32 "X"
#define PRIuSIZE "u"
#define PRIXSIZE "X"
#define PRIuTIME "u"
//Espressif ESP-IDF compiler?
#elif defined(IDF_VER)
#undef PRIu8
#undef PRIu16
#undef PRIx8
#undef PRIx16
#undef PRIX8
#undef PRIX16
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIX8 "X"
#define PRIX16 "X"
#define PRIuSIZE "u"
#define PRIXSIZE "X"
#define PRIuTIME "lu"
//Linux/FreeBSD GCC compiler
#elif defined(__linux__) || defined(__FreeBSD__)
#define PRIuSIZE "zu"
#define PRIXSIZE "zX"
#define PRIuTIME "lu"
//Win32 compiler?
#elif defined(_WIN32)
#define PRIuSIZE "Iu"
#define PRIXSIZE "IX"
#define PRIuTIME "lu"
//GCC compiler (with newlib-nano runtime library)?
#elif defined(__GNUC__) && defined(_NANO_FORMATTED_IO) && (_NANO_FORMATTED_IO != 0)
#undef PRIu8
#undef PRIu16
#undef PRIx8
#undef PRIx16
#undef PRIX8
#undef PRIX16
#define PRIu8 "u"
#define PRIu16 "u"
#define PRIx8 "x"
#define PRIx16 "x"
#define PRIX8 "X"
#define PRIX16 "X"
#define PRIuSIZE "u"
#define PRIXSIZE "X"
#define PRIuTIME "u"
//GCC compiler (with newlib-standard runtime library)?
#else
#define PRIuSIZE "u"
#define PRIXSIZE "X"
#define PRIuTIME "lu"
#endif
//ARM compiler V6?
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
int vsnprintf(char *dest, size_t size, const char *format, va_list ap);
char *strtok_r(char *s, const char *delim, char **last);
//GCC compiler (for PowerPC architecture)?
#elif defined(__GNUC__) && defined(__PPC_EABI__)
typedef uint32_t time_t;
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
char *strtok_r(char *s, const char *delim, char **last);
//GCC compiler?
#elif defined(__GNUC__)
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
char *strtok_r(char *s, const char *delim, char **last);
//Tasking compiler?
#elif defined(__TASKING__)
char *strtok_r(char *s, const char *delim, char **last);
//Microchip XC32 compiler?
#elif defined(__XC32)
#define sprintf _sprintf
int sprintf(char *str, const char *format, ...);
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
char *strtok_r(char *s, const char *delim, char **last);
//NXP CodeWarrior compiler?
#elif defined(__CWCC__)
typedef uint32_t time_t;
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
char *strtok_r(char *s, const char *delim, char **last);
//Renesas CC-RX compiler?
#elif defined(__CCRX__)
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
char *strtok_r(char *s, const char *delim, char **last);
//TI ARM compiler?
#elif defined(__TI_ARM__)
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
char *strtok_r(char *s, const char *delim, char **last);
#endif
//ARM compiler V6?
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#undef __packed_struct
#define __packed_struct struct __attribute__((packed))
#undef __packed_union
#define __packed_union union __attribute__((packed))
//GCC compiler?
#elif defined(__GNUC__)
#undef __packed_struct
#define __packed_struct struct __attribute__((__packed__))
#undef __packed_union
#define __packed_union union __attribute__((__packed__))
//ARM compiler?
#elif defined(__CC_ARM)
#pragma anon_unions
#undef __packed_struct
#define __packed_struct __packed struct
#undef __packed_union
#define __packed_union __packed union
//IAR compiler?
#elif defined(__IAR_SYSTEMS_ICC__)
#undef __packed_struct
#define __packed_struct __packed struct
#undef __packed_union
#define __packed_union __packed union
//Tasking compiler?
#elif defined(__TASKING__)
#undef __packed_struct
#define __packed_struct struct __packed__
#undef __packed_union
#define __packed_union union __packed__
//NXP CodeWarrior compiler?
#elif defined(__CWCC__)
#undef __packed_struct
#define __packed_struct struct
#undef __packed_union
#define __packed_union union
//Renesas CC-RX compiler?
#elif defined(__CCRX__)
#undef __packed_struct
#define __packed_struct struct
#undef __packed_union
#define __packed_union union
//TI ARM compiler?
#elif defined(__TI_ARM__)
#undef __packed_struct
#define __packed_struct struct __attribute__((__packed__))
#undef __packed_union
#define __packed_union union __attribute__((__packed__))
//Win32 compiler?
#elif defined(_WIN32)
#undef interface
#undef __packed_struct
#define __packed_struct struct
#undef __packed_union
#define __packed_union union
#endif
#ifndef __weak_func
//ARM compiler V6?
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#define __weak_func __attribute__((weak))
//GCC compiler?
#elif defined(__GNUC__)
#define __weak_func __attribute__((weak))
//ARM compiler?
#elif defined(__CC_ARM)
#define __weak_func __weak
//IAR compiler?
#elif defined(__IAR_SYSTEMS_ICC__)
#define __weak_func __weak
//Tasking compiler?
#elif defined(__TASKING__)
#define __weak_func __attribute__((weak))
//NXP CodeWarrior compiler?
#elif defined(__CWCC__)
#define __weak_func
//Renesas CC-RX compiler?
#elif defined(__CCRX__)
#define __weak_func
//TI ARM compiler?
#elif defined(__TI_ARM__)
#define __weak_func __attribute__((weak))
//Win32 compiler?
#elif defined(_WIN32)
#define __weak_func
#endif
#endif
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

1119
deps/cyclone/include/core/crypto.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/**
* @file crypto_legacy.h
* @brief Legacy definitions
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _CRYPTO_LEGACY_H
#define _CRYPTO_LEGACY_H
//Deprecated functions
#define mpiReadRaw(r, data, length) mpiImport(r, data, length, MPI_FORMAT_BIG_ENDIAN)
#define mpiWriteRaw(a, data, length) mpiExport(a, data, length, MPI_FORMAT_BIG_ENDIAN)
#ifdef CURVE25519_SUPPORT
#define X25519_SUPPORT CURVE25519_SUPPORT
#endif
#ifdef CURVE448_SUPPORT
#define X448_SUPPORT CURVE448_SUPPORT
#endif
#define ecdsaGenerateKeyPair ecGenerateKeyPair
#define ecdsaGeneratePrivateKey ecGeneratePrivateKey
#define ecdsaGeneratePublicKey ecGeneratePublicKey
#define MAX_HASH_CONTEXT_SIZE sizeof(HashContext)
#define MAX_CIPHER_CONTEXT_SIZE sizeof(CipherContext)
#ifdef SAMD51_CRYPTO_PUKCC_SUPPORT
#define SAMD51_CRYPTO_PKC_SUPPORT SAMD51_CRYPTO_PUKCC_SUPPORT
#endif
#ifdef SAME54_CRYPTO_PUKCC_SUPPORT
#define SAME54_CRYPTO_PKC_SUPPORT SAME54_CRYPTO_PUKCC_SUPPORT
#endif
#define yarrowRelease yarrowDeinit
#define X509CertificateInfo X509CertInfo
#define X509SignatureAlgoId X509SignAlgoId
#define EddsaMessageChunk DataChunk
#endif

481
deps/cyclone/include/cpu_endian.h vendored Normal file
View File

@@ -0,0 +1,481 @@
/**
* @file cpu_endian.h
* @brief Byte order conversion
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _CPU_ENDIAN_H
#define _CPU_ENDIAN_H
//Dependencies
#include "os_port.h"
#include "types.h"
//Undefine conflicting definitions
#ifdef HTONS
#undef HTONS
#endif
#ifdef HTONL
#undef HTONL
#endif
#ifdef HTONLL
#undef HTONLL
#endif
#ifdef htons
#undef htons
#endif
#ifdef htonl
#undef htonl
#endif
#ifdef htonll
#undef htonll
#endif
#ifdef NTOHS
#undef NTOHS
#endif
#ifdef NTOHL
#undef NTOHL
#endif
#ifdef NTOHLL
#undef NTOHLL
#endif
#ifdef ntohs
#undef ntohs
#endif
#ifdef ntohl
#undef ntohl
#endif
#ifdef ntohll
#undef ntohll
#endif
#ifdef HTOLE16
#undef HTOLE16
#endif
#ifdef HTOLE32
#undef HTOLE32
#endif
#ifdef HTOLE64
#undef HTOLE64
#endif
#ifdef htole16
#undef htole16
#endif
#ifdef htole32
#undef htole32
#endif
#ifdef htole64
#undef htole64
#endif
#ifdef LETOH16
#undef LETOH16
#endif
#ifdef LETOH32
#undef LETOH32
#endif
#ifdef LETOH64
#undef LETOH64
#endif
#ifdef letoh16
#undef letoh16
#endif
#ifdef letoh32
#undef letoh32
#endif
#ifdef letoh64
#undef letoh64
#endif
#ifdef HTOBE16
#undef HTOBE16
#endif
#ifdef HTOBE32
#undef HTOBE32
#endif
#ifdef HTOBE64
#undef HTOBE64
#endif
#ifdef htobe16
#undef htobe16
#endif
#ifdef htobe32
#undef htobe32
#endif
#ifdef htobe64
#undef htobe64
#endif
#ifdef BETOH16
#undef BETOH16
#endif
#ifdef BETOH32
#undef BETOH32
#endif
#ifdef BETOH64
#undef BETOH64
#endif
#ifdef betoh16
#undef betoh16
#endif
#ifdef betoh32
#undef betoh32
#endif
#ifdef betoh64
#undef betoh64
#endif
//Load unaligned 16-bit integer (little-endian encoding)
#define LOAD16LE(p) ( \
((uint16_t)(((uint8_t *)(p))[0]) << 0) | \
((uint16_t)(((uint8_t *)(p))[1]) << 8))
//Load unaligned 16-bit integer (big-endian encoding)
#define LOAD16BE(p) ( \
((uint16_t)(((uint8_t *)(p))[0]) << 8) | \
((uint16_t)(((uint8_t *)(p))[1]) << 0))
//Load unaligned 24-bit integer (little-endian encoding)
#define LOAD24LE(p) ( \
((uint32_t)(((uint8_t *)(p))[0]) << 0)| \
((uint32_t)(((uint8_t *)(p))[1]) << 8) | \
((uint32_t)(((uint8_t *)(p))[2]) << 16))
//Load unaligned 24-bit integer (big-endian encoding)
#define LOAD24BE(p) ( \
((uint32_t)(((uint8_t *)(p))[0]) << 16) | \
((uint32_t)(((uint8_t *)(p))[1]) << 8) | \
((uint32_t)(((uint8_t *)(p))[2]) << 0))
//Load unaligned 32-bit integer (little-endian encoding)
#define LOAD32LE(p) ( \
((uint32_t)(((uint8_t *)(p))[0]) << 0) | \
((uint32_t)(((uint8_t *)(p))[1]) << 8) | \
((uint32_t)(((uint8_t *)(p))[2]) << 16) | \
((uint32_t)(((uint8_t *)(p))[3]) << 24))
//Load unaligned 32-bit integer (big-endian encoding)
#define LOAD32BE(p) ( \
((uint32_t)(((uint8_t *)(p))[0]) << 24) | \
((uint32_t)(((uint8_t *)(p))[1]) << 16) | \
((uint32_t)(((uint8_t *)(p))[2]) << 8) | \
((uint32_t)(((uint8_t *)(p))[3]) << 0))
//Load unaligned 48-bit integer (little-endian encoding)
#define LOAD48LE(p) ( \
((uint64_t)(((uint8_t *)(p))[0]) << 0) | \
((uint64_t)(((uint8_t *)(p))[1]) << 8) | \
((uint64_t)(((uint8_t *)(p))[2]) << 16) | \
((uint64_t)(((uint8_t *)(p))[3]) << 24) | \
((uint64_t)(((uint8_t *)(p))[4]) << 32) | \
((uint64_t)(((uint8_t *)(p))[5]) << 40)
//Load unaligned 48-bit integer (big-endian encoding)
#define LOAD48BE(p) ( \
((uint64_t)(((uint8_t *)(p))[0]) << 40) | \
((uint64_t)(((uint8_t *)(p))[1]) << 32) | \
((uint64_t)(((uint8_t *)(p))[2]) << 24) | \
((uint64_t)(((uint8_t *)(p))[3]) << 16) | \
((uint64_t)(((uint8_t *)(p))[4]) << 8) | \
((uint64_t)(((uint8_t *)(p))[5]) << 0))
//Load unaligned 64-bit integer (little-endian encoding)
#define LOAD64LE(p) ( \
((uint64_t)(((uint8_t *)(p))[0]) << 0) | \
((uint64_t)(((uint8_t *)(p))[1]) << 8) | \
((uint64_t)(((uint8_t *)(p))[2]) << 16) | \
((uint64_t)(((uint8_t *)(p))[3]) << 24) | \
((uint64_t)(((uint8_t *)(p))[4]) << 32) | \
((uint64_t)(((uint8_t *)(p))[5]) << 40) | \
((uint64_t)(((uint8_t *)(p))[6]) << 48) | \
((uint64_t)(((uint8_t *)(p))[7]) << 56))
//Load unaligned 64-bit integer (big-endian encoding)
#define LOAD64BE(p) ( \
((uint64_t)(((uint8_t *)(p))[0]) << 56) | \
((uint64_t)(((uint8_t *)(p))[1]) << 48) | \
((uint64_t)(((uint8_t *)(p))[2]) << 40) | \
((uint64_t)(((uint8_t *)(p))[3]) << 32) | \
((uint64_t)(((uint8_t *)(p))[4]) << 24) | \
((uint64_t)(((uint8_t *)(p))[5]) << 16) | \
((uint64_t)(((uint8_t *)(p))[6]) << 8) | \
((uint64_t)(((uint8_t *)(p))[7]) << 0))
//Store unaligned 16-bit integer (little-endian encoding)
#define STORE16LE(a, p) \
((uint8_t *)(p))[0] = ((uint16_t)(a) >> 0) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint16_t)(a) >> 8) & 0xFFU
//Store unaligned 16-bit integer (big-endian encoding)
#define STORE16BE(a, p) \
((uint8_t *)(p))[0] = ((uint16_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint16_t)(a) >> 0) & 0xFFU
//Store unaligned 24-bit integer (little-endian encoding)
#define STORE24LE(a, p) \
((uint8_t *)(p))[0] = ((uint32_t)(a) >> 0) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint32_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint32_t)(a) >> 16) & 0xFFU
//Store unaligned 24-bit integer (big-endian encoding)
#define STORE24BE(a, p) \
((uint8_t *)(p))[0] = ((uint32_t)(a) >> 16) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint32_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint32_t)(a) >> 0) & 0xFFU
//Store unaligned 32-bit integer (little-endian encoding)
#define STORE32LE(a, p) \
((uint8_t *)(p))[0] = ((uint32_t)(a) >> 0) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint32_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint32_t)(a) >> 16) & 0xFFU, \
((uint8_t *)(p))[3] = ((uint32_t)(a) >> 24) & 0xFFU
//Store unaligned 32-bit integer (big-endian encoding)
#define STORE32BE(a, p) \
((uint8_t *)(p))[0] = ((uint32_t)(a) >> 24) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint32_t)(a) >> 16) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint32_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[3] = ((uint32_t)(a) >> 0) & 0xFFU
//Store unaligned 48-bit integer (little-endian encoding)
#define STORE48LE(a, p) \
((uint8_t *)(p))[0] = ((uint64_t)(a) >> 0) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint64_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint64_t)(a) >> 16) & 0xFFU, \
((uint8_t *)(p))[3] = ((uint64_t)(a) >> 24) & 0xFFU, \
((uint8_t *)(p))[4] = ((uint64_t)(a) >> 32) & 0xFFU, \
((uint8_t *)(p))[5] = ((uint64_t)(a) >> 40) & 0xFFU,
//Store unaligned 48-bit integer (big-endian encoding)
#define STORE48BE(a, p) \
((uint8_t *)(p))[0] = ((uint64_t)(a) >> 40) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint64_t)(a) >> 32) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint64_t)(a) >> 24) & 0xFFU, \
((uint8_t *)(p))[3] = ((uint64_t)(a) >> 16) & 0xFFU, \
((uint8_t *)(p))[4] = ((uint64_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[5] = ((uint64_t)(a) >> 0) & 0xFFU
//Store unaligned 64-bit integer (little-endian encoding)
#define STORE64LE(a, p) \
((uint8_t *)(p))[0] = ((uint64_t)(a) >> 0) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint64_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint64_t)(a) >> 16) & 0xFFU, \
((uint8_t *)(p))[3] = ((uint64_t)(a) >> 24) & 0xFFU, \
((uint8_t *)(p))[4] = ((uint64_t)(a) >> 32) & 0xFFU, \
((uint8_t *)(p))[5] = ((uint64_t)(a) >> 40) & 0xFFU, \
((uint8_t *)(p))[6] = ((uint64_t)(a) >> 48) & 0xFFU, \
((uint8_t *)(p))[7] = ((uint64_t)(a) >> 56) & 0xFFU
//Store unaligned 64-bit integer (big-endian encoding)
#define STORE64BE(a, p) \
((uint8_t *)(p))[0] = ((uint64_t)(a) >> 56) & 0xFFU, \
((uint8_t *)(p))[1] = ((uint64_t)(a) >> 48) & 0xFFU, \
((uint8_t *)(p))[2] = ((uint64_t)(a) >> 40) & 0xFFU, \
((uint8_t *)(p))[3] = ((uint64_t)(a) >> 32) & 0xFFU, \
((uint8_t *)(p))[4] = ((uint64_t)(a) >> 24) & 0xFFU, \
((uint8_t *)(p))[5] = ((uint64_t)(a) >> 16) & 0xFFU, \
((uint8_t *)(p))[6] = ((uint64_t)(a) >> 8) & 0xFFU, \
((uint8_t *)(p))[7] = ((uint64_t)(a) >> 0) & 0xFFU
//Swap a 16-bit integer
#define SWAPINT16(x) ( \
(((uint16_t)(x) & 0x00FFU) << 8) | \
(((uint16_t)(x) & 0xFF00U) >> 8))
//Swap a 32-bit integer
#define SWAPINT32(x) ( \
(((uint32_t)(x) & 0x000000FFUL) << 24) | \
(((uint32_t)(x) & 0x0000FF00UL) << 8) | \
(((uint32_t)(x) & 0x00FF0000UL) >> 8) | \
(((uint32_t)(x) & 0xFF000000UL) >> 24))
//Swap a 64-bit integer
#define SWAPINT64(x) ( \
(((uint64_t)(x) & 0x00000000000000FFULL) << 56) | \
(((uint64_t)(x) & 0x000000000000FF00ULL) << 40) | \
(((uint64_t)(x) & 0x0000000000FF0000ULL) << 24) | \
(((uint64_t)(x) & 0x00000000FF000000ULL) << 8) | \
(((uint64_t)(x) & 0x000000FF00000000ULL) >> 8) | \
(((uint64_t)(x) & 0x0000FF0000000000ULL) >> 24) | \
(((uint64_t)(x) & 0x00FF000000000000ULL) >> 40) | \
(((uint64_t)(x) & 0xFF00000000000000ULL) >> 56))
//Big-endian machine?
#if (__BYTE_ORDER == __BIG_ENDIAN)
//Host byte order to network byte order
#define HTONS(value) (value)
#define HTONL(value) (value)
#define HTONLL(value) (value)
#define htons(value) ((uint16_t) (value))
#define htonl(value) ((uint32_t) (value))
#define htonll(value) ((uint64_t) (value))
//Network byte order to host byte order
#define NTOHS(value) (value)
#define NTOHL(value) (value)
#define NTOHLL(value) (value)
#define ntohs(value) ((uint16_t) (value))
#define ntohl(value) ((uint32_t) (value))
#define ntohll(value) ((uint64_t) (value))
//Host byte order to little-endian byte order
#define HTOLE16(value) SWAPINT16(value)
#define HTOLE32(value) SWAPINT32(value)
#define HTOLE64(value) SWAPINT64(value)
#define htole16(value) swapInt16((uint16_t) (value))
#define htole32(value) swapInt32((uint32_t) (value))
#define htole64(value) swapInt64((uint64_t) (value))
//Little-endian byte order to host byte order
#define LETOH16(value) SWAPINT16(value)
#define LETOH32(value) SWAPINT32(value)
#define LETOH64(value) SWAPINT64(value)
#define letoh16(value) swapInt16((uint16_t) (value))
#define letoh32(value) swapInt32((uint32_t) (value))
#define letoh64(value) swapInt64((uint64_t) (value))
//Host byte order to big-endian byte order
#define HTOBE16(value) (value)
#define HTOBE32(value) (value)
#define HTOBE64(value) (value)
#define htobe16(value) ((uint16_t) (value))
#define htobe32(value) ((uint32_t) (value))
#define htobe64(value) ((uint64_t) (value))
//Big-endian byte order to host byte order
#define BETOH16(value) (value)
#define BETOH32(value) (value)
#define BETOH64(value) (value)
#define betoh16(value) ((uint16_t) (value))
#define betoh32(value) ((uint32_t) (value))
#define betoh64(value) ((uint64_t) (value))
//Little-endian machine?
#else
//Host byte order to network byte order
#define HTONS(value) SWAPINT16(value)
#define HTONL(value) SWAPINT32(value)
#define HTONLL(value) SWAPINT64(value)
#define htons(value) swapInt16((uint16_t) (value))
#define htonl(value) swapInt32((uint32_t) (value))
#define htonll(value) swapInt64((uint64_t) (value))
//Network byte order to host byte order
#define NTOHS(value) SWAPINT16(value)
#define NTOHL(value) SWAPINT32(value)
#define NTOHLL(value) SWAPINT64(value)
#define ntohs(value) swapInt16((uint16_t) (value))
#define ntohl(value) swapInt32((uint32_t) (value))
#define ntohll(value) swapInt64((uint64_t) (value))
//Host byte order to little-endian byte order
#define HTOLE16(value) (value)
#define HTOLE32(value) (value)
#define HTOLE64(value) (value)
#define htole16(value) ((uint16_t) (value))
#define htole32(value) ((uint32_t) (value))
#define htole64(value) ((uint64_t) (value))
//Little-endian byte order to host byte order
#define LETOH16(value) (value)
#define LETOH32(value) (value)
#define LETOH64(value) (value)
#define letoh16(value) ((uint16_t) (value))
#define letoh32(value) ((uint32_t) (value))
#define letoh64(value) ((uint64_t) (value))
//Host byte order to big-endian byte order
#define HTOBE16(value) SWAPINT16(value)
#define HTOBE32(value) SWAPINT32(value)
#define HTOBE64(value) SWAPINT64(value)
#define htobe16(value) swapInt16((uint16_t) (value))
#define htobe32(value) swapInt32((uint32_t) (value))
#define htobe64(value) swapInt64((uint64_t) (value))
//Big-endian byte order to host byte order
#define BETOH16(value) SWAPINT16(value)
#define BETOH32(value) SWAPINT32(value)
#define BETOH64(value) SWAPINT64(value)
#define betoh16(value) swapInt16((uint16_t) (value))
#define betoh32(value) swapInt32((uint32_t) (value))
#define betoh64(value) swapInt64((uint64_t) (value))
#endif
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
//Byte order conversion functions
uint16_t swapInt16(uint16_t value);
uint32_t swapInt32(uint32_t value);
uint64_t swapInt64(uint64_t value);
//Bit reversal functions
uint8_t reverseInt4(uint8_t value);
uint8_t reverseInt8(uint8_t value);
uint16_t reverseInt16(uint16_t value);
uint32_t reverseInt32(uint32_t value);
uint64_t reverseInt64(uint64_t value);
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

7
deps/cyclone/include/crypto_config.h vendored Normal file
View File

@@ -0,0 +1,7 @@
#include "os_port.h"
#define HKDF_SUPPORT ENABLED
#define SHA256_SUPPORT ENABLED
#define AES_SUPPORT ENABLED
#define ECB_SUPPORT ENABLED
#define GCM_SUPPORT ENABLED

320
deps/cyclone/include/error.h vendored Normal file
View File

@@ -0,0 +1,320 @@
/**
* @file error.h
* @brief Error codes description
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _ERROR_H
#define _ERROR_H
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Error codes
**/
typedef enum cyc_error_st
{
NO_ERROR = 0, ///<Success
ERROR_FAILURE = 1, ///<Generic error code
ERROR_INVALID_PARAMETER, ///<Invalid parameter
ERROR_PARAMETER_OUT_OF_RANGE, ///<Specified parameter is out of range
ERROR_BAD_CRC,
ERROR_BAD_BLOCK,
ERROR_INVALID_RECIPIENT, ///<Invalid recipient
ERROR_INVALID_INTERFACE, ///<Invalid interface
ERROR_INVALID_ENDPOINT, ///<Invalid endpoint
ERROR_INVALID_ALT_SETTING, ///<Alternate setting does not exist
ERROR_UNSUPPORTED_REQUEST, ///<Unsupported request
ERROR_UNSUPPORTED_CONFIGURATION, ///<Unsupported configuration
ERROR_UNSUPPORTED_FEATURE, ///<Unsupported feature
ERROR_ENDPOINT_BUSY, ///<Endpoint already in use
ERROR_USB_RESET,
ERROR_ABORTED,
ERROR_OUT_OF_MEMORY = 100,
ERROR_OUT_OF_RESOURCES,
ERROR_INVALID_REQUEST,
ERROR_NOT_IMPLEMENTED,
ERROR_VERSION_NOT_SUPPORTED,
ERROR_INVALID_SYNTAX,
ERROR_AUTHENTICATION_FAILED,
ERROR_UNEXPECTED_RESPONSE,
ERROR_INVALID_RESPONSE,
ERROR_UNEXPECTED_VALUE,
ERROR_WAIT_CANCELED,
ERROR_OPEN_FAILED = 200,
ERROR_CONNECTION_FAILED,
ERROR_CONNECTION_REFUSED,
ERROR_CONNECTION_CLOSING,
ERROR_CONNECTION_RESET,
ERROR_NOT_CONNECTED,
ERROR_ALREADY_CLOSED,
ERROR_ALREADY_CONNECTED,
ERROR_INVALID_SOCKET,
ERROR_PROTOCOL_UNREACHABLE,
ERROR_PORT_UNREACHABLE,
ERROR_INVALID_FRAME,
ERROR_INVALID_HEADER,
ERROR_WRONG_CHECKSUM,
ERROR_WRONG_IDENTIFIER,
ERROR_WRONG_CLIENT_ID,
ERROR_WRONG_SERVER_ID,
ERROR_WRONG_COOKIE,
ERROR_NO_RESPONSE,
ERROR_RECEIVE_QUEUE_FULL,
ERROR_TIMEOUT,
ERROR_WOULD_BLOCK,
ERROR_INVALID_NAME,
ERROR_INVALID_OPTION,
ERROR_UNEXPECTED_STATE,
ERROR_INVALID_COMMAND,
ERROR_INVALID_PROTOCOL,
ERROR_INVALID_STATUS,
ERROR_INVALID_ADDRESS,
ERROR_INVALID_PORT,
ERROR_INVALID_MESSAGE,
ERROR_INVALID_KEY,
ERROR_INVALID_KEY_LENGTH,
ERROR_INVALID_EPOCH,
ERROR_INVALID_SEQUENCE_NUMBER,
ERROR_INVALID_CHARACTER,
ERROR_INVALID_LENGTH,
ERROR_INVALID_PADDING,
ERROR_INVALID_MAC,
ERROR_INVALID_TAG,
ERROR_INVALID_TYPE,
ERROR_INVALID_VALUE,
ERROR_INVALID_CLASS,
ERROR_INVALID_VERSION,
ERROR_INVALID_PIN_CODE,
ERROR_WRONG_LENGTH,
ERROR_WRONG_TYPE,
ERROR_WRONG_ENCODING,
ERROR_WRONG_VALUE,
ERROR_INCONSISTENT_VALUE,
ERROR_UNSUPPORTED_TYPE,
ERROR_UNSUPPORTED_ALGO,
ERROR_UNSUPPORTED_CIPHER_SUITE,
ERROR_UNSUPPORTED_CIPHER_MODE,
ERROR_UNSUPPORTED_CIPHER_ALGO,
ERROR_UNSUPPORTED_HASH_ALGO,
ERROR_UNSUPPORTED_KEY_EXCH_ALGO,
ERROR_UNSUPPORTED_SIGNATURE_ALGO,
ERROR_UNSUPPORTED_ELLIPTIC_CURVE,
ERROR_INVALID_SIGNATURE_ALGO,
ERROR_CERTIFICATE_REQUIRED,
ERROR_MESSAGE_TOO_LONG,
ERROR_OUT_OF_RANGE,
ERROR_MESSAGE_DISCARDED,
ERROR_INVALID_PACKET,
ERROR_BUFFER_EMPTY,
ERROR_BUFFER_OVERFLOW,
ERROR_BUFFER_UNDERFLOW,
ERROR_INVALID_RESOURCE,
ERROR_INVALID_PATH,
ERROR_NOT_FOUND,
ERROR_ACCESS_DENIED,
ERROR_NOT_WRITABLE,
ERROR_AUTH_REQUIRED,
ERROR_TRANSMITTER_BUSY,
ERROR_NO_RUNNING,
ERROR_INVALID_FILE = 300,
ERROR_FILE_NOT_FOUND,
ERROR_FILE_OPENING_FAILED,
ERROR_FILE_READING_FAILED,
ERROR_END_OF_FILE,
ERROR_UNEXPECTED_END_OF_FILE,
ERROR_UNKNOWN_FILE_FORMAT,
ERROR_INVALID_DIRECTORY,
ERROR_DIRECTORY_NOT_FOUND,
ERROR_FILE_SYSTEM_NOT_SUPPORTED = 400,
ERROR_UNKNOWN_FILE_SYSTEM,
ERROR_INVALID_FILE_SYSTEM,
ERROR_INVALID_BOOT_SECTOR_SIGNATURE,
ERROR_INVALID_SECTOR_SIZE,
ERROR_INVALID_CLUSTER_SIZE,
ERROR_INVALID_FILE_RECORD_SIZE,
ERROR_INVALID_INDEX_BUFFER_SIZE,
ERROR_INVALID_VOLUME_DESCRIPTOR_SIGNATURE,
ERROR_INVALID_VOLUME_DESCRIPTOR,
ERROR_INVALID_FILE_RECORD,
ERROR_INVALID_INDEX_BUFFER,
ERROR_INVALID_DATA_RUNS,
ERROR_WRONG_TAG_IDENTIFIER,
ERROR_WRONG_TAG_CHECKSUM,
ERROR_WRONG_MAGIC_NUMBER,
ERROR_WRONG_SEQUENCE_NUMBER,
ERROR_DESCRIPTOR_NOT_FOUND,
ERROR_ATTRIBUTE_NOT_FOUND,
ERROR_RESIDENT_ATTRIBUTE,
ERROR_NOT_RESIDENT_ATTRIBUTE,
ERROR_INVALID_SUPER_BLOCK,
ERROR_INVALID_SUPER_BLOCK_SIGNATURE,
ERROR_INVALID_BLOCK_SIZE,
ERROR_UNSUPPORTED_REVISION_LEVEL,
ERROR_INVALID_INODE_SIZE,
ERROR_INODE_NOT_FOUND,
ERROR_UNEXPECTED_MESSAGE = 500,
ERROR_URL_TOO_LONG,
ERROR_QUERY_STRING_TOO_LONG,
ERROR_NO_ADDRESS,
ERROR_NO_BINDING,
ERROR_NOT_ON_LINK,
ERROR_USE_MULTICAST,
ERROR_NAK_RECEIVED,
ERROR_EXCEPTION_RECEIVED,
ERROR_NO_CARRIER,
ERROR_INVALID_LEVEL,
ERROR_WRONG_STATE,
ERROR_END_OF_STREAM,
ERROR_LINK_DOWN,
ERROR_INVALID_OPTION_LENGTH,
ERROR_IN_PROGRESS,
ERROR_NO_ACK,
ERROR_INVALID_METADATA,
ERROR_NOT_CONFIGURED,
ERROR_ALREADY_CONFIGURED,
ERROR_NAME_RESOLUTION_FAILED,
ERROR_NO_ROUTE,
ERROR_WRITE_FAILED,
ERROR_READ_FAILED,
ERROR_UPLOAD_FAILED,
ERROR_READ_ONLY_ACCESS,
ERROR_INVALID_SIGNATURE,
ERROR_INVALID_TICKET,
ERROR_NO_TICKET,
ERROR_BAD_RECORD_MAC,
ERROR_RECORD_OVERFLOW,
ERROR_HANDSHAKE_FAILED,
ERROR_NO_CERTIFICATE,
ERROR_BAD_CERTIFICATE,
ERROR_UNSUPPORTED_CERTIFICATE,
ERROR_UNKNOWN_CERTIFICATE,
ERROR_CERTIFICATE_EXPIRED,
ERROR_CERTIFICATE_REVOKED,
ERROR_UNKNOWN_CA,
ERROR_DECODING_FAILED,
ERROR_DECRYPTION_FAILED,
ERROR_ILLEGAL_PARAMETER,
ERROR_MISSING_EXTENSION,
ERROR_UNSUPPORTED_EXTENSION,
ERROR_INAPPROPRIATE_FALLBACK,
ERROR_NO_APPLICATION_PROTOCOL,
ERROR_MORE_DATA_REQUIRED,
ERROR_TLS_NOT_SUPPORTED,
ERROR_PRNG_NOT_READY,
ERROR_SERVICE_CLOSING,
ERROR_INVALID_TIMESTAMP,
ERROR_NO_DNS_SERVER,
ERROR_OBJECT_NOT_FOUND,
ERROR_INSTANCE_NOT_FOUND,
ERROR_ADDRESS_NOT_FOUND,
ERROR_UNKNOWN_IDENTITY,
ERROR_UNKNOWN_ENGINE_ID,
ERROR_UNKNOWN_USER_NAME,
ERROR_UNKNOWN_CONTEXT,
ERROR_UNAVAILABLE_CONTEXT,
ERROR_UNSUPPORTED_SECURITY_LEVEL,
ERROR_NOT_IN_TIME_WINDOW,
ERROR_AUTHORIZATION_FAILED,
ERROR_INVALID_FUNCTION_CODE,
ERROR_DEVICE_BUSY,
ERROR_REQUEST_REJECTED,
ERROR_INVALID_CHANNEL,
ERROR_INVALID_GROUP,
ERROR_UNKNOWN_SERVICE,
ERROR_UNKNOWN_REQUEST,
ERROR_FLOW_CONTROL,
ERROR_INVALID_PASSWORD,
ERROR_INVALID_HANDLE,
ERROR_BAD_NONCE,
ERROR_UNEXPECTED_STATUS,
ERROR_RESPONSE_TOO_LARGE,
ERROR_INVALID_SESSION,
ERROR_TICKET_EXPIRED,
ERROR_INVALID_ENTRY,
ERROR_TABLE_FULL,
ERROR_END_OF_TABLE,
ERROR_ALREADY_RUNNING,
ERROR_UNKOWN_KEY,
ERROR_UNKNOWN_TYPE,
ERROR_UNSUPPORTED_OPTION,
ERROR_INVALID_SPI,
ERROR_RETRY,
ERROR_POLICY_FAILURE,
ERROR_INVALID_PROPOSAL,
ERROR_INVALID_SELECTOR,
ERROR_WRONG_NONCE,
ERROR_WRONG_ISSUER,
ERROR_RESPONSE_EXPIRED,
ERROR_CRL_EXPIRED,
ERROR_NO_MATCH,
ERROR_PARTIAL_MATCH
} cyc_error_t;
#ifndef error_t
#define error_t cyc_error_t
#endif
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,62 @@
/**
* @file hash_algorithms.h
* @brief Collection of hash algorithms
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _HASH_ALGORITHMS_H
#define _HASH_ALGORITHMS_H
//Dependencies
#include "core/crypto.h"
#include "hash/sha256.h"
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_HASH_DIGEST_SIZE SHA256_DIGEST_SIZE
#define MAX_HASH_BLOCK_SIZE SHA256_BLOCK_SIZE
/**
* @brief Generic hash algorithm context
**/
typedef union
{
uint8_t digest[MAX_HASH_DIGEST_SIZE];
Sha256Context sha256Context;
} HashContext;
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

96
deps/cyclone/include/hash/sha256.h vendored Normal file
View File

@@ -0,0 +1,96 @@
/**
* @file sha256.h
* @brief SHA-256 (Secure Hash Algorithm 256)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _SHA256_H
#define _SHA256_H
//Dependencies
#include "core/crypto.h"
//Application specific context
#ifndef SHA256_PRIVATE_CONTEXT
#define SHA256_PRIVATE_CONTEXT
#endif
//SHA-256 block size
#define SHA256_BLOCK_SIZE 64
//SHA-256 digest size
#define SHA256_DIGEST_SIZE 32
//Minimum length of the padding string
#define SHA256_MIN_PAD_SIZE 9
//Common interface for hash algorithms
#define SHA256_HASH_ALGO (&sha256HashAlgo)
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SHA-256 algorithm context
**/
typedef struct
{
union
{
uint32_t h[8];
uint8_t digest[32];
};
union
{
uint32_t w[16];
uint8_t buffer[64];
};
size_t size;
uint64_t totalSize;
SHA256_PRIVATE_CONTEXT
} Sha256Context;
//SHA-256 related constants
extern const uint8_t SHA256_OID[9];
extern const HashAlgo sha256HashAlgo;
//SHA-256 related functions
error_t sha256Compute(const void *data, size_t length, uint8_t *digest);
void sha256Init(Sha256Context *context);
void sha256Update(Sha256Context *context, const void *data, size_t length);
void sha256Final(Sha256Context *context, uint8_t *digest);
void sha256FinalRaw(Sha256Context *context, uint8_t *digest);
void sha256ProcessBlock(Sha256Context *context);
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

58
deps/cyclone/include/kdf/hkdf.h vendored Normal file
View File

@@ -0,0 +1,58 @@
/**
* @file hkdf.h
* @brief HKDF (HMAC-based Key Derivation Function)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _HKDF_H
#define _HKDF_H
//Dependencies
#include "core/crypto.h"
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
//HKDF related functions
error_t hkdf(const HashAlgo *hash, const uint8_t *ikm, size_t ikmLen,
const uint8_t *salt, size_t saltLen, const uint8_t *info, size_t infoLen,
uint8_t *okm, size_t okmLen);
error_t hkdfExtract(const HashAlgo *hash, const uint8_t *ikm, size_t ikmLen,
const uint8_t *salt, size_t saltLen, uint8_t *prk);
error_t hkdfExpand(const HashAlgo *hash, const uint8_t *prk, size_t prkLen,
const uint8_t *info, size_t infoLen, uint8_t *okm, size_t okmLen);
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

102
deps/cyclone/include/mac/hmac.h vendored Normal file
View File

@@ -0,0 +1,102 @@
/**
* @file hmac.h
* @brief HMAC (Keyed-Hashing for Message Authentication)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
#ifndef _HMAC_H
#define _HMAC_H
//Dependencies
#include "core/crypto.h"
#include "hash/hash_algorithms.h"
//Application specific context
#ifndef HMAC_PRIVATE_CONTEXT
#define HMAC_PRIVATE_CONTEXT
#endif
//Inner padding (ipad)
#define HMAC_IPAD 0x36
//Outer padding (opad)
#define HMAC_OPAD 0x5C
//C++ guard
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief HMAC algorithm context
**/
typedef struct
{
const HashAlgo *hash;
HashContext hashContext;
uint8_t key[MAX_HASH_BLOCK_SIZE];
uint8_t digest[MAX_HASH_DIGEST_SIZE];
HMAC_PRIVATE_CONTEXT
} HmacContext;
//HMAC related constants
extern const uint8_t HMAC_WITH_MD5_OID[8];
extern const uint8_t HMAC_WITH_TIGER_OID[8];
extern const uint8_t HMAC_WITH_RIPEMD160_OID[8];
extern const uint8_t HMAC_WITH_SHA1_OID[8];
extern const uint8_t HMAC_WITH_SHA224_OID[8];
extern const uint8_t HMAC_WITH_SHA256_OID[8];
extern const uint8_t HMAC_WITH_SHA384_OID[8];
extern const uint8_t HMAC_WITH_SHA512_OID[8];
extern const uint8_t HMAC_WITH_SHA512_224_OID[8];
extern const uint8_t HMAC_WITH_SHA512_256_OID[8];
extern const uint8_t HMAC_WITH_SHA3_224_OID[9];
extern const uint8_t HMAC_WITH_SHA3_256_OID[9];
extern const uint8_t HMAC_WITH_SHA3_384_OID[9];
extern const uint8_t HMAC_WITH_SHA3_512_OID[9];
extern const uint8_t HMAC_WITH_SM3_OID[10];
//HMAC related functions
error_t hmacCompute(const HashAlgo *hash, const void *key, size_t keyLen,
const void *data, size_t dataLen, uint8_t *digest);
error_t hmacInit(HmacContext *context, const HashAlgo *hash,
const void *key, size_t keyLen);
void hmacUpdate(HmacContext *context, const void *data, size_t length);
void hmacFinal(HmacContext *context, uint8_t *digest);
void hmacFinalRaw(HmacContext *context, uint8_t *digest);
void hmacDeinit(HmacContext *context);
//C++ guard
#ifdef __cplusplus
}
#endif
#endif

110
deps/cyclone/include/os_port.h vendored Normal file
View File

@@ -0,0 +1,110 @@
/**
* @file os_port.h
* @brief RTOS abstraction layer
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
/**
* Rewrote for youtubeUnblock
*/
#ifndef _OS_PORT_H
#define _OS_PORT_H
//Dependencies
#include "types.h"
#include "compiler_port.h"
//Compilation flags used to enable/disable features
#define ENABLED 1
#define DISABLED 0
#define timeCompare(t1, t2) ((int32_t) ((t1) - (t2)))
//Miscellaneous macros
#if !defined(__AT32F403A_407_LIBRARY_VERSION) && \
!defined(__AT32F435_437_LIBRARY_VERSION)
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#endif
#ifndef LSB
#define LSB(x) ((x) & 0xFF)
#endif
#ifndef MSB
#define MSB(x) (((x) >> 8) & 0xFF)
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef arraysize
#define arraysize(a) (sizeof(a) / sizeof(a[0]))
#endif
//Memory management
#ifndef osAllocMem
#define osAllocMem malloc
#endif
#ifndef osFreeMem
#define osFreeMem free
#endif
//Fill block of memory
#ifndef osMemset
#define osMemset(p, value, length) (void) memset(p, value, length)
#endif
//Copy block of memory
#ifndef osMemcpy
#define osMemcpy(dest, src, length) (void) memcpy(dest, src, length)
#endif
//Move block of memory
#ifndef osMemmove
#define osMemmove(dest, src, length) (void) memmove(dest, src, length)
#endif
//Compare two blocks of memory
#ifndef osMemcmp
#define osMemcmp(p1, p2, length) memcmp(p1, p2, length)
#endif
//Search for the first occurrence of a given character
#ifndef osMemchr
#define osMemchr(p, c, length) memchr(p, c, length)
#endif
#endif

361
deps/cyclone/sha256.c vendored Normal file
View File

@@ -0,0 +1,361 @@
/**
* @file sha256.c
* @brief SHA-256 (Secure Hash Algorithm 256)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneCRYPTO Open.
*
* 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 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, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @section Description
*
* SHA-256 is a secure hash algorithm for computing a condensed representation
* of an electronic message. Refer to FIPS 180-4 for more details
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL CRYPTO_TRACE_LEVEL
//Dependencies
#include "core/crypto.h"
#include "hash/sha256.h"
//Check crypto library configuration
#if (SHA224_SUPPORT == ENABLED || SHA256_SUPPORT == ENABLED)
//Macro to access the workspace as a circular buffer
#define W(n) w[(n) & 0x0F]
//SHA-256 auxiliary functions
#define CH(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define SIGMA1(x) (ROR32(x, 2) ^ ROR32(x, 13) ^ ROR32(x, 22))
#define SIGMA2(x) (ROR32(x, 6) ^ ROR32(x, 11) ^ ROR32(x, 25))
#define SIGMA3(x) (ROR32(x, 7) ^ ROR32(x, 18) ^ SHR32(x, 3))
#define SIGMA4(x) (ROR32(x, 17) ^ ROR32(x, 19) ^ SHR32(x, 10))
//SHA-256 padding
static const uint8_t padding[64] =
{
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
//SHA-256 constants
static const uint32_t k[64] =
{
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
};
//SHA-256 object identifier (2.16.840.1.101.3.4.2.1)
const uint8_t SHA256_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};
//Common interface for hash algorithms
const HashAlgo sha256HashAlgo =
{
"SHA-256",
SHA256_OID,
sizeof(SHA256_OID),
sizeof(Sha256Context),
SHA256_BLOCK_SIZE,
SHA256_DIGEST_SIZE,
SHA256_MIN_PAD_SIZE,
TRUE,
(HashAlgoCompute) sha256Compute,
(HashAlgoInit) sha256Init,
(HashAlgoUpdate) sha256Update,
(HashAlgoFinal) sha256Final,
#if ((defined(MIMXRT1050_CRYPTO_HASH_SUPPORT) && MIMXRT1050_CRYPTO_HASH_SUPPORT == ENABLED) || \
(defined(MIMXRT1060_CRYPTO_HASH_SUPPORT) && MIMXRT1060_CRYPTO_HASH_SUPPORT == ENABLED) || \
(defined(MIMXRT1160_CRYPTO_HASH_SUPPORT) && MIMXRT1160_CRYPTO_HASH_SUPPORT == ENABLED) || \
(defined(MIMXRT1170_CRYPTO_HASH_SUPPORT) && MIMXRT1170_CRYPTO_HASH_SUPPORT == ENABLED))
NULL,
#else
(HashAlgoFinalRaw) sha256FinalRaw
#endif
};
/**
* @brief Digest a message using SHA-256
* @param[in] data Pointer to the message being hashed
* @param[in] length Length of the message
* @param[out] digest Pointer to the calculated digest
* @return Error code
**/
__weak_func error_t sha256Compute(const void *data, size_t length, uint8_t *digest)
{
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
Sha256Context *context;
#else
Sha256Context context[1];
#endif
//Check parameters
if(data == NULL && length != 0)
return ERROR_INVALID_PARAMETER;
if(digest == NULL)
return ERROR_INVALID_PARAMETER;
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Allocate a memory buffer to hold the SHA-256 context
context = cryptoAllocMem(sizeof(Sha256Context));
//Failed to allocate memory?
if(context == NULL)
return ERROR_OUT_OF_MEMORY;
#endif
//Initialize the SHA-256 context
sha256Init(context);
//Digest the message
sha256Update(context, data, length);
//Finalize the SHA-256 message digest
sha256Final(context, digest);
#if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
//Free previously allocated memory
cryptoFreeMem(context);
#endif
//Successful processing
return NO_ERROR;
}
/**
* @brief Initialize SHA-256 message digest context
* @param[in] context Pointer to the SHA-256 context to initialize
**/
__weak_func void sha256Init(Sha256Context *context)
{
//Set initial hash value
context->h[0] = 0x6A09E667;
context->h[1] = 0xBB67AE85;
context->h[2] = 0x3C6EF372;
context->h[3] = 0xA54FF53A;
context->h[4] = 0x510E527F;
context->h[5] = 0x9B05688C;
context->h[6] = 0x1F83D9AB;
context->h[7] = 0x5BE0CD19;
//Number of bytes in the buffer
context->size = 0;
//Total length of the message
context->totalSize = 0;
}
/**
* @brief Update the SHA-256 context with a portion of the message being hashed
* @param[in] context Pointer to the SHA-256 context
* @param[in] data Pointer to the buffer being hashed
* @param[in] length Length of the buffer
**/
__weak_func void sha256Update(Sha256Context *context, const void *data, size_t length)
{
size_t n;
//Process the incoming data
while(length > 0)
{
//The buffer can hold at most 64 bytes
n = MIN(length, 64 - context->size);
//Copy the data to the buffer
osMemcpy(context->buffer + context->size, data, n);
//Update the SHA-256 context
context->size += n;
context->totalSize += n;
//Advance the data pointer
data = (uint8_t *) data + n;
//Remaining bytes to process
length -= n;
//Process message in 16-word blocks
if(context->size == 64)
{
//Transform the 16-word block
sha256ProcessBlock(context);
//Empty the buffer
context->size = 0;
}
}
}
/**
* @brief Finish the SHA-256 message digest
* @param[in] context Pointer to the SHA-256 context
* @param[out] digest Calculated digest (optional parameter)
**/
__weak_func void sha256Final(Sha256Context *context, uint8_t *digest)
{
uint_t i;
size_t paddingSize;
uint64_t totalSize;
//Length of the original message (before padding)
totalSize = context->totalSize * 8;
//Pad the message so that its length is congruent to 56 modulo 64
if(context->size < 56)
{
paddingSize = 56 - context->size;
}
else
{
paddingSize = 64 + 56 - context->size;
}
//Append padding
sha256Update(context, padding, paddingSize);
//Append the length of the original message
context->w[14] = htobe32((uint32_t) (totalSize >> 32));
context->w[15] = htobe32((uint32_t) totalSize);
//Calculate the message digest
sha256ProcessBlock(context);
//Convert from host byte order to big-endian byte order
for(i = 0; i < 8; i++)
{
context->h[i] = htobe32(context->h[i]);
}
//Copy the resulting digest
if(digest != NULL)
{
osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
}
}
/**
* @brief Finish the SHA-256 message digest (no padding added)
* @param[in] context Pointer to the SHA-256 context
* @param[out] digest Calculated digest
**/
__weak_func void sha256FinalRaw(Sha256Context *context, uint8_t *digest)
{
uint_t i;
//Convert from host byte order to big-endian byte order
for(i = 0; i < 8; i++)
{
context->h[i] = htobe32(context->h[i]);
}
//Copy the resulting digest
osMemcpy(digest, context->digest, SHA256_DIGEST_SIZE);
//Convert from big-endian byte order to host byte order
for(i = 0; i < 8; i++)
{
context->h[i] = betoh32(context->h[i]);
}
}
/**
* @brief Process message in 16-word blocks
* @param[in] context Pointer to the SHA-256 context
**/
__weak_func void sha256ProcessBlock(Sha256Context *context)
{
uint_t i;
uint32_t temp1;
uint32_t temp2;
//Initialize the 8 working registers
uint32_t a = context->h[0];
uint32_t b = context->h[1];
uint32_t c = context->h[2];
uint32_t d = context->h[3];
uint32_t e = context->h[4];
uint32_t f = context->h[5];
uint32_t g = context->h[6];
uint32_t h = context->h[7];
//Process message in 16-word blocks
uint32_t *w = context->w;
//Convert from big-endian byte order to host byte order
for(i = 0; i < 16; i++)
{
w[i] = betoh32(w[i]);
}
//SHA-256 hash computation (alternate method)
for(i = 0; i < 64; i++)
{
//Prepare the message schedule
if(i >= 16)
{
W(i) += SIGMA4(W(i + 14)) + W(i + 9) + SIGMA3(W(i + 1));
}
//Calculate T1 and T2
temp1 = h + SIGMA2(e) + CH(e, f, g) + k[i] + W(i);
temp2 = SIGMA1(a) + MAJ(a, b, c);
//Update working registers
h = g;
g = f;
f = e;
e = d + temp1;
d = c;
c = b;
b = a;
a = temp1 + temp2;
}
//Update the hash value
context->h[0] += a;
context->h[1] += b;
context->h[2] += c;
context->h[3] += d;
context->h[4] += e;
context->h[5] += f;
context->h[6] += g;
context->h[7] += h;
}
#endif

565
kargs.c
View File

@@ -1,565 +0,0 @@
#include "config.h"
#include "types.h"
#include <linux/moduleparam.h>
#include "types.h"
#include "args.h"
#include "logging.h"
#define MAX_ARGC 1024
static char *argv[MAX_ARGC];
static int params_set(const char *cval, const struct kernel_param *kp) {
int ret = 0;
int cv_len = strlen(cval);
if (cv_len >= 1 && cval[cv_len - 1] == '\n') {
cv_len--;
}
const char *ytb_prefix = "youtubeUnblock ";
int ytbp_len = strlen(ytb_prefix);
int len = cv_len + ytbp_len;
char *val = kmalloc(len + 1, GFP_KERNEL); // 1 for null-terminator
strncpy(val, ytb_prefix, ytbp_len);
strncpy(val + ytbp_len, cval, cv_len);
val[len] = '\0';
int argc = 0;
argv[argc++] = val;
for (int i = 0; i < len; i++) {
if (val[i] == ' ') {
val[i] = '\0';
// safe because of null-terminator
if (val[i + 1] != ' ' && val[i + 1] != '\0') {
argv[argc++] = val + i + 1;
}
}
}
ret = yparse_args(argc, argv);
kfree(val);
return ret;
}
static int params_get(char *buffer, const struct kernel_param *kp) {
size_t len = print_config(buffer, 4000);
return len;
}
static const struct kernel_param_ops params_ops = {
.set = params_set,
.get = params_get,
};
module_param_cb(parameters, &params_ops, NULL, 0664);
//
// static char custom_fake_buf[MAX_FAKE_SIZE];
//
// struct config_t config = {
// .threads = THREADS_NUM,
// .queue_start_num = DEFAULT_QUEUE_NUM,
// .mark = DEFAULT_RAWSOCKET_MARK,
// .use_ipv6 = 1,
//
// .verbose = VERBOSE_DEBUG,
// .use_gso = 1,
//
// .default_config = default_section_config,
// .custom_configs_len = 0
// };
//
// #define def_section (&config.default_config)
//
// static int unumeric_set(const char *val, const struct kernel_param *kp) {
// int n = 0, ret;
// ret = kstrtoint(val, 10, &n);
// if (ret != 0 || n < 0)
// return -EINVAL;
//
//
// return param_set_int(val, kp);
// }
//
// static int boolean_set(const char *val, const struct kernel_param *kp) {
// int n = 0, ret;
// ret = kstrtoint(val, 10, &n);
// if (ret != 0 || (n != 0 && n != 1))
// return -EINVAL;
//
// return param_set_int(val, kp);
// }
//
// static int inverse_boolean_set(const char *val, const struct kernel_param *kp) {
// int n = 0, ret;
// ret = kstrtoint(val, 10, &n);
// if (ret != 0 || (n != 0 && n != 1))
// return -EINVAL;
//
// n = !n;
// if (kp->arg == NULL)
// return -EINVAL;
//
// *(int *)kp->arg = n;
// return 0;
// }
//
// static int inverse_boolean_get(char *buffer, const struct kernel_param *kp) {
// if (*(int *)kp->arg == 0) {
// buffer[0] = '1';
// } else {
// buffer[0] = '0';
// }
// buffer[1] = '\0';
// return strlen(buffer);
// }
//
// static const struct kernel_param_ops unumeric_parameter_ops = {
// .set = unumeric_set,
// .get = param_get_int
// };
//
// static const struct kernel_param_ops boolean_parameter_ops = {
// .set = boolean_set,
// .get = param_get_int
// };
//
// static const struct kernel_param_ops inverse_boolean_ops = {
// .set = inverse_boolean_set,
// .get = inverse_boolean_get,
// };
//
// module_param_cb(fake_sni, &boolean_parameter_ops, &def_section->fake_sni, 0664);
// module_param_cb(fake_sni_seq_len, &unumeric_parameter_ops, &def_section->fake_sni_seq_len, 0664);
// module_param_cb(faking_ttl, &unumeric_parameter_ops, &def_section->faking_ttl, 0664);
// module_param_cb(fake_seq_offset, &unumeric_parameter_ops, &def_section->fakeseq_offset, 0664);
// module_param_cb(frag_sni_reverse, &unumeric_parameter_ops, &def_section->frag_sni_reverse, 0664);
// module_param_cb(frag_sni_faked, &boolean_parameter_ops, &def_section->frag_sni_faked, 0664);
// module_param_cb(frag_middle_sni, &boolean_parameter_ops, &def_section->frag_middle_sni, 0664);
// module_param_cb(frag_sni_pos, &unumeric_parameter_ops, &def_section->frag_sni_pos, 0664);
// module_param_cb(fk_winsize, &unumeric_parameter_ops, &def_section->fk_winsize, 0664);
// module_param_cb(synfake, &boolean_parameter_ops, &def_section->synfake, 0664);
// module_param_cb(synfake_len, &unumeric_parameter_ops, &def_section->synfake_len, 0664);
// module_param_cb(packet_mark, &unumeric_parameter_ops, &config.mark, 0664);
// // module_param_cb(seg2delay, &unumeric_parameter_ops, &def_section->seg2_delay, 0664);
//
// static int sni_domains_set(const char *val, const struct kernel_param *kp) {
// size_t len;
// int ret;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// if (len >= 1 && val[len - 1] == '\n') {
// len--;
// }
//
// ret = param_set_charp(val, kp);
//
// if (ret < 0) {
// def_section->domains_strlen = 0;
// } else {
// def_section->domains_strlen = len;
// if (len == 3 && !strncmp(val, "all", len)) {
// def_section->all_domains = 1;
// } else {
// def_section->all_domains = 0;
// }
// }
//
//
// return ret;
// }
//
// static const struct kernel_param_ops sni_domains_ops = {
// .set = sni_domains_set,
// .get = param_get_charp,
// };
//
// module_param_cb(sni_domains, &sni_domains_ops, &def_section->domains_str, 0664);
//
// static int exclude_domains_set(const char *val, const struct kernel_param *kp) {
// size_t len;
// int ret;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// ret = param_set_charp(val, kp);
//
// if (ret < 0) {
// def_section->exclude_domains_strlen = 0;
// } else {
// def_section->exclude_domains_strlen = len;
// }
//
// return ret;
// }
//
// static const struct kernel_param_ops exclude_domains_ops = {
// .set = exclude_domains_set,
// .get = param_get_charp,
// };
//
// module_param_cb(exclude_domains, &exclude_domains_ops, &def_section->exclude_domains_str, 0664);
//
// module_param_cb(no_ipv6, &inverse_boolean_ops, &config.use_ipv6, 0664);
//
// static int quic_drop_set(const char *val, const struct kernel_param *kp) {
// int n = 0, ret;
// ret = kstrtoint(val, 10, &n);
// if (ret != 0 || (n != 0 && n != 1))
// return -EINVAL;
//
// if (n) {
// def_section->udp_mode = UDP_MODE_DROP;
// def_section->udp_filter_quic = UDP_FILTER_QUIC_ALL;
// } else {
// def_section->udp_filter_quic = UDP_FILTER_QUIC_DISABLED;
// }
//
// return 0;
// }
//
// static int quic_drop_get(char *buffer, const struct kernel_param *kp) {
// if (def_section->udp_mode == UDP_MODE_DROP &&
// def_section->udp_filter_quic == UDP_FILTER_QUIC_ALL) {
// return sprintf(buffer, "%d\n", 1);
// } else {
// return sprintf(buffer, "%d\n", 0);
// }
// }
//
// static const struct kernel_param_ops quic_drop_ops = {
// .set = quic_drop_set,
// .get = quic_drop_get
// };
//
// module_param_cb(quic_drop, &quic_drop_ops, NULL, 0664);
//
// static int verbosity_set(const char *val, const struct kernel_param *kp) {
// size_t len;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// if (len >= 1 && val[len - 1] == '\n') {
// len--;
// }
//
// if (strncmp(val, "trace", len) == 0) {
// *(int *)kp->arg = VERBOSE_TRACE;
// } else if (strncmp(val, "debug", len) == 0) {
// *(int *)kp->arg = VERBOSE_DEBUG;
// } else if (strncmp(val, "silent", len) == 0) {
// *(int *)kp->arg = VERBOSE_INFO;
// } else {
// return -EINVAL;
// }
//
// return 0;
// }
//
//
// static int verbosity_get(char *buffer, const struct kernel_param *kp) {
// switch (*(int *)kp->arg) {
// case VERBOSE_TRACE:
// strcpy(buffer, "trace\n");
// break;
// case VERBOSE_DEBUG:
// strcpy(buffer, "debug\n");
// break;
// case VERBOSE_INFO:
// strcpy(buffer, "silent\n");
// break;
// default:
// strcpy(buffer, "unknown\n");
// }
//
// return strlen(buffer);
// }
//
// static const struct kernel_param_ops verbosity_ops = {
// .set = verbosity_set,
// .get = verbosity_get,
// };
//
// module_param_cb(verbosity, &verbosity_ops, &config.verbose, 0664);
//
// static int frag_strat_set(const char *val, const struct kernel_param *kp) {
// size_t len;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// if (len >= 1 && val[len - 1] == '\n') {
// len--;
// }
//
// if (strncmp(val, "tcp", len) == 0) {
// *(int *)kp->arg = FRAG_STRAT_TCP;
// } else if (strncmp(val, "ip", len) == 0) {
// *(int *)kp->arg = FRAG_STRAT_IP;
// } else if (strncmp(val, "none", len) == 0) {
// *(int *)kp->arg = FRAG_STRAT_NONE;
// } else {
// return -EINVAL;
// }
//
// return 0;
// }
//
// static int frag_strat_get(char *buffer, const struct kernel_param *kp) {
// switch (*(int *)kp->arg) {
// case FRAG_STRAT_TCP:
// strcpy(buffer, "tcp\n");
// break;
// case FRAG_STRAT_IP:
// strcpy(buffer, "ip\n");
// break;
// case FRAG_STRAT_NONE:
// strcpy(buffer, "none\n");
// break;
// default:
// strcpy(buffer, "unknown\n");
// }
//
// return strlen(buffer);
// }
//
// static const struct kernel_param_ops frag_strat_ops = {
// .set = frag_strat_set,
// .get = frag_strat_get,
// };
//
// module_param_cb(fragmentation_strategy, &frag_strat_ops, &def_section->fragmentation_strategy, 0664);
//
// static int fake_strat_set(const char *val, const struct kernel_param *kp) {
// size_t len;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// if (len >= 1 && val[len - 1] == '\n') {
// len--;
// }
//
// if (strncmp(val, "randseq", len) == 0) {
// *(int *)kp->arg = FAKE_STRAT_RAND_SEQ;
// } else if (strncmp(val, "ttl", len) == 0) {
// *(int *)kp->arg = FAKE_STRAT_TTL;
// } else if (strncmp(val, "tcp_check", len) == 0) {
// *(int *)kp->arg = FAKE_STRAT_TCP_CHECK;
// } else if (strncmp(val, "pastseq", len) == 0) {
// *(int *)kp->arg = FAKE_STRAT_PAST_SEQ;
// } else if (strncmp(val, "md5sum", len) == 0) {
// *(int *)kp->arg = FAKE_STRAT_TCP_MD5SUM;
// } else {
// return -EINVAL;
// }
//
// return 0;
// }
//
// static int fake_strat_get(char *buffer, const struct kernel_param *kp) {
// switch (*(int *)kp->arg) {
// case FAKE_STRAT_RAND_SEQ:
// strcpy(buffer, "randseq\n");
// break;
// case FAKE_STRAT_TTL:
// strcpy(buffer, "ttl\n");
// break;
// case FAKE_STRAT_TCP_CHECK:
// strcpy(buffer, "tcp_check\n");
// break;
// case FAKE_STRAT_PAST_SEQ:
// strcpy(buffer, "pastseq\n");
// break;
// case FAKE_STRAT_TCP_MD5SUM:
// strcpy(buffer, "md5sum\n");
// break;
// default:
// strcpy(buffer, "unknown\n");
// }
//
// return strlen(buffer);
// }
//
// static const struct kernel_param_ops fake_strat_ops = {
// .set = fake_strat_set,
// .get = fake_strat_get,
// };
//
// module_param_cb(faking_strategy, &fake_strat_ops, &def_section->faking_strategy, 0664);
//
// static int sni_detection_set(const char *val, const struct kernel_param *kp) {
// size_t len;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// if (len >= 1 && val[len - 1] == '\n') {
// len--;
// }
//
// if (strncmp(val, "parse", len) == 0) {
// *(int *)kp->arg = SNI_DETECTION_PARSE;
// } else if (strncmp(val, "brute", len) == 0) {
// *(int *)kp->arg = SNI_DETECTION_BRUTE;
// } else {
// return -EINVAL;
// }
//
// return 0;
// }
//
// static int sni_detection_get(char *buffer, const struct kernel_param *kp) {
// switch (*(int *)kp->arg) {
// case SNI_DETECTION_PARSE:
// strcpy(buffer, "parse\n");
// break;
// case SNI_DETECTION_BRUTE:
// strcpy(buffer, "brute\n");
// break;
// default:
// strcpy(buffer, "unknown\n");
// }
//
// return strlen(buffer);
// }
//
// static const struct kernel_param_ops sni_detection_ops = {
// .set = sni_detection_set,
// .get = sni_detection_get,
// };
//
// module_param_cb(sni_detection, &sni_detection_ops, &def_section->sni_detection, 0664);
//
// static int fake_type_set(const char *val, const struct kernel_param *kp) {
// size_t len;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// if (len >= 1 && val[len - 1] == '\n') {
// len--;
// }
//
// if (strncmp(val, "default", len) == 0) {
// *(int *)kp->arg = FAKE_PAYLOAD_DEFAULT;
// } else if (strncmp(val, "custom", len) == 0) {
// *(int *)kp->arg = FAKE_PAYLOAD_CUSTOM;
// } else if (strncmp(val, "random", len) == 0) {
// *(int *)kp->arg = FAKE_PAYLOAD_RANDOM;
// } else {
// return -EINVAL;
// }
//
// return 0;
// }
//
// static int fake_type_get(char *buffer, const struct kernel_param *kp) {
// switch (*(int *)kp->arg) {
// case FAKE_PAYLOAD_DEFAULT:
// strcpy(buffer, "default\n");
// break;
// case FAKE_PAYLOAD_RANDOM:
// strcpy(buffer, "random\n");
// break;
// case FAKE_PAYLOAD_CUSTOM:
// strcpy(buffer, "custom\n");
// break;
// default:
// strcpy(buffer, "unknown\n");
// }
//
// return strlen(buffer);
// }
//
// static const struct kernel_param_ops fake_type_ops = {
// .set = fake_type_set,
// .get = fake_type_get,
// };
//
// module_param_cb(fake_sni_type, &fake_type_ops, &def_section->fake_sni_type, 0664);
//
// static int fake_custom_pl_set(const char *val, const struct kernel_param *kp) {
// size_t len;
//
// len = strnlen(val, STR_MAXLEN + 1);
// if (len == STR_MAXLEN + 1) {
// pr_err("%s: string parameter too long\n", kp->name);
// return -ENOSPC;
// }
//
// if (len >= 1 && val[len - 1] == '\n') {
// len--;
// }
//
// uint8_t *const custom_buf = (uint8_t *)custom_fake_buf;
// const char *custom_hex_fake = val;
// size_t custom_hlen = len;
//
// if ((custom_hlen & 1) == 1) {
// return -EINVAL;
// }
//
//
// size_t custom_len = custom_hlen >> 1;
// if (custom_len > MAX_FAKE_SIZE) {
// return -EINVAL;
// }
//
// for (int i = 0; i < custom_len; i++) {
// sscanf(custom_hex_fake + (i << 1), "%2hhx", custom_buf + i);
// }
//
// def_section->fake_custom_pkt_sz = custom_len;
// def_section->fake_custom_pkt = (char *)custom_buf;
//
// return 0;
// }
//
// static int fake_custom_pl_get(char *buffer, const struct kernel_param *kp) {
// int cflen = def_section->fake_custom_pkt_sz;
// const uint8_t *cbf_data = def_section->fake_custom_pkt;
// int bflen = def_section->fake_custom_pkt_sz << 1;
//
// for (int i = 0; i < cflen; i++) {
// sprintf(buffer + (i << 1), "%02x", *((unsigned char *)cbf_data + i));
// }
//
// return bflen;
// }
//
// static const struct kernel_param_ops fake_custom_pl_ops = {
// .set = fake_custom_pl_set,
// .get = fake_custom_pl_get,
// };
//
// module_param_cb(fake_custom_payload, &fake_custom_pl_ops, &def_section->fake_custom_pkt, 0664);

View File

@@ -9,11 +9,13 @@ LDFLAGS :=
KERNEL_BUILDER_MAKEDIR:=/lib/modules/$(shell uname -r)/build
override EXTRA_CFLAGS += -DPKG_VERSION=\"$(PKG_FULLVERSION)\"
.PHONY: kmake kload kunload kreload kclean kmclean xclean
kmake: kmod
kmod:
$(MAKE) -C $(KERNEL_BUILDER_MAKEDIR) M=$(PWD) EXTRA_CFLAGS='-DPKG_VERSION=\"$(PKG_FULLVERSION)\"' modules
$(MAKE) -C $(KERNEL_BUILDER_MAKEDIR) M=$(PWD) EXTRA_CFLAGS='$(EXTRA_CFLAGS)' modules
kload:
insmod kyoutubeUnblock.ko

View File

@@ -1,464 +0,0 @@
#ifndef KERNEL_SPACE
#error "You are trying to compile the kernel module not in the kernel space"
#endif
// Kernel module for youtubeUnblock.
// Build with make kmake
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_acct.h>
#include "mangle.h"
#include "config.h"
#include "utils.h"
#include "logging.h"
#include "args.h"
#if defined(PKG_VERSION)
MODULE_VERSION(PKG_VERSION);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vadim Vetrov <vetrovvd@gmail.com>");
MODULE_DESCRIPTION("Linux kernel module for youtubeUnblock");
static struct socket *rawsocket;
static struct socket *raw6socket;
static int open_raw_socket(void) {
int ret = 0;
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
if (ret < 0) {
lgerror(ret, "Unable to create raw socket\n");
goto err;
}
// That's funny, but this is how it is done in the kernel
// https://elixir.bootlin.com/linux/v3.17.7/source/net/core/sock.c#L916
rawsocket->sk->sk_mark=config.mark;
return 0;
err:
return ret;
}
static void close_raw_socket(void) {
sock_release(rawsocket);
}
static int send_raw_ipv4(const uint8_t *pkt, uint32_t pktlen) {
int ret = 0;
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
struct iphdr *iph;
if ((ret = ip4_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
return ret;
}
struct sockaddr_in daddr = {
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr = {
.s_addr = iph->daddr
}
};
struct msghdr msg;
struct kvec iov;
memset(&msg, 0, sizeof(msg));
iov.iov_base = (__u8 *)pkt;
iov.iov_len = pktlen;
msg.msg_flags = MSG_DONTWAIT;
msg.msg_name = &daddr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
ret = kernel_sendmsg(rawsocket, &msg, &iov, 1, pktlen);
return ret;
}
static int open_raw6_socket(void) {
int ret = 0;
ret = sock_create(AF_INET6, SOCK_RAW, IPPROTO_RAW, &raw6socket);
if (ret < 0) {
lgerror(ret, "Unable to create raw socket\n");
goto err;
}
// That's funny, but this is how it is done in the kernel
// https://elixir.bootlin.com/linux/v3.17.7/source/net/core/sock.c#L916
raw6socket->sk->sk_mark=config.mark;
return 0;
err:
return ret;
}
static void close_raw6_socket(void) {
sock_release(raw6socket);
}
static int send_raw_ipv6(const uint8_t *pkt, uint32_t pktlen) {
int ret = 0;
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
struct ip6_hdr *iph;
if ((ret = ip6_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
return ret;
}
struct sockaddr_in6 daddr = {
.sin6_family = AF_INET6,
/* Always 0 for raw socket */
.sin6_port = 0,
.sin6_addr = iph->ip6_dst
};
struct kvec iov;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
iov.iov_base = (__u8 *)pkt;
iov.iov_len = pktlen;
msg.msg_flags = MSG_DONTWAIT;
msg.msg_name = &daddr;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_control = NULL;
msg.msg_controllen = 0;
ret = kernel_sendmsg(raw6socket, &msg, &iov, 1, pktlen);
return ret;
}
static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
int ret;
if (pktlen > AVAILABLE_MTU) {
lgdebug("The packet is too big and may cause issues!");
NETBUF_ALLOC(buff1, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(buff1)) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
NETBUF_ALLOC(buff2, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(buff2)) {
lgerror(-ENOMEM, "Allocation error");
NETBUF_FREE(buff2);
return -ENOMEM;
}
uint32_t buff1_size = MAX_PACKET_SIZE;
uint32_t buff2_size = MAX_PACKET_SIZE;
if ((ret = tcp_frag(pkt, pktlen, AVAILABLE_MTU-128,
buff1, &buff1_size, buff2, &buff2_size)) < 0) {
goto erret_lc;
}
int sent = 0;
ret = send_raw_socket(buff1, buff1_size);
if (ret >= 0) sent += ret;
else {
goto erret_lc;
}
ret = send_raw_socket(buff2, buff2_size);
if (ret >= 0) sent += ret;
else {
goto erret_lc;
}
NETBUF_FREE(buff1);
NETBUF_FREE(buff2);
return sent;
erret_lc:
NETBUF_FREE(buff1);
NETBUF_FREE(buff2);
return ret;
}
int ipvx = netproto_version(pkt, pktlen);
if (ipvx == IP4VERSION) {
ret = send_raw_ipv4(pkt, pktlen);
} else if (ipvx == IP6VERSION) {
ret = send_raw_ipv6(pkt, pktlen);
} else {
printf("proto version %d is unsupported\n", ipvx);
return -EINVAL;
}
lgtrace_addp("raw_sock_send: %d", ret);
return ret;
}
static int delay_packet_send(const unsigned char *data, unsigned int data_len, unsigned int delay_ms) {
lginfo("delay_packet_send won't work on current youtubeUnblock version");
return send_raw_socket(data, data_len);
}
struct instance_config_t instance_config = {
.send_raw_packet = send_raw_socket,
.send_delayed_packet = delay_packet_send,
};
static int connbytes_pkts(const struct sk_buff *skb) {
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
u_int64_t pkts = 0;
const struct nf_conn_counter *counters;
ct = nf_ct_get(skb, &ctinfo);
if (!ct)
return -1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
const struct nf_conn_acct *acct;
acct = nf_conn_acct_find(ct);
if (!acct)
return -1;
counters = acct->counter;
#else
counters = nf_conn_acct_find(ct);
if (!counters)
return -1;
#endif
pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
return pkts;
}
/* If this is a Red Hat-based kernel (Red Hat, CentOS, Fedora, etc)... */
#ifdef RHEL_RELEASE_CODE
#if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 2)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
const struct nf_hook_state *state) \
#elif RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#else
#error "Sorry; this version of RHEL is not supported because it's kind of old."
#endif /* RHEL_RELEASE_CODE >= x */
/* If this NOT a RedHat-based kernel (Ubuntu, Debian, SuSE, etc)... */
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
void *priv, \
struct sk_buff *skb, \
const struct nf_hook_state *state)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct nf_hook_state *state)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
unsigned int hooknum, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#else
#error "Linux < 3.0 isn't supported at all."
#endif /* LINUX_VERSION_CODE > n */
#endif /* RHEL or not RHEL */
static NF_CALLBACK(ykb_nf_hook, skb) {
int ret;
if ((skb->mark & config.mark) == config.mark)
goto accept;
if (skb->head == NULL)
goto accept;
if (skb->len > MAX_PACKET_SIZE)
goto accept;
if (config.connbytes_limit != 0 && connbytes_pkts(skb) > config.connbytes_limit)
goto accept;
ret = skb_linearize(skb);
if (ret < 0) {
lgerror(ret, "Cannot linearize");
goto accept;
}
int vrd = process_packet(skb->data, skb->len);
switch(vrd) {
case PKT_ACCEPT:
goto accept;
case PKT_DROP:
goto drop;
}
accept:
return NF_ACCEPT;
drop:
kfree_skb(skb);
return NF_STOLEN;
}
static struct nf_hook_ops ykb_nf_reg __read_mostly = {
.hook = ykb_nf_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_MANGLE,
};
static struct nf_hook_ops ykb6_nf_reg __read_mostly = {
.hook = ykb_nf_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP6_PRI_MANGLE,
};
static int __init ykb_init(void) {
int ret = 0;
ret = init_config(&config);
if (ret < 0) goto err;
ret = open_raw_socket();
if (ret < 0) goto err;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
struct net *n;
for_each_net(n) {
ret = nf_register_net_hook(n, &ykb_nf_reg);
if (ret < 0) {
lgerror(ret, "register net_hook");
}
}
#else
ret = nf_register_hook(&ykb_nf_reg);
if (ret < 0) {
lgerror(ret, "register net_hook");
}
#endif
if (config.use_ipv6) {
ret = open_raw6_socket();
if (ret < 0) {
config.use_ipv6 = 0;
lgwarning("ipv6 disabled!");
goto ipv6_fallback;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
struct net *n;
for_each_net(n) {
ret = nf_register_net_hook(n, &ykb6_nf_reg);
if (ret < 0) {
lgerror(ret, "register net6_hook");
}
}
#else
ret = nf_register_hook(&ykb6_nf_reg);
if (ret < 0) {
lgerror(ret, "register net6_hook");
}
#endif
}
ipv6_fallback:
lginfo("youtubeUnblock kernel module started.\n");
return 0;
err:
return ret;
}
static void __exit ykb_destroy(void) {
if (config.use_ipv6) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
struct net *n;
for_each_net(n)
nf_unregister_net_hook(n, &ykb6_nf_reg);
#else
nf_unregister_hook(&ykb6_nf_reg);
#endif
close_raw6_socket();
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
struct net *n;
for_each_net(n)
nf_unregister_net_hook(n, &ykb_nf_reg);
#else
nf_unregister_hook(&ykb_nf_reg);
#endif
close_raw_socket();
free_config(config);
lginfo("youtubeUnblock kernel module destroyed.\n");
}
module_init(ykb_init);
module_exit(ykb_destroy);

View File

@@ -1,70 +0,0 @@
#ifndef LOGGING_H
#define LOGGING_H
#include "config.h"
#define LOG_LEVEL (config.verbose)
#ifdef KERNEL_SPACE
#include <linux/kernel.h>
#include <linux/module.h>
#define printf pr_info
#define perror pr_err
#define LOG_ERR KERN_ERR
#define LOG_INFO KERN_INFO
#define LOG_WARN KERN_WARNING
#define log_message(level, msg, ...) \
(printk(level msg, ##__VA_ARGS__))
#define lgerror(ret, msg, ...) \
(log_message(LOG_ERR, msg ": %d\n", ##__VA_ARGS__, ret))
#else
#include <stdio.h> // IWYU pragma: export
#include <errno.h>
#include <syslog.h>
#define log_message(level, msg, ...) \
(config.syslog ? (void)(syslog((level), msg, ##__VA_ARGS__)) : (void)(printf(msg, ##__VA_ARGS__)))
#define lgerror(ret, msg, ...) __extension__ ({ \
errno = -(ret); \
log_message(LOG_ERR, msg ": %s\n", ##__VA_ARGS__, strerror(errno)); \
})
#endif /* PROGRAM_SPACE */
#define lgerr(msg, ...) \
(log_message(LOG_ERR, msg, ##__VA_ARGS__))
#define lgwarning(msg, ...) \
(log_message(LOG_WARN, msg, ##__VA_ARGS__))
#define lginfo(msg, ...) \
(log_message(LOG_INFO, msg, ##__VA_ARGS__))
#define print_message(...) \
(lginfo(__VA_ARGS__))
#define lgdebug(msg, ...) \
(LOG_LEVEL >= VERBOSE_DEBUG ? log_message(LOG_INFO, msg, ##__VA_ARGS__) : (void)0)
#define lgdebugmsg(msg, ...) lgdebug(msg "\n", ##__VA_ARGS__)
#define lgtrace(msg, ...) \
(LOG_LEVEL >= VERBOSE_TRACE ? log_message(LOG_INFO, msg, ##__VA_ARGS__) : (void)0)
#define lgtracemsg(msg, ...) lgtrace(msg "\n", __VA_ARGS__)
#define lgtrace_start(msg, ...) \
(LOG_LEVEL >= VERBOSE_TRACE ? log_message(LOG_INFO, "[TRACE] " msg " ( ", ##__VA_ARGS__) : (void)0)
#define lgtrace_addp(msg, ...) \
(LOG_LEVEL >= VERBOSE_TRACE ? log_message(LOG_INFO, msg", ", ##__VA_ARGS__) : (void)0)
#define lgtrace_end() \
(LOG_LEVEL >= VERBOSE_TRACE ? log_message(LOG_INFO, ") \n") : (void)0)
#endif /* LOGGING_H */

View File

@@ -1,58 +0,0 @@
#ifndef YU_MANGLE_H
#define YU_MANGLE_H
#include "types.h"
#include "tls.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 uint8_t *packet, uint32_t packet_len);
/**
* Processe the TCP packet.
* Returns verdict.
*/
int process_tcp_packet(const struct section_config_t *section, const uint8_t *raw_payload, uint32_t raw_payload_len);
/**
* Processes the UDP packet.
* Returns verdict.
*/
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, uint32_t pktlen);
/**
* Sends fake client hello.
*/
int post_fake_sni(struct fake_type f_type,
const void *iph, unsigned int iph_len,
const struct tcphdr *tcph, unsigned int tcph_len);
/**
* Splits packet by poses and posts.
* Poses are relative to start of TCP payload.
* dvs used internally and should be zero.
*/
int send_tcp_frags(const struct section_config_t *section,
const uint8_t *packet, uint32_t pktlen,
const uint32_t *poses, uint32_t poses_len, uint32_t dvs);
/**
* Splits packet by poses and posts.
* Poses are relative to start of TCP payload.
* dvs used internally and should be zero.
*/
int send_ip4_frags(const struct section_config_t *section,
const uint8_t *packet, uint32_t pktlen,
const uint32_t *poses, uint32_t poses_len, uint32_t dvs);
#endif /* YU_MANGLE_H */

321
quic.c
View File

@@ -1,321 +0,0 @@
#include "quic.h"
#include "logging.h"
/**
* Packet number.
*/
struct quic_pnumber {
uint8_t d1;
uint8_t d2;
uint8_t d3;
uint8_t d4;
};
uint64_t quic_parse_varlength(uint8_t *variable, uint64_t *mlen) {
if (mlen && *mlen == 0) return 0;
uint64_t vr = (*variable & 0x3F);
uint8_t len = 1 << (*variable >> 6);
if (mlen) {
if (*mlen < len) return 0;
*mlen = len;
}
++variable;
for (uint8_t i = 1; i < len; i++) {
vr = (vr << 8) + *variable;
++variable;
}
return vr;
}
int quic_parse_data(uint8_t *raw_payload, uint32_t raw_payload_len,
struct quic_lhdr **qch, uint32_t *qch_len,
struct quic_cids *qci,
uint8_t **payload, uint32_t *plen) {
if ( raw_payload == NULL ||
raw_payload_len < sizeof(struct quic_lhdr))
goto invalid_packet;
struct quic_lhdr *nqch = (struct quic_lhdr *)raw_payload;
uint32_t left_len = raw_payload_len - sizeof(struct quic_lhdr);
uint8_t *cur_rawptr = raw_payload + sizeof(struct quic_lhdr);
if (!nqch->fixed) {
lgtrace_addp("quic fixed unset");
return -EPROTO;
}
uint8_t found = 0;
for (uint8_t i = 0; i < 2; i++) {
if (ntohl(nqch->version) == supported_versions[i]) {
found = 1;
}
}
if (!found) {
lgtrace_addp("quic version undefined %d", ntohl(nqch->version));
return -EPROTO;
}
lgtrace_addp("quic version valid %d", ntohl(nqch->version));
if (left_len < 2) goto invalid_packet;
struct quic_cids nqci = {0};
nqci.dst_len = *cur_rawptr++;
left_len--;
if (left_len < nqci.dst_len) goto invalid_packet;
nqci.dst_id = cur_rawptr;
cur_rawptr += nqci.dst_len;
left_len -= nqci.dst_len;
nqci.src_len = *cur_rawptr++;
left_len--;
if (left_len < nqci.src_len) goto invalid_packet;
nqci.src_id = cur_rawptr;
cur_rawptr += nqci.src_len;
left_len -= nqci.src_len;
if (qch) *qch = nqch;
if (qch_len) {
*qch_len = sizeof(struct quic_lhdr) +
nqci.src_len + nqci.dst_len;
}
if (qci) *qci = nqci;
if (payload) *payload = cur_rawptr;
if (plen) *plen = left_len;
return 0;
invalid_packet:
return -EINVAL;
}
int quic_parse_initial_message(uint8_t *inpayload, uint32_t inplen,
const struct quic_lhdr *qch,
struct quici_hdr *qhdr,
uint8_t **payload, uint32_t *plen) {
if (inplen < 3) goto invalid_packet;
struct quici_hdr nqhdr;
uint8_t *cur_ptr = inpayload;
uint32_t left_len = inplen;
uint64_t tlen = left_len;
nqhdr.token_len = quic_parse_varlength(cur_ptr, &tlen);
nqhdr.token = cur_ptr + tlen;
if (left_len < nqhdr.token_len + tlen)
goto invalid_packet;
cur_ptr += tlen + nqhdr.token_len;
left_len -= tlen + nqhdr.token_len;
tlen = left_len;
nqhdr.length = quic_parse_varlength(cur_ptr, &tlen);
if (left_len != nqhdr.length + tlen &&
left_len <= qch->number_length + 1)
goto invalid_packet;
uint32_t packet_number = 0;
for (uint8_t i = 0; i <= qch->number_length; i++) {
packet_number = (packet_number << 8) + *cur_ptr++;
left_len--;
}
nqhdr.packet_number = packet_number;
if (qhdr) *qhdr = nqhdr;
if (payload) *payload = cur_ptr;
if (plen) *plen = left_len;
return 0;
invalid_packet:
lgerror(-EINVAL, "QUIC invalid Initial packet");
return -EINVAL;
}
int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen) {
void *iph;
uint32_t iph_len;
struct udphdr *udph;
uint8_t *data;
uint32_t dlen;
int ret;
ret = udp_payload_split(payload, *plen,
&iph, &iph_len, &udph,
&data, &dlen);
uint32_t ipxv = netproto_version(payload, *plen);
if (ret < 0) {
return ret;
}
if (strategy.strategy == FAKE_STRAT_TTL) {
lgtrace_addp("Set fake ttl to %d", strategy.faking_ttl);
if (ipxv == IP4VERSION) {
((struct iphdr *)iph)->ttl = strategy.faking_ttl;
} else if (ipxv == IP6VERSION) {
((struct ip6_hdr *)iph)->ip6_hops = strategy.faking_ttl;
} else {
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
return -EINVAL;
}
}
if (ipxv == IP4VERSION) {
((struct iphdr *)iph)->frag_off = 0;
}
set_ip_checksum(iph, iph_len);
if (strategy.strategy == FAKE_STRAT_UDP_CHECK) {
lgtrace_addp("break fake udp checksum");
udph->check += 1;
}
return 0;
}
int gen_fake_udp(struct udp_fake_type type,
const void *ipxh, uint32_t iph_len,
const struct udphdr *udph,
uint8_t *buf, uint32_t *buflen) {
uint32_t data_len = type.fake_len;
if (!ipxh || !udph || !buf || !buflen)
return -EINVAL;
int ipxv = netproto_version(ipxh, iph_len);
if (ipxv == IP4VERSION) {
const struct iphdr *iph = ipxh;
memcpy(buf, iph, iph_len);
struct iphdr *niph = (struct iphdr *)buf;
niph->protocol = IPPROTO_UDP;
} else if (ipxv == IP6VERSION) {
const struct ip6_hdr *iph = ipxh;
iph_len = sizeof(struct ip6_hdr);
memcpy(buf, iph, iph_len);
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_nxt = IPPROTO_UDP;
} else {
return -EINVAL;
}
uint32_t dlen = iph_len + sizeof(struct udphdr) + data_len;
if (*buflen < dlen)
return -ENOMEM;
memcpy(buf + iph_len, udph, sizeof(struct udphdr));
uint8_t *bfdptr = buf + iph_len + sizeof(struct udphdr);
memset(bfdptr, 0, data_len);
if (ipxv == IP4VERSION) {
struct iphdr *niph = (struct iphdr *)buf;
niph->tot_len = htons(dlen);
niph->id = randint();
} else if (ipxv == IP6VERSION) {
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_plen = htons(dlen - iph_len);
}
struct udphdr *nudph = (struct udphdr *)(buf + iph_len);
nudph->len = htons(sizeof(struct udphdr) + data_len);
set_udp_checksum(nudph, buf, iph_len);
udp_fail_packet(type.strategy, buf, &dlen, *buflen);
*buflen = dlen;
return 0;
}
int detect_udp_filtered(const struct section_config_t *section,
const uint8_t *payload, uint32_t plen) {
const void *iph;
uint32_t iph_len;
const struct udphdr *udph;
const uint8_t *data;
uint32_t dlen;
int ret;
ret = udp_payload_split((uint8_t *)payload, plen,
(void **)&iph, &iph_len,
(struct udphdr **)&udph,
(uint8_t **)&data, &dlen);
int udp_dport = ntohs(udph->dest);
lgtrace_addp("UDP dport: %d", udp_dport);
if (ret < 0) {
goto skip;
}
if (section->udp_filter_quic) {
const struct quic_lhdr *qch;
uint32_t qch_len;
struct quic_cids qci;
uint8_t *quic_raw_payload;
uint32_t quic_raw_plen;
lgtrace_addp("QUIC probe");
ret = quic_parse_data((uint8_t *)data, dlen,
(struct quic_lhdr **)&qch, &qch_len, &qci,
&quic_raw_payload, &quic_raw_plen);
if (ret < 0) {
lgtrace_addp("QUIC undefined type");
goto match_port;
}
lgtrace_addp("QUIC detected");
uint8_t qtype = qch->type;
if (qch->version == QUIC_V1)
qtype = quic_convtype_v1(qtype);
else if (qch->version == QUIC_V2)
qtype = quic_convtype_v2(qtype);
if (qtype != QUIC_INITIAL_TYPE) {
lgtrace_addp("QUIC message type: %d", qtype);
goto match_port;
}
lgtrace_addp("QUIC initial message");
goto approve;
}
match_port:
for (int i = 0; i < section->udp_dport_range_len; 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;
}
}
skip:
return 0;
approve:
return 1;
}

141
quic.h
View File

@@ -1,141 +0,0 @@
#ifndef QUIC_H
#define QUIC_H
#include "types.h"
#include "utils.h"
/**
* @macro
*
* :macro:`NGTCP2_INITIAL_SALT_V1` is a salt value which is used to
* derive initial secret. It is used for QUIC v1.
*/
#define QUIC_INITIAL_SALT_V1 \
"\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17\x9a\xe6\xa4\xc8\x0c\xad" \
"\xcc\xbb\x7f\x0a"
/**
* @macro
*
* :macro:`NGTCP2_INITIAL_SALT_V2` is a salt value which is used to
* derive initial secret. It is used for QUIC v2.
*/
#define QUIC_INITIAL_SALT_V2 \
"\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb" \
"\xf9\xbd\x2e\xd9"
#define QUIC_INITIAL_TYPE 0
#define QUIC_0_RTT_TYPE 1
#define QUIC_HANDSHAKE_TYPE 2
#define QUIC_RETRY_TYPE 3
#define QUIC_INITIAL_TYPE_V1 0b00
#define QUIC_0_RTT_TYPE_V1 0b01
#define QUIC_HANDSHAKE_TYPE_V1 0b10
#define QUIC_RETRY_TYPE_V1 0b11
#define quic_convtype_v1(type) (type)
#define QUIC_INITIAL_TYPE_V2 0b01
#define QUIC_0_RTT_TYPE_V2 0b10
#define QUIC_HANDSHAKE_TYPE_V2 0b11
#define QUIC_RETRY_TYPE_V2 0b00
#define quic_convtype_v2(type) (((type) + 1) & 0b11)
#define QUIC_V1 1 // RFC 9000
#define QUIC_V2 0x6b3343cf // RFC 9369
static const uint32_t supported_versions[] = {
QUIC_V1,
QUIC_V2,
};
/**
* Quic Large Header
*/
struct quic_lhdr {
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t number_length:2;
uint8_t reserved:2;
uint8_t type:2;
uint8_t fixed:1;
uint8_t form:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t form:1;
uint8_t fixed:1;
uint8_t type:2;
uint8_t reserved:2;
uint8_t number_length:2;
#else
#error "Undefined endian"
#endif
uint32_t version;
}__attribute__((packed));
/**
* Quic Large Header Ids
* (separated from the original header because of varying dst
*/
struct quic_cids {
uint8_t dst_len;
uint8_t *dst_id;
uint8_t src_len;
uint8_t *src_id;
};
/**
* Parses QUIС raw data (UDP payload) to quic large header and
* quic payload.
*
* \qch_len is sizeof(qch) + qci->dst_len + qci->src_id
* \payload is Type-Specific payload (#17.2).
*/
int quic_parse_data(uint8_t *raw_payload, uint32_t raw_payload_len,
struct quic_lhdr **qch, uint32_t *qch_len,
struct quic_cids *qci,
uint8_t **payload, uint32_t *plen);
/**
* Parses QUIC variable-length integer. (#16)
* \variable is a pointer to the sequence to be parsed
* (varlen integer in big endian format)
*
* \mlen Used to signal about variable length and validate left length
* in the buffer.
*/
uint64_t quic_parse_varlength(uint8_t *variable, uint64_t *mlen);
// quici stands for QUIC Initial
/**
* This structure should be parsed
*/
struct quici_hdr {
uint64_t token_len;
uint8_t *token;
uint64_t length;
uint32_t packet_number;
};
/**
* Parses QUIC initial payload.
* \inpayload is a raw QUIC payload (payload after quic large header)
*/
int quic_parse_initial_message(uint8_t *inpayload, uint32_t inplen,
const struct quic_lhdr *qch,
struct quici_hdr *qhdr,
uint8_t **payload, uint32_t *plen);
// Like fail_packet for TCP
int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen);
// Like gen_fake_sni for TCP
int gen_fake_udp(struct udp_fake_type type,
const void *ipxh, uint32_t iph_len,
const struct udphdr *udph,
uint8_t *buf, uint32_t *buflen);
int detect_udp_filtered(const struct section_config_t *section,
const uint8_t *payload, uint32_t plen);
#endif /* QUIC_H */

View File

@@ -1,3 +1,22 @@
/*
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/>.
*/
#include "config.h"
#include "types.h"
@@ -7,12 +26,26 @@
#include "getopt.h"
#include "raw_replacements.h"
/**
* Logging definitions
*/
char ylgh_buf[LOGGING_BUFSIZE];
size_t ylgh_leftbuf = LOGGING_BUFSIZE;
char *ylgh_curptr = ylgh_buf;
int ylgh_ndnl = 0;
struct logging_config_t logging_conf = default_logging_config_set;
#ifdef KERNEL_SPACE
static int errno = 0;
#define strtol kstrtol
#endif
struct config_t config = default_config_set;
void parse_global_lgconf(const struct config_t *config) {
logging_conf.syslog = config->syslog;
logging_conf.verbose = config->verbose;
logging_conf.instaflush = config->instaflush;
}
static int parse_sni_domains(struct domains_list **dlist, const char *domains_str, size_t domains_strlen) {
// Empty and shouldn't be used
@@ -234,6 +267,7 @@ enum {
OPT_FRAG_SNI_POS,
OPT_FK_WINSIZE,
OPT_TRACE,
OPT_INSTAFLUSH,
OPT_QUIC_DROP,
OPT_SNI_DETECTION,
OPT_NO_IPV6,
@@ -241,10 +275,12 @@ enum {
OPT_PACKET_MARK,
OPT_SYNFAKE,
OPT_SYNFAKE_LEN,
OPT_NO_DPORT_FILTER,
OPT_SEG2DELAY,
OPT_THREADS,
OPT_SILENT,
OPT_NO_GSO,
OPT_NO_CONNTRACK,
OPT_QUEUE_NUM,
OPT_UDP_MODE,
OPT_UDP_FAKE_SEQ_LEN,
@@ -289,10 +325,13 @@ static struct option long_opt[] = {
{"udp-faking-strategy", 1, 0, OPT_UDP_FAKING_STRATEGY},
{"udp-dport-filter", 1, 0, OPT_UDP_DPORT_FILTER},
{"udp-filter-quic", 1, 0, OPT_UDP_FILTER_QUIC},
{"no-dport-filter", 0, 0, OPT_NO_DPORT_FILTER},
{"threads", 1, 0, OPT_THREADS},
{"silent", 0, 0, OPT_SILENT},
{"trace", 0, 0, OPT_TRACE},
{"instaflush", 0, 0, OPT_INSTAFLUSH},
{"no-gso", 0, 0, OPT_NO_GSO},
{"no-conntrack", 0, 0, OPT_NO_CONNTRACK},
{"no-ipv6", 0, 0, OPT_NO_IPV6},
{"daemonize", 0, 0, OPT_DAEMONIZE},
{"noclose", 0, 0, OPT_NOCLOSE},
@@ -349,13 +388,16 @@ void print_usage(const char *argv0) {
printf("\t--udp-fake-len=<size of upd fake>\n");
printf("\t--udp-faking-strategy={checksum|ttl|none}\n");
printf("\t--udp-dport-filter=<5,6,200-500>\n");
printf("\t--udp-filter-quic={disabled|all}\n");
printf("\t--udp-filter-quic={disabled|all|parse}\n");
printf("\t--no-dport-filter\n");
printf("\t--threads=<threads number>\n");
printf("\t--packet-mark=<mark>\n");
printf("\t--connbytes-limit=<pkts>\n");
printf("\t--silent\n");
printf("\t--trace\n");
printf("\t--instaflush\n");
printf("\t--no-gso\n");
printf("\t--no-conntrack\n");
printf("\t--no-ipv6\n");
printf("\t--daemonize\n");
printf("\t--noclose\n");
@@ -365,20 +407,19 @@ void print_usage(const char *argv0) {
printf("\n");
}
int yparse_args(int argc, char *argv[]) {
int yparse_args(struct config_t *config, int argc, char *argv[]) {
int opt;
int optIdx = 0;
optind=1, opterr=1, optreset=0;
long num;
int ret;
struct config_t rep_config;
ret = init_config(&rep_config);
ret = init_config(config);
if (ret < 0)
return ret;
struct section_config_t *default_section = rep_config.last_section;
struct section_config_t *default_section = config->last_section;
struct section_config_t *sect_config = rep_config.last_section;
struct section_config_t *sect_config = config->last_section;
int sect_i = 0;
sect_config->id = sect_i++;
@@ -391,13 +432,13 @@ int yparse_args(int argc, char *argv[]) {
while ((opt = getopt_long(argc, argv, "", long_opt, &optIdx)) != -1) {
switch (opt) {
case OPT_CLS:
free_config(rep_config);
ret = init_config(&rep_config);
free_config(config);
ret = init_config(config);
if (ret < 0)
return ret;
default_section = rep_config.last_section;
default_section = config->last_section;
sect_config = rep_config.last_section;
sect_config = config->last_section;
sect_i = 0;
sect_config->id = sect_i++;
section_iter = SECT_ITER_DEFAULT;
@@ -420,25 +461,49 @@ int yparse_args(int argc, char *argv[]) {
break;
#endif
case OPT_TRACE:
rep_config.verbose = 2;
config->verbose = VERBOSE_TRACE;
break;
case OPT_INSTAFLUSH:
config->instaflush = 1;
break;
case OPT_SILENT:
rep_config.verbose = 0;
config->verbose = VERBOSE_INFO;
break;
case OPT_NO_GSO:
rep_config.use_gso = 0;
#ifndef KERNEL_SPACE
config->use_gso = 0;
#else
lgerr("--no-gso is not supported in kernel space");
goto invalid_opt;
#endif
break;
case OPT_NO_CONNTRACK:
#ifndef KERNEL_SPACE
config->use_conntrack = 0;
#else
lgerr("--no-conntrack is not supported in kernel space. Compile with make kmake EXTRA_CFLAGS=\"-DNO_CONNTRACK\" instead." );
goto invalid_opt;
#endif
break;
case OPT_NO_IPV6:
rep_config.use_ipv6 = 0;
#ifndef KERNEL_SPACE
config->use_ipv6 = 0;
#else
lgerr("--no-ipv6 argument is not available "
"in the kernel module. "
"If you want to disable ipv6, compile with "
"make kmake EXTRA_CFLAGS=\"-DNO_IPV6\".");
goto invalid_opt;
#endif
break;
case OPT_DAEMONIZE:
rep_config.daemonize = 1;
config->daemonize = 1;
break;
case OPT_NOCLOSE:
rep_config.noclose = 1;
config->noclose = 1;
break;
case OPT_SYSLOG:
rep_config.syslog = 1;
config->syslog = 1;
break;
case OPT_THREADS:
num = parse_numeric_option(optarg);
@@ -446,7 +511,7 @@ int yparse_args(int argc, char *argv[]) {
goto invalid_opt;
}
rep_config.threads = num;
config->threads = num;
break;
case OPT_QUEUE_NUM:
num = parse_numeric_option(optarg);
@@ -454,7 +519,7 @@ int yparse_args(int argc, char *argv[]) {
goto invalid_opt;
}
rep_config.queue_start_num = num;
config->queue_start_num = num;
break;
case OPT_PACKET_MARK:
num = parse_numeric_option(optarg);
@@ -462,24 +527,24 @@ int yparse_args(int argc, char *argv[]) {
goto invalid_opt;
}
rep_config.mark = num;
config->mark = num;
break;
case OPT_CONNBYTES_LIMIT:
num = parse_numeric_option(optarg);
if (errno != 0 || num < 0) {
goto invalid_opt;
}
rep_config.connbytes_limit = num;
config->connbytes_limit = num;
break;
case OPT_START_SECTION:
{
struct section_config_t *nsect;
ret = init_section_config(&nsect, rep_config.last_section);
ret = init_section_config(&nsect, config->last_section);
if (ret < 0) {
goto error;
}
rep_config.last_section->next = nsect;
rep_config.last_section = nsect;
config->last_section->next = nsect;
config->last_section = nsect;
sect_config = nsect;
sect_config->id = sect_i++;
section_iter = SECT_ITER_INSIDE;
@@ -655,6 +720,9 @@ int yparse_args(int argc, char *argv[]) {
sect_config->fk_winsize = num;
break;
case OPT_NO_DPORT_FILTER:
sect_config->dport_filter = 0;
break;
case OPT_SEG2DELAY:
num = parse_numeric_option(optarg);
if (errno != 0 || num < 0) {
@@ -745,6 +813,8 @@ int yparse_args(int argc, char *argv[]) {
sect_config->udp_filter_quic = UDP_FILTER_QUIC_DISABLED;
} else if (strcmp(optarg, "all") == 0) {
sect_config->udp_filter_quic = UDP_FILTER_QUIC_ALL;
} else if (strcmp(optarg, "parse") == 0) {
sect_config->udp_filter_quic = UDP_FILTER_QUIC_PARSED;
} else {
goto invalid_opt;
}
@@ -756,16 +826,12 @@ int yparse_args(int argc, char *argv[]) {
}
struct config_t old_config = config;
config = rep_config;
free_config(old_config);
errno = 0;
return 0;
#ifndef KERNEL_SPACE
stop_exec:
free_config(rep_config);
free_config(config);
errno = 0;
return 1;
#endif
@@ -784,7 +850,7 @@ error:
}
errno = -ret;
free_config(rep_config);
free_config(config);
return ret;
}
@@ -803,23 +869,7 @@ static size_t print_config_section(const struct section_config_t *section, char
size_t sz;
if (section->tls_enabled) {
print_cnf_buf("--tls=enabled");
if (section->all_domains) {
print_cnf_buf("--sni-domains=all");
} else if (section->sni_domains != NULL) {
print_cnf_raw("--sni-domains=");
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) {
print_cnf_raw("--exclude-domains=");
for (struct domains_list *sne = section->exclude_sni_domains; sne != NULL; sne = sne->next) {
print_cnf_raw("%s,", sne->domain_name);
}
print_cnf_raw(" ");
}
print_cnf_buf("--tls=enabled");
switch(section->fragmentation_strategy) {
case FRAG_STRAT_IP:
@@ -874,17 +924,7 @@ static size_t print_config_section(const struct section_config_t *section, char
print_cnf_buf("--fake-seq-offset=%d", section->fakeseq_offset);
break;
}
switch(section->sni_detection) {
case SNI_DETECTION_BRUTE:
print_cnf_buf("--sni-detection=brute");
break;
case SNI_DETECTION_PARSE:
print_cnf_buf("--sni-detection=parse");
break;
}
}
print_cnf_buf("--seg2delay=%d", section->seg2_delay);
}
@@ -892,6 +932,33 @@ static size_t print_config_section(const struct section_config_t *section, char
print_cnf_buf("--tls=disabled");
}
if (section->all_domains) {
print_cnf_buf("--sni-domains=all");
} else if (section->sni_domains != NULL) {
print_cnf_raw("--sni-domains=");
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) {
print_cnf_raw("--exclude-domains=");
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) {
case SNI_DETECTION_BRUTE:
print_cnf_buf("--sni-detection=brute");
break;
case SNI_DETECTION_PARSE:
print_cnf_buf("--sni-detection=parse");
break;
}
if (section->synfake) {
print_cnf_buf("--synfake=1");
print_cnf_buf("--synfake-len=%d", section->synfake_len);
@@ -911,6 +978,9 @@ static size_t print_config_section(const struct section_config_t *section, char
case UDP_FILTER_QUIC_DISABLED:
print_cnf_buf("--udp-filter-quic=disabled");
break;
case UDP_FILTER_QUIC_PARSED:
print_cnf_buf("--udp-filter-quic=parse");
break;
}
if (section->udp_dport_range_len != 0) {
@@ -951,53 +1021,63 @@ static size_t print_config_section(const struct section_config_t *section, char
}
}
if (section->dport_filter == 0) {
print_cnf_buf("--no-dport-filter");
}
return buffer_size - buf_sz;
}
// Returns written buffer length
size_t print_config(char *buffer, size_t buffer_size) {
size_t print_config(const struct config_t *config, char *buffer, size_t buffer_size) {
char *buf_ptr = buffer;
size_t buf_sz = buffer_size;
size_t sz;
#ifndef KERNEL_SPACE
print_cnf_buf("--queue-num=%d", config.queue_start_num);
print_cnf_buf("--threads=%d", config.threads);
print_cnf_buf("--queue-num=%d", config->queue_start_num);
print_cnf_buf("--threads=%d", config->threads);
#endif
print_cnf_buf("--packet-mark=%d", config.mark);
print_cnf_buf("--packet-mark=%d", config->mark);
#ifndef KERNEL_SPACE
if (config.daemonize) {
if (config->daemonize) {
print_cnf_buf("--daemonize");
}
if (config.syslog) {
if (config->syslog) {
print_cnf_buf("--syslog");
}
if (config.noclose) {
if (config->noclose) {
print_cnf_buf("--noclose");
}
if (!config.use_gso) {
if (!config->use_gso) {
print_cnf_buf("--no-gso");
}
if (!config->use_conntrack) {
print_cnf_buf("--no-conntrack");
}
#endif
#ifdef KERNEL_SPACE
print_cnf_buf("--connbytes-limit=%d", config.connbytes_limit);
print_cnf_buf("--connbytes-limit=%d", config->connbytes_limit);
#endif
if (!config.use_ipv6) {
if (!config->use_ipv6) {
print_cnf_buf("--no-ipv6");
}
if (config.verbose == VERBOSE_TRACE) {
if (config->verbose == VERBOSE_TRACE) {
print_cnf_buf("--trace");
}
if (config.verbose == VERBOSE_INFO) {
if (config->instaflush) {
print_cnf_buf("--instaflush");
}
if (config->verbose == VERBOSE_INFO) {
print_cnf_buf("--silent");
}
size_t wbuf_len = print_config_section(config.first_section, buf_ptr, buf_sz);
size_t wbuf_len = print_config_section(config->first_section, buf_ptr, buf_sz);
buf_ptr += wbuf_len;
buf_sz -= wbuf_len;
for (struct section_config_t *section = config.first_section->next;
for (struct section_config_t *section = config->first_section->next;
section != NULL; section = section->next) {
print_cnf_buf("--fbegin");
wbuf_len = print_config_section(section, buf_ptr, buf_sz);
@@ -1009,12 +1089,12 @@ size_t print_config(char *buffer, size_t buffer_size) {
return buffer_size - buf_sz;
}
void print_welcome(void) {
void print_welcome(const struct config_t *config) {
char *welcome_message = malloc(4000);
if (welcome_message == NULL)
return;
size_t sz = print_config(welcome_message, 4000);
size_t sz = print_config(config, welcome_message, 4000);
printf("Running with flags: %.*s\n", (int)sz, welcome_message);
free(welcome_message);
}
@@ -1077,8 +1157,8 @@ void free_config_section(struct section_config_t *section) {
free(section);
}
void free_config(struct config_t config) {
for (struct section_config_t *sct = config.last_section; sct != NULL;) {
void free_config(struct config_t *config) {
for (struct section_config_t *sct = config->last_section; sct != NULL;) {
struct section_config_t *psct = sct->prev;
free_config_section(sct);
sct = psct;

46
src/args.h Normal file
View File

@@ -0,0 +1,46 @@
/*
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 ARGS_H
#define ARGS_H
#include "types.h"
#include "config.h"
void print_version(void);
void print_usage(const char *argv0);
/**
* Initializes _config_ and parses args to it.
*/
int yparse_args(struct config_t *config, int argc, char *argv[]);
size_t print_config(const struct config_t *config, char *buffer, size_t buffer_size);
void parse_global_lgconf(const struct config_t *config);
// Initializes configuration storage.
int init_config(struct config_t *config);
// Allocates and initializes configuration section.
int init_section_config(struct section_config_t **section, struct section_config_t *prev);
// Frees configuration section
void free_config_section(struct section_config_t *config);
// Frees sections under config
void free_config(struct config_t *config);
/* Prints starting messages */
void print_welcome(const struct config_t *config);
#endif /* ARGS_H */

View File

@@ -1,3 +1,22 @@
/*
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 YTB_CONFIG_H
#define YTB_CONFIG_H
@@ -7,12 +26,12 @@
#include "types.h"
typedef int (*raw_send_t)(const unsigned char *data, unsigned int data_len);
typedef int (*raw_send_t)(const unsigned char *data, size_t data_len);
/**
* Sends the packet after delay_ms. The function should schedule send and return immediately
* (for example, open daemon thread)
*/
typedef int (*delayed_send_t)(const unsigned char *data, unsigned int data_len, unsigned int delay_ms);
typedef int (*delayed_send_t)(const unsigned char *data, size_t data_len, unsigned int delay_ms);
struct instance_config_t {
raw_send_t send_raw_packet;
@@ -20,6 +39,14 @@ struct instance_config_t {
};
extern struct instance_config_t instance_config;
struct logging_config_t {
int verbose;
int instaflush;
int syslog;
};
extern struct logging_config_t logging_conf;
struct udp_dport_range {
uint16_t start;
uint16_t end;
@@ -73,6 +100,8 @@ struct section_config_t {
unsigned int fk_winsize;
int fakeseq_offset;
int dport_filter;
#define SNI_DETECTION_PARSE 0
#define SNI_DETECTION_BRUTE 1
int sni_detection;
@@ -94,11 +123,13 @@ struct config_t {
int threads;
int use_gso;
int use_ipv6;
int use_conntrack;
unsigned int mark;
int daemonize;
// Same as daemon() noclose
int noclose;
int syslog;
int instaflush;
int connbytes_limit;
@@ -109,9 +140,12 @@ struct config_t {
struct section_config_t *first_section;
struct section_config_t *last_section;
#ifdef KERNEL_SPACE
struct kref refcount;
#endif
};
extern struct config_t config;
#define ITER_CONFIG_SECTIONS(config, section) \
for (struct section_config_t *section = (config)->last_section; section != NULL; section = section->prev)
@@ -185,9 +219,9 @@ if ((fake_bitmask) & strategy)
#define DEFAULT_QUEUE_NUM 537
#define MAX_PACKET_SIZE 8192
#define MAX_PACKET_SIZE (1 << 16)
#define DEFAULT_SNISTR "googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com"
#define DEFAULT_SNISTR "googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,youtubei.googleapis.com,youtube.googleapis.com,youtubeembeddedplayer.googleapis.com,googleusercontent.com,gstatic.com,l.google.com"
static const char default_snistr[] = DEFAULT_SNISTR;
@@ -199,6 +233,7 @@ enum {
enum {
UDP_FILTER_QUIC_DISABLED,
UDP_FILTER_QUIC_ALL,
UDP_FILTER_QUIC_PARSED,
};
#define default_section_config { \
@@ -222,6 +257,7 @@ enum {
.synfake = 0, \
.synfake_len = 0, \
\
.dport_filter = 1, \
.seg2_delay = 0, \
\
.sni_detection = SNI_DETECTION_PARSE, \
@@ -248,6 +284,7 @@ enum {
\
.verbose = VERBOSE_DEBUG, \
.use_gso = 1, \
.use_conntrack = 1, \
\
.first_section = NULL, \
.last_section = NULL, \
@@ -255,11 +292,51 @@ enum {
.daemonize = 0, \
.noclose = 0, \
.syslog = 0, \
.instaflush = 0, \
}
#define CONFIG_SET(config) \
struct config_t config = default_config_set; \
config->last_section = &(config.default_config) \
#define default_logging_config_set { \
.verbose = VERBOSE_DEBUG, \
.syslog = 0, \
.instaflush = 0, \
}
struct ytb_conntrack {
uint32_t mask;
uint64_t orig_packets;
uint64_t repl_packets;
uint64_t orig_bytes;
uint64_t repl_bytes;
uint32_t connmark;
uint32_t id;
};
enum yct_attrs {
YCTATTR_ORIG_PACKETS,
YCTATTR_REPL_PACKETS,
YCTATTR_ORIG_BYTES,
YCTATTR_REPL_BYTES,
YCTATTR_CONNMARK,
YCTATTR_CONNID,
};
/* enum yct_attrs attr, struct ytb_conntrack * yct */
#define yct_set_mask_attr(attr, yct) \
((yct)->mask |= (1 << (attr)))
/* enum yct_attrs attr, const struct ytb_conntrack * yct */
#define yct_is_mask_attr(attr, yct) \
(((yct)->mask & (1 << (attr))) == (1 << (attr)))
/* enum yct_attrs attr, struct ytb_conntrack * yct */
#define yct_del_mask_attr(attr, yct) \
(yct)->mask &= ~(1 << (attr))
struct packet_data {
const uint8_t *payload;
size_t payload_len;
struct ytb_conntrack yct;
};
#endif /* YTB_CONFIG_H */

View File

@@ -1,3 +1,27 @@
/*
Copyright 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "types.h"
#include "logging.h"
#include "getopt.h"
@@ -9,7 +33,7 @@ int optind=1, opterr=1, optopt, __optpos, optreset=0;
static void __getopt_msg(const char *b, const char *c, size_t l)
{
lgerr("%s %.*s\n", b, (int)l, c);
lgerr("%s %.*s", b, (int)l, c);
}
int getopt(int argc, char * const argv[], const char *optstring)

78
src/inet_ntop.c Normal file
View File

@@ -0,0 +1,78 @@
/**
musl libc
musl, pronounced like the word "mussel", is an MIT-licensed
implementation of the standard C library targetting the Linux syscall
API, suitable for use in a wide range of deployment environments. musl
offers efficient static and dynamic linking support, lightweight code
and low runtime overhead, strong fail-safe guarantees under correct
usage, and correctness in the sense of standards conformance and
safety. musl is built on the principle that these goals are best
achieved through simple code that is easy to understand and maintain.
The 1.1 release series for musl features coverage for all interfaces
defined in ISO C99 and POSIX 2008 base, along with a number of
non-standardized interfaces for compatibility with Linux, BSD, and
glibc functionality.
For basic installation instructions, see the included INSTALL file.
Information on full musl-targeted compiler toolchains, system
bootstrapping, and Linux distributions built on musl can be found on
the project website:
http://www.musl-libc.org/
*/
#include "types.h"
// #ifndef KERNEL_SPACE
// #error "For user space use glibc inet_ntop"
// #endif
const char *inet_ntop(int af, const void *restrict a0, char *restrict s, socklen_t l)
{
const unsigned char *a = a0;
int i, j, max, best;
char buf[100];
switch (af) {
case AF_INET:
if (snprintf(s, l, "%d.%d.%d.%d", a[0],a[1],a[2],a[3]) < l)
return s;
break;
case AF_INET6:
if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12))
snprintf(buf, sizeof buf,
"%x:%x:%x:%x:%x:%x:%x:%x",
256*a[0]+a[1],256*a[2]+a[3],
256*a[4]+a[5],256*a[6]+a[7],
256*a[8]+a[9],256*a[10]+a[11],
256*a[12]+a[13],256*a[14]+a[15]);
else
snprintf(buf, sizeof buf,
"%x:%x:%x:%x:%x:%x:%d.%d.%d.%d",
256*a[0]+a[1],256*a[2]+a[3],
256*a[4]+a[5],256*a[6]+a[7],
256*a[8]+a[9],256*a[10]+a[11],
a[12],a[13],a[14],a[15]);
/* Replace longest /(^0|:)[:0]{2,}/ with "::" */
for (i=best=0, max=2; buf[i]; i++) {
if (i && buf[i] != ':') continue;
j = strspn(buf+i, ":0");
if (j>max) best=i, max=j;
}
if (max>3) {
buf[best] = buf[best+1] = ':';
memmove(buf+best+2, buf+best+max, i-best-max+1);
}
if (strlen(buf) < l) {
strcpy(s, buf);
return s;
}
break;
default:
return 0;
}
return 0;
}

660
src/kytunblock.c Normal file
View File

@@ -0,0 +1,660 @@
/*
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 KERNEL_SPACE
#error "You are trying to compile the kernel module not in the kernel space"
#endif
// Kernel module for youtubeUnblock.
// Build with make kmake
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#ifdef IS_ENABLED
#if !(IS_ENABLED(CONFIG_NF_CONNTRACK))
#define NO_CONNTRACK
#endif /* IS CONNTRACK ENABLED */
#endif /* ifdef IS_ENABLED */
#ifndef NO_CONNTRACK
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_acct.h>
#endif
#include "mangle.h"
#include "config.h"
#include "utils.h"
#include "logging.h"
#include "args.h"
#if defined(PKG_VERSION)
MODULE_VERSION(PKG_VERSION);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vadim Vetrov <vetrovvd@gmail.com>");
MODULE_DESCRIPTION("Linux kernel module for youtubeUnblock");
static struct socket *rawsocket;
static struct socket *raw6socket;
#define MAX_ARGC 1024
static char *argv[MAX_ARGC];
static struct config_t *cur_config;
static void config_release(struct kref *ref)
{
struct config_t *config = container_of(ref, struct config_t, refcount);
free_config(config);
kfree(config);
pr_warn("Config release\n");
}
static int params_set(const char *cval, const struct kernel_param *kp) {
int ret;
int cv_len = strlen(cval);
if (cv_len >= 1 && cval[cv_len - 1] == '\n') {
cv_len--;
}
const char *ytb_prefix = "youtubeUnblock ";
int ytbp_len = strlen(ytb_prefix);
int len = cv_len + ytbp_len;
char *val = kmalloc(len + 1, GFP_KERNEL); // 1 for null-terminator
strncpy(val, ytb_prefix, ytbp_len);
strncpy(val + ytbp_len, cval, cv_len);
val[len] = '\0';
int argc = 0;
argv[argc++] = val;
for (int i = 0; i < len; i++) {
if (val[i] == ' ') {
val[i] = '\0';
// safe because of null-terminator
if (val[i + 1] != ' ' && val[i + 1] != '\0') {
argv[argc++] = val + i + 1;
}
}
}
struct config_t *config;
config = kmalloc(sizeof(*config), GFP_KERNEL);
if (!config) {
ret = -ENOMEM;
goto ret_fval;
}
ret = yparse_args(config, argc, argv);
if (ret < 0) {
kfree(config);
goto ret_fval;
}
kref_init(&config->refcount);
struct config_t *old_config = cur_config;
cur_config = config;
parse_global_lgconf(cur_config);
kref_put(&old_config->refcount, config_release);
ret_fval:
kfree(val);
return ret;
}
static int params_get(char *buffer, const struct kernel_param *kp) {
size_t len = print_config(cur_config, buffer, 4000);
return len;
}
static const struct kernel_param_ops params_ops = {
.set = params_set,
.get = params_get,
};
module_param_cb(parameters, &params_ops, NULL, 0664);
static int open_raw_socket(void) {
int ret = 0;
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
if (ret < 0) {
lgerror(ret, "Unable to create raw socket\n");
goto err;
}
// That's funny, but this is how it is done in the kernel
// https://elixir.bootlin.com/linux/v3.17.7/source/net/core/sock.c#L916
rawsocket->sk->sk_mark=cur_config->mark;
return 0;
err:
return ret;
}
static void close_raw_socket(void) {
sock_release(rawsocket);
rawsocket = NULL;
}
static int send_raw_ipv4(const uint8_t *pkt, size_t pktlen) {
int ret = 0;
if (rawsocket == NULL) {
return -ENOTSOCK;
}
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
struct iphdr *iph;
if ((ret = ip4_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
return ret;
}
struct sockaddr_in daddr = {
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr = {
.s_addr = iph->daddr
}
};
struct msghdr msg;
struct kvec iov;
memset(&msg, 0, sizeof(msg));
iov.iov_base = (__u8 *)pkt;
iov.iov_len = pktlen;
msg.msg_flags = MSG_DONTWAIT;
msg.msg_name = &daddr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
ret = kernel_sendmsg(rawsocket, &msg, &iov, 1, pktlen);
return ret;
}
static int open_raw6_socket(void) {
int ret = 0;
ret = sock_create(AF_INET6, SOCK_RAW, IPPROTO_RAW, &raw6socket);
if (ret < 0) {
lgerror(ret, "Unable to create raw socket\n");
goto err;
}
// That's funny, but this is how it is done in the kernel
// https://elixir.bootlin.com/linux/v3.17.7/source/net/core/sock.c#L916
raw6socket->sk->sk_mark=cur_config->mark;
return 0;
err:
return ret;
}
static void close_raw6_socket(void) {
sock_release(raw6socket);
raw6socket = NULL;
}
static int send_raw_ipv6(const uint8_t *pkt, size_t pktlen) {
int ret = 0;
if (raw6socket == NULL) {
return -ENOTSOCK;
}
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
struct ip6_hdr *iph;
if ((ret = ip6_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
return ret;
}
struct sockaddr_in6 daddr = {
.sin6_family = AF_INET6,
/* Always 0 for raw socket */
.sin6_port = 0,
.sin6_addr = iph->ip6_dst
};
struct kvec iov;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
iov.iov_base = (__u8 *)pkt;
iov.iov_len = pktlen;
msg.msg_flags = MSG_DONTWAIT;
msg.msg_name = &daddr;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_control = NULL;
msg.msg_controllen = 0;
ret = kernel_sendmsg(raw6socket, &msg, &iov, 1, pktlen);
return ret;
}
static int send_raw_socket(const uint8_t *pkt, size_t pktlen) {
int ret;
if (pktlen > AVAILABLE_MTU) {
lgtrace("Split packet!");
size_t buff1_size = pktlen;
uint8_t *buff1 = malloc(buff1_size);
if (buff1 == NULL) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
size_t buff2_size = pktlen;
uint8_t *buff2 = malloc(buff2_size);
if (buff2 == NULL) {
lgerror(-ENOMEM, "Allocation error");
free(buff1);
return -ENOMEM;
}
if ((ret = tcp_frag(pkt, pktlen, AVAILABLE_MTU-128,
buff1, &buff1_size, buff2, &buff2_size)) < 0) {
goto erret_lc;
}
int sent = 0;
ret = send_raw_socket(buff1, buff1_size);
if (ret >= 0) sent += ret;
else {
goto erret_lc;
}
ret = send_raw_socket(buff2, buff2_size);
if (ret >= 0) sent += ret;
else {
goto erret_lc;
}
free(buff1);
free(buff2);
return sent;
erret_lc:
free(buff1);
free(buff2);
return ret;
}
int ipvx = netproto_version(pkt, pktlen);
if (ipvx == IP4VERSION) {
ret = send_raw_ipv4(pkt, pktlen);
} else if (ipvx == IP6VERSION) {
ret = send_raw_ipv6(pkt, pktlen);
} else {
printf("proto version %d is unsupported\n", ipvx);
return -EINVAL;
}
lgtrace_addp("raw_sock_send: %d", ret);
return ret;
}
static int delay_packet_send(const unsigned char *data, size_t data_len, unsigned int delay_ms) {
lginfo("delay_packet_send won't work on current youtubeUnblock version");
return send_raw_socket(data, data_len);
}
struct instance_config_t instance_config = {
.send_raw_packet = send_raw_socket,
.send_delayed_packet = delay_packet_send,
};
static int conntrack_parse(const struct sk_buff *skb,
struct ytb_conntrack *yct) {
#ifndef NO_CONNTRACK
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_conn_counter *counters;
ct = nf_ct_get(skb, &ctinfo);
if (!ct)
return -1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
const struct nf_conn_acct *acct;
acct = nf_conn_acct_find(ct);
if (!acct)
return -1;
counters = acct->counter;
#else
counters = nf_conn_acct_find(ct);
if (!counters)
return -1;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
yct->orig_packets = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
yct->orig_bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
yct->repl_packets = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
yct->repl_bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
#else
yct->orig_packets = counters[IP_CT_DIR_ORIGINAL].packets;
yct->orig_bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
yct->repl_packets = counters[IP_CT_DIR_REPLY].packets;
yct->repl_bytes = counters[IP_CT_DIR_REPLY].bytes;
#endif
yct_set_mask_attr(YCTATTR_ORIG_PACKETS, yct);
yct_set_mask_attr(YCTATTR_ORIG_BYTES, yct);
yct_set_mask_attr(YCTATTR_REPL_PACKETS, yct);
yct_set_mask_attr(YCTATTR_REPL_BYTES, yct);
#if defined(CONFIG_NF_CONNTRACK_MARK)
yct->connmark = READ_ONCE(ct->mark);
yct_set_mask_attr(YCTATTR_CONNMARK, yct);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
yct->id = nf_ct_get_id(ct);
yct_set_mask_attr(YCTATTR_CONNID, yct);
#endif
#endif /* NO_CONNTRACK */
return 0;
}
/* If this is a Red Hat-based kernel (Red Hat, CentOS, Fedora, etc)... */
#ifdef RHEL_RELEASE_CODE
#if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 2)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
const struct nf_hook_state *state) \
#elif RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#else
#error "Sorry; this version of RHEL is not supported because it's kind of old."
#endif /* RHEL_RELEASE_CODE >= x */
/* If this NOT a RedHat-based kernel (Ubuntu, Debian, SuSE, etc)... */
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
void *priv, \
struct sk_buff *skb, \
const struct nf_hook_state *state)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct nf_hook_state *state)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
const struct nf_hook_ops *ops, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
#define NF_CALLBACK(name, skb) unsigned int name( \
unsigned int hooknum, \
struct sk_buff *skb, \
const struct net_device *in, \
const struct net_device *out, \
int (*okfn)(struct sk_buff *))
#else
#error "Linux < 3.0 isn't supported at all."
#endif /* LINUX_VERSION_CODE > n */
#endif /* RHEL or not RHEL */
static NF_CALLBACK(ykb_nf_hook, skb) {
int ret;
struct packet_data pd = {0};
uint8_t *data_buf = NULL;
int nf_verdict = NF_ACCEPT;
struct config_t *config = cur_config;
kref_get(&config->refcount);
if ((skb->mark & config->mark) == config->mark) {
goto send_verdict;
}
if (skb->head == NULL) {
goto send_verdict;
}
if (skb->len >= MAX_PACKET_SIZE) {
goto send_verdict;
}
ret = conntrack_parse(skb, &pd.yct);
if (ret < 0) {
lgtrace("[TRACE] conntrack_parse error code\n");
}
if (config->connbytes_limit != 0 && yct_is_mask_attr(YCTATTR_ORIG_PACKETS, &pd.yct) && pd.yct.orig_packets > config->connbytes_limit)
goto send_verdict;
if (skb_is_nonlinear(skb)) {
data_buf = kmalloc(skb->len, GFP_KERNEL);
if (data_buf == NULL) {
lgerror(-ENOMEM, "Cannot allocate packet buffer");
}
ret = skb_copy_bits(skb, 0, data_buf, skb->len);
if (ret) {
lgerror(ret, "Cannot copy bits");
goto send_verdict;
}
pd.payload = data_buf;
} else {
pd.payload = skb->data;
}
pd.payload_len = skb->len;
int vrd = process_packet(config, &pd);
switch(vrd) {
case PKT_ACCEPT:
nf_verdict = NF_ACCEPT;
break;
case PKT_DROP:
nf_verdict = NF_STOLEN;
kfree_skb(skb);
break;
}
send_verdict:
kfree(data_buf);
kref_put(&config->refcount, config_release);
return nf_verdict;
}
static struct nf_hook_ops ykb_hook_ops[] = {
{
.hook = ykb_nf_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_MANGLE,
}
#ifndef NO_IPV6
,{
.hook = ykb_nf_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP6_PRI_MANGLE,
}
#endif
};
static const size_t ykb_hooks_sz = sizeof(ykb_hook_ops) / sizeof(struct nf_hook_ops);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
static int ykb_net_init(struct net *net)
{
int ret;
ret = nf_register_net_hooks(net, ykb_hook_ops, ykb_hooks_sz);
if (ret < 0)
return ret;
return 0;
}
static void ykb_net_exit(struct net *net)
{
nf_unregister_net_hooks(net, ykb_hook_ops, ykb_hooks_sz);
}
static struct pernet_operations ykb_pernet_ops = {
.init = ykb_net_init,
.exit = ykb_net_exit
};
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */
static int __init ykb_init(void) {
int ret;
#ifdef NO_CONNTRACK
lgwarning("Conntrack is disabled.");
#endif
#ifdef NO_IPV6
lgwarning("IPv6 is disabled.");
#endif
cur_config = kmalloc(sizeof(*cur_config), GFP_KERNEL);
if (!cur_config) {
return -ENOMEM;
}
ret = init_config(cur_config);
if (ret < 0) {
kfree(cur_config);
goto err;
}
kref_init(&cur_config->refcount);
ret = open_raw_socket();
if (ret < 0) {
lgerror(ret, "ipv4 rawsocket initialization failed!");
goto err_config;
}
#ifndef NO_IPV6
ret = open_raw6_socket();
if (ret < 0) {
lgerror(ret, "ipv6 rawsocket initialization failed!");
goto err_close4_sock;
}
#endif /* NO_IPV6 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
ret = register_pernet_subsys(&ykb_pernet_ops);
#else
ret = nf_register_hooks(ykb_hook_ops, ykb_hooks_sz);
#endif
if (ret < 0)
goto err_close_sock;
lginfo("youtubeUnblock kernel module started.\n");
return 0;
err_close_sock:
#ifndef NO_IPV6
close_raw6_socket();
#endif
err_close4_sock:
close_raw_socket();
err_config:
kref_put(&cur_config->refcount, config_release);
err:
return ret;
}
static void __exit ykb_destroy(void) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
unregister_pernet_subsys(&ykb_pernet_ops);
#else
nf_unregister_hooks(ykb_hook_ops, ykb_hooks_sz);
#endif
#ifndef NO_IPV6
close_raw6_socket();
#endif
close_raw_socket();
kref_put(&cur_config->refcount, config_release);
lginfo("youtubeUnblock kernel module destroyed.\n");
}
module_init(ykb_init);
module_exit(ykb_destroy);

151
src/logging.h Normal file
View File

@@ -0,0 +1,151 @@
/*
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 LOGGING_H
#define LOGGING_H
#include "config.h"
/**
* Defined in args.c
*/
#define LOGGING_BUFSIZE 4096
extern char ylgh_buf[LOGGING_BUFSIZE];
extern size_t ylgh_leftbuf;
extern char *ylgh_curptr;
extern int ylgh_ndnl;
#define LOG_LEVEL (logging_conf.verbose)
#define DO_INSTAFLUSH (logging_conf.instaflush)
#define DO_SYSLOG (logging_conf.syslog)
#ifdef KERNEL_SPACE
#define LOG_ERR KERN_ERR
#define LOG_INFO KERN_INFO
#define LOG_WARNING KERN_WARNING
#include <linux/kernel.h>
#include <linux/module.h>
#define printf pr_info
#define perror pr_err
#define print_message(level, msg, ...) \
(printk(level msg, ##__VA_ARGS__))
#else
#include <stdio.h> // IWYU pragma: export
#include <errno.h>
#include <syslog.h>
#define print_message(level, msg, ...) \
(DO_SYSLOG ? (void)(syslog((level), msg, ##__VA_ARGS__)) : (void)(printf(msg, ##__VA_ARGS__) + fflush(stdout)))
#endif /* PROGRAM_SPACE */
/**
* For flushing only. Use log_buf_write for writing.
*/
#define log_buf_flush(level) __extension__ ({ \
if (ylgh_leftbuf != LOGGING_BUFSIZE) { \
print_message(level, "%s", ylgh_buf);\
ylgh_curptr = ylgh_buf; \
ylgh_leftbuf = LOGGING_BUFSIZE; \
} \
})
#define log_buf(level, msg, ...) __extension__ ({ \
int lgrtrt; \
lgrtrt=snprintf(ylgh_curptr, ylgh_leftbuf, msg, ##__VA_ARGS__); \
if (lgrtrt < 0 || lgrtrt >= ylgh_leftbuf) { \
ylgh_leftbuf = 0; \
log_buf_flush(level); \
} else { \
ylgh_leftbuf -= lgrtrt; \
ylgh_curptr += lgrtrt; \
} \
})
#define log_buf_write(level) __extension__ ({ \
if (ylgh_ndnl) { \
log_buf(level, "\n"); \
ylgh_ndnl = 0; \
} \
log_buf_flush(level); \
})
#define log_message(level, msg, ...) __extension__ ({ \
if (ylgh_leftbuf != LOGGING_BUFSIZE) { \
log_buf_write(LOG_INFO); \
log_buf(level, "[NOTICE] "); \
} \
log_buf(level, msg, ##__VA_ARGS__); \
ylgh_ndnl = 1; \
log_buf_write(level); \
})
#ifdef KERNEL_SPACE
#define lgerror(code, msg, ...) \
(log_message(LOG_ERR, msg ": %d", ##__VA_ARGS__, code))
#else
#define lgerror(code, msg, ...) \
log_message(LOG_ERR, msg ": %s", ##__VA_ARGS__, strerror(-code));
#endif
#define lgerr(msg, ...) \
(log_message(LOG_ERR, msg, ##__VA_ARGS__))
#define lgwarning(msg, ...) \
(log_message(LOG_WARNING, msg, ##__VA_ARGS__))
#define lginfo(msg, ...) \
(log_message(LOG_INFO, msg, ##__VA_ARGS__))
#define lgdebug(msg, ...) \
(LOG_LEVEL >= VERBOSE_DEBUG ? log_message(LOG_INFO, msg, ##__VA_ARGS__) : (void)0)
#define lgtrace(msg, ...) \
(LOG_LEVEL >= VERBOSE_TRACE ? log_message(LOG_INFO, msg, ##__VA_ARGS__) : (void)0)
#define lgtrace_start() \
lgtrace("---[TRACE PACKET START]---")
#define lgtrace_wr(msg, ...) __extension__ ({ \
if (LOG_LEVEL >= VERBOSE_TRACE) { \
ylgh_ndnl = 1; \
log_buf(LOG_INFO, msg, ##__VA_ARGS__); \
if (DO_INSTAFLUSH) { \
log_buf_flush(LOG_INFO); \
} \
} \
})
#define lgtrace_addp(msg, ...) \
lgtrace_wr(msg ", ", ##__VA_ARGS__)
#define lgtrace_write() \
(LOG_LEVEL >= VERBOSE_TRACE ? log_buf_write(LOG_INFO) : (void)0)
#define lgtrace_end() __extension__ ({ \
if (LOG_LEVEL >= VERBOSE_TRACE) { \
log_buf_write(LOG_INFO); \
print_message(LOG_INFO, "\n"); \
} \
})
#endif /* LOGGING_H */

View File

@@ -1,3 +1,22 @@
/*
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/>.
*/
#define _GNU_SOURCE
#include "types.h" // IWYU pragma: keep
#include "mangle.h"
@@ -9,37 +28,46 @@
#ifndef KERNEL_SPACE
#include <stdlib.h>
#else
#include "linux/inet.h"
#endif
int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
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;
if (raw_payload_len > MAX_PACKET_SIZE) {
return PKT_ACCEPT;
}
const struct iphdr *iph;
const struct ip6_hdr *ip6h;
uint32_t iph_len;
size_t iph_len;
const uint8_t *ip_payload;
uint32_t ip_payload_len;
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_addp("IPv%d", ipver);
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);
(uint8_t **)&ip_payload, &ip_payload_len);
if (ret < 0)
goto accept;
transport_proto = iph->protocol;
} else if (ipver == IP6VERSION && config.use_ipv6) {
}
#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);
@@ -49,21 +77,86 @@ int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
transport_proto = ip6h->ip6_nxt;
} else {
lgtracemsg("Unknown layer 3 protocol version: %d", ipver);
}
#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;
if (transport_proto == IPPROTO_TCP)
lgtrace_addp("TCP");
else if (transport_proto == IPPROTO_UDP)
lgtrace_addp("UDP");
ITER_CONFIG_SECTIONS(&config, section) {
lgtrace_addp("Section #%d", CONFIG_SECTION_NUMBER(section));
ITER_CONFIG_SECTIONS(config, section) {
lgtrace_wr("Section #%d: ", CONFIG_SECTION_NUMBER(section));
switch (transport_proto) {
case IPPROTO_TCP:
@@ -75,10 +168,12 @@ int process_packet(const uint8_t *raw_payload, uint32_t raw_payload_len) {
}
if (verdict == PKT_CONTINUE) {
lgtrace_addp("continue_flow");
lgtrace_wr("continue_flow");
lgtrace_write();
continue;
}
lgtrace_write();
goto ret_verdict;
}
@@ -89,26 +184,26 @@ ret_verdict:
switch (verdict) {
case PKT_ACCEPT:
lgtrace_addp("accept");
lgtrace_wr("accept");
break;
case PKT_DROP:
lgtrace_addp("drop");
lgtrace_wr("drop");
break;
default:
lgtrace_addp("unknow verdict: %d", verdict);
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, uint32_t raw_payload_len) {
int process_tcp_packet(const struct section_config_t *section, const uint8_t *raw_payload, size_t raw_payload_len) {
const void *ipxh;
uint32_t iph_len;
size_t iph_len;
const struct tcphdr *tcph;
uint32_t tcph_len;
size_t tcph_len;
const uint8_t *data;
uint32_t dlen;
size_t dlen;
int ipxv = netproto_version(raw_payload, raw_payload_len);
@@ -120,28 +215,33 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
if (ret < 0) {
goto accept;
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");
NETBUF_ALLOC(payload, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(payload)) {
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");
goto accept;
return PKT_ACCEPT;
}
memcpy(payload, ipxh, iph_len);
memcpy(payload + iph_len, tcph, tcph_len);
uint32_t fake_len = section->fake_sni_pkt_sz;
if (section->synfake_len)
fake_len = min(section->synfake_len, fake_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;
@@ -156,48 +256,49 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
}
ret = instance_config.send_raw_packet(payload, iph_len + tcph_len + fake_len);
ret = instance_config.send_raw_packet(payload, payload_len);
if (ret < 0) {
lgerror(ret, "send_syn_altered");
NETBUF_FREE(payload);
goto accept;
free(payload);
return PKT_ACCEPT;
}
NETBUF_FREE(payload);
goto drop;
free(payload);
return PKT_DROP;
}
if (tcph->syn) goto continue_flow;
if (tcph->syn)
return PKT_CONTINUE;
if (!section->tls_enabled)
goto continue_flow;
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, data + vrd.sni_offset);
lgtrace_addp("SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
}
if (vrd.target_sni) {
lgdebugmsg("Target SNI detected: %.*s", vrd.sni_len, data + vrd.sni_offset);
lgdebug("Target SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
size_t target_sni_offset = vrd.target_sni_ptr - data;
uint32_t payload_len = raw_payload_len;
NETBUF_ALLOC(payload, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(payload)) {
size_t payload_len = raw_payload_len;
uint8_t *payload = malloc(raw_payload_len);
if (payload == NULL) {
lgerror(-ENOMEM, "Allocation error");
goto accept;
return PKT_ACCEPT;
}
memcpy(payload, raw_payload, raw_payload_len);
void *iph;
uint32_t iph_len;
size_t iph_len;
struct tcphdr *tcph;
uint32_t tcph_len;
size_t tcph_len;
uint8_t *data;
uint32_t dlen;
size_t dlen;
int ret = tcp_payload_split(payload, payload_len,
&iph, &iph_len, &tcph, &tcph_len,
@@ -213,6 +314,7 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
set_tcp_checksum(tcph, iph, iph_len);
}
/*
if (0) {
int delta = 2;
ret = seqovl_packet(payload, &payload_len, delta);
@@ -223,124 +325,116 @@ int process_tcp_packet(const struct section_config_t *section, const uint8_t *ra
lgerror(ret, "seqovl_packet delta %d", delta);
}
}
*/
if (dlen > 1480 && config.verbose) {
lgdebugmsg("WARNING! Client Hello packet is too big and may cause issues!");
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);
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 = vrd.sni_target_offset;
mid_offset = ipd_offset + vrd.sni_target_len / 2;
case FRAG_STRAT_TCP:
{
ipd_offset = target_sni_offset;
mid_offset = ipd_offset + vrd.target_sni_len / 2;
uint32_t poses[2];
int cnt = 0;
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]) {
uint32_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;
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
poses[cnt++] = section->frag_sni_pos;
}
break;
case FRAG_STRAT_IP:
if (ipxv == IP4VERSION) {
ipd_offset = ((char *)data - (char *)tcph) + vrd.sni_target_offset;
mid_offset = ipd_offset + vrd.sni_target_len / 2;
mid_offset += 8 - mid_offset % 8;
uint32_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]) {
uint32_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\n");
goto default_send;
if (section->frag_middle_sni) {
poses[cnt++] = mid_offset;
}
default:
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;
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:
NETBUF_FREE(payload);
goto accept;
free(payload);
return PKT_ACCEPT;
drop_lc:
NETBUF_FREE(payload);
goto drop;
free(payload);
return PKT_DROP;
}
continue_flow:
return PKT_CONTINUE;
accept:
return PKT_ACCEPT;
drop:
return PKT_DROP;
}
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, uint32_t pktlen) {
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, size_t pktlen) {
const void *iph;
uint32_t iph_len;
size_t iph_len;
const struct udphdr *udph;
const uint8_t *data;
uint32_t dlen;
size_t dlen;
int ret = udp_payload_split((uint8_t *)pkt, pktlen,
(void **)&iph, &iph_len,
@@ -353,18 +447,6 @@ int process_udp_packet(const struct section_config_t *section, const uint8_t *pk
goto accept;
}
if (dlen > 10 && config.verbose == VERBOSE_TRACE) {
char logging_buf[128];
char *bufpt = logging_buf;
bufpt += sprintf(bufpt, "UDP payload start: [ ");
for (int i = 0; i < 10; i++) {
bufpt += sprintf(bufpt, "%02x ", data[i]);
}
bufpt += sprintf(bufpt, "]");
lgtrace_addp("%s", logging_buf);
}
if (!detect_udp_filtered(section, pkt, pktlen))
goto continue_flow;
@@ -372,12 +454,8 @@ int process_udp_packet(const struct section_config_t *section, const uint8_t *pk
goto drop;
else if (section->udp_mode == UDP_MODE_FAKE) {
for (int i = 0; i < section->udp_fake_seq_len; i++) {
NETBUF_ALLOC(fake_udp, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(fake_udp)) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
uint32_t fsn_len = MAX_PACKET_SIZE;
uint8_t *fake_udp;
size_t fake_udp_len;
struct udp_fake_type fake_type = {
.fake_len = section->udp_fake_len,
@@ -386,24 +464,25 @@ int process_udp_packet(const struct section_config_t *section, const uint8_t *pk
.faking_ttl = section->faking_ttl,
},
};
ret = gen_fake_udp(fake_type, iph, iph_len, udph, fake_udp, &fsn_len);
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_lc;
goto erret;
}
lgtrace_addp("post fake udp #%d", i + 1);
ret = instance_config.send_raw_packet(fake_udp, fsn_len);
ret = instance_config.send_raw_packet(fake_udp, fake_udp_len);
if (ret < 0) {
lgerror(ret, "send fake udp");
goto erret_lc;
}
NETBUF_FREE(fake_udp);
free(fake_udp);
continue;
erret_lc:
NETBUF_FREE(fake_udp);
free(fake_udp);
erret:
goto accept;
}
@@ -420,72 +499,58 @@ drop:
return PKT_DROP;
}
int send_ip4_frags(const struct section_config_t *section, const uint8_t *packet, uint32_t pktlen, const uint32_t *poses, uint32_t poses_sz, uint32_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 (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
if (!instance_config.send_delayed_packet) {
return -EINVAL;
}
lgtrace_addp("Sent %d delayed for %d", pktlen, section->seg2_delay);
lgtrace_addp("Sent %zu delayed for %d", pktlen, section->seg2_delay);
instance_config.send_delayed_packet(
packet, pktlen, section->seg2_delay);
return 0;
} else {
lgtrace_addp("Sent %d bytes", pktlen);
lgtrace_addp("Sent %zu bytes", pktlen);
return instance_config.send_raw_packet(
packet, pktlen);
}
} else {
NETBUF_ALLOC(frag1, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(frag1)) {
size_t f1len = pktlen;
uint8_t *frag1 = malloc(f1len);
if (frag1 == NULL) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
NETBUF_ALLOC(frag2, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(frag2)) {
size_t f2len = pktlen;
uint8_t *frag2 = malloc(f2len);
if (frag2 == NULL) {
lgerror(-ENOMEM, "Allocation error");
NETBUF_FREE(frag1);
free(frag1);
return -ENOMEM;
}
/*
NETBUF_ALLOC(fake_pad, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(fake_pad)) {
lgerror(-ENOMEM, "Allocation error");
NETBUF_FREE(frag1);
NETBUF_FREE(frag2);
return -ENOMEM;
}
*/
uint32_t f1len = MAX_PACKET_SIZE;
uint32_t f2len = MAX_PACKET_SIZE;
// uint32_t fake_pad_len = MAX_PACKET_SIZE;
int ret;
if (dvs > poses[0]) {
lgerror(-EINVAL, "send_frags: Recursive dvs(%d) is more than poses0(%d)", dvs, poses[0]);
lgerror(-EINVAL, "send_frags: Recursive dvs(%zu) is more than poses0(%zu)", dvs, poses[0]);
ret = -EINVAL;
goto erret_lc;
}
uint32_t frag_pos = poses[0] - dvs;
size_t frag_pos = poses[0] - dvs;
frag_pos += 8 - frag_pos % 8;
ret = ip4_frag(packet, pktlen, frag_pos,
frag1, &f1len, frag2, &f2len);
if (ret < 0) {
lgerror(ret, "send_frags: frag: with context packet with size %d, position: %d, recursive dvs: %d", pktlen, poses[0], dvs);
lgerror(ret, "send_frags: frag: with context packet with size %zu, position: %zu, recursive dvs: %zu", pktlen, poses[0], dvs);
goto erret_lc;
}
dvs += frag_pos;
if (section->frag_sni_reverse)
goto send_frag2;
send_frag1:
@@ -497,54 +562,22 @@ send_frag1:
if (section->frag_sni_reverse)
goto out_lc;
send_fake:
/*
if (section->frag_sni_faked) {
ITER_FAKE_STRAT(section->faking_strategy, strategy) {
uint32_t iphfl;
fake_pad_len = f2len;
ret = ip4_payload_split(frag2, f2len, NULL, &iphfl, NULL, NULL);
if (ret < 0) {
lgerror("Invalid frag2", ret);
goto erret_lc;
}
memcpy(fake_pad, frag2, iphfl + sizeof(struct udphdr));
memset(fake_pad + iphfl + sizeof(struct udphdr), 0, f2len - iphfl - sizeof(struct udphdr));
((struct iphdr *)fake_pad)->tot_len = htons(fake_pad_len);
((struct iphdr *)fake_pad)->id = 1;
((struct iphdr *)fake_pad)->ttl = 8;
((struct iphdr *)fake_pad)->frag_off = 0;
ip4_set_checksum((struct iphdr*)fake_pad);
// *(struct udphdr *)(fake_pad + iphfl) = *(struct udphdr *)(frag2 + iphfl);
ret = send_ip4_frags(fake_pad, fake_pad_len, NULL, 0, 0);
if (ret < 0) {
goto erret_lc;
}
}
}
*/
if (section->frag_sni_reverse)
goto send_frag1;
send_frag2:
ret = send_ip4_frags(section, frag2, f2len, poses + 1, poses_sz - 1, dvs);
ret = send_ip4_frags(section, frag2, f2len, poses + 1, poses_sz - 1, poses[0]);
if (ret < 0) {
goto erret_lc;
}
if (section->frag_sni_reverse)
goto send_fake;
goto send_frag1;
out_lc:
NETBUF_FREE(frag1);
NETBUF_FREE(frag2);
// NETBUF_FREE(fake_pad);
free(frag1);
free(frag2);
goto out;
erret_lc:
NETBUF_FREE(frag1);
NETBUF_FREE(frag2);
// NETBUF_FREE(fake_pad);
free(frag1);
free(frag2);
return ret;
}
@@ -552,7 +585,7 @@ out:
return 0;
}
int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet, uint32_t pktlen, const uint32_t *poses, uint32_t poses_sz, uint32_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 (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
if (!instance_config.send_delayed_packet) {
@@ -564,67 +597,62 @@ int send_tcp_frags(const struct section_config_t *section, const uint8_t *packet
return 0;
} else {
lgtrace_addp("raw send packet of %d bytes with %d dvs", pktlen, dvs);
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
return instance_config.send_raw_packet(
packet, pktlen);
}
} else {
NETBUF_ALLOC(frag1, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(frag1)) {
size_t f1len = pktlen;
uint8_t *frag1 = malloc(f1len);
if (frag1 == NULL) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
NETBUF_ALLOC(frag2, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(frag2)) {
size_t f2len = pktlen;
uint8_t *frag2 = malloc(f2len);
if (frag2 == NULL) {
lgerror(-ENOMEM, "Allocation error");
NETBUF_FREE(frag1);
free(frag1);
return -ENOMEM;
}
uint32_t f1len = MAX_PACKET_SIZE;
uint32_t f2len = MAX_PACKET_SIZE;
int ret;
if (dvs > poses[0]) {
lgerror(-EINVAL, "send_frags: Recursive dvs(%d) is more than poses0(%d)", dvs, poses[0]);
lgerror(-EINVAL, "send_frags: Recursive dvs(%zu) is more than poses0(%zu)", dvs, poses[0]);
ret = -EINVAL;
goto erret_lc;
}
ret = tcp_frag(packet, pktlen, poses[0] - dvs,
frag1, &f1len, frag2, &f2len);
lgtrace_addp("Packet split in %d bytes position of payload start, dvs: %d to two packets of %d and %d lengths", poses[0], dvs, f1len, f2len);
lgtrace_addp("Packet split in %zu bytes position of payload start, dvs: %zu to two packets of %zu and %zu lengths", poses[0], dvs, f1len, f2len);
if (ret < 0) {
lgerror(ret, "send_frags: tcp_frag: with context packet with size %d, position: %d, recursive dvs: %d", pktlen, poses[0], dvs);
lgerror(ret, "send_frags: tcp_frag: with context packet with size %zu, position: %zu", pktlen, poses[0]);
goto erret_lc;
}
dvs += poses[0];
if (section->frag_sni_reverse)
goto send_frag2;
send_frag1:
{
ret = send_tcp_frags(section, frag1, f1len, NULL, 0, 0);
if (ret < 0) {
goto erret_lc;
}
if (section->frag_sni_reverse)
goto out_lc;
ret = send_tcp_frags(section, frag1, f1len, NULL, 0, 0);
if (ret < 0) {
goto erret_lc;
}
if (section->frag_sni_reverse)
goto out_lc;
send_fake:
if (section->frag_sni_faked) {
uint32_t iphfl, tcphfl;
size_t iphfl, tcphfl;
void *iph;
struct tcphdr *tcph;
ret = tcp_payload_split(frag2, f2len, &iph, &iphfl, &tcph, &tcphfl, NULL, NULL);
@@ -644,22 +672,20 @@ send_fake:
goto send_frag1;
send_frag2:
{
ret = send_tcp_frags(section, frag2, f2len, poses + 1, poses_sz - 1, dvs);
if (ret < 0) {
goto erret_lc;
}
if (section->frag_sni_reverse)
goto send_fake;
ret = send_tcp_frags(section, frag2, f2len, poses + 1, poses_sz - 1, poses[0]);
if (ret < 0) {
goto erret_lc;
}
if (section->frag_sni_reverse)
goto send_fake;
out_lc:
NETBUF_FREE(frag1);
NETBUF_FREE(frag2);
free(frag1);
free(frag2);
goto out;
erret_lc:
NETBUF_FREE(frag1);
NETBUF_FREE(frag2);
free(frag1);
free(frag2);
return ret;
}
out:
@@ -688,38 +714,34 @@ int post_fake_sni(struct fake_type f_type,
// one goes for default fake
for (int i = 0; i < fake_seq_type.sequence_len; i++) {
NETBUF_ALLOC(fake_sni, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(fake_sni)) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
uint32_t fsn_len = MAX_PACKET_SIZE;
uint8_t *fake_sni;
size_t fake_sni_len;
ret = gen_fake_sni(
fake_seq_type,
fsiph, iph_len, fstcph, tcph_len,
fake_sni, &fsn_len);
&fake_sni, &fake_sni_len);
if (ret < 0) {
lgerror(ret, "gen_fake_sni");
goto erret_lc;
return ret;
}
lgtrace_addp("post fake sni #%d", i + 1);
if (f_type.seg2delay) {
ret = instance_config.send_delayed_packet(fake_sni, fsn_len, 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, fsn_len);
ret = instance_config.send_raw_packet(fake_sni, fake_sni_len);
}
if (ret < 0) {
lgerror(ret, "send fake sni");
goto erret_lc;
}
uint32_t iph_len;
uint32_t tcph_len;
uint32_t plen;
size_t iph_len;
size_t tcph_len;
size_t plen;
ret = tcp_payload_split(
fake_sni, fsn_len,
fake_sni, fake_sni_len,
&fsiph, &iph_len,
&fstcph, &tcph_len,
NULL, &plen);
@@ -745,10 +767,10 @@ int post_fake_sni(struct fake_type f_type,
fsiph = (void *)rfsiph;
fstcph = (void *)rfstcph;
NETBUF_FREE(fake_sni);
free(fake_sni);
continue;
erret_lc:
NETBUF_FREE(fake_sni);
free(fake_sni);
return ret;
}
}

78
src/mangle.h Normal file
View File

@@ -0,0 +1,78 @@
/*
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_MANGLE_H
#define YU_MANGLE_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
/**
* 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 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);
/**
* Sends fake client hello.
*/
int post_fake_sni(struct fake_type f_type,
const void *iph, unsigned int iph_len,
const struct tcphdr *tcph, unsigned int tcph_len);
/**
* Splits packet by poses and posts.
* Poses are relative to start of TCP payload.
* dvs used internally and should be zero.
*/
int send_tcp_frags(const struct section_config_t *section,
const uint8_t *packet, size_t pktlen,
const size_t *poses, size_t poses_len, size_t dvs);
/**
* Splits packet by poses and posts.
* Poses are relative to start of TCP payload.
* dvs used internally and should be zero.
*/
int send_ip4_frags(const struct section_config_t *section,
const uint8_t *packet, size_t pktlen,
const size_t *poses, size_t poses_len, size_t dvs);
#endif /* YU_MANGLE_H */

551
src/quic.c Normal file
View File

@@ -0,0 +1,551 @@
/*
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/>.
*/
#include "quic.h"
#include "tls.h"
#include "logging.h"
/**
* Packet number.
*/
struct quic_pnumber {
uint8_t d1;
uint8_t d2;
uint8_t d3;
uint8_t d4;
};
uint64_t quic_parse_varlength(const uint8_t *variable, size_t *mlen) {
if (mlen && *mlen == 0) return 0;
uint64_t vr = (*variable & 0x3F);
uint8_t len = 1 << (*variable >> 6);
if (mlen) {
if (*mlen < len) {
*mlen = 0;
return 0;
}
*mlen = len;
}
++variable;
for (uint8_t i = 1; i < len; i++) {
vr = (vr << 8) + *variable;
++variable;
}
return vr;
}
int quic_get_version(uint32_t *version, const struct quic_lhdr *qch) {
uint32_t qversion = ntohl(qch->version);
*version = qversion;
switch (qversion) {
case QUIC_V1:
case QUIC_V2:
return 0;
default:
return -EINVAL;
}
}
int quic_check_is_initial(const struct quic_lhdr *qch) {
uint32_t qversion;
int ret;
ret = quic_get_version(&qversion, qch);
if (qversion < 0) return 0;
uint8_t qtype = qch->type;
switch (qversion) {
case QUIC_V1:
qtype = quic_convtype_v1(qtype);
break;
case QUIC_V2:
qtype = quic_convtype_v2(qtype);
break;
default:
return 0;
}
if (qtype != QUIC_INITIAL_TYPE) {
return 0;
}
return 1;
}
int quic_parse_data(const uint8_t *raw_payload, size_t raw_payload_len,
const struct quic_lhdr **qch, size_t *qch_len,
struct quic_cids *qci,
const uint8_t **payload, size_t *plen) {
if ( raw_payload == NULL ||
raw_payload_len < sizeof(struct quic_lhdr))
goto invalid_packet;
const struct quic_lhdr *nqch = (const struct quic_lhdr *)raw_payload;
size_t left_len = raw_payload_len - sizeof(struct quic_lhdr);
const uint8_t *cur_rawptr = raw_payload + sizeof(struct quic_lhdr);
int ret;
uint32_t qversion;
if (!nqch->fixed) {
lgtrace_addp("quic fixed unset");
return -EPROTO;
}
ret = quic_get_version(&qversion, nqch);
if (ret < 0) {
lgtrace_addp("quic version undefined %u", qversion);
return -EPROTO;
}
lgtrace_addp("quic version valid %u", qversion);
if (left_len < 2) goto invalid_packet;
struct quic_cids nqci = {0};
nqci.dst_len = *cur_rawptr++;
left_len--;
if (left_len < nqci.dst_len) goto invalid_packet;
nqci.dst_id = cur_rawptr;
cur_rawptr += nqci.dst_len;
left_len -= nqci.dst_len;
nqci.src_len = *cur_rawptr++;
left_len--;
if (left_len < nqci.src_len) goto invalid_packet;
nqci.src_id = cur_rawptr;
cur_rawptr += nqci.src_len;
left_len -= nqci.src_len;
if (qch) *qch = nqch;
if (qch_len) {
*qch_len = sizeof(struct quic_lhdr) +
nqci.src_len + nqci.dst_len;
}
if (qci) *qci = nqci;
if (payload) *payload = cur_rawptr;
if (plen) *plen = left_len;
return 0;
invalid_packet:
return -EINVAL;
}
int quic_parse_initial_header(const uint8_t *inpayload, size_t inplen,
struct quici_hdr *qhdr) {
if (inplen < 3) goto invalid_packet;
struct quici_hdr nqhdr;
const uint8_t *cur_ptr = inpayload;
size_t left_len = inplen;
size_t tlen = left_len;
nqhdr.token_len = quic_parse_varlength(cur_ptr, &tlen);
nqhdr.token = cur_ptr + tlen;
if (left_len < nqhdr.token_len + tlen)
goto invalid_packet;
cur_ptr += tlen + nqhdr.token_len;
left_len -= tlen + nqhdr.token_len;
tlen = left_len;
nqhdr.length = quic_parse_varlength(cur_ptr, &tlen);
if (left_len < nqhdr.length + tlen ||
nqhdr.length < QUIC_SAMPLE_SIZE +
QUIC_SAMPLE_OFFSET
)
goto invalid_packet;
cur_ptr += tlen;
nqhdr.protected_payload = cur_ptr;
nqhdr.sample = cur_ptr + QUIC_SAMPLE_OFFSET;
nqhdr.sample_length = QUIC_SAMPLE_SIZE;
if (qhdr) *qhdr = nqhdr;
return 0;
invalid_packet:
lgerror(-EINVAL, "QUIC invalid Initial packet");
return -EINVAL;
}
ssize_t quic_parse_crypto(struct quic_frame_crypto *crypto_frame,
const uint8_t *frame, size_t flen) {
const uint8_t *curptr = frame;
size_t curptr_len = flen;
size_t vln;
*crypto_frame = (struct quic_frame_crypto){0};
if (flen == 0 || *frame != QUIC_FRAME_CRYPTO ||
crypto_frame == NULL)
return -EINVAL;
curptr++, curptr_len--;
vln = curptr_len;
size_t offset = quic_parse_varlength(curptr, &vln);
curptr += vln, curptr_len -= vln;
if (vln == 0) {
return -EINVAL;
}
vln = curptr_len;
size_t length = quic_parse_varlength(curptr, &vln);
curptr += vln, curptr_len -= vln;
if (vln == 0) {
return -EINVAL;
}
if (length > curptr_len)
return -EINVAL;
crypto_frame->offset = offset;
crypto_frame->payload_length = length;
crypto_frame->payload = curptr;
curptr += length;
curptr_len -= length;
return flen - curptr_len;
}
int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, size_t *plen, size_t avail_buflen) {
void *iph;
size_t iph_len;
struct udphdr *udph;
uint8_t *data;
size_t dlen;
int ret;
ret = udp_payload_split(payload, *plen,
&iph, &iph_len, &udph,
&data, &dlen);
uint32_t ipxv = netproto_version(payload, *plen);
if (ret < 0) {
return ret;
}
if (strategy.strategy == FAKE_STRAT_TTL) {
lgtrace_addp("Set fake ttl to %d", strategy.faking_ttl);
if (ipxv == IP4VERSION) {
((struct iphdr *)iph)->ttl = strategy.faking_ttl;
} else if (ipxv == IP6VERSION) {
((struct ip6_hdr *)iph)->ip6_hops = strategy.faking_ttl;
} else {
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
return -EINVAL;
}
}
if (ipxv == IP4VERSION) {
((struct iphdr *)iph)->frag_off = 0;
}
set_ip_checksum(iph, iph_len);
if (strategy.strategy == FAKE_STRAT_UDP_CHECK) {
lgtrace_addp("break fake udp checksum");
udph->check += 1;
}
return 0;
}
int gen_fake_udp(struct udp_fake_type type,
const void *ipxh, size_t iph_len,
const struct udphdr *udph,
uint8_t **ubuf, size_t *ubuflen) {
size_t data_len = type.fake_len;
int ret;
if (!ipxh || !udph || !ubuf || !ubuflen)
return -EINVAL;
int ipxv = netproto_version(ipxh, iph_len);
if (ipxv == IP6VERSION) {
iph_len = sizeof(struct ip6_hdr);
}
size_t dlen = iph_len + sizeof(struct udphdr) + data_len;
size_t buffer_len = dlen + 50;
uint8_t *buf = malloc(buffer_len);
if (buf == NULL) {
return -ENOMEM;
}
if (ipxv == IP4VERSION) {
const struct iphdr *iph = ipxh;
memcpy(buf, iph, iph_len);
struct iphdr *niph = (struct iphdr *)buf;
niph->protocol = IPPROTO_UDP;
} else if (ipxv == IP6VERSION) {
const struct ip6_hdr *iph = ipxh;
memcpy(buf, iph, iph_len);
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_nxt = IPPROTO_UDP;
} else {
ret = -EINVAL;
goto error;
}
memcpy(buf + iph_len, udph, sizeof(struct udphdr));
uint8_t *bfdptr = buf + iph_len + sizeof(struct udphdr);
memset(bfdptr, 0, data_len);
if (ipxv == IP4VERSION) {
struct iphdr *niph = (struct iphdr *)buf;
niph->tot_len = htons(dlen);
niph->id = randint();
} else if (ipxv == IP6VERSION) {
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_plen = htons(dlen - iph_len);
}
struct udphdr *nudph = (struct udphdr *)(buf + iph_len);
nudph->len = htons(sizeof(struct udphdr) + data_len);
set_udp_checksum(nudph, buf, iph_len);
ret = udp_fail_packet(type.strategy, buf, &dlen, buffer_len);
if (ret < 0) {
lgerror(ret, "udp_fail_packet");
goto error;
}
*ubuflen = dlen;
*ubuf = buf;
return 0;
error:
free(buf);
return ret;
}
int parse_quic_decrypted(
const struct section_config_t *section,
const uint8_t *decrypted_message, size_t decrypted_message_len,
uint8_t **crypto_message_buf, size_t *crypto_message_buf_len
) {
const uint8_t *curptr = decrypted_message;
ssize_t curptr_len = decrypted_message_len;
ssize_t fret;
struct quic_frame_crypto fr_cr;
uint8_t *crypto_message = calloc(AVAILABLE_MTU, 1);
if (crypto_message == NULL) {
lgerror(-ENOMEM, "No memory");
return -ENOMEM;
}
int crypto_message_len = AVAILABLE_MTU;
while (curptr_len > 0) {
uint8_t type = curptr[0];
switch (type) {
case QUIC_FRAME_PING:
lgtrace_addp("ping");
goto pl_incr;
case QUIC_FRAME_PADDING:
if (curptr == decrypted_message ||
*(curptr - 1) != QUIC_FRAME_PADDING) {
lgtrace_addp("padding");
}
pl_incr:
curptr++, curptr_len--;
break;
case QUIC_FRAME_CRYPTO:
fret = quic_parse_crypto(&fr_cr, curptr, curptr_len);
lgtrace_addp("crypto len=%zu offset=%zu fret=%zd", fr_cr.payload_length, fr_cr.offset, fret);
if (fret < 0) {
lgtrace_addp("Crypto parse error");
goto out;
}
curptr += fret;
curptr_len -= fret;
if (fr_cr.offset <= crypto_message_len &&
fr_cr.payload_length <= crypto_message_len &&
fr_cr.payload_length + fr_cr.offset <= crypto_message_len
) {
memcpy(crypto_message + fr_cr.offset,
fr_cr.payload, fr_cr.payload_length);
}
break;
default:
lgtrace_addp("Frame invalid hash: %02x", type);
goto out;
}
}
out:
lgtrace_addp("crypto message parsed");
*crypto_message_buf = crypto_message;
*crypto_message_buf_len = crypto_message_len;
return 0;
}
int detect_udp_filtered(const struct section_config_t *section,
const uint8_t *payload, size_t plen) {
const void *iph;
size_t iph_len;
const struct udphdr *udph;
const uint8_t *data;
size_t dlen;
int ret;
ret = udp_payload_split((uint8_t *)payload, plen,
(void **)&iph, &iph_len,
(struct udphdr **)&udph,
(uint8_t **)&data, &dlen);
int udp_dport = ntohs(udph->dest);
if (ret < 0) {
goto skip;
}
if (section->udp_filter_quic != UDP_FILTER_QUIC_DISABLED) {
if (section->dport_filter && ntohs(udph->dest) != 443)
goto match_port;
const struct quic_lhdr *qch;
size_t qch_len;
struct quic_cids qci;
const uint8_t *quic_in_payload;
size_t quic_in_plen;
lgtrace_addp("QUIC probe");
ret = quic_parse_data((uint8_t *)data, dlen,
&qch, &qch_len, &qci,
&quic_in_payload, &quic_in_plen);
if (ret < 0) {
lgtrace_addp("QUIC undefined type");
goto match_port;
}
lgtrace_addp("QUIC detected");
if (!quic_check_is_initial(qch)) {
lgtrace_addp("QUIC not initial");
goto match_port;
}
lgtrace_addp("QUIC initial message");
if (section->udp_filter_quic == UDP_FILTER_QUIC_ALL) {
lgtrace_addp("QUIC early approve");
goto approve;
}
uint8_t *decrypted_payload;
size_t decrypted_payload_len;
const uint8_t *decrypted_message;
size_t decrypted_message_len;
uint8_t *crypto_message;
size_t crypto_message_len;
struct tls_verdict tlsv;
ret = quic_parse_initial_message(
data, dlen,
&decrypted_payload, &decrypted_payload_len,
&decrypted_message, &decrypted_message_len
);
if (ret < 0) {
goto match_port;
}
ret = parse_quic_decrypted(section,
decrypted_message, decrypted_message_len,
&crypto_message, &crypto_message_len
);
free(decrypted_payload);
decrypted_payload = NULL;
if (ret < 0) {
goto match_port;
}
if (section->sni_detection == SNI_DETECTION_BRUTE) {
ret = bruteforce_analyze_sni_str(section, crypto_message, crypto_message_len, &tlsv);
} else {
ret = analyze_tls_message(
section, crypto_message, crypto_message_len, &tlsv
);
}
if (tlsv.sni_len != 0) {
lgtrace_addp("QUIC SNI detected: %.*s", tlsv.sni_len, tlsv.sni_ptr);
}
if (tlsv.target_sni) {
lgdebug("QUIC target SNI detected: %.*s", tlsv.sni_len, tlsv.sni_ptr);
free(crypto_message);
crypto_message = NULL;
goto approve;
}
free(crypto_message);
crypto_message = NULL;
}
match_port:
for (int i = 0; i < section->udp_dport_range_len; 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;
}
}
skip:
return 0;
approve:
return 1;
}

246
src/quic.h Normal file
View File

@@ -0,0 +1,246 @@
/*
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 QUIC_H
#define QUIC_H
#include "types.h"
#include "utils.h"
/**
* @macro
*
* :macro:`NGTCP2_INITIAL_SALT_V1` is a salt value which is used to
* derive initial secret. It is used for QUIC v1.
*/
#define QUIC_INITIAL_SALT_V1 \
"\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17\x9a\xe6\xa4\xc8\x0c\xad" \
"\xcc\xbb\x7f\x0a"
/**
* @macro
*
* :macro:`NGTCP2_INITIAL_SALT_V2` is a salt value which is used to
* derive initial secret. It is used for QUIC v2.
*/
#define QUIC_INITIAL_SALT_V2 \
"\x0d\xed\xe3\xde\xf7\x00\xa6\xdb\x81\x93\x81\xbe\x6e\x26\x9d\xcb" \
"\xf9\xbd\x2e\xd9"
#define QUIC_INITIAL_TYPE 0
#define QUIC_0_RTT_TYPE 1
#define QUIC_HANDSHAKE_TYPE 2
#define QUIC_RETRY_TYPE 3
#define QUIC_INITIAL_TYPE_V1 0b00
#define QUIC_0_RTT_TYPE_V1 0b01
#define QUIC_HANDSHAKE_TYPE_V1 0b10
#define QUIC_RETRY_TYPE_V1 0b11
#define quic_convtype_v1(type) (type)
#define QUIC_INITIAL_TYPE_V2 0b01
#define QUIC_0_RTT_TYPE_V2 0b10
#define QUIC_HANDSHAKE_TYPE_V2 0b11
#define QUIC_RETRY_TYPE_V2 0b00
#define quic_convtype_v2(type) (((type) + 1) & __extension__ 0b11)
#define QUIC_FRAME_CRYPTO 0x06
#define QUIC_FRAME_PADDING 0x00
#define QUIC_FRAME_PING 0x01
#define QUIC_V1 1 // RFC 9000
#define QUIC_V2 0x6b3343cf // RFC 9369
static const uint32_t supported_versions[] = {
QUIC_V1,
QUIC_V2,
};
// In bytes
#define QUIC_SAMPLE_OFFSET 4
#define QUIC_SAMPLE_SIZE 16
#define QUIC_INITIAL_SECRET_SIZE 32
#define QUIC_CLIENT_IN_SIZE 32
#define QUIC_KEY_SIZE 16
#define QUIC_IV_SIZE 12
#define QUIC_HP_SIZE 16
// Altough tag is not defined, it present in the end of message
#define QUIC_TAG_SIZE 16
/**
* Describes type-specific bytes for Initial message
*/
struct quici_lhdr_typespec {
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t number_length:2;//protected
uint8_t reserved:2; //protected
uint8_t discard:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t discard:4;
uint8_t reserved:2; //protected
uint8_t number_length:2;//protected
#else
#error "Undefined endian"
#endif
}__attribute__((packed));
/**
* Quic Large Header
*/
struct quic_lhdr {
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t type_specific:4;// protected
uint8_t type:2;
uint8_t fixed:1;
uint8_t form:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t form:1;
uint8_t fixed:1;
uint8_t type:2;
uint8_t type_specific:4;// protected
#else
#error "Undefined endian"
#endif
uint32_t version;
}__attribute__((packed));
/**
* Quic Large Header Ids
* (separated from the original header because of varying dst
*/
struct quic_cids {
uint8_t dst_len;
const uint8_t *dst_id;
uint8_t src_len;
const uint8_t *src_id;
};
/**
* Parses QUIС raw data (UDP payload) to quic large header and
* quic payload.
*
* \qch_len is sizeof(qch) + qci->dst_len + qci->src_id
* \payload is Type-Specific payload (#17.2).
*/
int quic_parse_data(const uint8_t *raw_payload, size_t raw_payload_len,
const struct quic_lhdr **qch, size_t *qch_len,
struct quic_cids *qci,
const uint8_t **payload, size_t *plen);
/**
* Parses QUIC variable-length integer. (#16)
* \variable is a pointer to the sequence to be parsed
* (varlen integer in big endian format)
*
* \mlen Used to signal about variable length and validate left length
* in the buffer.
*
* On error/buffer overflow mlen set to 0, otherwise it is higher
*/
uint64_t quic_parse_varlength(const uint8_t *variable, size_t *mlen);
// quici stands for QUIC Initial
/**
* This structure should be parsed
*/
struct quici_hdr {
size_t token_len;
const uint8_t *token;
size_t length;
const uint8_t *protected_payload; // with packet number
// RFC 9001 5.4.2
size_t sample_length;
const uint8_t *sample;
};
/**
* Checks for quic version and checks if it is supported
*/
int quic_get_version(uint32_t *version, const struct quic_lhdr *qch);
/**
* Checks quic message to be initial according to version.
* 0 on false, 1 on true
*/
int quic_check_is_initial(const struct quic_lhdr *qch);
struct quic_frame_crypto {
size_t offset;
size_t payload_length;
const uint8_t *payload;
};
/**
* Parses quic crypto frame
* Returns parsed size or -EINVAL on error
*/
ssize_t quic_parse_crypto(struct quic_frame_crypto *crypto_frame,
const uint8_t *frame, size_t flen);
/**
* Parses QUIC initial message header.
* \inpayload is a QUIC Initial message payload (payload after quic large header)
*/
int quic_parse_initial_header(const uint8_t *inpayload, size_t inplen,
struct quici_hdr *qhdr);
/**
* Parses and decrypts QUIC Initial Message.
*
* \quic_header QUIC payload, the start of UDP payload
* \udecrypted_payload QUIC decrypted payload. Contains all the QUIC packet, with all headers
* \udecrypted_message QUIC decrypted message, typically TLS Client Hello
*
*/
int quic_parse_initial_message(
const uint8_t *quic_payload, size_t quic_plen,
uint8_t **udecrypted_payload, size_t *udecrypted_payload_len,
const uint8_t **udecrypted_message, size_t *udecrypted_message_len
);
/**
* CRYPTO frames may be randomly spried in the message.
* This function _allocates_ crypto_message_buf and fills it with CRYPTO frames
* according to offset and payload_length
*/
int parse_quic_decrypted(
const struct section_config_t *section,
const uint8_t *decrypted_message, size_t decrypted_message_len,
uint8_t **crypto_message_buf, size_t *crypto_message_buf_len
);
// Like fail_packet for TCP
int udp_fail_packet(struct udp_failing_strategy strategy, uint8_t *payload, size_t *plen, size_t avail_buflen);
// Like gen_fake_sni for TCP, Allocates and generates udp fake
int gen_fake_udp(struct udp_fake_type type,
const void *ipxh, size_t iph_len,
const struct udphdr *udph,
uint8_t **buf, size_t *buflen);
int detect_udp_filtered(const struct section_config_t *section,
const uint8_t *payload, size_t plen);
#endif /* QUIC_H */

276
src/quic_crypto.c Normal file
View File

@@ -0,0 +1,276 @@
/*
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/>.
*/
#include "quic.h"
#include "kdf/hkdf.h"
#include "hash/sha256.h"
#include "cipher/aes.h"
#include "cipher_modes/ecb.h"
#include "aead/gcm.h"
#include "logging.h"
const uint8_t quic_client_in_info[] = "\0\x20\x0ftls13 client in\0";
const uint8_t quic_key_info[] = "\0\x10\x0etls13 quic key\0";
const uint8_t quic_iv_info[] = "\0\x0c\x0dtls13 quic iv\0";
const uint8_t quic_hp_info[] = "\0\x10\x0dtls13 quic hp\0";
const uint8_t quic2_key_info[] = "\0\x10\x10tls13 quicv2 key\0";
const uint8_t quic2_iv_info[] = "\0\x0c\x0ftls13 quicv2 iv\0";
const uint8_t quic2_hp_info[] = "\0\x10\x0ftls13 quicv2 hp\0";
int quic_parse_initial_message(
const uint8_t *quic_payload, size_t quic_plen,
uint8_t **udecrypted_payload, size_t *udecrypted_payload_len,
const uint8_t **udecrypted_message, size_t *udecrypted_message_len
) {
int ret;
const struct quic_lhdr *qch;
size_t qch_len;
struct quic_cids qci;
const uint8_t *inpayload;
size_t inplen;
struct quici_hdr qich;
size_t quic_header_len;
size_t inheader_len;
struct quici_lhdr_typespec qich_ltspc;
int packet_number_length;
const uint8_t *packet_number = NULL;
const uint8_t *protected_payload = NULL;
size_t protected_payload_length;
uint8_t initial_secret[QUIC_INITIAL_SECRET_SIZE];
uint8_t client_initial_secret[QUIC_CLIENT_IN_SIZE];
uint8_t quic_key[QUIC_KEY_SIZE];
uint8_t quic_iv[QUIC_IV_SIZE];
uint8_t quic_hp[QUIC_HP_SIZE];
uint8_t mask[QUIC_SAMPLE_SIZE];
uint8_t *decrypted_payload = NULL;
size_t decrypted_payload_len;
uint8_t *decrypted_packet_number = NULL;
uint8_t *dcptr = NULL;
// Decrypted plain message without header
uint8_t *decrypted_message = NULL;
size_t decrypted_message_len;
AesContext actx;
GcmContext gctx;
uint32_t qversion;
const uint8_t *iv_info;
size_t iv_info_size;
const uint8_t *key_info;
size_t key_info_size;
const uint8_t *hp_info;
size_t hp_info_size;
const uint8_t *initial_salt;
size_t initial_salt_size;
ret = quic_parse_data(quic_payload, quic_plen,
&qch, &qch_len, &qci, &inpayload, &inplen
);
ret = quic_get_version(&qversion, qch);
if (ret < 0) {
return -EINVAL;
}
if (!quic_check_is_initial(qch)) {
return -EINVAL;
}
switch (qversion) {
case QUIC_V1:
iv_info = quic_iv_info;
iv_info_size = sizeof(quic_iv_info) - 1;
key_info = quic_key_info;
key_info_size = sizeof(quic_key_info) - 1;
hp_info = quic_hp_info;
hp_info_size = sizeof(quic_hp_info) - 1;
initial_salt = (const uint8_t *)QUIC_INITIAL_SALT_V1;
initial_salt_size = sizeof(QUIC_INITIAL_SALT_V1) - 1;
break;
case QUIC_V2:
iv_info = quic2_iv_info;
iv_info_size = sizeof(quic2_iv_info) - 1;
key_info = quic2_key_info;
key_info_size = sizeof(quic2_key_info) - 1;
hp_info = quic2_hp_info;
hp_info_size = sizeof(quic2_hp_info) - 1;
initial_salt = (const uint8_t *)QUIC_INITIAL_SALT_V2;
initial_salt_size = sizeof(QUIC_INITIAL_SALT_V2) - 1;
break;
default:
return -EINVAL;
}
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);
if (ret < 0) {
lgerror(ret, "quic_parse_initial_header");
goto error_nfr;
}
inheader_len = qich.protected_payload - inpayload;
decrypted_payload_len = quic_header_len + inplen;
decrypted_payload = malloc(decrypted_payload_len);
if (decrypted_payload == NULL) {
ret = -ENOMEM;
goto error_nfr;
}
dcptr = decrypted_payload;
// Copy quic large header
memcpy(dcptr, quic_payload, quic_header_len);
dcptr += quic_header_len;
// Copy quic initial large header (until packet number)
memcpy(dcptr, inpayload, inheader_len);
dcptr += inheader_len;
ret = hkdfExtract(SHA256_HASH_ALGO, (const unsigned char *)qci.dst_id, qci.dst_len, initial_salt, initial_salt_size, initial_secret);
if (ret) {
lgerr("hkdfExtract initial_secret: %d", ret);
ret = -EINVAL;
goto error;
}
ret = hkdfExpand(SHA256_HASH_ALGO, initial_secret, SHA256_DIGEST_SIZE, quic_client_in_info, sizeof(quic_client_in_info) - 1, client_initial_secret, QUIC_CLIENT_IN_SIZE);
if (ret) {
lgerr("hkdfExpand client_initial_secret: %d", ret);
ret = -EINVAL;
goto error;
}
ret = hkdfExpand(SHA256_HASH_ALGO, client_initial_secret, SHA256_DIGEST_SIZE, key_info, key_info_size, quic_key, QUIC_KEY_SIZE);
if (ret) {
lgerr("hkdfExpand quic_key: %d", ret);
ret = -EINVAL;
goto error;
}
ret = hkdfExpand(SHA256_HASH_ALGO, client_initial_secret, SHA256_DIGEST_SIZE, iv_info, iv_info_size, quic_iv, QUIC_IV_SIZE);
if (ret) {
lgerr("hkdfExpand quic_iv: %d", ret);
ret = -EINVAL;
goto error;
}
ret = hkdfExpand(SHA256_HASH_ALGO, client_initial_secret, SHA256_DIGEST_SIZE, hp_info, hp_info_size, quic_hp, QUIC_HP_SIZE);
if (ret) {
lgerr("hkdfExpand quic_hp: %d", ret);
ret = -EINVAL;
goto error;
}
// Decrypt packet number length and packet number
ret = aesInit(&actx, quic_hp, QUIC_HP_SIZE);
if (ret) {
lgerr("aesInit with quic_hp: %d", ret);
ret = -EINVAL;
goto error;
}
ret = ecbEncrypt(&aesCipherAlgo, &actx,
qich.sample, mask, qich.sample_length);
if (ret) {
lgerr("ecbEncrypt for mask: %d", ret);
ret = -EINVAL;
goto error;
}
// Update decrypted payload header with decrypted packet_number_length
decrypted_payload[0] ^= mask[0] & 0x0f;
qich_ltspc = (struct quici_lhdr_typespec){decrypted_payload[0]};
packet_number_length = qich_ltspc.number_length + 1;
if (qich.length < packet_number_length) {
ret = -EINVAL;
goto error;
}
packet_number = qich.protected_payload;
protected_payload = qich.protected_payload + packet_number_length;
protected_payload_length = qich.length - packet_number_length;
decrypted_packet_number = dcptr;
for (int i = 0; i < packet_number_length; i++) {
decrypted_packet_number[i] = packet_number[i] ^ mask[i + 1];
}
dcptr += packet_number_length;
for (int i = QUIC_IV_SIZE - packet_number_length, j = 0;
i < QUIC_IV_SIZE; i++, j++) {
quic_iv[i] ^= decrypted_packet_number[j];
}
ret = aesInit(&actx, quic_key, QUIC_KEY_SIZE);
if (ret) {
lgerr("aesInit for quic_key: %d", ret);
ret = -EINVAL;
goto error;
}
ret = gcmInit(&gctx, &aesCipherAlgo, &actx);
if (ret) {
lgerr("gcmInit: %d", ret);
ret = -EINVAL;
goto error;
}
decrypted_message = dcptr;
ret = gcmDecrypt(
&gctx, quic_iv, QUIC_IV_SIZE,
NULL, 0,
protected_payload, decrypted_message, protected_payload_length,
quic_key, QUIC_KEY_SIZE
);
if (ret != 0 && ret != ERROR_FAILURE) {
lgerr("gcmInit: %d", ret);
ret = -EINVAL;
goto error;
}
// TAG is padded in the end of decrypted message
decrypted_message_len = protected_payload_length - QUIC_TAG_SIZE;
if (!udecrypted_payload) {
lgerr("decrypted_payload cannot be NULL!");
ret = -EINVAL;
goto error;
}
*udecrypted_payload = decrypted_payload;
if (udecrypted_payload_len)
*udecrypted_payload_len = decrypted_payload_len;
if (udecrypted_message)
*udecrypted_message = decrypted_message;
if (udecrypted_message_len)
*udecrypted_message_len = decrypted_message_len;
return 0;
error:
free(decrypted_payload);
error_nfr:
return ret;
}

414
src/tls.c Normal file
View File

@@ -0,0 +1,414 @@
/*
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/>.
*/
#include "types.h"
#include "tls.h"
#include "config.h"
#include "logging.h"
#include "utils.h"
#ifndef KERNEL_SPACE
#include <fcntl.h>
#include <unistd.h>
#endif
int bruteforce_analyze_sni_str(
const struct section_config_t *section,
const uint8_t *data, size_t dlen,
struct tls_verdict *vrd
) {
*vrd = (struct tls_verdict){0};
if (section->all_domains) {
vrd->target_sni = 1;
vrd->sni_len = 0;
vrd->sni_ptr = data + dlen / 2;
return 0;
}
int max_domain_len = 0;
for (struct domains_list *sne = section->sni_domains; sne != NULL;
sne = sne->next) {
max_domain_len = max((int)sne->domain_len, max_domain_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;
}
static int analyze_sni_str(
const struct section_config_t *section,
const char *sni_name, int sni_len,
struct tls_verdict *vrd
) {
if (section->all_domains) {
vrd->target_sni = 1;
goto check_domain;
}
for (struct domains_list *sne = section->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 &&
sni_len < 128 &&
!strncmp(sni_startp,
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:
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 &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
sne->domain_len)) {
vrd->target_sni = 0;
lgdebug("Excluded SNI: %.*s",
vrd->sni_len, vrd->sni_ptr);
}
}
}
return 0;
}
int analyze_tls_message(
const struct section_config_t *section,
const uint8_t *message_data,
size_t message_length,
struct tls_verdict *tlsv
) {
*tlsv = (struct tls_verdict){0};
const uint8_t *handshakeProto = message_data;
const uint8_t *data_end = message_data + message_length;
if (handshakeProto + 1 >= data_end)
goto invalid;
uint8_t handshakeType = *handshakeProto;
if (handshakeType != TLS_HANDSHAKE_TYPE_CLIENT_HELLO)
goto next;
const uint8_t *msgPtr = handshakeProto;
msgPtr += 1;
msgPtr += 3 + 2 + 32;
if (msgPtr + 1 >= data_end)
goto invalid;
uint8_t sessionIdLength = *msgPtr;
msgPtr++;
msgPtr += sessionIdLength;
if (msgPtr + 2 >= data_end)
goto invalid;
uint16_t ciphersLength = ntohs(*(uint16_t *)msgPtr);
msgPtr += 2;
msgPtr += ciphersLength;
if (msgPtr + 1 >= data_end)
goto invalid;
uint8_t compMethodsLen = *msgPtr;
msgPtr++;
msgPtr += compMethodsLen;
if (msgPtr + 2 >= data_end)
goto invalid;
uint16_t extensionsLen = ntohs(*(uint16_t *)msgPtr);
msgPtr += 2;
const uint8_t *extensionsPtr = msgPtr;
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
if (extensions_end > data_end) extensions_end = data_end;
while (extensionsPtr < extensions_end) {
const uint8_t *extensionPtr = extensionsPtr;
if (extensionPtr + 4 >= extensions_end)
goto invalid;
uint16_t extensionType =
ntohs(*(uint16_t *)extensionPtr);
extensionPtr += 2;
uint16_t extensionLen =
ntohs(*(uint16_t *)extensionPtr);
extensionPtr += 2;
if (extensionPtr + extensionLen > extensions_end)
goto invalid;
if (extensionType != TLS_EXTENSION_SNI)
goto nextExtension;
const uint8_t *sni_ext_ptr = extensionPtr;
if (sni_ext_ptr + 2 >= extensions_end)
goto invalid;
uint16_t sni_ext_dlen = ntohs(*(uint16_t *)sni_ext_ptr);
sni_ext_ptr += 2;
const uint8_t *sni_ext_end = sni_ext_ptr + sni_ext_dlen;
if (sni_ext_end > extensions_end)
goto invalid;
if (sni_ext_ptr + 3 >= sni_ext_end)
goto invalid;
sni_ext_ptr++;
uint16_t sni_len = ntohs(*(uint16_t *)sni_ext_ptr);
sni_ext_ptr += 2;
if (sni_ext_ptr + sni_len > sni_ext_end)
goto invalid;
const char *sni_name = (char *)sni_ext_ptr;
tlsv->sni_ptr = (const uint8_t *)sni_name;
tlsv->sni_len = sni_len;
tlsv->target_sni_ptr = tlsv->sni_ptr;
tlsv->target_sni_len = tlsv->sni_len;
analyze_sni_str(section, sni_name, sni_len, tlsv);
return TLS_MESSAGE_ANALYZE_FOUND;
nextExtension:
extensionsPtr += 2 + 2 + extensionLen;
}
next:
return TLS_MESSAGE_ANALYZE_GOTO_NEXT;
invalid:
return TLS_MESSAGE_ANALYZE_INVALID;
}
/**
* Processes tls payload of the tcp request.
*
* data Payload data of TCP.
* dlen Length of `data`.
*/
struct tls_verdict analyze_tls_data(
const struct section_config_t *section,
const uint8_t *data,
size_t dlen)
{
struct tls_verdict vrd = {0};
const uint8_t *data_end = data + dlen;
const uint8_t *message_ptr = data;
int ret;
if (section->sni_detection == SNI_DETECTION_BRUTE) {
bruteforce_analyze_sni_str(section, data, dlen, &vrd);
goto out;
}
while (message_ptr + 5 < data_end) {
uint8_t tls_content_type = *message_ptr;
message_ptr++;
uint8_t tls_vmajor = *message_ptr;
if (tls_vmajor != 0x03) break;
message_ptr++;
// uint8_t tls_vminor = *message_ptr;
message_ptr++;
uint16_t message_length = ntohs(*(const uint16_t *)message_ptr);
message_ptr += 2;
const uint8_t *tls_message_data = message_ptr;
// Since real length may be truncated use minimum of two
size_t tls_message_length = min((int)message_length, (int)(data_end - message_ptr));
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
goto nextMessage;
ret = analyze_tls_message(
section,
tls_message_data,
tls_message_length,
&vrd
);
switch (ret) {
case TLS_MESSAGE_ANALYZE_GOTO_NEXT:
goto nextMessage;
case TLS_MESSAGE_ANALYZE_FOUND:
case TLS_MESSAGE_ANALYZE_INVALID:
default:
goto out;
}
nextMessage:
message_ptr += tls_message_length;
}
out:
return vrd;
}
int gen_fake_sni(struct fake_type type,
const void *ipxh, size_t iph_len,
const struct tcphdr *tcph, size_t tcph_len,
uint8_t **ubuf, size_t *ubuflen) {
size_t data_len = type.fake_len;
uint8_t *buf = NULL;
int ret;
if (type.type == FAKE_PAYLOAD_RANDOM && data_len == 0) {
data_len = (size_t)randint() % 1200;
}
if (!ipxh || !tcph || !ubuf || !ubuflen)
return -EINVAL;
int ipxv = netproto_version(ipxh, iph_len);
if (ipxv == IP6VERSION) {
iph_len = sizeof(struct ip6_hdr);
}
size_t dlen = iph_len + tcph_len + data_len;
size_t buffer_len = dlen + 50;
buf = malloc(buffer_len);
if (buf == NULL) {
return -ENOMEM;
}
if (ipxv == IP4VERSION) {
const struct iphdr *iph = ipxh;
memcpy(buf, iph, iph_len);
struct iphdr *niph = (struct iphdr *)buf;
niph->protocol = IPPROTO_TCP;
} else if (ipxv == IP6VERSION) {
const struct ip6_hdr *iph = ipxh;
memcpy(buf, iph, iph_len);
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_nxt = IPPROTO_TCP;
} else {
ret = -EINVAL;
goto error;
}
memcpy(buf + iph_len, tcph, tcph_len);
uint8_t *bfdptr = buf + iph_len + tcph_len;
switch (type.type) {
case FAKE_PAYLOAD_DATA:
memcpy(bfdptr, type.fake_data, data_len);
break;
default: // FAKE_PAYLOAD_RANDOM
#ifdef KERNEL_SPACE
get_random_bytes(bfdptr, data_len);
#else /* KERNEL_SPACE */
#if _NO_GETRANDOM
{
int ret = open("/dev/urandom", O_RDONLY);
if (ret < 0) {
lgerror(ret, "Unable to open /dev/urandom");
return ret;
}
read(ret, bfdptr, data_len);
close(ret);
}
#else /* _NO_GETRANDOM */
getrandom(bfdptr, data_len, 0);
#endif /* _NO_GETRANDOM */
#endif /* KERNEL_SPACE */
}
if (ipxv == IP4VERSION) {
struct iphdr *niph = (struct iphdr *)buf;
niph->tot_len = htons(dlen);
} else if (ipxv == IP6VERSION) {
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_plen = htons(dlen - iph_len);
}
ret = fail_packet(type.strategy, buf, &dlen, buffer_len);
if (ret < 0) {
lgerror(ret, "fail_packet");
goto error;
}
*ubuflen = dlen;
*ubuf = buf;
return 0;
error:
free(buf);
return ret;
}

85
src/tls.h Normal file
View File

@@ -0,0 +1,85 @@
/*
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 TLS_H
#define TLS_H
#include "types.h"
#include "utils.h"
/**
* Result of analyze_tls_data function
*/
struct tls_verdict {
const uint8_t *sni_ptr;
int sni_len;
int target_sni; /* boolean, 1 if target found */
const uint8_t *target_sni_ptr; /* pointer to target domain instead of entire sni */
int target_sni_len; /* length of target domain instead of entire sni */
};
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
#define TLS_EXTENSION_SNI 0x0000
#define TLS_EXTENSION_CLIENT_HELLO_ENCRYPTED 0xfe0d
#define TLS_MESSAGE_ANALYZE_INVALID -1
#define TLS_MESSAGE_ANALYZE_FOUND 0
#define TLS_MESSAGE_ANALYZE_GOTO_NEXT 1
/**
* Analyzes each TLS Client Hello message (inside TLS Record or QUIC CRYPTO FRAME)
*/
int analyze_tls_message(
const struct section_config_t *section,
const uint8_t *message_data,
size_t message_length,
struct tls_verdict *tlsv
);
/**
* Tries to bruteforce over the packet and match domains as plain text
*/
int bruteforce_analyze_sni_str(
const struct section_config_t *section,
const uint8_t *data, size_t dlen,
struct tls_verdict *vrd
);
/**
* Processes the packet and finds TLS Client Hello information inside it.
* data pointer points to start of TLS Message (TCP Payload)
*
* Note that all the constant pointers of tls_verdict will be relative to data pointer
*/
struct tls_verdict analyze_tls_data(const struct section_config_t *section, const uint8_t *data, size_t dlen);
/**
* Allocates and generates the fake client hello message
*/
int gen_fake_sni(struct fake_type type,
const void *iph, size_t iph_len,
const struct tcphdr *tcph, size_t tcph_len,
uint8_t **ubuf, size_t *ubuflen);
#endif /* TLS_H */

View File

@@ -1,3 +1,22 @@
/*
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/>.
*/
#define _GNU_SOURCE
#ifndef TYPES_H
#define TYPES_H
@@ -8,12 +27,25 @@
#include <linux/string.h> // IWYU pragma: export
#include <linux/types.h>
typedef __u8 uint8_t;
typedef __u16 uint16_t;
typedef __u32 uint32_t;
typedef __u64 uint64_t;
typedef __s8 int8_t;
typedef __s16 int16_t;
typedef __s32 int32_t;
typedef __s64 int64_t;
typedef __s32 int_least32_t; /* integer of >= 32 bits */
typedef __s16 int_least16_t; /* integer of >= 16 bits */
#else /* USER_SPACE */
#include <errno.h> // IWYU pragma: export
#include <stdint.h> // IWYU pragma: export
#include <string.h> // IWYU pragma: export
#include <stdlib.h> // IWYU pragma: export
#include <stdio.h> // IWYU pragma: export
#define _NO_GETRANDOM ((__GLIBC__ <= 2 && __GLIBC_MINOR__ < 25))
@@ -36,6 +68,7 @@
#define free kfree
#define malloc(size) kmalloc((size), GFP_KERNEL)
#define calloc(n, size) kcalloc((n), (size), GFP_KERNEL)
#define ip6_hdr ipv6hdr
@@ -93,41 +126,21 @@ free((item)); \
#endif /* not a KERNEL_SPACE */
/* An alternative memory allocation strategy for userspace app */
// #define ALLOC_MALLOC
/**
* Use NETBUF_ALLOC and NETBUF_FREE as an abstraction of memory allocation.
* Do not use it within expressions, consider these defines as separate statements.
*
* Use NETBUF_CHECK to check that buffer was properly allocated.
*/
#ifdef KERNEL_SPACE
#include <linux/gfp.h>
#define NETBUF_ALLOC(buf, buf_len) __u8* buf = kmalloc(buf_len, GFP_KERNEL);
#define NETBUF_CHECK(buf) ((buf) != NULL)
#define NETBUF_FREE(buf) kfree(buf);
#elif defined(ALLOC_MALLOC)
#include <stdlib.h>
#define NETBUF_ALLOC(buf, buf_len) __u8* buf = malloc(buf_len);
#define NETBUF_CHECK(buf) ((buf) != NULL)
#define NETBUF_FREE(buf) free(buf);
#else
#define NETBUF_ALLOC(buf, buf_len) __u8 buf[buf_len];
#define NETBUF_CHECK(buf) (1)
#define NETBUF_FREE(buf) ;
#endif
static inline int randint(void) {
int rnd;
#ifdef KERNEL_SPACE
get_random_bytes(&rnd, sizeof(rnd));
get_random_bytes(&rnd, sizeof(rnd));
#else
rnd = random();
rnd = random();
#endif
return rnd;
}
#ifdef KERNEL_SPACE
#define socklen_t size_t
#endif
const char *inet_ntop(int af, const void * a0, char * s, socklen_t l);
#endif /* TYPES_H */

View File

@@ -1,3 +1,22 @@
/*
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/>.
*/
#include "utils.h"
#include "logging.h"
#include "types.h"
@@ -21,7 +40,7 @@
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
{
#ifdef KERNEL_SPACE
uint32_t tcp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
size_t tcp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
tcph->check = 0;
tcph->check = csum_tcpudp_magic(
iph->saddr, iph->daddr, tcp_packet_len,
@@ -35,7 +54,7 @@ void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
void udp4_set_checksum(struct udphdr *udph, struct iphdr *iph)
{
#ifdef KERNEL_SPACE
uint32_t udp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
size_t udp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
udph->check = 0;
udph->check = csum_tcpudp_magic(
iph->saddr, iph->daddr, udp_packet_len,
@@ -78,7 +97,7 @@ void udp6_set_checksum(struct udphdr *udph, struct ip6_hdr *iph) {
#endif
}
int set_ip_checksum(void *iph, uint32_t iphb_len) {
int set_ip_checksum(void *iph, size_t iphb_len) {
int ipvx = netproto_version(iph, iphb_len);
if (ipvx == IP4VERSION) {
@@ -90,7 +109,7 @@ int set_ip_checksum(void *iph, uint32_t iphb_len) {
return 0;
}
int set_tcp_checksum(struct tcphdr *tcph, void *iph, uint32_t iphb_len) {
int set_tcp_checksum(struct tcphdr *tcph, void *iph, size_t iphb_len) {
int ipvx = netproto_version(iph, iphb_len);
if (ipvx == IP4VERSION) {
@@ -103,7 +122,7 @@ int set_tcp_checksum(struct tcphdr *tcph, void *iph, uint32_t iphb_len) {
return 0;
}
int set_udp_checksum(struct udphdr *udph, void *iph, uint32_t iphb_len) {
int set_udp_checksum(struct udphdr *udph, void *iph, size_t iphb_len) {
int ipvx = netproto_version(iph, iphb_len);
if (ipvx == IP4VERSION) {
@@ -118,9 +137,9 @@ int set_udp_checksum(struct udphdr *udph, void *iph, uint32_t iphb_len) {
}
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
uint8_t **payload, uint32_t *plen) {
int ip4_payload_split(uint8_t *pkt, size_t buflen,
struct iphdr **iph, size_t *iph_len,
uint8_t **payload, size_t *plen) {
if (pkt == NULL || buflen < sizeof(struct iphdr)) {
lgerror(-EINVAL, "ip4_payload_split: pkt|buflen");
return -EINVAL;
@@ -132,10 +151,12 @@ int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
return -EINVAL;
}
uint32_t hdr_len = hdr->ihl * 4;
uint32_t pktlen = ntohs(hdr->tot_len);
size_t hdr_len = hdr->ihl * 4;
size_t pktlen = ntohs(hdr->tot_len);
if (buflen < pktlen || hdr_len > pktlen) {
lgerror(-EINVAL, "ip4_payload_split: buflen cmp pktlen");
lgerror(-EINVAL, "ip4_payload_split: buflen cmp pktlen: "
"buflen = %zu pktlen = %zu hdr_len = %zu",
buflen, pktlen, hdr_len);
return -EINVAL;
}
@@ -151,17 +172,17 @@ int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
return 0;
}
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
struct tcphdr **tcph, uint32_t *tcph_len,
uint8_t **payload, uint32_t *plen) {
int tcp4_payload_split(uint8_t *pkt, size_t buflen,
struct iphdr **iph, size_t *iph_len,
struct tcphdr **tcph, size_t *tcph_len,
uint8_t **payload, size_t *plen) {
struct iphdr *hdr;
uint32_t hdr_len;
size_t hdr_len;
struct tcphdr *thdr;
uint32_t thdr_len;
size_t thdr_len;
uint8_t *tcph_pl;
uint32_t tcph_plen;
size_t tcph_plen;
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
&tcph_pl, &tcph_plen)){
@@ -193,9 +214,9 @@ int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
return 0;
}
int ip6_payload_split(uint8_t *pkt, uint32_t buflen,
struct ip6_hdr **iph, uint32_t *iph_len,
uint8_t **payload, uint32_t *plen) {
int ip6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
uint8_t **payload, size_t *plen) {
if (pkt == NULL || buflen < sizeof(struct ip6_hdr)) {
lgerror(-EINVAL, "ip6_payload_split: pkt|buflen");
return -EINVAL;
@@ -207,10 +228,11 @@ int ip6_payload_split(uint8_t *pkt, uint32_t buflen,
return -EINVAL;
}
uint32_t hdr_len = sizeof(struct ip6_hdr);
uint32_t pktlen = ntohs(hdr->ip6_plen);
size_t hdr_len = sizeof(struct ip6_hdr);
size_t pktlen = ntohs(hdr->ip6_plen);
if (buflen < pktlen) {
lgerror(-EINVAL, "ip6_payload_split: buflen cmp pktlen: %d %d", buflen, pktlen);
lgerror(-EINVAL, "ip6_payload_split: buflen cmp pktlen: "
"buflen = %zu pktlen = %zu", buflen, pktlen);
return -EINVAL;
}
@@ -226,17 +248,17 @@ int ip6_payload_split(uint8_t *pkt, uint32_t buflen,
return 0;
}
int tcp6_payload_split(uint8_t *pkt, uint32_t buflen,
struct ip6_hdr **iph, uint32_t *iph_len,
struct tcphdr **tcph, uint32_t *tcph_len,
uint8_t **payload, uint32_t *plen) {
int tcp6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
struct tcphdr **tcph, size_t *tcph_len,
uint8_t **payload, size_t *plen) {
struct ip6_hdr *hdr;
uint32_t hdr_len;
size_t hdr_len;
struct tcphdr *thdr;
uint32_t thdr_len;
size_t thdr_len;
uint8_t *tcph_pl;
uint32_t tcph_plen;
size_t tcph_plen;
if (ip6_payload_split(pkt, buflen, &hdr, &hdr_len,
&tcph_pl, &tcph_plen)){
@@ -268,10 +290,10 @@ int tcp6_payload_split(uint8_t *pkt, uint32_t buflen,
return 0;
}
int tcp_payload_split(uint8_t *pkt, uint32_t buflen,
void **iph, uint32_t *iph_len,
struct tcphdr **tcph, uint32_t *tcph_len,
uint8_t **payload, uint32_t *plen) {
int tcp_payload_split(uint8_t *pkt, size_t buflen,
void **iph, size_t *iph_len,
struct tcphdr **tcph, size_t *tcph_len,
uint8_t **payload, size_t *plen) {
int netvers = netproto_version(pkt, buflen);
if (netvers == IP4VERSION) {
return tcp4_payload_split(pkt, buflen, (struct iphdr **)iph, iph_len, tcph, tcph_len, payload, plen);
@@ -284,16 +306,16 @@ int tcp_payload_split(uint8_t *pkt, uint32_t buflen,
}
int udp4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
int udp4_payload_split(uint8_t *pkt, size_t buflen,
struct iphdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, uint32_t *plen) {
uint8_t **payload, size_t *plen) {
struct iphdr *hdr;
uint32_t hdr_len;
size_t hdr_len;
struct udphdr *uhdr;
uint8_t *ip_ph;
uint32_t ip_phlen;
size_t ip_phlen;
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
&ip_ph, &ip_phlen)){
@@ -322,16 +344,16 @@ int udp4_payload_split(uint8_t *pkt, uint32_t buflen,
return 0;
}
int udp6_payload_split(uint8_t *pkt, uint32_t buflen,
struct ip6_hdr **iph, uint32_t *iph_len,
int udp6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, uint32_t *plen) {
uint8_t **payload, size_t *plen) {
struct ip6_hdr *hdr;
uint32_t hdr_len;
size_t hdr_len;
struct udphdr *uhdr;
uint8_t *ip_ph;
uint32_t ip_phlen;
size_t ip_phlen;
if (ip6_payload_split(pkt, buflen, &hdr, &hdr_len,
&ip_ph, &ip_phlen)){
@@ -360,10 +382,10 @@ int udp6_payload_split(uint8_t *pkt, uint32_t buflen,
return 0;
}
int udp_payload_split(uint8_t *pkt, uint32_t buflen,
void **iph, uint32_t *iph_len,
int udp_payload_split(uint8_t *pkt, size_t buflen,
void **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, uint32_t *plen) {
uint8_t **payload, size_t *plen) {
int netvers = netproto_version(pkt, buflen);
if (netvers == IP4VERSION) {
return udp4_payload_split(pkt, buflen, (struct iphdr **)iph, iph_len, udph, payload, plen);
@@ -376,14 +398,14 @@ int udp_payload_split(uint8_t *pkt, uint32_t buflen,
}
// split packet to two ipv4 fragments.
int ip4_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
uint8_t *frag1, uint32_t *f1len,
uint8_t *frag2, uint32_t *f2len) {
int ip4_frag(const uint8_t *pkt, size_t buflen, size_t payload_offset,
uint8_t *frag1, size_t *f1len,
uint8_t *frag2, size_t *f2len) {
struct iphdr *hdr;
const uint8_t *payload;
uint32_t plen;
uint32_t hdr_len;
size_t plen;
size_t hdr_len;
int ret;
if (!frag1 || !f1len || !frag2 || !f2len)
@@ -406,11 +428,11 @@ int ip4_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
return -EINVAL;
}
uint32_t f1_plen = payload_offset;
uint32_t f1_dlen = f1_plen + hdr_len;
size_t f1_plen = payload_offset;
size_t f1_dlen = f1_plen + hdr_len;
uint32_t f2_plen = plen - payload_offset;
uint32_t f2_dlen = f2_plen + hdr_len;
size_t f2_plen = plen - payload_offset;
size_t f2_dlen = f2_plen + hdr_len;
if (*f1len < f1_dlen || *f2len < f2_dlen) {
return -ENOMEM;
@@ -455,15 +477,15 @@ int ip4_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
}
// split packet to two tcp-on-ipv4 segments.
int tcp_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
uint8_t *seg1, uint32_t *s1len,
uint8_t *seg2, uint32_t *s2len) {
int tcp_frag(const uint8_t *pkt, size_t buflen, size_t payload_offset,
uint8_t *seg1, size_t *s1len,
uint8_t *seg2, size_t *s2len) {
void *hdr;
uint32_t hdr_len;
size_t hdr_len;
struct tcphdr *tcph;
uint32_t tcph_len;
uint32_t plen;
size_t tcph_len;
size_t plen;
const uint8_t *payload;
int ret;
@@ -487,7 +509,7 @@ int tcp_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
if (
ntohs(iphdr->frag_off) & IP_MF ||
ntohs(iphdr->frag_off) & IP_OFFMASK) {
lgdebugmsg("tcp_frag: ip4: frag value: %d",
lgdebug("tcp_frag: ip4: frag value: %d",
ntohs(iphdr->frag_off));
lgerror(-EINVAL, "tcp_frag: ip4: ip fragmentation is set");
return -EINVAL;
@@ -499,11 +521,11 @@ int tcp_frag(const uint8_t *pkt, uint32_t buflen, uint32_t payload_offset,
return -EINVAL;
}
uint32_t s1_plen = payload_offset;
uint32_t s1_dlen = s1_plen + hdr_len + tcph_len;
size_t s1_plen = payload_offset;
size_t s1_dlen = s1_plen + hdr_len + tcph_len;
uint32_t s2_plen = plen - payload_offset;
uint32_t s2_dlen = s2_plen + hdr_len + tcph_len;
size_t s2_plen = plen - payload_offset;
size_t s2_dlen = s2_plen + hdr_len + tcph_len;
if (*s1len < s1_dlen || *s2len < s2_dlen)
return -ENOMEM;
@@ -570,7 +592,7 @@ void z_function(const char *str, int *zbuf, size_t len) {
}
}
void shift_data(uint8_t *data, uint32_t dlen, uint32_t delta) {
void shift_data(uint8_t *data, size_t dlen, size_t delta) {
uint8_t *ndptr = data + delta + dlen;
uint8_t *dptr = data + dlen;
uint8_t *ndlptr = data;
@@ -594,20 +616,20 @@ struct tcp_md5sig_opt {
// Real length of the option, with NOOP fillers
#define TCP_MD5SIG_OPT_RLEN 20
int fail_packet(struct failing_strategy strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen) {
int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen, size_t avail_buflen) {
void *iph;
uint32_t iph_len;
size_t iph_len;
struct tcphdr *tcph;
uint32_t tcph_len;
size_t tcph_len;
uint8_t *data;
uint32_t dlen;
size_t dlen;
int ret;
ret = tcp_payload_split(payload, *plen,
&iph, &iph_len, &tcph, &tcph_len,
&data, &dlen);
uint32_t ipxv = netproto_version(payload, *plen);
int ipxv = netproto_version(payload, *plen);
if (ret < 0) {
return ret;
@@ -615,13 +637,13 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, uint32_t *pl
if (strategy.strategy == FAKE_STRAT_RAND_SEQ) {
lgtrace("fake seq: %u -> ", ntohl(tcph->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));
} else if (strategy.strategy == FAKE_STRAT_PAST_SEQ) {
lgtrace("fake seq: %u -> ", ntohl(tcph->seq));
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
tcph->seq = htonl(ntohl(tcph->seq) - dlen);
lgtrace_addp("%u", ntohl(tcph->seq));
@@ -691,15 +713,15 @@ int fail_packet(struct failing_strategy strategy, uint8_t *payload, uint32_t *pl
return 0;
}
int seqovl_packet(uint8_t *payload, uint32_t *plen, uint32_t seq_delta) {
int seqovl_packet(uint8_t *payload, size_t *plen, size_t seq_delta) {
int ipxv = netproto_version(payload, *plen);
void *iph;
uint32_t iph_len;
size_t iph_len;
struct tcphdr *tcph;
uint32_t tcph_len;
size_t tcph_len;
uint8_t *data;
uint32_t dlen;
size_t dlen;
int ret = tcp_payload_split(payload, *plen,

View File

@@ -1,3 +1,22 @@
/*
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 UTILS_H
#define UTILS_H
@@ -12,33 +31,33 @@
* payload_offset indicates the position relatively to start of IP payload
* (start of transport header)
*/
int ip4_frag(const uint8_t *pkt, uint32_t pktlen,
uint32_t payload_offset,
uint8_t *frag1, uint32_t *f1len,
uint8_t *frag2, uint32_t *f2len);
int ip4_frag(const uint8_t *pkt, size_t pktlen,
size_t payload_offset,
uint8_t *frag1, size_t *f1len,
uint8_t *frag2, size_t *f2len);
/**
* Splits the packet to two TCP segments on position payload_offset
* payload_offset indicates the position relatively to start of TCP payload.
*/
// int tcp4_frag(const uint8_t *pkt, uint32_t pktlen,
// uint32_t payload_offset,
// uint8_t *seg1, uint32_t *s1len,
// uint8_t *seg2, uint32_t *s2len);
int tcp_frag(const uint8_t *pkt, uint32_t pktlen,
uint32_t payload_offset,
uint8_t *seg1, uint32_t *s1len,
uint8_t *seg2, uint32_t *s2len);
// int tcp4_frag(const uint8_t *pkt, size_t pktlen,
// size_t payload_offset,
// uint8_t *seg1, size_t *s1len,
// uint8_t *seg2, size_t *s2len);
int tcp_frag(const uint8_t *pkt, size_t pktlen,
size_t payload_offset,
uint8_t *seg1, size_t *s1len,
uint8_t *seg2, size_t *s2len);
/**
* Splits the raw packet payload to ip header and ip payload.
*/
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
uint8_t **payload, uint32_t *plen);
int ip4_payload_split(uint8_t *pkt, size_t buflen,
struct iphdr **iph, size_t *iph_len,
uint8_t **payload, size_t *plen);
static inline int netproto_version(const uint8_t *pkt, uint32_t buflen) {
static inline int netproto_version(const uint8_t *pkt, size_t buflen) {
if (pkt == NULL || buflen == 0)
return -1;
@@ -49,48 +68,48 @@ static inline int netproto_version(const uint8_t *pkt, uint32_t buflen) {
/**
* Splits the raw packet payload to ip header, tcp header and tcp payload.
*/
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
struct tcphdr **tcph, uint32_t *tcph_len,
uint8_t **payload, uint32_t *plen);
int tcp4_payload_split(uint8_t *pkt, size_t buflen,
struct iphdr **iph, size_t *iph_len,
struct tcphdr **tcph, size_t *tcph_len,
uint8_t **payload, size_t *plen);
/**
* Splits the raw packet payload to ip header and ip payload.
*/
int ip6_payload_split(uint8_t *pkt, uint32_t buflen,
struct ip6_hdr **iph, uint32_t *iph_len,
uint8_t **payload, uint32_t *plen);
int ip6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
uint8_t **payload, size_t *plen);
/**
* Splits the raw packet payload to ip header, tcp header and tcp payload.
*/
int tcp6_payload_split(uint8_t *pkt, uint32_t buflen,
struct ip6_hdr **iph, uint32_t *iph_len,
struct tcphdr **tcph, uint32_t *tcph_len,
uint8_t **payload, uint32_t *plen);
int tcp6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
struct tcphdr **tcph, size_t *tcph_len,
uint8_t **payload, size_t *plen);
int tcp_payload_split(uint8_t *pkt, uint32_t buflen,
void **iph, uint32_t *iph_len,
struct tcphdr **tcph, uint32_t *tcph_len,
uint8_t **payload, uint32_t *plen);
int tcp_payload_split(uint8_t *pkt, size_t buflen,
void **iph, size_t *iph_len,
struct tcphdr **tcph, size_t *tcph_len,
uint8_t **payload, size_t *plen);
/**
* Splits the raw packet payload to ip header, udp header and udp payload.
*/
int udp4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
int udp4_payload_split(uint8_t *pkt, size_t buflen,
struct iphdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, uint32_t *plen);
uint8_t **payload, size_t *plen);
int udp6_payload_split(uint8_t *pkt, uint32_t buflen,
struct ip6_hdr **iph, uint32_t *iph_len,
int udp6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, uint32_t *plen);
uint8_t **payload, size_t *plen);
int udp_payload_split(uint8_t *pkt, uint32_t buflen,
void **iph, uint32_t *iph_len,
int udp_payload_split(uint8_t *pkt, size_t buflen,
void **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, uint32_t *plen);
uint8_t **payload, size_t *plen);
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph);
void ip4_set_checksum(struct iphdr *iph);
@@ -99,22 +118,22 @@ void tcp6_set_checksum(struct tcphdr *tcph, struct ip6_hdr *iph);
void udp4_set_checksum(struct udphdr *udph, struct iphdr *iph);
void udp6_set_checksum(struct udphdr *udph, struct ip6_hdr *iph);
int set_ip_checksum(void *iph, uint32_t iphb_len);
int set_tcp_checksum(struct tcphdr *tcph, void *iph, uint32_t iphb_len);
int set_udp_checksum(struct udphdr *udph, void *iph, uint32_t iphb_len);
int set_ip_checksum(void *iph, size_t iphb_len);
int set_tcp_checksum(struct tcphdr *tcph, void *iph, size_t iphb_len);
int set_udp_checksum(struct udphdr *udph, void *iph, size_t iphb_len);
void z_function(const char *str, int *zbuf, size_t len);
/**
* Shifts data left delta bytes. Fills delta buffer with zeroes.
*/
void shift_data(uint8_t *data, uint32_t dlen, uint32_t delta);
void shift_data(uint8_t *data, size_t dlen, size_t delta);
struct failing_strategy {
unsigned int strategy;
uint8_t faking_ttl;
uint32_t randseq_offset;
size_t randseq_offset;
};
@@ -165,12 +184,12 @@ struct udp_fake_type {
*
* Does not support bitmask, pass standalone strategy.
*/
int fail_packet(struct failing_strategy strategy, uint8_t *payload, uint32_t *plen, uint32_t avail_buflen);
int fail_packet(struct failing_strategy strategy, uint8_t *payload, size_t *plen, size_t avail_buflen);
/**
* Shifts the payload right and pushes zeroes before it. Useful for TCP TLS faking.
*/
int seqovl_packet(uint8_t *payload, uint32_t *plen, uint32_t seq_delta);
int seqovl_packet(uint8_t *payload, size_t *plen, size_t seq_delta);
@@ -178,7 +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,
.randseq_offset = (uint32_t)section->fakeseq_offset
.randseq_offset = (size_t)section->fakeseq_offset
};
return fl_strat;
}

View File

@@ -1,3 +1,22 @@
/*
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/>.
*/
#define _GNU_SOURCE
#ifndef __linux__
#error "The package is linux only!"
@@ -40,6 +59,8 @@ int rawsocket = -2;
pthread_mutex_t raw6socket_lock;
int raw6socket = -2;
static struct config_t *cur_config = NULL;
static int open_socket(struct mnl_socket **_nl) {
struct mnl_socket *nl = NULL;
nl = mnl_socket_open(NETLINK_NETFILTER);
@@ -87,16 +108,16 @@ static int open_raw_socket(void) {
return -1;
}
int mark = config.mark;
int mark = cur_config->mark;
if (setsockopt(rawsocket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
{
lgerror(-errno, "setsockopt(SO_MARK, %d) failed\n", mark);
lgerror(-errno, "setsockopt(SO_MARK, %d) failed", mark);
return -1;
}
int mst = pthread_mutex_init(&rawsocket_lock, NULL);
if (mst) {
lgerror(-errno, "Mutex err: %d\n", mst);
lgerror(-errno, "Mutex err: %d", mst);
close(rawsocket);
errno = mst;
@@ -139,16 +160,16 @@ static int open_raw6_socket(void) {
return -1;
}
int mark = config.mark;
int mark = cur_config->mark;
if (setsockopt(raw6socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
{
lgerror(-errno, "setsockopt(SO_MARK, %d) failed\n", mark);
lgerror(-errno, "setsockopt(SO_MARK, %d) failed", mark);
return -1;
}
int mst = pthread_mutex_init(&raw6socket_lock, NULL);
if (mst) {
lgerror(-errno, "Mutex err: %d\n", mst);
lgerror(-errno, "Mutex err: %d", mst);
close(raw6socket);
return -1;
@@ -177,7 +198,232 @@ static int close_raw6_socket(void) {
return 0;
}
static int send_raw_ipv4(const uint8_t *pkt, uint32_t pktlen) {
/*
* 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;
@@ -198,14 +444,14 @@ static int send_raw_ipv4(const uint8_t *pkt, uint32_t pktlen) {
}
};
if (config.threads != 1)
if (cur_config->threads != 1)
pthread_mutex_lock(&rawsocket_lock);
int sent = sendto(rawsocket,
pkt, pktlen, MSG_DONTWAIT,
(struct sockaddr *)&daddr, sizeof(daddr));
if (config.threads != 1)
if (cur_config->threads != 1)
pthread_mutex_unlock(&rawsocket_lock);
/* The function will return -errno on error as well as errno value set itself */
@@ -214,7 +460,7 @@ static int send_raw_ipv4(const uint8_t *pkt, uint32_t pktlen) {
return sent;
}
static int send_raw_ipv6(const uint8_t *pkt, uint32_t pktlen) {
static int send_raw_ipv6(const uint8_t *pkt, size_t pktlen) {
int ret;
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
@@ -233,7 +479,7 @@ static int send_raw_ipv6(const uint8_t *pkt, uint32_t pktlen) {
.sin6_addr = iph->ip6_dst
};
if (config.threads != 1)
if (cur_config->threads != 1)
pthread_mutex_lock(&rawsocket_lock);
int sent = sendto(raw6socket,
@@ -242,7 +488,7 @@ static int send_raw_ipv6(const uint8_t *pkt, uint32_t pktlen) {
lgtrace_addp("rawsocket sent %d", sent);
if (config.threads != 1)
if (cur_config->threads != 1)
pthread_mutex_unlock(&rawsocket_lock);
/* The function will return -errno on error as well as errno value set itself */
@@ -251,56 +497,52 @@ static int send_raw_ipv6(const uint8_t *pkt, uint32_t pktlen) {
return sent;
}
static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
static int send_raw_socket(const uint8_t *pkt, size_t pktlen) {
int ret;
if (pktlen > AVAILABLE_MTU) {
lgtrace("Split packet!\n");
lgtrace("Split packet!");
NETBUF_ALLOC(buff1, MNL_SOCKET_BUFFER_SIZE);
if (!NETBUF_CHECK(buff1)) {
size_t buff1_size = pktlen;
uint8_t *buff1 = malloc(buff1_size);
if (buff1 == NULL) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
NETBUF_ALLOC(buff2, MNL_SOCKET_BUFFER_SIZE);
if (!NETBUF_CHECK(buff2)) {
size_t buff2_size = pktlen;
uint8_t *buff2 = malloc(buff2_size);
if (buff2 == NULL) {
lgerror(-ENOMEM, "Allocation error");
NETBUF_FREE(buff1);
free(buff1);
return -ENOMEM;
}
uint32_t buff1_size = MNL_SOCKET_BUFFER_SIZE;
uint32_t buff2_size = MNL_SOCKET_BUFFER_SIZE;
if ((ret = tcp_frag(pkt, pktlen, AVAILABLE_MTU-128,
buff1, &buff1_size, buff2, &buff2_size)) < 0) {
errno = -ret;
goto free_buffs;
goto erret_lc;
}
int sent = 0;
int status = send_raw_socket(buff1, buff1_size);
ret = send_raw_socket(buff1, buff1_size);
if (status >= 0) sent += status;
if (ret >= 0) sent += ret;
else {
ret = status;
goto free_buffs;
goto erret_lc;
}
status = send_raw_socket(buff2, buff2_size);
if (status >= 0) sent += status;
ret = send_raw_socket(buff2, buff2_size);
if (ret >= 0) sent += ret;
else {
ret = status;
goto free_buffs;
goto erret_lc;
}
ret = sent;
free_buffs:
NETBUF_FREE(buff1)
NETBUF_FREE(buff2)
free(buff1);
free(buff2);
return sent;
erret_lc:
free(buff1);
free(buff2);
return ret;
}
@@ -311,7 +553,7 @@ free_buffs:
} else if (ipvx == IP6VERSION) {
ret = send_raw_ipv6(pkt, pktlen);
} else {
lginfo("proto version %d is unsupported\n", ipvx);
printf("proto version %d is unsupported\n", ipvx);
return -EINVAL;
}
@@ -319,14 +561,6 @@ free_buffs:
return ret;
}
struct packet_data {
uint32_t id;
uint16_t hw_proto;
uint8_t hook;
void *payload;
uint16_t payload_len;
};
// Per-queue data. Passed to queue_cb.
struct queue_data {
@@ -354,7 +588,7 @@ static int fallback_accept_packet(uint32_t id, struct queue_data qdata) {
struct dps_t {
uint8_t *pkt;
uint32_t pktlen;
size_t pktlen;
// Time for the packet in milliseconds
uint32_t timer;
};
@@ -363,7 +597,7 @@ void *delay_packet_send_fn(void *data) {
struct dps_t *dpdt = data;
uint8_t *pkt = dpdt->pkt;
uint32_t pktlen = dpdt->pktlen;
size_t pktlen = dpdt->pktlen;
usleep(dpdt->timer * 1000);
int ret = send_raw_socket(pkt, pktlen);
@@ -377,7 +611,7 @@ void *delay_packet_send_fn(void *data) {
return NULL;
}
int delay_packet_send(const unsigned char *data, unsigned int data_len, unsigned int delay_ms) {
int delay_packet_send(const unsigned char *data, size_t data_len, unsigned int delay_ms) {
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
dpdt->pkt = malloc(data_len);
memcpy(dpdt->pkt, data, data_len);
@@ -399,6 +633,12 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
struct nfqnl_msg_packet_hdr *ph = NULL;
struct nlattr *attr[NFQA_MAX+1] = {0};
struct packet_data packet = {0};
struct ytb_conntrack *yct = &packet.yct;
struct nfgenmsg *nfg;
struct nlmsghdr *verdnlh;
int ret;
uint16_t l3num;
uint32_t id;
if (nfq_nlmsg_parse(nlh, attr) < 0) {
lgerror(-errno, "Attr parse");
@@ -411,39 +651,55 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) {
return MNL_CB_ERROR;
}
nfg = mnl_nlmsg_get_payload(nlh);
l3num = nfg->nfgen_family;
ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]);
packet.id = ntohl(ph->packet_id);
packet.hw_proto = ntohs(ph->hw_protocol);
packet.hook = ph->hook;
id = ntohl(ph->packet_id);
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) {
lgerr("The packet was truncated! Skip!\n");
return fallback_accept_packet(packet.id, *qdata);
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 ((ntohl(mnl_attr_get_u32(attr[NFQA_MARK])) & config.mark) ==
config.mark) {
return fallback_accept_packet(packet.id, *qdata);
if ((ntohl(mnl_attr_get_u32(attr[NFQA_MARK])) & cur_config->mark) ==
cur_config->mark) {
return fallback_accept_packet(id, *qdata);
}
}
if (attr[NFQA_CT] != NULL) {
ret = yct_payload_parse(
mnl_attr_get_payload(attr[NFQA_CT]),
mnl_attr_get_payload_len(attr[NFQA_CT]),
l3num, yct);
if (ret < 0) {
lgerror(ret, "Cannot parse CT");
struct nlmsghdr *verdnlh;
goto ct_out;
}
lgtrace("[CONNTRACK TRACE] orig_packets=%lu repl_packets=%lu orig_bytes=%lu repl_bytes=%lu connmark=%d id=%ud\n", yct->orig_packets, yct->repl_packets, yct->orig_bytes, yct->repl_bytes, yct->connmark, yct->id);
}
ct_out:
verdnlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qdata->queue_num);
int ret = process_packet(packet.payload, packet.payload_len);
ret = process_packet(cur_config, &packet);
switch (ret) {
case PKT_DROP:
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_DROP);
nfq_nlmsg_verdict_put(verdnlh, id, NF_DROP);
break;
default:
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_ACCEPT);
nfq_nlmsg_verdict_put(verdnlh, id, NF_ACCEPT);
break;
}
@@ -468,12 +724,11 @@ int init_queue(int queue_num) {
uint32_t portid = mnl_socket_get_portid(nl);
struct nlmsghdr *nlh;
NETBUF_ALLOC(bbuf, BUF_SIZE);
if (!NETBUF_CHECK(bbuf)) {
char *buf = malloc(BUF_SIZE);
if (buf == NULL) {
lgerror(-ENOMEM, "Allocation error");
goto die_alloc;
}
char *buf = (char *)bbuf;
/* Support for kernels versions < 3.8 */
// Obsolete and ignored in kernel version 3.8
@@ -495,7 +750,7 @@ int init_queue(int queue_num) {
goto die;
}
if (config.use_ipv6) {
if (cur_config->use_ipv6) {
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, PF_INET6, NFQNL_CFG_CMD_PF_UNBIND);
@@ -525,10 +780,20 @@ int init_queue(int queue_num) {
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff);
if (config.use_gso) {
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(NFQA_CFG_F_GSO));
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(NFQA_CFG_F_GSO));
unsigned int cfg_flags = NFQA_CFG_F_GSO | NFQA_CFG_F_CONNTRACK | NFQA_CFG_F_FAIL_OPEN;
unsigned int cfg_mask = 0;
if (cur_config->use_gso) {
cfg_mask |= NFQA_CFG_F_GSO;
}
if (cur_config->use_conntrack) {
cfg_mask |= NFQA_CFG_F_CONNTRACK;
}
cfg_mask |= NFQA_CFG_F_FAIL_OPEN;
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(cfg_flags));
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(cfg_mask));
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
@@ -548,7 +813,7 @@ int init_queue(int queue_num) {
.queue_num = queue_num
};
lginfo("Queue %d started\n", qdata.queue_num);
lginfo("Queue %d started", qdata.queue_num);
while (1) {
ret = mnl_socket_recvfrom(nl, buf, BUF_SIZE);
@@ -559,23 +824,23 @@ int init_queue(int queue_num) {
ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, &qdata);
if (ret < 0) {
lgerror(-EPERM, "mnl_cb_run");
if (errno == EPERM) {
lgerror(-errno, "Probably another instance of youtubeUnblock with the same queue number is running\n");
lgerror(ret, "mnl_cb_run");
if (ret == -EPERM) {
lgerr("Probably another instance of youtubeUnblock with the same queue number is running");
} else {
lgerror(-errno, "Make sure the nfnetlink_queue kernel module is loaded\n");
lgerr("Make sure the nfnetlink_queue kernel module is loaded");
}
goto die;
}
}
NETBUF_FREE(bbuf)
free(buf);
close_socket(&nl);
return 0;
die:
NETBUF_FREE(bbuf)
free(buf);
die_alloc:
close_socket(&nl);
return -1;
@@ -600,7 +865,7 @@ void *init_queue_wrapper(void *qdconf) {
thres->status = init_queue(qconf->queue_num);
lgerror(thres->status, "Thread %d exited with status %d\n", qconf->i, thres->status);
lgerror(thres->status, "Thread %d exited with status %d", qconf->i, thres->status);
return thres;
}
@@ -612,7 +877,9 @@ struct instance_config_t instance_config = {
int main(int argc, char *argv[]) {
int ret;
if ((ret = yparse_args(argc, argv)) != 0) {
struct config_t config;
if ((ret = yparse_args(&config, argc, argv)) != 0) {
if (ret < 0) {
lgerror(-errno, "Unable to parse args");
exit(EXIT_FAILURE);
@@ -621,7 +888,10 @@ int main(int argc, char *argv[]) {
}
print_version();
print_welcome();
print_welcome(&config);
parse_global_lgconf(&config);
cur_config = &config;
if (open_raw_socket() < 0) {
@@ -651,7 +921,7 @@ int main(int argc, char *argv[]) {
qres = init_queue_wrapper(&tconf);
} else {
lginfo("%d threads wil be used\n", config.threads);
lginfo("%d threads wil be used", config.threads);
struct queue_conf thread_confs[MAX_THREADS];
pthread_t threads[MAX_THREADS];

18
test/main_fn.c Normal file
View File

@@ -0,0 +1,18 @@
#include "config.h"
#include "unity_fixture.h"
struct instance_config_t instance_config = {
.send_raw_packet = NULL,
.send_delayed_packet = NULL,
};
static void RunAllTests(void)
{
RUN_TEST_GROUP(TLSTest)
RUN_TEST_GROUP(QuicTest);
}
int main(int argc, const char * argv[])
{
return UnityMain(argc, argv, RunAllTests);
}

255
test/quic.c Normal file
View File

@@ -0,0 +1,255 @@
// RFC 9001 Appendix A.
static const char quic_testing_payload[] = "\xc0\x00\x00\x00\x01\x08\x83\x94\xc8\xf0\x3e\x51\x57\x08\x00\x00\x44\x9e\x7b\x9a\xec\x34\xd1\xb1\xc9\x8d\xd7\x68\x9f\xb8\xec\x11\xd2\x42\xb1\x23\xdc\x9b\xd8\xba\xb9\x36\xb4\x7d\x92\xec\x35\x6c\x0b\xab\x7d\xf5\x97\x6d\x27\xcd\x44\x9f\x63\x30\x00\x99\xf3\x99\x1c\x26\x0e\xc4\xc6\x0d\x17\xb3\x1f\x84\x29\x15\x7b\xb3\x5a\x12\x82\xa6\x43\xa8\xd2\x26\x2c\xad\x67\x50\x0c\xad\xb8\xe7\x37\x8c\x8e\xb7\x53\x9e\xc4\xd4\x90\x5f\xed\x1b\xee\x1f\xc8\xaa\xfb\xa1\x7c\x75\x0e\x2c\x7a\xce\x01\xe6\x00\x5f\x80\xfc\xb7\xdf\x62\x12\x30\xc8\x37\x11\xb3\x93\x43\xfa\x02\x8c\xea\x7f\x7f\xb5\xff\x89\xea\xc2\x30\x82\x49\xa0\x22\x52\x15\x5e\x23\x47\xb6\x3d\x58\xc5\x45\x7a\xfd\x84\xd0\x5d\xff\xfd\xb2\x03\x92\x84\x4a\xe8\x12\x15\x46\x82\xe9\xcf\x01\x2f\x90\x21\xa6\xf0\xbe\x17\xdd\xd0\xc2\x08\x4d\xce\x25\xff\x9b\x06\xcd\xe5\x35\xd0\xf9\x20\xa2\xdb\x1b\xf3\x62\xc2\x3e\x59\x6d\x11\xa4\xf5\xa6\xcf\x39\x48\x83\x8a\x3a\xec\x4e\x15\xda\xf8\x50\x0a\x6e\xf6\x9e\xc4\xe3\xfe\xb6\xb1\xd9\x8e\x61\x0a\xc8\xb7\xec\x3f\xaf\x6a\xd7\x60\xb7\xba\xd1\xdb\x4b\xa3\x48\x5e\x8a\x94\xdc\x25\x0a\xe3\xfd\xb4\x1e\xd1\x5f\xb6\xa8\xe5\xeb\xa0\xfc\x3d\xd6\x0b\xc8\xe3\x0c\x5c\x42\x87\xe5\x38\x05\xdb\x05\x9a\xe0\x64\x8d\xb2\xf6\x42\x64\xed\x5e\x39\xbe\x2e\x20\xd8\x2d\xf5\x66\xda\x8d\xd5\x99\x8c\xca\xbd\xae\x05\x30\x60\xae\x6c\x7b\x43\x78\xe8\x46\xd2\x9f\x37\xed\x7b\x4e\xa9\xec\x5d\x82\xe7\x96\x1b\x7f\x25\xa9\x32\x38\x51\xf6\x81\xd5\x82\x36\x3a\xa5\xf8\x99\x37\xf5\xa6\x72\x58\xbf\x63\xad\x6f\x1a\x0b\x1d\x96\xdb\xd4\xfa\xdd\xfc\xef\xc5\x26\x6b\xa6\x61\x17\x22\x39\x5c\x90\x65\x56\xbe\x52\xaf\xe3\xf5\x65\x63\x6a\xd1\xb1\x7d\x50\x8b\x73\xd8\x74\x3e\xeb\x52\x4b\xe2\x2b\x3d\xcb\xc2\xc7\x46\x8d\x54\x11\x9c\x74\x68\x44\x9a\x13\xd8\xe3\xb9\x58\x11\xa1\x98\xf3\x49\x1d\xe3\xe7\xfe\x94\x2b\x33\x04\x07\xab\xf8\x2a\x4e\xd7\xc1\xb3\x11\x66\x3a\xc6\x98\x90\xf4\x15\x70\x15\x85\x3d\x91\xe9\x23\x03\x7c\x22\x7a\x33\xcd\xd5\xec\x28\x1c\xa3\xf7\x9c\x44\x54\x6b\x9d\x90\xca\x00\xf0\x64\xc9\x9e\x3d\xd9\x79\x11\xd3\x9f\xe9\xc5\xd0\xb2\x3a\x22\x9a\x23\x4c\xb3\x61\x86\xc4\x81\x9e\x8b\x9c\x59\x27\x72\x66\x32\x29\x1d\x6a\x41\x82\x11\xcc\x29\x62\xe2\x0f\xe4\x7f\xeb\x3e\xdf\x33\x0f\x2c\x60\x3a\x9d\x48\xc0\xfc\xb5\x69\x9d\xbf\xe5\x89\x64\x25\xc5\xba\xc4\xae\xe8\x2e\x57\xa8\x5a\xaf\x4e\x25\x13\xe4\xf0\x57\x96\xb0\x7b\xa2\xee\x47\xd8\x05\x06\xf8\xd2\xc2\x5e\x50\xfd\x14\xde\x71\xe6\xc4\x18\x55\x93\x02\xf9\x39\xb0\xe1\xab\xd5\x76\xf2\x79\xc4\xb2\xe0\xfe\xb8\x5c\x1f\x28\xff\x18\xf5\x88\x91\xff\xef\x13\x2e\xef\x2f\xa0\x93\x46\xae\xe3\x3c\x28\xeb\x13\x0f\xf2\x8f\x5b\x76\x69\x53\x33\x41\x13\x21\x19\x96\xd2\x00\x11\xa1\x98\xe3\xfc\x43\x3f\x9f\x25\x41\x01\x0a\xe1\x7c\x1b\xf2\x02\x58\x0f\x60\x47\x47\x2f\xb3\x68\x57\xfe\x84\x3b\x19\xf5\x98\x40\x09\xdd\xc3\x24\x04\x4e\x84\x7a\x4f\x4a\x0a\xb3\x4f\x71\x95\x95\xde\x37\x25\x2d\x62\x35\x36\x5e\x9b\x84\x39\x2b\x06\x10\x85\x34\x9d\x73\x20\x3a\x4a\x13\xe9\x6f\x54\x32\xec\x0f\xd4\xa1\xee\x65\xac\xcd\xd5\xe3\x90\x4d\xf5\x4c\x1d\xa5\x10\xb0\xff\x20\xdc\xc0\xc7\x7f\xcb\x2c\x0e\x0e\xb6\x05\xcb\x05\x04\xdb\x87\x63\x2c\xf3\xd8\xb4\xda\xe6\xe7\x05\x76\x9d\x1d\xe3\x54\x27\x01\x23\xcb\x11\x45\x0e\xfc\x60\xac\x47\x68\x3d\x7b\x8d\x0f\x81\x13\x65\x56\x5f\xd9\x8c\x4c\x8e\xb9\x36\xbc\xab\x8d\x06\x9f\xc3\x3b\xd8\x01\xb0\x3a\xde\xa2\xe1\xfb\xc5\xaa\x46\x3d\x08\xca\x19\x89\x6d\x2b\xf5\x9a\x07\x1b\x85\x1e\x6c\x23\x90\x52\x17\x2f\x29\x6b\xfb\x5e\x72\x40\x47\x90\xa2\x18\x10\x14\xf3\xb9\x4a\x4e\x97\xd1\x17\xb4\x38\x13\x03\x68\xcc\x39\xdb\xb2\xd1\x98\x06\x5a\xe3\x98\x65\x47\x92\x6c\xd2\x16\x2f\x40\xa2\x9f\x0c\x3c\x87\x45\xc0\xf5\x0f\xba\x38\x52\xe5\x66\xd4\x45\x75\xc2\x9d\x39\xa0\x3f\x0c\xda\x72\x19\x84\xb6\xf4\x40\x59\x1f\x35\x5e\x12\xd4\x39\xff\x15\x0a\xab\x76\x13\x49\x9d\xbd\x49\xad\xab\xc8\x67\x6e\xef\x02\x3b\x15\xb6\x5b\xfc\x5c\xa0\x69\x48\x10\x9f\x23\xf3\x50\xdb\x82\x12\x35\x35\xeb\x8a\x74\x33\xbd\xab\xcb\x90\x92\x71\xa6\xec\xbc\xb5\x8b\x93\x6a\x88\xcd\x4e\x8f\x2e\x6f\xf5\x80\x01\x75\xf1\x13\x25\x3d\x8f\xa9\xca\x88\x85\xc2\xf5\x52\xe6\x57\xdc\x60\x3f\x25\x2e\x1a\x8e\x30\x8f\x76\xf0\xbe\x79\xe2\xfb\x8f\x5d\x5f\xbb\xe2\xe3\x0e\xca\xdd\x22\x07\x23\xc8\xc0\xae\xa8\x07\x8c\xdf\xcb\x38\x68\x26\x3f\xf8\xf0\x94\x00\x54\xda\x48\x78\x18\x93\xa7\xe4\x9a\xd5\xaf\xf4\xaf\x30\x0c\xd8\x04\xa6\xb6\x27\x9a\xb3\xff\x3a\xfb\x64\x49\x1c\x85\x19\x4a\xab\x76\x0d\x58\xa6\x06\x65\x4f\x9f\x44\x00\xe8\xb3\x85\x91\x35\x6f\xbf\x64\x25\xac\xa2\x6d\xc8\x52\x44\x25\x9f\xf2\xb1\x9c\x41\xb9\xf9\x6f\x3c\xa9\xec\x1d\xde\x43\x4d\xa7\xd2\xd3\x92\xb9\x05\xdd\xf3\xd1\xf9\xaf\x93\xd1\xaf\x59\x50\xbd\x49\x3f\x5a\xa7\x31\xb4\x05\x6d\xf3\x1b\xd2\x67\xb6\xb9\x0a\x07\x98\x31\xaa\xf5\x79\xbe\x0a\x39\x01\x31\x37\xaa\xc6\xd4\x04\xf5\x18\xcf\xd4\x68\x40\x64\x7e\x78\xbf\xe7\x06\xca\x4c\xf5\xe9\xc5\x45\x3e\x9f\x7c\xfd\x2b\x8b\x4c\x8d\x16\x9a\x44\xe5\x5c\x88\xd4\xa9\xa7\xf9\x47\x42\x41\xe2\x21\xaf\x44\x86\x00\x18\xab\x08\x56\x97\x2e\x19\x4c\xd9\x34";
static const char quic_decrypted_header[] = "\xc3\x00\x00\x00\x01\x08\x83\x94\xc8\xf0\x3e\x51\x57\x08\x00\x00\x44\x9e\x00\x00\x00\x02";
static const char quic_decrypted_crypto[] = "\x06\x00\x40\xf1\x01\x00\x00\xed\x03\x03\xeb\xf8\xfa\x56\xf1\x29\x39\xb9\x58\x4a\x38\x96\x47\x2e\xc4\x0b\xb8\x63\xcf\xd3\xe8\x68\x04\xfe\x3a\x47\xf0\x6a\x2b\x69\x48\x4c\x00\x00\x04\x13\x01\x13\x02\x01\x00\x00\xc0\x00\x00\x00\x10\x00\x0e\x00\x00\x0b\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d\xff\x01\x00\x01\x00\x00\x0a\x00\x08\x00\x06\x00\x1d\x00\x17\x00\x18\x00\x10\x00\x07\x00\x05\x04\x61\x6c\x70\x6e\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\x93\x70\xb2\xc9\xca\xa4\x7f\xba\xba\xf4\x55\x9f\xed\xba\x75\x3d\xe1\x71\xfa\x71\xf5\x0f\x1c\xe1\x5d\x43\xe9\x94\xec\x74\xd7\x48\x00\x2b\x00\x03\x02\x03\x04\x00\x0d\x00\x10\x00\x0e\x04\x03\x05\x03\x06\x03\x02\x03\x08\x04\x08\x05\x08\x06\x00\x2d\x00\x02\x01\x01\x00\x1c\x00\x02\x40\x01\x00\x39\x00\x32\x04\x08\xff\xff\xff\xff\xff\xff\xff\xff\x05\x04\x80\x00\xff\xff\x07\x04\x80\x00\xff\xff\x08\x01\x10\x01\x04\x80\x00\x75\x30\x09\x01\x10\x0f\x08\x83\x94\xc8\xf0\x3e\x51\x57\x08\x06\x04\x80\x00\xff\xff";
static const int quic_padding_len = 917;
// Just a QUIC payload but with sparse frames (like ping, padding, ping, crypto 0, padding, ping, ping, padding, ping, crypto 425, padding)
static const char quic_sparse_payload[] = "\306\000\000\000\001\bB\302\246\317\237]S\226\000\000D\320\372/\3503Ac\222\312\360\355\030\223\231\340\360\022\222e\177$@\270\312\006\205-\267\304\207\036Zq?\246\2072zza\272\337\365'\335_\246\255\2502\347\245r\217>\2556\t\033\347\234w*Q4\003\330\270\037\271\004\346\254B(G\022\356\232\221P\357\305>\301T\331J xv.<\224\344Q\267\v\017b\254\260f\313\232\2213D:F\371\214\177\342C\234\022\301\316\277\342/\027\337X\317\250\200N< 6y\313\r\224\310i\263-\212\372\030\264Z\003#D4\234\315\205H\373\227\026yx\245d\375\211U\223\235\204\236\"T\255i\001\3308)ca%\243\376.mMc\225\b&\276\245n\233V\300\334\261\261\247\266(\334kA\314\250\261\271\353\nC\034\273\276\324\361J\341\017\361N\212\3128\261\233z\267|\344\260d\376\344\342\357\336\255X\366w\313\225C\022\022s\256\202\3568k!\177\025\375K~\224y\216\022\341\376\230\024\346\212l\025\253\300\256\031\360O\200|\331\342\315=I\306dS\030\306\320\212\177\356\350\207\360D7\177\agQ\"\031o6\202\352k\206]\210\370k5k\252\221\254\245\364\333\247\310\207\024\202Q#\314\214\264\341R?UL\340\271\313\213nj\217;\rU\304C\274\361[\327\002\321\372\212LO\325\324\237<\336\361<\205\331w\177`\210\\\276\304\314\220\235\3437\206g\323\275\036\a\033A!\254\217\341\277y6\211\304\031`-d\207wj\037\334MjY'!\327\245\002\255;\b\251\215\tY\310/\366N\224\206\027\037*\311\235\302\236=\377C\264\343o\255\264f\235%\036\026y\353\271(\3160\343*\300>\214&}\177-\363jj\336\204'\266\310\210\312\347\211h)\351\031\325\231\332\177\332#\3552bC\2775)\336\353\271gY\305\315`\212\342\325\376\250\2235y\a\315b\200R\361S\022\333\f\023\r\313\370\267\n\205\314\374\257\376\211\304Y?}.u\244b\315\221\264\211\371\256\224\332C\333@\025\027nb)G\360S\326_\277\362\201\365]\2745\376\253#\251\240\224=\316Y_\233\260\302\260\227.}\260\226\244\241r\320\347_\2273V\237\0262\375^\374F\266!\036k\346\352\204\222\300VuN\027\216\"\2531j\330\222\335\354Uz\367,\376\201\272O\177\376\026\220:?\n\202S\220\373\343\333'+%*rW\n\177Y{\347\211\357+\364(\270\034\207\371\221>\200Ua\026\034\235e\246D\036\352X\202\350\036\303\231\210\351j+\227e\352il\362\273`\360\361\304e\356\206\321\2232\327]\246\325\273\361\233G\336n\212.\335\250\t\177\233$\243\334<\304%\332\000\346\2777\343c\026`|\222\3666\207\021\034\001~\206\221I\f\316\f\006\000\036~\313kH\243L\343B\261Yg\031\362\324\370-\260B\330?e>fd\r\3544\\\312E\231\000\210oZ\033s\207\220\36379f=\017\032\256~\222\377!q\270w\305!\312o\343\035_\003U\313P\356\363^\016o\203,Yf \354\321\0038:\363I\300\215+h\316\305\257\305\002\t\232c\333'~\341\352\3170\362\244A\211\360\272\371\321\371Q\b\237\3076s.\032\322k\202,\345\374\266\233b OS\035\b*\242J\265\215\357\317\325\356\322\031g\2610G]\272i\265\\,\226\237\323\355\351\237\345\032b\364\347\250\227\217\323\353Y\002q[\335\365\034\363$*\312\231\317\302}\2600~\261O\336\265(d\240\323\214zr\371=\027\203\376\330\032w\002,90~{\3677\230\363\250b\320\202I\221\213?\272\227\ncc\343\031Ow\0347s\313\356\037\312t\206\002\006\336\270\203\277\020j\210g\372MU\2758\333\326:\312\262\r\022\210\275[}\314\377\035\241\267s\326\211\300\236;\217\001/\354k\365+?n\230e\350\002z\\K\035\227j\331\031\rj\230<z\272\220\311\036\000\264\017\020\255S\343\001\246\311\021\301\t\006\337\245\3565\2657D{9\b\271s=\a\202\254\326\365T+e\370)7AE\241\217z\276\331xe\n<\320\206\246-\313\330\035\"&\347\201\275\234r\355>\306\306\236\367\021p#\001\203\262\206+kg\313u\205a\004\t2>\322\224\327\001.c\t\225\244=\243M\006\311\347z\262\021Hl\027\202\271\033\345~\334\214\034\202\024m@\372\361Kk@~\374\340Z\260D\245\272'M\232\001$\242wJ:\r\r-\244\363\217\t\261WgS7\272\213\357\314\240\371\374\313\233r\235\017\235\031\230%}Z\345\"";
unsigned char filebr[] = {
0x06, 0x16, 0xea, 0x20, 0xf5, 0xb6, 0x09, 0x0e, 0x90, 0x54, 0x17, 0x78,
0xaa, 0x9a, 0xd9, 0xe1, 0xb8, 0xdf, 0xdc, 0x8e, 0xf8, 0x3a, 0xdb, 0x59,
0xbb, 0x84, 0x60, 0x2b
};
#include "unity.h"
#include "unity_fixture.h"
#include "quic.h"
#include "types.h"
#include <stdio.h>
#include "tls.h"
#include "config.h"
#include "logging.h"
static struct section_config_t sconf = default_section_config;
TEST_GROUP(QuicTest);
TEST_SETUP(QuicTest)
{
}
TEST_TEAR_DOWN(QuicTest)
{
}
TEST(QuicTest, Test_decrypts)
{
int ret;
uint8_t *decrypted_payload;
size_t decrypted_payload_len;
const uint8_t *decrypted_message;
size_t decrypted_message_len;
ret = quic_parse_initial_message(
(const uint8_t *)quic_testing_payload, sizeof(quic_testing_payload) - 1,
&decrypted_payload, &decrypted_payload_len,
&decrypted_message, &decrypted_message_len
);
TEST_ASSERT_EQUAL(ret, 0);
TEST_ASSERT_EQUAL(sizeof(quic_testing_payload) - 1, decrypted_payload_len);
TEST_ASSERT_EQUAL_MEMORY(quic_decrypted_header, decrypted_payload, sizeof(quic_decrypted_header) - 1);
TEST_ASSERT_EQUAL(decrypted_message, decrypted_payload + sizeof(quic_decrypted_header) - 1);
TEST_ASSERT_EQUAL_MEMORY(quic_decrypted_crypto, decrypted_message, sizeof(quic_decrypted_crypto) - 1);
const uint8_t *curptr = decrypted_message + (sizeof(quic_decrypted_crypto) - 1);
ssize_t curptr_len = decrypted_message_len - (sizeof(quic_decrypted_crypto) - 1);
TEST_ASSERT_EQUAL(quic_padding_len, curptr_len);
while (curptr_len-- > 0) {
TEST_ASSERT_EQUAL(0x00, *curptr++);
}
TEST_ASSERT_EQUAL(decrypted_message + decrypted_message_len, curptr);
// tag is left
TEST_ASSERT_EQUAL(16, decrypted_payload + decrypted_payload_len - curptr);
#undef free
free(decrypted_payload);
#define free unity_free
}
TEST(QuicTest, Test_crypto_parser_valid)
{
ssize_t fret;
struct quic_frame_crypto fr_cr;
fret = quic_parse_crypto(&fr_cr, (const uint8_t *)quic_decrypted_crypto, sizeof(quic_decrypted_crypto));
TEST_ASSERT_EQUAL(sizeof(quic_decrypted_crypto) - 1, fret);
TEST_ASSERT_EQUAL(0, fr_cr.offset);
TEST_ASSERT_EQUAL(241, fr_cr.payload_length);
// one for type, one for offset, two for length
TEST_ASSERT_EQUAL(quic_decrypted_crypto + 4, fr_cr.payload);
}
TEST(QuicTest, Test_crypto_parser_tls)
{
ssize_t fret;
int ret;
struct quic_frame_crypto fr_cr;
struct tls_verdict tlsv;
fret = quic_parse_crypto(&fr_cr, (const uint8_t *)quic_decrypted_crypto, sizeof(quic_decrypted_crypto));
TEST_ASSERT_GREATER_OR_EQUAL(0, fret);
ret = analyze_tls_message(&sconf, fr_cr.payload, fr_cr.payload_length, &tlsv);
TEST_ASSERT_GREATER_OR_EQUAL(0, ret);
TEST_ASSERT_EQUAL_STRING_LEN("example.com", tlsv.sni_ptr, 11);
}
TEST(QuicTest, Test_crypto_parser_invalid)
{
ssize_t fret;
struct quic_frame_crypto fr_cr;
fret = quic_parse_crypto(&fr_cr, NULL, 0);
TEST_ASSERT_EQUAL(-EINVAL, fret);
}
TEST(QuicTest, Test_varlength_parser)
{
uint8_t varlv[4];
uint64_t mlen, var;
varlv[0] = 0x00;
varlv[1] = 0x00;
varlv[2] = 0x00;
varlv[3] = 0x00;
mlen = 4;
var = quic_parse_varlength(varlv, &mlen);
TEST_ASSERT_EQUAL(0, var);
TEST_ASSERT_EQUAL(1, mlen);
varlv[0] = 0x40;
varlv[1] = 0xf1;
varlv[2] = 0x00;
varlv[3] = 0x00;
mlen = 4;
var = quic_parse_varlength(varlv, &mlen);
TEST_ASSERT_EQUAL(241, var);
TEST_ASSERT_EQUAL(2, mlen);
mlen = 2;
var = quic_parse_varlength(varlv, &mlen);
TEST_ASSERT_EQUAL(241, var);
TEST_ASSERT_EQUAL(2, mlen);
// overflow
mlen = 1;
var = quic_parse_varlength(varlv, &mlen);
TEST_ASSERT_EQUAL(0, var);
TEST_ASSERT_EQUAL(0, mlen);
}
TEST(QuicTest, Test_parse_quic_decrypted)
{
#undef free
int ret;
uint8_t *decrypted_payload;
size_t decrypted_payload_len;
const uint8_t *decrypted_message;
size_t decrypted_message_len;
uint8_t *crypto_message;
size_t crypto_message_len;
struct tls_verdict tlsv = {0};
ret = quic_parse_initial_message(
(const uint8_t *)quic_testing_payload, sizeof(quic_testing_payload) - 1,
&decrypted_payload, &decrypted_payload_len,
&decrypted_message, &decrypted_message_len
);
TEST_ASSERT_EQUAL(0, ret);
ret = parse_quic_decrypted(
&sconf, decrypted_message, decrypted_message_len,
&crypto_message, &crypto_message_len);
TEST_ASSERT_EQUAL(0, ret);
free(decrypted_payload);
decrypted_payload = NULL;
ret = analyze_tls_message(
&sconf, crypto_message, crypto_message_len, &tlsv
);
TEST_ASSERT_EQUAL(11, tlsv.sni_len);
TEST_ASSERT_EQUAL_STRING_LEN("example.com", tlsv.sni_ptr, 11);
free(crypto_message);
#define free unity_free
}
TEST(QuicTest, Test_parse_quic_decrypted_on_sparse)
{
#undef free
int ret;
uint8_t *decrypted_payload;
size_t decrypted_payload_len;
const uint8_t *decrypted_message;
size_t decrypted_message_len;
uint8_t *crypto_message;
size_t crypto_message_len;
struct tls_verdict tlsv = {0};
ret = quic_parse_initial_message(
(const uint8_t *)quic_sparse_payload, sizeof(quic_sparse_payload) - 1,
&decrypted_payload, &decrypted_payload_len,
&decrypted_message, &decrypted_message_len
);
TEST_ASSERT_EQUAL(0, ret);
ret = parse_quic_decrypted(
&sconf, decrypted_message, decrypted_message_len,
&crypto_message, &crypto_message_len);
TEST_ASSERT_EQUAL(0, ret);
free(decrypted_payload);
decrypted_payload = NULL;
ret = analyze_tls_message(
&sconf, crypto_message, crypto_message_len, &tlsv
);
TEST_ASSERT_EQUAL(19, tlsv.sni_len);
TEST_ASSERT_EQUAL_STRING_LEN("ipm.adblockplus.dev", tlsv.sni_ptr, 19);
free(crypto_message);
#define free unity_free
}
TEST(QuicTest, Test_parse_quic_decrypted_on_fail)
{
#undef free
int ret;
uint8_t *crypto_message;
size_t crypto_message_len;
struct tls_verdict tlsv = {0};
ret = parse_quic_decrypted(
&sconf, filebr, sizeof(filebr) - 1,
&crypto_message, &crypto_message_len);
TEST_ASSERT_EQUAL(0, ret);
ret = analyze_tls_message(
&sconf, crypto_message, crypto_message_len, &tlsv
);
TEST_ASSERT_EQUAL(0, tlsv.sni_len);
free(crypto_message);
#define free unity_free
}
TEST_GROUP_RUNNER(QuicTest)
{
RUN_TEST_CASE(QuicTest, Test_decrypts);
RUN_TEST_CASE(QuicTest, Test_crypto_parser_valid);
RUN_TEST_CASE(QuicTest, Test_crypto_parser_tls);
RUN_TEST_CASE(QuicTest, Test_crypto_parser_invalid);
RUN_TEST_CASE(QuicTest, Test_varlength_parser);
RUN_TEST_CASE(QuicTest, Test_parse_quic_decrypted)
RUN_TEST_CASE(QuicTest, Test_parse_quic_decrypted_on_sparse)
RUN_TEST_CASE(QuicTest, Test_parse_quic_decrypted_on_fail)
}

59
test/tls.c Normal file
View File

@@ -0,0 +1,59 @@
static const char tls_chlo_message[] = "\001\000\002\000\003\003*{D\360FDTZ\305\231\272\006\240\246oa\365}ut\321\033\354\361}\334\227\342\215\257]\332\000\000\006\023\001\023\002\023\003\001\000\001\321\0009\000_\t\002@g\017\000\005\004\200`\000\000q'\004\200\001\026\210\a\004\200`\000\000\001\004\200\000u0\003\002E\300\006\004\200`\000\000\316E,\310\0160;\306\003g\201k\004\004\200\360\000\000\200\000GR\004\000\000\000\001 \004\200\001\000\000\200\377s\333\f\000\000\000\001\n\212\nJ\000\000\000\001\b\002@d\000\020\000\005\000\003\002h3\000+\000\003\002\003\004\000\n\000\b\000\006\000\035\000\027\000\030\000\033\000\003\002\000\002Di\000\005\000\003\002h3\000\r\000\024\000\022\004\003\b\004\004\001\005\003\b\005\005\001\b\006\006\001\002\001\000-\000\002\001\001\376\r\000\332\000\000\001\000\001|\000 \004\256\340\330}\337lC3\304gv\325}\rT\370O,i^\001\357\323\373?\205@3\023\354{\000\260\247cf\207\3276\312\205G\017\213Y\231\b\301~\225r\v\001X\026\335\254H\231\237\237\263\027b\b\327\0351W\000\177tc\213:^\f\362\340\225_\272\331\351\002\026rds\326\034\345*5!\221\265\206\270\240\375\nw\v\340 \003\340\307\230H\203#\212\371\364\257H\220\230L\230{\243\355\v'\325@\240EZ\306\230a\233;\033|=(\372P\232\216\215\203\374\234\222\375\004\3058l\275+?\f\306\335\342Q\313\"F\377G<2Jqb\033\033,|\302w\337bO\032\276\374\312X\364}\255xq\274\2348\247K\345t\327\345\322M\004\220\376*\344\365\0003\000&\000$\000\035\000 W\356I\271\201\350\263[cn\\H?\376s``\v\230\306?E=2\017u\306\027\nc{c\000\000\000\030\000\026\000\000\023abc.defghijklm.ndev";
static const char tls_bruteforce_message[] = "ahl qlwer 12oi34j 1l2kjrdosij f982j jfa osdijwoeij rasdjf oiajsqw9erj pqwoijf lasdj foijyoutube.com";
#include "unity.h"
#include "unity_fixture.h"
#include "types.h"
#include <stdio.h>
#include "tls.h"
#include "config.h"
#include "logging.h"
static struct section_config_t sconf = default_section_config;
TEST_GROUP(TLSTest);
TEST_SETUP(TLSTest)
{
}
TEST_TEAR_DOWN(TLSTest)
{
}
TEST(TLSTest, Test_CHLO_message_detect)
{
struct tls_verdict tlsv;
int ret;
ret = analyze_tls_message(&sconf, (const uint8_t *)tls_chlo_message, sizeof(tls_chlo_message) - 1, &tlsv);
TEST_ASSERT_EQUAL(0, ret);
TEST_ASSERT_GREATER_OR_EQUAL(19, tlsv.sni_len);
TEST_ASSERT_EQUAL_STRING_LEN("abc.defghijklm.ndev", tlsv.sni_ptr, 19);
}
TEST(TLSTest, Test_Bruteforce_detects)
{
struct tls_verdict tlsv;
struct domains_list dmns = {
.domain_name = "youtube.com",
.domain_len = 11,
.next = NULL
};
sconf.sni_domains = &dmns;
int 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(11, tlsv.sni_len);
TEST_ASSERT_EQUAL_STRING_LEN("youtube.com", tlsv.sni_ptr, 11);
TEST_ASSERT_EQUAL_PTR(tls_bruteforce_message +
sizeof(tls_bruteforce_message) - 12, tlsv.sni_ptr);
}
TEST_GROUP_RUNNER(TLSTest)
{
RUN_TEST_CASE(TLSTest, Test_CHLO_message_detect);
RUN_TEST_CASE(TLSTest, Test_Bruteforce_detects);
}

2501
test/unity/unity.c Normal file

File diff suppressed because it is too large Load Diff

698
test/unity/unity.h Normal file
View File

@@ -0,0 +1,698 @@
/* =========================================================================
Unity - A Test Framework for C
ThrowTheSwitch.org
Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
SPDX-License-Identifier: MIT
========================================================================= */
#ifndef UNITY_FRAMEWORK_H
#define UNITY_FRAMEWORK_H
#define UNITY
#define UNITY_VERSION_MAJOR 2
#define UNITY_VERSION_MINOR 6
#define UNITY_VERSION_BUILD 1
#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD)
#ifdef __cplusplus
extern "C"
{
#endif
#include "unity_internals.h"
/*-------------------------------------------------------
* Test Setup / Teardown
*-------------------------------------------------------*/
/* These functions are intended to be called before and after each test.
* If using unity directly, these will need to be provided for each test
* executable built. If you are using the test runner generator and/or
* Ceedling, these are optional. */
void setUp(void);
void tearDown(void);
/* These functions are intended to be called at the beginning and end of an
* entire test suite. suiteTearDown() is passed the number of tests that
* failed, and its return value becomes the exit code of main(). If using
* Unity directly, you're in charge of calling these if they are desired.
* If using Ceedling or the test runner generator, these will be called
* automatically if they exist. */
void suiteSetUp(void);
int suiteTearDown(int num_failures);
/*-------------------------------------------------------
* Test Reset and Verify
*-------------------------------------------------------*/
/* These functions are intended to be called before during tests in order
* to support complex test loops, etc. Both are NOT built into Unity. Instead
* the test runner generator will create them. resetTest will run teardown and
* setup again, verifying any end-of-test needs between. verifyTest will only
* run the verification. */
void resetTest(void);
void verifyTest(void);
/*-------------------------------------------------------
* Configuration Options
*-------------------------------------------------------
* All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above.
* Integers/longs/pointers
* - Unity attempts to automatically discover your integer sizes
* - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in <stdint.h>
* - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in <limits.h>
* - If you cannot use the automatic methods above, you can force Unity by using these options:
* - define UNITY_SUPPORT_64
* - set UNITY_INT_WIDTH
* - set UNITY_LONG_WIDTH
* - set UNITY_POINTER_WIDTH
* Floats
* - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons
* - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT
* - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats
* - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons
* - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default)
* - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE
* - define UNITY_DOUBLE_TYPE to specify something other than double
* - define UNITY_EXCLUDE_FLOAT_PRINT to trim binary size, won't print floating point values in errors
* Output
* - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired
* - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure
* Optimization
* - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge
* - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests.
* Test Cases
* - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script
* Parameterized Tests
* - you'll want to create a define of TEST_CASE(...), TEST_RANGE(...) and/or TEST_MATRIX(...) which basically evaluates to nothing
* Tests with Arguments
* - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity
*-------------------------------------------------------
* Basic Fail and Ignore
*-------------------------------------------------------*/
#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, (message))
#define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL)
#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message))
#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL)
#define TEST_MESSAGE(message) UnityMessage((message), __LINE__)
#define TEST_ONLY()
#ifdef UNITY_INCLUDE_PRINT_FORMATTED
#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), ##__VA_ARGS__)
#endif
/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails.
* This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */
#define TEST_PASS() TEST_ABORT()
#define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while (0)
/*-------------------------------------------------------
* Build Directives
*-------------------------------------------------------
* These macros do nothing, but they are useful for additional build context.
* Tools (like Ceedling) can scan for these directives and make use of them for
* per-test-executable #include search paths and linking. */
/* Add source files to a test executable's compilation and linking. Ex: TEST_SOURCE_FILE("sandwiches.c") */
#define TEST_SOURCE_FILE(a)
/* Customize #include search paths for a test executable's compilation. Ex: TEST_INCLUDE_PATH("src/module_a/inc") */
#define TEST_INCLUDE_PATH(a)
/*-------------------------------------------------------
* Test Asserts (simple)
*-------------------------------------------------------*/
/* Boolean */
#define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE")
#define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE")
#define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE")
#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE")
#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL")
#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL")
#define TEST_ASSERT_EMPTY(pointer) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, " Expected Empty")
#define TEST_ASSERT_NOT_EMPTY(pointer) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, " Expected Non-Empty")
/* Integers (of all sizes) */
#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_size_t(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(-1), (actual), __LINE__, NULL)
#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(0), (actual), __LINE__, NULL)
#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(-1), (actual), __LINE__, NULL)
#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(0), (actual), __LINE__, NULL)
/* Integer Not Equal To (of all sizes) */
#define TEST_ASSERT_NOT_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, NULL)
/* Integer Greater Than/ Less Than (of all sizes) */
#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL)
/* Integer Ranges (of all sizes) */
#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_size_t_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_CHAR_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, NULL)
/* Integer Array Ranges (of all sizes) */
#define TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_size_t_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_HEX_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
#define TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL)
/* Structs and Strings */
#define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL)
/* Arrays */
#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_size_t_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
/* Arrays Compared To Single Value */
#define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_size_t(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_HEX(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, NULL)
/* Floating Point (If Enabled) */
#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_NOT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_NOT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_NOT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_FLOAT_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_FLOAT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_FLOAT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_FLOAT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_FLOAT(threshold, actual) UNITY_TEST_ASSERT_LESS_THAN_FLOAT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_FLOAT(threshold, actual) UNITY_TEST_ASSERT_LESS_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL)
#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL)
/* Double (If Enabled) */
#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_NOT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_NOT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_NOT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_DOUBLE_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, NULL)
#define TEST_ASSERT_GREATER_THAN_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_DOUBLE((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_THAN_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_LESS_THAN_DOUBLE((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_LESS_OR_EQUAL_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_LESS_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL)
#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL)
/* Shorthand */
#ifdef UNITY_SHORTHAND_AS_OLD
#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal")
#endif
#ifdef UNITY_SHORTHAND_AS_INT
#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#endif
#ifdef UNITY_SHORTHAND_AS_MEM
#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, NULL)
#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#endif
#ifdef UNITY_SHORTHAND_AS_RAW
#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, " Expected Equal")
#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal")
#endif
#ifdef UNITY_SHORTHAND_AS_NONE
#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#endif
/*-------------------------------------------------------
* Test Asserts (with additional messages)
*-------------------------------------------------------*/
/* Boolean */
#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message))
#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message))
#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message))
#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message))
#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message))
#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message))
#define TEST_ASSERT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, (message))
#define TEST_ASSERT_NOT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, (message))
/* Integers (of all sizes) */
#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_size_t_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, (message))
#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, (message))
#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message))
#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message))
/* Integer Not Equal To (of all sizes) */
#define TEST_ASSERT_NOT_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, (message))
/* Integer Greater Than/ Less Than (of all sizes) */
#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message))
/* Integer Ranges (of all sizes) */
#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_size_t_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_CHAR_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, (message))
/* Integer Array Ranges (of all sizes) */
#define TEST_ASSERT_INT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_INT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_INT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_INT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_INT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_UINT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_UINT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_UINT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_UINT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_UINT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_size_t_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_HEX_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_HEX8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_HEX16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_HEX32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_HEX64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
#define TEST_ASSERT_CHAR_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message))
/* Structs and Strings */
#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message))
#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message))
/* Arrays */
#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_size_t_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_CHAR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
/* Arrays Compared To Single Value*/
#define TEST_ASSERT_EACH_EQUAL_INT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_INT8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_INT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_INT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_INT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_UINT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_UINT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_UINT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_size_t_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_HEX64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_PTR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_STRING_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_MEMORY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_CHAR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, (message))
/* Floating Point (If Enabled) */
#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_FLOAT((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_FLOAT_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_FLOAT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_FLOAT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_THAN_FLOAT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message))
#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message))
/* Double (If Enabled) */
#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message))
#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_DOUBLE_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_EACH_EQUAL_DOUBLE_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, (message))
#define TEST_ASSERT_GREATER_THAN_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_DOUBLE((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_THAN_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_THAN_DOUBLE((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_LESS_OR_EQUAL_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message))
#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message))
/* Shorthand */
#ifdef UNITY_SHORTHAND_AS_OLD
#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))
#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message))
#endif
#ifdef UNITY_SHORTHAND_AS_INT
#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message)
#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#endif
#ifdef UNITY_SHORTHAND_AS_MEM
#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, message)
#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#endif
#ifdef UNITY_SHORTHAND_AS_RAW
#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, message)
#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message)
#endif
#ifdef UNITY_SHORTHAND_AS_NONE
#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand)
#endif
/* end of UNITY_FRAMEWORK_H */
#ifdef __cplusplus
}
#endif
#endif

310
test/unity/unity_fixture.c Normal file
View File

@@ -0,0 +1,310 @@
/* =========================================================================
Unity - A Test Framework for C
ThrowTheSwitch.org
Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
SPDX-License-Identifier: MIT
========================================================================= */
#include "unity_fixture.h"
#include "unity_internals.h"
#include <string.h>
struct UNITY_FIXTURE_T UnityFixture;
/* If you decide to use the function pointer approach.
* Build with -D UNITY_OUTPUT_CHAR=outputChar and include <stdio.h>
* int (*outputChar)(int) = putchar; */
void setUp(void) { /*does nothing*/ }
void tearDown(void) { /*does nothing*/ }
static void announceTestRun(unsigned int runNumber)
{
UnityPrint("Unity test run ");
UnityPrintNumberUnsigned(runNumber+1);
UnityPrint(" of ");
UnityPrintNumberUnsigned(UnityFixture.RepeatCount);
UNITY_PRINT_EOL();
}
int UnityMain(int argc, const char* argv[], void (*runAllTests)(void))
{
int result = UnityGetCommandLineOptions(argc, argv);
unsigned int r;
if (result != 0)
return result;
for (r = 0; r < UnityFixture.RepeatCount; r++)
{
UnityBegin(argv[0]);
announceTestRun(r);
runAllTests();
if (!UnityFixture.Verbose) UNITY_PRINT_EOL();
UnityEnd();
}
return (int)Unity.TestFailures;
}
static int selected(const char* filter, const char* name)
{
if (filter == 0)
return 1;
return strstr(name, filter) ? 1 : 0;
}
static int testSelected(const char* test)
{
return selected(UnityFixture.NameFilter, test);
}
static int groupSelected(const char* group)
{
return selected(UnityFixture.GroupFilter, group);
}
void UnityTestRunner(unityfunction* setup,
unityfunction* testBody,
unityfunction* teardown,
const char* printableName,
const char* group,
const char* name,
const char* file,
unsigned int line)
{
if (testSelected(name) && groupSelected(group))
{
Unity.TestFile = file;
Unity.CurrentTestName = printableName;
Unity.CurrentTestLineNumber = line;
if (UnityFixture.Verbose)
{
UnityPrint(printableName);
#ifndef UNITY_REPEAT_TEST_NAME
Unity.CurrentTestName = NULL;
#endif
}
else if (UnityFixture.Silent)
{
/* Do Nothing */
}
else
{
UNITY_OUTPUT_CHAR('.');
}
Unity.NumberOfTests++;
UnityPointer_Init();
UNITY_EXEC_TIME_START();
if (TEST_PROTECT())
{
setup();
testBody();
}
if (TEST_PROTECT())
{
teardown();
}
if (TEST_PROTECT())
{
UnityPointer_UndoAllSets();
}
UnityConcludeFixtureTest();
}
}
void UnityIgnoreTest(const char* printableName, const char* group, const char* name)
{
if (testSelected(name) && groupSelected(group))
{
Unity.NumberOfTests++;
Unity.TestIgnores++;
if (UnityFixture.Verbose)
{
UnityPrint(printableName);
UNITY_PRINT_EOL();
}
else if (UnityFixture.Silent)
{
/* Do Nothing */
}
else
{
UNITY_OUTPUT_CHAR('!');
}
}
}
/*-------------------------------------------------------- */
/*Automatic pointer restoration functions */
struct PointerPair
{
void** pointer;
void* old_value;
};
static struct PointerPair pointer_store[UNITY_MAX_POINTERS];
static int pointer_index = 0;
void UnityPointer_Init(void)
{
pointer_index = 0;
}
void UnityPointer_Set(void** pointer, void* newValue, UNITY_LINE_TYPE line)
{
if (pointer_index >= UNITY_MAX_POINTERS)
{
UNITY_TEST_FAIL(line, "Too many pointers set");
}
else
{
pointer_store[pointer_index].pointer = pointer;
pointer_store[pointer_index].old_value = *pointer;
*pointer = newValue;
pointer_index++;
}
}
void UnityPointer_UndoAllSets(void)
{
while (pointer_index > 0)
{
pointer_index--;
*(pointer_store[pointer_index].pointer) =
pointer_store[pointer_index].old_value;
}
}
int UnityGetCommandLineOptions(int argc, const char* argv[])
{
int i;
UnityFixture.Verbose = 0;
UnityFixture.Silent = 0;
UnityFixture.GroupFilter = 0;
UnityFixture.NameFilter = 0;
UnityFixture.RepeatCount = 1;
if (argc == 1)
return 0;
for (i = 1; i < argc; )
{
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
{
/* Usage */
UnityPrint("Runs a series of unit tests.");
UNITY_PRINT_EOL();
UNITY_PRINT_EOL();
UnityPrint("When no flag is specified, all tests are run.");
UNITY_PRINT_EOL();
UNITY_PRINT_EOL();
UnityPrint("Optional flags:");
UNITY_PRINT_EOL();
UnityPrint(" -v Verbose output: show all tests executed even if they pass");
UNITY_PRINT_EOL();
UnityPrint(" -s Silent mode: minimal output showing only test failures");
UNITY_PRINT_EOL();
UnityPrint(" -g NAME Only run tests in groups that contain the string NAME");
UNITY_PRINT_EOL();
UnityPrint(" -n NAME Only run tests whose name contains the string NAME");
UNITY_PRINT_EOL();
UnityPrint(" -r NUMBER Repeatedly run all tests NUMBER times");
UNITY_PRINT_EOL();
UnityPrint(" -h, --help Display this help message");
UNITY_PRINT_EOL();
UNITY_PRINT_EOL();
#ifdef UNITY_CUSTOM_HELP_MSG
/* User-defined help message, e.g. to point to project-specific documentation */
UnityPrint(UNITY_CUSTOM_HELP_MSG);
UNITY_PRINT_EOL();
#else
/* Default help suffix if a custom one is not defined */
UnityPrint("More information about Unity: https://www.throwtheswitch.org/unity");
UNITY_PRINT_EOL();
#endif
return 1; /* Exit without running the tests */
}
else if (strcmp(argv[i], "-v") == 0)
{
UnityFixture.Verbose = 1;
i++;
}
else if (strcmp(argv[i], "-s") == 0)
{
UnityFixture.Silent = 1;
i++;
}
else if (strcmp(argv[i], "-g") == 0)
{
i++;
if (i >= argc)
return 1;
UnityFixture.GroupFilter = argv[i];
i++;
}
else if (strcmp(argv[i], "-n") == 0)
{
i++;
if (i >= argc)
return 1;
UnityFixture.NameFilter = argv[i];
i++;
}
else if (strcmp(argv[i], "-r") == 0)
{
UnityFixture.RepeatCount = 2;
i++;
if (i < argc)
{
if (*(argv[i]) >= '0' && *(argv[i]) <= '9')
{
unsigned int digit = 0;
UnityFixture.RepeatCount = 0;
while (argv[i][digit] >= '0' && argv[i][digit] <= '9')
{
UnityFixture.RepeatCount *= 10;
UnityFixture.RepeatCount += (unsigned int)argv[i][digit++] - '0';
}
i++;
}
}
}
else
{
/* ignore unknown parameter */
i++;
}
}
return 0;
}
void UnityConcludeFixtureTest(void)
{
if (Unity.CurrentTestIgnored)
{
Unity.TestIgnores++;
UNITY_PRINT_EOL();
}
else if (!Unity.CurrentTestFailed)
{
if (UnityFixture.Verbose)
{
UnityPrint(" ");
UnityPrint(UnityStrPass);
UNITY_EXEC_TIME_STOP();
UNITY_PRINT_EXEC_TIME();
UNITY_PRINT_EOL();
}
}
else /* Unity.CurrentTestFailed */
{
Unity.TestFailures++;
UNITY_PRINT_EOL();
}
Unity.CurrentTestFailed = 0;
Unity.CurrentTestIgnored = 0;
}

View File

@@ -0,0 +1,94 @@
/* =========================================================================
Unity - A Test Framework for C
ThrowTheSwitch.org
Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
SPDX-License-Identifier: MIT
========================================================================= */
#ifndef UNITY_FIXTURE_H_
#define UNITY_FIXTURE_H_
#include "unity.h"
#include "unity_fixture_internals.h"
#ifndef UNITY_FIXTURE_NO_EXTRAS
#include "unity_memory.h"
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#include "unity_internals.h"
int UnityMain(int argc, const char* argv[], void (*runAllTests)(void));
#define TEST_GROUP(group)\
static const char* TEST_GROUP_##group = #group
#define TEST_SETUP(group) void TEST_##group##_SETUP(void);\
void TEST_##group##_SETUP(void)
#define TEST_TEAR_DOWN(group) void TEST_##group##_TEAR_DOWN(void);\
void TEST_##group##_TEAR_DOWN(void)
#define TEST(group, name) \
void TEST_##group##_##name##_(void);\
void TEST_##group##_##name##_run(void);\
void TEST_##group##_##name##_run(void)\
{\
UnityTestRunner(TEST_##group##_SETUP,\
TEST_##group##_##name##_,\
TEST_##group##_TEAR_DOWN,\
"TEST(" #group ", " #name ")",\
TEST_GROUP_##group, #name,\
__FILE__, __LINE__);\
}\
void TEST_##group##_##name##_(void)
#define IGNORE_TEST(group, name) \
void TEST_##group##_##name##_(void);\
void TEST_##group##_##name##_run(void);\
void TEST_##group##_##name##_run(void)\
{\
UnityIgnoreTest("IGNORE_TEST(" #group ", " #name ")", TEST_GROUP_##group, #name);\
}\
void TEST_##group##_##name##_(void)
/* Call this for each test, insider the group runner */
#define RUN_TEST_CASE(group, name) \
{ void TEST_##group##_##name##_run(void);\
TEST_##group##_##name##_run(); }
/* This goes at the bottom of each test file or in a separate c file */
#define TEST_GROUP_RUNNER(group)\
void TEST_##group##_GROUP_RUNNER(void);\
void TEST_##group##_GROUP_RUNNER(void)
/* Call this from main */
#define RUN_TEST_GROUP(group)\
{ void TEST_##group##_GROUP_RUNNER(void);\
TEST_##group##_GROUP_RUNNER(); }
/* CppUTest Compatibility Macros */
#ifndef UNITY_EXCLUDE_CPPUTEST_ASSERTS
/* Sets a pointer and automatically restores it to its old value after teardown */
#define UT_PTR_SET(ptr, newPointerValue) UnityPointer_Set((void**)&(ptr), (void*)(newPointerValue), __LINE__)
#define TEST_ASSERT_POINTERS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_PTR((expected), (actual))
#define TEST_ASSERT_BYTES_EQUAL(expected, actual) TEST_ASSERT_EQUAL_HEX8(0xff & (expected), 0xff & (actual))
#define FAIL(message) TEST_FAIL_MESSAGE((message))
#define CHECK(condition) TEST_ASSERT_TRUE((condition))
#define LONGS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_INT((expected), (actual))
#define STRCMP_EQUAL(expected, actual) TEST_ASSERT_EQUAL_STRING((expected), (actual))
#define DOUBLES_EQUAL(expected, actual, delta) TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual))
#endif
#ifdef __cplusplus
}
#endif
#endif /* UNITY_FIXTURE_H_ */

View File

@@ -0,0 +1,50 @@
/* =========================================================================
Unity - A Test Framework for C
ThrowTheSwitch.org
Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
SPDX-License-Identifier: MIT
========================================================================= */
#ifndef UNITY_FIXTURE_INTERNALS_H_
#define UNITY_FIXTURE_INTERNALS_H_
#ifdef __cplusplus
extern "C"
{
#endif
struct UNITY_FIXTURE_T
{
int Verbose;
int Silent;
unsigned int RepeatCount;
const char* NameFilter;
const char* GroupFilter;
};
extern struct UNITY_FIXTURE_T UnityFixture;
typedef void unityfunction(void);
void UnityTestRunner(unityfunction* setup,
unityfunction* testBody,
unityfunction* teardown,
const char* printableName,
const char* group,
const char* name,
const char* file, unsigned int line);
void UnityIgnoreTest(const char* printableName, const char* group, const char* name);
int UnityGetCommandLineOptions(int argc, const char* argv[]);
void UnityConcludeFixtureTest(void);
void UnityPointer_Set(void** pointer, void* newValue, UNITY_LINE_TYPE line);
void UnityPointer_UndoAllSets(void);
void UnityPointer_Init(void);
#ifndef UNITY_MAX_POINTERS
#define UNITY_MAX_POINTERS 5
#endif
#ifdef __cplusplus
}
#endif
#endif /* UNITY_FIXTURE_INTERNALS_H_ */

1183
test/unity/unity_internals.h Normal file

File diff suppressed because it is too large Load Diff

203
test/unity/unity_memory.c Normal file
View File

@@ -0,0 +1,203 @@
/* =========================================================================
Unity - A Test Framework for C
ThrowTheSwitch.org
Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
SPDX-License-Identifier: MIT
========================================================================= */
#include "unity.h"
#include "unity_memory.h"
#include <string.h>
#define MALLOC_DONT_FAIL -1
static int malloc_count;
static int malloc_fail_countdown = MALLOC_DONT_FAIL;
void UnityMalloc_StartTest(void)
{
malloc_count = 0;
malloc_fail_countdown = MALLOC_DONT_FAIL;
}
void UnityMalloc_EndTest(void)
{
malloc_fail_countdown = MALLOC_DONT_FAIL;
if (malloc_count != 0)
{
UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "This test leaks!");
}
}
void UnityMalloc_MakeMallocFailAfterCount(int countdown)
{
malloc_fail_countdown = countdown;
}
/* These definitions are always included from unity_fixture_malloc_overrides.h */
/* We undef to use them or avoid conflict with <stdlib.h> per the C standard */
#undef malloc
#undef free
#undef calloc
#undef realloc
#ifdef UNITY_EXCLUDE_STDLIB_MALLOC
static unsigned char unity_heap[UNITY_INTERNAL_HEAP_SIZE_BYTES];
static size_t heap_index;
#else
#include <stdlib.h>
#endif
typedef struct GuardBytes
{
size_t size;
size_t guard_space;
} Guard;
#define UNITY_MALLOC_ALIGNMENT (UNITY_POINTER_WIDTH / 8)
static const char end[] = "END";
static size_t unity_size_round_up(size_t size)
{
size_t rounded_size;
rounded_size = ((size + UNITY_MALLOC_ALIGNMENT - 1) / UNITY_MALLOC_ALIGNMENT) * UNITY_MALLOC_ALIGNMENT;
return rounded_size;
}
void* unity_malloc(size_t size)
{
char* mem;
Guard* guard;
size_t total_size;
total_size = sizeof(Guard) + unity_size_round_up(size + sizeof(end));
if (malloc_fail_countdown != MALLOC_DONT_FAIL)
{
if (malloc_fail_countdown == 0)
return NULL;
malloc_fail_countdown--;
}
if (size == 0) return NULL;
#ifdef UNITY_EXCLUDE_STDLIB_MALLOC
if (heap_index + total_size > UNITY_INTERNAL_HEAP_SIZE_BYTES)
{
guard = NULL;
}
else
{
/* We know we can get away with this cast because we aligned memory already */
guard = (Guard*)(void*)(&unity_heap[heap_index]);
heap_index += total_size;
}
#else
guard = (Guard*)UNITY_MALLOC(total_size);
#endif
if (guard == NULL) return NULL;
malloc_count++;
guard->size = size;
guard->guard_space = 0;
mem = (char*)&(guard[1]);
memcpy(&mem[size], end, sizeof(end));
return (void*)mem;
}
static int isOverrun(void* mem)
{
Guard* guard = (Guard*)mem;
char* memAsChar = (char*)mem;
guard--;
return guard->guard_space != 0 || strcmp(&memAsChar[guard->size], end) != 0;
}
static void release_memory(void* mem)
{
Guard* guard = (Guard*)mem;
guard--;
malloc_count--;
#ifdef UNITY_EXCLUDE_STDLIB_MALLOC
{
size_t block_size;
block_size = unity_size_round_up(guard->size + sizeof(end));
if (mem == unity_heap + heap_index - block_size)
{
heap_index -= (sizeof(Guard) + block_size);
}
}
#else
UNITY_FREE(guard);
#endif
}
void unity_free(void* mem)
{
int overrun;
if (mem == NULL)
{
return;
}
overrun = isOverrun(mem);
release_memory(mem);
if (overrun)
{
UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during free()");
}
}
void* unity_calloc(size_t num, size_t size)
{
void* mem = unity_malloc(num * size);
if (mem == NULL) return NULL;
memset(mem, 0, num * size);
return mem;
}
void* unity_realloc(void* oldMem, size_t size)
{
Guard* guard = (Guard*)oldMem;
void* newMem;
if (oldMem == NULL) return unity_malloc(size);
guard--;
if (isOverrun(oldMem))
{
release_memory(oldMem);
UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during realloc()");
}
if (size == 0)
{
release_memory(oldMem);
return NULL;
}
if (guard->size >= size) return oldMem;
#ifdef UNITY_EXCLUDE_STDLIB_MALLOC /* Optimization if memory is expandable */
{
size_t old_total_size = unity_size_round_up(guard->size + sizeof(end));
if ((oldMem == unity_heap + heap_index - old_total_size) &&
((heap_index - old_total_size + unity_size_round_up(size + sizeof(end))) <= UNITY_INTERNAL_HEAP_SIZE_BYTES))
{
release_memory(oldMem); /* Not thread-safe, like unity_heap generally */
return unity_malloc(size); /* No memcpy since data is in place */
}
}
#endif
newMem = unity_malloc(size);
if (newMem == NULL) return NULL; /* Do not release old memory */
memcpy(newMem, oldMem, guard->size);
release_memory(oldMem);
return newMem;
}

61
test/unity/unity_memory.h Normal file
View File

@@ -0,0 +1,61 @@
/* =========================================================================
Unity - A Test Framework for C
ThrowTheSwitch.org
Copyright (c) 2007-25 Mike Karlesky, Mark VanderVoord, & Greg Williams
SPDX-License-Identifier: MIT
========================================================================= */
#ifndef UNITY_MEMORY_OVERRIDES_H_
#define UNITY_MEMORY_OVERRIDES_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stddef.h>
#ifdef UNITY_EXCLUDE_STDLIB_MALLOC
/* Define this macro to remove the use of stdlib.h, malloc, and free.
* Many embedded systems do not have a heap or malloc/free by default.
* This internal unity_malloc() provides allocated memory deterministically from
* the end of an array only, unity_free() only releases from end-of-array,
* blocks are not coalesced, and memory not freed in LIFO order is stranded. */
#ifndef UNITY_INTERNAL_HEAP_SIZE_BYTES
#define UNITY_INTERNAL_HEAP_SIZE_BYTES 256
#endif
#endif
/* These functions are used by Unity to allocate and release memory
* on the heap and can be overridden with platform-specific implementations.
* For example, when using FreeRTOS UNITY_MALLOC becomes pvPortMalloc()
* and UNITY_FREE becomes vPortFree(). */
#if !defined(UNITY_MALLOC) || !defined(UNITY_FREE)
#include <stdlib.h>
#define UNITY_MALLOC(size) malloc(size)
#define UNITY_FREE(ptr) free(ptr)
#else
extern void* UNITY_MALLOC(size_t size);
extern void UNITY_FREE(void* ptr);
#endif
#define malloc unity_malloc
#define calloc unity_calloc
#define realloc unity_realloc
#define free unity_free
void* unity_malloc(size_t size);
void* unity_calloc(size_t num, size_t size);
void* unity_realloc(void * oldMem, size_t size);
void unity_free(void * mem);
/* You must compile with malloc replacement, as defined in unity_fixture_malloc_overrides.h */
void UnityMalloc_StartTest(void);
void UnityMalloc_EndTest(void);
void UnityMalloc_MakeMallocFailAfterCount(int countdown);
#ifdef __cplusplus
}
#endif
#endif

334
tls.c
View File

@@ -1,334 +0,0 @@
#include "types.h"
#include "tls.h"
#include "config.h"
#include "logging.h"
#include "utils.h"
#ifndef KERNEL_SPACE
#include <fcntl.h>
#include <unistd.h>
#endif
static int bruteforce_analyze_sni_str(
const struct section_config_t *section,
const uint8_t *data, size_t dlen,
struct tls_verdict *vrd
) {
if (section->all_domains) {
vrd->target_sni = 1;
vrd->sni_len = 0;
vrd->sni_offset = dlen / 2;
return 0;
}
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;
if (sne->domain_len + dlen + 1 > MAX_PACKET_SIZE) {
continue;
}
NETBUF_ALLOC(buf, MAX_PACKET_SIZE);
if (!NETBUF_CHECK(buf)) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
NETBUF_ALLOC(nzbuf, MAX_PACKET_SIZE * sizeof(int));
if (!NETBUF_CHECK(nzbuf)) {
lgerror(-ENOMEM, "Allocation error");
NETBUF_FREE(buf);
return -ENOMEM;
}
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 (unsigned int k = 0; k < dlen; k++) {
if (zbuf[k] == domain_len) {
vrd->target_sni = 1;
vrd->sni_len = domain_len;
vrd->sni_offset = (k - domain_len - 1);
vrd->sni_target_offset = vrd->sni_offset;
vrd->sni_target_len = vrd->sni_len;
NETBUF_FREE(buf);
NETBUF_FREE(nzbuf);
return 0;
}
}
NETBUF_FREE(buf);
NETBUF_FREE(nzbuf);
}
return 0;
}
static int analyze_sni_str(
const struct section_config_t *section,
const char *sni_name, int sni_len, const uint8_t *data,
struct tls_verdict *vrd
) {
if (section->all_domains) {
vrd->target_sni = 1;
goto check_domain;
}
for (struct domains_list *sne = section->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 &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
sne->domain_len)) {
vrd->target_sni = 1;
vrd->sni_target_offset = (const uint8_t *)sni_startp - data;
vrd->sni_target_len = sne->domain_len;
break;
}
}
check_domain:
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 &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
sne->domain_len)) {
vrd->target_sni = 0;
lgdebugmsg("Excluded SNI: %.*s",
vrd->sni_len, data + vrd->sni_offset);
}
}
}
return 0;
}
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
#define TLS_EXTENSION_SNI 0x0000
#define TLS_EXTENSION_CLIENT_HELLO_ENCRYPTED 0xfe0d
/**
* Processes tls payload of the tcp request.
*
* data Payload data of TCP.
* dlen Length of `data`.
*/
struct tls_verdict analyze_tls_data(
const struct section_config_t *section,
const uint8_t *data,
uint32_t dlen)
{
struct tls_verdict vrd = {0};
size_t i = 0;
const uint8_t *data_end = data + dlen;
if (section->sni_detection == SNI_DETECTION_BRUTE) {
bruteforce_analyze_sni_str(section, data, dlen, &vrd);
goto out;
}
while (i + 4 < dlen) {
const uint8_t *msgData = data + i;
uint8_t tls_content_type = *msgData;
uint8_t tls_vmajor = *(msgData + 1);
uint16_t message_length = ntohs(*(uint16_t *)(msgData + 3));
if (tls_vmajor != 0x03) goto nextMessage;
if (i + 5 > dlen) break;
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
goto nextMessage;
const uint8_t *handshakeProto = msgData + 5;
if (handshakeProto + 1 >= data_end) break;
uint8_t handshakeType = *handshakeProto;
if (handshakeType != TLS_HANDSHAKE_TYPE_CLIENT_HELLO)
goto nextMessage;
const uint8_t *msgPtr = handshakeProto;
msgPtr += 1;
msgPtr += 3 + 2 + 32;
if (msgPtr + 1 >= data_end) break;
uint8_t sessionIdLength = *msgPtr;
msgPtr++;
msgPtr += sessionIdLength;
if (msgPtr + 2 >= data_end) break;
uint16_t ciphersLength = ntohs(*(uint16_t *)msgPtr);
msgPtr += 2;
msgPtr += ciphersLength;
if (msgPtr + 1 >= data_end) break;
uint8_t compMethodsLen = *msgPtr;
msgPtr++;
msgPtr += compMethodsLen;
if (msgPtr + 2 >= data_end) break;
uint16_t extensionsLen = ntohs(*(uint16_t *)msgPtr);
msgPtr += 2;
const uint8_t *extensionsPtr = msgPtr;
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
if (extensions_end > data_end) extensions_end = data_end;
while (extensionsPtr < extensions_end) {
const uint8_t *extensionPtr = extensionsPtr;
if (extensionPtr + 4 >= extensions_end) break;
uint16_t extensionType =
ntohs(*(uint16_t *)extensionPtr);
extensionPtr += 2;
uint16_t extensionLen =
ntohs(*(uint16_t *)extensionPtr);
extensionPtr += 2;
if (extensionPtr + extensionLen > extensions_end)
break;
if (extensionType != TLS_EXTENSION_SNI)
goto nextExtension;
const uint8_t *sni_ext_ptr = extensionPtr;
if (sni_ext_ptr + 2 >= extensions_end) break;
uint16_t sni_ext_dlen = ntohs(*(uint16_t *)sni_ext_ptr);
sni_ext_ptr += 2;
const uint8_t *sni_ext_end = sni_ext_ptr + sni_ext_dlen;
if (sni_ext_end >= extensions_end) break;
if (sni_ext_ptr + 3 >= sni_ext_end) break;
sni_ext_ptr++;
uint16_t sni_len = ntohs(*(uint16_t *)sni_ext_ptr);
sni_ext_ptr += 2;
if (sni_ext_ptr + sni_len > sni_ext_end) break;
const char *sni_name = (char *)sni_ext_ptr;
vrd.sni_offset = (uint8_t *)sni_name - data;
vrd.sni_target_offset = vrd.sni_offset;
vrd.sni_len = sni_len;
vrd.sni_target_len = vrd.sni_len;
analyze_sni_str(section, sni_name, sni_len, data, &vrd);
goto out;
nextExtension:
extensionsPtr += 2 + 2 + extensionLen;
}
nextMessage:
i += 5 + message_length;
}
out:
return vrd;
}
int gen_fake_sni(struct fake_type type,
const void *ipxh, uint32_t iph_len,
const struct tcphdr *tcph, uint32_t tcph_len,
uint8_t *buf, uint32_t *buflen) {
uint32_t data_len = type.fake_len;
if (type.type == FAKE_PAYLOAD_RANDOM && data_len == 0) {
data_len = (uint32_t)randint() % 1200;
}
if (!ipxh || !tcph || !buf || !buflen)
return -EINVAL;
int ipxv = netproto_version(ipxh, iph_len);
if (ipxv == IP4VERSION) {
const struct iphdr *iph = ipxh;
memcpy(buf, iph, iph_len);
struct iphdr *niph = (struct iphdr *)buf;
niph->protocol = IPPROTO_TCP;
} else if (ipxv == IP6VERSION) {
const struct ip6_hdr *iph = ipxh;
iph_len = sizeof(struct ip6_hdr);
memcpy(buf, iph, iph_len);
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_nxt = IPPROTO_TCP;
} else {
return -EINVAL;
}
uint32_t dlen = iph_len + tcph_len + data_len;
if (*buflen < dlen)
return -ENOMEM;
memcpy(buf + iph_len, tcph, tcph_len);
uint8_t *bfdptr = buf + iph_len + tcph_len;
switch (type.type) {
case FAKE_PAYLOAD_DATA:
memcpy(bfdptr, type.fake_data, data_len);
break;
default: // FAKE_PAYLOAD_RANDOM
#ifdef KERNEL_SPACE
get_random_bytes(bfdptr, data_len);
#else /* KERNEL_SPACE */
#if _NO_GETRANDOM
{
int ret = open("/dev/urandom", O_RDONLY);
if (ret < 0) {
lgerror(ret, "Unable to open /dev/urandom");
return ret;
}
read(ret, bfdptr, data_len);
close(ret);
}
#else /* _NO_GETRANDOM */
getrandom(bfdptr, data_len, 0);
#endif /* _NO_GETRANDOM */
#endif /* KERNEL_SPACE */
}
if (ipxv == IP4VERSION) {
struct iphdr *niph = (struct iphdr *)buf;
niph->tot_len = htons(dlen);
} else if (ipxv == IP6VERSION) {
struct ip6_hdr *niph = (struct ip6_hdr *)buf;
niph->ip6_plen = htons(dlen - iph_len);
}
fail_packet(type.strategy, buf, &dlen, *buflen);
*buflen = dlen;
return 0;
}

34
tls.h
View File

@@ -1,34 +0,0 @@
#ifndef TLS_H
#define TLS_H
#include "types.h"
#include "utils.h"
/**
* Result of analyze_tls_data function
*/
struct tls_verdict {
int target_sni; /* google video hello packet */
int sni_offset; /* offset from start of tcp _payload_ */
int sni_target_offset; /* offset of target domain instead of entire sni */
int sni_target_len; /* offset of target domain instead of entire sni */
int sni_len;
};
/**
* Processes the packet and finds TLS Client Hello information inside it.
* data pointer points to start of TLS Message (TCP Payload)
*/
struct tls_verdict analyze_tls_data(const struct section_config_t *section, const uint8_t *data, uint32_t dlen);
/**
* Generates the fake client hello message
*/
int gen_fake_sni(struct fake_type type,
const void *iph, uint32_t iph_len,
const struct tcphdr *tcph, uint32_t tcph_len,
uint8_t *buf, uint32_t *buflen);
#endif /* TLS_H */

View File

@@ -4,6 +4,8 @@ USE_SYS_LIBS := no
#Userspace app makes here
BUILD_DIR := $(CURDIR)/build
DEPSDIR := $(BUILD_DIR)/deps
INCLUDE_DIR := $(CURDIR)/src
SRC_DIR := $(CURDIR)/src
CC:=gcc
CCLD:=$(CC)
@@ -15,7 +17,7 @@ ifeq ($(USE_SYS_LIBS), no)
REQ = $(LIBNETFILTER_QUEUE) $(LIBMNL) $(LIBCRYPTO)
endif
override CFLAGS += -DPKG_VERSION=\"$(PKG_FULLVERSION)\" -Wall -Wpedantic -Wno-unused-variable -std=gnu99
override CFLAGS += -DPKG_VERSION=\"$(PKG_FULLVERSION)\" -I$(INCLUDE_DIR) -Wall -Wpedantic -Wno-unused-variable -std=gnu99 -Ideps/cyclone/include
LIBNFNETLINK_CFLAGS := -I$(DEPSDIR)/include
LIBNFNETLINK_LIBS := -L$(DEPSDIR)/lib
@@ -30,16 +32,24 @@ endif
export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CFLAGS LIBMNL_LIBS
APP:=$(BUILD_DIR)/youtubeUnblock
TEST_APP:=$(BUILD_DIR)/testYoutubeUnblock
SRCS := youtubeUnblock.c mangle.c args.c utils.c quic.c tls.c getopt.c
SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
APP_EXEC := youtubeUnblock.c
APP_OBJ := $(APP_EXEC:%.c=$(BUILD_DIR)/%.o)
TEST_SRCS := $(shell find test -name "*.c")
TEST_OBJS := $(TEST_SRCS:%.c=$(BUILD_DIR)/%.o)
TEST_CFLAGS := -Itest/unity -Itest
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.la
LIBMNL := $(DEPSDIR)/lib/libmnl.la
LIBNETFILTER_QUEUE := $(DEPSDIR)/lib/libnetfilter_queue.la
#LIBCRYPTO := $(DEPSDIR)/lib64/libcrypto.a
LIBCYCLONE := $(DEPSDIR)/lib/libcyclone.a
.PHONY: default all dev dev_attrs prepare_dirs
.PHONY: default all test build_test dev dev_attrs prepare_dirs
default: all
run_dev: dev
@@ -52,14 +62,21 @@ dev_attrs:
all: prepare_dirs $(APP)
build_test: prepare_dirs $(TEST_APP)
test: build_test
$(TEST_APP)
prepare_dirs:
mkdir -p $(BUILD_DIR)
mkdir -p $(BUILD_DIR)/crypto
mkdir -p $(BUILD_DIR)/test
mkdir -p $(BUILD_DIR)/test/unity
mkdir -p $(DEPSDIR)
$(LIBCRYPTO):
cd deps/openssl && ./Configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--cross-compile-prefix=$(CROSS_COMPILE_PLATFORM)-,) --no-shared
$(MAKE) -C deps/openssl
$(MAKE) install_sw -C deps/openssl
$(LIBCYCLONE):
$(MAKE) -C deps/cyclone CFLAGS="$(CFLAGS)"
mkdir -p $(DEPSDIR)/lib
cp deps/cyclone/libcyclone.a $(DEPSDIR)/lib/libcyclone.a
$(LIBNFNETLINK):
cd deps/libnfnetlink && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
@@ -76,14 +93,22 @@ $(LIBNETFILTER_QUEUE): $(LIBNFNETLINK) $(LIBMNL)
$(MAKE) -C deps/libnetfilter_queue
$(MAKE) install -C deps/libnetfilter_queue
$(APP): $(OBJS) $(REQ)
$(APP): $(OBJS) $(APP_OBJ) $(REQ) $(LIBCYCLONE)
@echo 'CCLD $(APP)'
$(CCLD) $(OBJS) -o $(APP) $(LDFLAGS) -lmnl -lnetfilter_queue -lpthread
$(CCLD) $(OBJS) $(APP_OBJ) -o $(APP) $(LDFLAGS) -lmnl -lnetfilter_queue -lpthread -lcyclone
$(BUILD_DIR)/%.o: %.c $(REQ) config.h
$(TEST_APP): $(APP) $(TEST_OBJS) $(REQ) $(LIBCYCLONE)
@echo 'CCLD $(TEST_APP)'
$(CCLD) $(OBJS) $(TEST_OBJS) -o $(TEST_APP) $(LDFLAGS) -lmnl -lnetfilter_queue -lpthread -lcyclone
$(BUILD_DIR)/%.o: src/%.c $(REQ) $(INCLUDE_DIR)/config.h
@echo 'CC $@'
$(CC) -c $(CFLAGS) $(LDFLAGS) $< -o $@
$(BUILD_DIR)/test/%.o: test/%.c $(REQ) $(INCLUDE_DIR)/config.h
@echo 'CC $@'
$(CC) -c $(CFLAGS) $(LDFLAGS) $(TEST_CFLAGS) $< -o $@
install: all
install -d $(DESTDIR)$(PREFIX)/bin/
install -m 755 $(APP) $(DESTDIR)$(PREFIX)/bin/
@@ -106,5 +131,5 @@ ifeq ($(USE_SYS_LIBS), no)
$(MAKE) distclean -C deps/libnetfilter_queue || true
$(MAKE) distclean -C deps/libmnl || true
$(MAKE) distclean -C deps/libnfnetlink || true
#$(MAKE) distclean -C deps/openssl || true
endif
$(MAKE) clean -C deps/cyclone || true