299 Commits

Author SHA1 Message Date
Vadim Vetrov
f37c3dd496 Bump version 2025-02-21 00:19:43 +03:00
Vadim Vetrov
0cf1035a14 Describe youtube does not work with all domains 2025-02-08 19:15:58 +03:00
Vadim Vetrov
7ebaccfa19 Merge branch 'aho_corasick' 2025-02-08 11:43:06 +03:00
Vadim Vetrov
705da0f4c6 Merge pull request #229 from metrapoliten/fixes
Различные фиксы
2025-02-07 18:23:48 +03:00
Vadim Vetrov
df70763b4a fix: safety defenders for delay_packet_send 2025-02-06 18:43:31 +03:00
Artyom Gavrilov
49304cc111 fix: добавление проверки malloc 2025-02-06 00:29:27 +03:00
Artyom Gavrilov
b832541766 fix: перемещение проверки на нужное место 2025-02-05 23:55:41 +03:00
Artyom Gavrilov
2884cb72f9 fix: проверка указателя перед разыменованием 2025-02-05 23:50:10 +03:00
Artyom Gavrilov
34271ece2c fix: восстановление проверки fseek
Вероятно в этом месте должна была быть проверка вызова fseek.
2025-02-05 23:50:10 +03:00
Artyom Gavrilov
ad6b84a961 fix: проверка ftell на возвращаемое значение 2025-02-05 23:50:10 +03:00
Artyom Gavrilov
5f20220d4e fix: изменение типа переменной на подходящий
По стандарту ftell возвращает long.
2025-02-05 23:50:10 +03:00
Artyom Gavrilov
6cc23a2991 fix: изменение проверки fseek
По стандарту fseek при неудаче возвращает любое значение кроме нуля.
2025-02-05 23:50:10 +03:00
Artyom Gavrilov
c73885aca3 fix: изменение проверки qversion
qversion >= 0, т.к. тип переменной - uint32_t. Провека должна быть по
переменной ret.
2025-02-05 23:48:46 +03:00
Artyom Gavrilov
78dd12c526 fix: проверка указателя до его использования 2025-02-05 22:52:13 +03:00
Artyom Gavrilov
d7489fc08a fix: проверка указателя до его использования 2025-02-05 22:47:02 +03:00
Vadim Vetrov
6da6f63541 Delete old domains data structures 2025-02-04 18:40:59 +03:00
Vadim Vetrov
a7b689b320 Fix warnings 2025-02-03 15:30:10 +03:00
Vadim Vetrov
f7d0bed7aa Use Aho-Corasick algorithm in tls parsing 2025-02-02 23:36:19 +03:00
Vadim Vetrov
d225e673c7 Implement Aho-Corasick algorithm 2025-02-02 20:00:57 +03:00
Vadim Vetrov
d9c360910b procfs for old kernels 2025-02-01 21:02:05 +03:00
Vadim Vetrov
42917a75fc Add youtubeUnblock statistics
The statistis will be printed on exit in userspace version. In kernel
space version, use `cat /proc/kyoutubeUnblock`.

The feature was proposed by @IceCat74 in #220
2025-02-01 20:38:33 +03:00
Vadim Vetrov
a03d05ca19 Fixed entware hash 2025-01-28 19:05:45 +03:00
Vadim Vetrov
91f8210437 Merge pull request #223 from Waujito/sni_domains_file
Allow to specify sni domains as file
2025-01-27 20:03:43 +03:00
Vadim Vetrov
ef78f5e185 Add --fake-custom-sni-file option
Allows to specify fake as a binary file
2025-01-27 19:51:28 +03:00
Vadim Vetrov
4eaeceed4e Fix README jumps 2025-01-27 16:55:31 +03:00
Vadim Vetrov
ab3e1b7dd1 Increase connbytes limit
As reported in #220
2025-01-27 16:54:42 +03:00
Vadim Vetrov
134a326cc7 Update README.md 2025-01-27 16:44:24 +03:00
Vadim Vetrov
baf9ca58c1 Update README.md 2025-01-27 16:40:13 +03:00
Vadim Vetrov
49de2cad6a Allow to specify sni domains as file 2025-01-20 22:26:17 +03:00
Vadim Vetrov
2289b4c738 Fix all domains with bruteforce analyzer 2025-01-19 21:26:56 +03:00
Vadim Vetrov
3f11a65a73 Disable conntrack by default
On some devices conntrack may return EPERM
2025-01-19 18:08:09 +03:00
Vadim Vetrov
bb133f8b88 Merge branch 'dev' 2025-01-18 23:21:54 +03:00
Vadim Vetrov
2809a5cc74 Fix Illegal instruction 2025-01-18 23:20:47 +03:00
Vadim Vetrov
b434c922ea Update README.md 2025-01-17 19:55:52 +03:00
Vadim Vetrov
12d6617d95 Merge pull request #214 from Waujito/kmod_fix
Kmod fix #213
2025-01-16 13:51:16 +03:00
Vadim Vetrov
f68f1ff6c7 Builder for 3.0.101 2025-01-12 03:34:33 +03:00
Vadim Vetrov
452e640d9f kmod -DNO_IPV6 packet filter 2025-01-12 01:45:31 +03:00
Vadim Vetrov
dfedde9aa8 Deglobalize struct config.
New config structure allows to implement refcounting in the kernel module to
escape borderline cases on module exit or config hot swap.
2025-01-11 03:42:50 +03:00
Vadim Vetrov
1027240062 Fix old kernel versions builders 2025-01-10 14:41:16 +03:00
Vadim Vetrov
351bbfb097 Use register_pernet_subsys for nf hook registration 2025-01-10 13:30:59 +03:00
Vadim Vetrov
2e67c161f8 Fix sni bruteforce when domain is at the end 2025-01-09 21:40:34 +03:00
Vadim Vetrov
d87ab29199 Use mallocs instead of NETBUF_ALLOC
malloc won't hurt when youtubeUnblock is processing the packet. But it
is better for kmod and a way cleaner than NETBUF_ALLOC defines.
2025-01-09 19:44:30 +03:00
Vadim Vetrov
9985fcea49 More verbose payload_split loggers 2025-01-09 18:31:38 +03:00
Vadim Vetrov
6393c11960 Use skb_copy_bits instead of skb_linearize
Encountered noticeable issues in performance caused by skb_linearize
2025-01-09 18:30:23 +03:00
Vadim Vetrov
9b58869864 Add --no-dport-filter flag
This flag allows to reduce amount of network packet to analyze.
2025-01-09 00:53:56 +03:00
Vadim Vetrov
37c8a798fd Disallow to use --no-ipv6 in kernel space 2025-01-09 00:21:12 +03:00
Vadim Vetrov
16ba8801c1 Concurrency defenders in config parse and module destroy
This commit is parr of #213 fix.
In this issue kernel module crashes on high bandwidth usage has been
reported. The part of the problem is concurrency usage: when config gets
freed, callbacks keep to depend on it.
2025-01-09 00:21:12 +03:00
Vadim Vetrov
cadec5a05c Allow to disable conntrack in userspace 2025-01-09 00:20:20 +03:00
Vadim Vetrov
59581e91b2 Allow to disable conntrack in kernel module 2025-01-09 00:09:47 +03:00
Vadim Vetrov
84d47b8a3d Add conntrack parse skeleton 2025-01-08 03:44:20 +03:00
Vadim Vetrov
8bf2ab9e9b Add libcyclone.a to gitignore 2025-01-08 03:43:07 +03:00
Vadim Vetrov
a3bd918484 Update trace logging 2025-01-07 23:28:01 +03:00
Vadim Vetrov
7b321b5a2d Use size_t instead of uint32_t
Encountered some crossplatform errors with uint_t-like length type
definition.
2025-01-07 13:51:07 +03:00
Vadim Vetrov
1b62bb6cb2 Fix segfault in parse_quic_decrypted 2025-01-07 13:26:29 +03:00
Vadim Vetrov
40e1101d68 Do not hide sni domains with tls disabled 2025-01-04 19:27:12 +03:00
Vadim Vetrov
71c105a900 Disable early approve with all domains 2025-01-04 19:25:05 +03:00
Vadim Vetrov
e852d37edb Differ quic initial salt versions 2025-01-04 19:22:54 +03:00
Vadim Vetrov
e98bb5ecad Implement sni-detection brute for QUIC 2025-01-04 17:47:49 +03:00
Vadim Vetrov
60e33318cb Fix workflow commit hash 2025-01-04 15:44:46 +03:00
Vadim Vetrov
fff2309863 Rename parsed to parse in --udp-filter-quic 2025-01-04 01:25:02 +03:00
Vadim Vetrov
0b9bc8e72a Add quic disassemble
Project all the CRYPTO messages to one buffer according to length/offset
2025-01-04 01:24:54 +03:00
Vadim Vetrov
2470c590fb Fix tls sni ext in the end of the packet parser 2025-01-03 18:04:40 +03:00
Vadim Vetrov
b89c8a29ff Fix default domain list
The default domain list may lead to conflicts in QUIC parse support in
some browsers. Especially, QUIC drop for googleapis domain may disable all the QUIC.
2025-01-03 15:53:29 +03:00
Vadim Vetrov
0280fe383f Add --udp-filter-quic=parse
This will enable QUIC decryption and parsing.
2025-01-03 15:52:53 +03:00
Vadim Vetrov
91e6825cb2 Fix error messages 2025-01-03 03:24:37 +03:00
Vadim Vetrov
43823cab57 Fix dvs for mangle tcp 2025-01-03 00:04:56 +03:00
Vadim Vetrov
ded8c49e4b Add copyright notices
youtubeUnblock becames bigger and copyright notices in each file will
make it easier for anyone to do something over it.
2025-01-02 22:28:29 +03:00
Vadim Vetrov
defaa25172 Fix quic_crypto buildsystem 2025-01-02 20:49:29 +03:00
Vadim Vetrov
b11a183bb3 Connect QUIC decryption to UDP processing 2025-01-02 20:37:34 +03:00
Vadim Vetrov
e5153e9186 Remaster tls parser for quic crypto 2025-01-02 19:09:27 +03:00
Vadim Vetrov
fa7fe5294d Add testing infrastructure 2025-01-02 19:03:20 +03:00
Vadim Vetrov
5c84f2e9b5 Add crypto files 2025-01-02 01:28:25 +03:00
Vadim Vetrov
1a88bffbd9 Merge pull request #207 from Waujito/udp_update
Add none strategy to udp-faking-strategy
2024-12-30 13:18:42 +03:00
Vadim Vetrov
254b363599 Add none strategy to udp-faking-strategy 2024-12-30 13:06:56 +03:00
Vadim Vetrov
bc345ed6d4 Fix conflict between quic drop and udp port filter 2024-12-27 19:31:19 +03:00
Vadim Vetrov
123c87a24d Document new UCI system 2024-12-22 17:31:47 +03:00
Vadim Vetrov
e28a288ea0 Top up fbegin fend in section scope 2024-12-22 15:24:43 +03:00
Vadim Vetrov
d1dab6928b Issues tagged with udp label 2024-12-22 15:22:45 +03:00
Vadim Vetrov
fd980e5d98 Update README flags 2024-12-22 15:20:51 +03:00
Vadim Vetrov
9a3b139fb5 Update README with new arguments for openwrt 2024-12-19 19:12:42 +03:00
Vadim Vetrov
6568aa37f2 Fix print_args errors 2024-12-19 03:08:39 +03:00
Vadim Vetrov
3a1deb054a Fix some userspace argparse errors 2024-12-19 02:52:31 +03:00
Vadim Vetrov
ed5a669393 Fix sni domains all in print config 2024-12-19 02:23:39 +03:00
Vadim Vetrov
5fcb4a8012 Update documentation for udp 2024-12-19 02:14:14 +03:00
Vadim Vetrov
8718fc5f6c Merge pull request #200 from Waujito/discord
UDP faking support
2024-12-19 01:55:26 +03:00
Vadim Vetrov
062200d9ea Allow to use fbegin without fend 2024-12-18 22:00:49 +03:00
Vadim Vetrov
25199288e8 Cleanup args welcome 2024-12-18 20:24:57 +03:00
Vadim Vetrov
1822983b34 Delete debug logs 2024-12-09 01:45:14 +03:00
Vadim Vetrov
ba0f87d195 Fix possible errors while building kernel module 2024-12-09 01:34:31 +03:00
Vadim Vetrov
e8bdd05839 Fix possible memory leak
sni_domains wasn't freeed after default initialization
2024-12-09 01:32:12 +03:00
Vadim Vetrov
f4e5cdb328 Update documentation for kernel module 2024-12-08 22:47:33 +03:00
Vadim Vetrov
8b602a9f44 Fix GCC warnings 2024-12-08 22:45:53 +03:00
Vadim Vetrov
42e6d574a0 Add connbytes to kernel module 2024-12-08 22:19:20 +03:00
Vadim Vetrov
457a7a7f04 Massive update of argparse system
This is required for furhter maintance of kernel module. Aims to provide
common interface for both
2024-12-08 16:06:50 +03:00
Vadim Vetrov
9b5c8a729d Allow to disable TLS processing for the section 2024-12-06 18:25:43 +03:00
Vadim Vetrov
b452ed2d55 quic_drop for kmod 2024-12-06 14:05:37 +03:00
Vadim Vetrov
f9a51944dd Add args for UDP faking support. 2024-12-06 13:45:50 +03:00
Vadim Vetrov
7480cd31b8 Fix lgerror errno logging 2024-12-06 11:00:09 +03:00
Vadim Vetrov
b2ac2e0d03 UDP faking support 2024-12-05 01:24:51 +03:00
Vadim Vetrov
5ee77d517b Bump release version to 5 2024-12-02 20:42:51 +03:00
Vadim Vetrov
f5a6c5718f Do not duplicate default CFLAGS 2024-12-01 18:24:30 +03:00
Vadim Vetrov
aefabe7e0a Fix SIGSEGV/stacksmash in UDP logger.
The bug was reported in #197. Caused by insufficient size of logging
buffer.
2024-12-01 18:19:09 +03:00
Vadim Vetrov
fd1ae1e574 Move entware builders from entware branch to openwrt 2024-11-30 14:15:14 +03:00
Vadim Vetrov
7303abdaf2 Merge pull request #174 from Waujito/daemonize
Daemonize youtubeUnblock with flags, without any overhead
2024-11-29 23:24:50 +03:00
Vadim Vetrov
cb138b902a Improve UDP payload logging 2024-11-29 21:43:27 +03:00
Vadim Vetrov
3a5dbff8ac Update kmod logging 2024-11-29 21:42:57 +03:00
Vadim Vetrov
62551a9f82 Replace incrementing defines with one enum 2024-11-29 11:22:55 +03:00
Vadim Vetrov
ef120ca100 Update logging
Add syslog for daemonize. This allows to log not only to the standard
output but also in system log
2024-11-29 11:22:55 +03:00
Vadim Vetrov
a4975dcdcd Daemonize youtubeUnblock with flags, without any overhead 2024-11-29 11:22:54 +03:00
Vadim Vetrov
7ec29bd47b Merge pull request #193 from Waujito/workflow_update
Move workflow binaries builds to docker instead of cache
2024-11-29 11:07:55 +03:00
Vadim Vetrov
20ce07821b Move test builders from cache to docker 2024-11-29 10:56:01 +03:00
Vadim Vetrov
eb544c11ce Entware binaries on docker instead of cache 2024-11-29 09:54:09 +03:00
Vadim Vetrov
3376860c0f Kyber on firefox 2024-11-26 18:47:29 +03:00
Vadim Vetrov
438a3c17d8 Update workflows
musl-cross and openwrt sdk docker image implemented breaking updates.
2024-11-26 18:08:47 +03:00
Vadim Vetrov
046ecc4c97 Merge pull request #191 from MayanKoyote/main-dev
README.md & args.c: minor correction of typos
2024-11-25 23:56:34 +03:00
MayanKoyote
bb8992578f args.c: minor correction of typos 2024-11-26 00:25:35 +05:00
MayanKoyote
cb46c89423 README.md & args.c: minor correction of typos 2024-11-26 00:15:10 +05:00
Vadim Vetrov
d87d3c9efb Old openwrt (#168) 2024-11-02 10:56:44 +03:00
Vadim Vetrov
562f17e932 Merge branch 'dev' 2024-10-29 12:04:51 +03:00
Vadim Vetrov
56b6126f52 Mention --queue-balance in multithreading flag
Raw threading lead to confusion like in #177
2024-10-29 11:59:46 +03:00
Vadim Vetrov
235bf823db Add issue templates 2024-10-29 11:11:29 +03:00
Vadim Vetrov
c9537bae95 Add versioning 2024-10-29 01:55:37 +03:00
Vadim Vetrov
0ee6d667e4 Fix starting logs 2024-10-29 00:12:27 +03:00
Vadim Vetrov
aa96769559 Fix youtubeUnblock freeze when more than queue_size packets being sent
as fake_sni_seq_len

The problem affects both the userspace version and kernel space one. The
problem was reported in #166 and hopefully #167 also relates to it. The
problem occures because each packet sent by rawsocket is being enqueued
in the nf_queue, but each rawsocket waits for the packet to be
processed by linux kernel network stack. This leads to the infinitily
waiting rawsocket when the queue fullfills.
2024-10-27 02:42:06 +03:00
Vadim Vetrov
ae9592c71f Userspace: handle --no-ipv6 for PF_INET6 UNBIND/BIND_PF 2024-10-27 00:09:45 +03:00
Vadim Vetrov
93972f8404 Update Padavan manual (#163) 2024-10-26 18:04:24 +03:00
Vadim Vetrov
7070ddfc74 Userspace: better support for ALLOC_MALLOC
An alternative memory allocation strategy for userspace
2024-10-26 14:50:21 +03:00
Vadim Vetrov
0e9b3ff018 Add notice about kmods in readme 2024-10-25 22:28:39 +03:00
Vadim Vetrov
f344e525d2 Add armv7sf 2024-10-25 22:11:21 +03:00
Vadim Vetrov
f1ab2ac1a9 Userspace youtubeUnblock: support kernel versions less than 3.8
The behaviour of nfnetlink_queue is changed since then but old kernels
require BIND/UNBIND_PF commands.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0360ae412d09bc6f4864c801effcb20bfd84520e

Co-Authored-by: renr4 <renr4@users.noreply.github.com>
2024-10-22 17:51:41 +03:00
renr
55d359d3e7 Padavan support 2024-10-19 22:46:42 +03:00
Vadim Vetrov
37a517eb8a Fix #155 synfake option deleted but present in openwrt 2024-10-14 01:17:07 +03:00
Vadim Vetrov
ee56b67d20 Merge pull request #132 from Waujito/custom_fakes
Custom fakes
2024-10-14 00:25:45 +03:00
Vadim Vetrov
ed08feaf20 Mention #148 in README Troubleshooting 2024-10-14 00:22:50 +03:00
Vadim Vetrov
96cf0365ee Fix possible errors on older compilers 2024-10-14 00:15:37 +03:00
Vadim Vetrov
4c7b63fa7f Add multiple sections with config sets for various domains 2024-10-13 23:31:26 +03:00
Vadim Vetrov
58f4802f64 Update kernel module parameters 2024-10-12 19:08:49 +03:00
Vadim Vetrov
05cc0054d8 Fix getrandom on older versions 2024-10-12 16:55:27 +03:00
Vadim Vetrov
e9b033ccca Update faking strategies
Use random ip4 id for frags, use sequential ip4 id for fakes
2024-10-12 12:23:06 +03:00
Vadim Vetrov
30bc3a8d3f Update workflow for separate luci-app-youtubeUnblock 2024-10-11 22:37:26 +03:00
Vadim Vetrov
c617f238af Descibe benefits of kernel module
As asked in #128
2024-09-29 13:23:16 +03:00
Vadim Vetrov
43ca3fe07e Mention about opkg update
Asked in #123
2024-09-29 13:02:38 +03:00
Vadim Vetrov
9dc40bbdf1 Fix split on preset domain list 2024-09-28 23:06:45 +03:00
Vadim Vetrov
666b3575fc Fix kmod fake, update kmod verbosity settings 2024-09-28 22:45:35 +03:00
Vadim Vetrov
263a04bb95 Kernel module code cleanup 2024-09-28 22:17:11 +03:00
Vadim Vetrov
6b21e9b3b3 Add checker for kernel module 2024-09-28 21:29:54 +03:00
Vadim Vetrov
98a3fd5acd Add workflow for test build 2024-09-28 14:02:55 +03:00
Vadim Vetrov
3ee979f7d1 Enhance middle sni split
Instead of real middle sni we use targetted middle sni for explicit (not
all) sni domain list
2024-09-28 11:31:46 +03:00
Vadim Vetrov
82c49119d3 Add more custom fake message, random fake message 2024-09-26 18:11:05 +03:00
Vadim Vetrov
0fe45ec33f Delete owrt directory
The scripts moved to the openwrt branch https://github.com/Waujito/youtubeUnblock/tree/openwrt
2024-09-21 21:16:19 +03:00
Vadim Vetrov
43d0118767 Describe the new release delivery system 2024-09-21 19:27:47 +03:00
Vadim Vetrov
79df04cb07 Update CI workflow 2024-09-21 19:20:29 +03:00
Vadim Vetrov
2d1b58bc6d Delete workflow for kmod 2024-09-21 18:16:09 +03:00
Vadim Vetrov
cdb26833ba Merge pull request #98 from Waujito/kmod
Kernel module
2024-09-21 08:11:01 -07:00
Vadim Vetrov
c786a44dd5 Fix warnings 2024-09-20 23:06:59 +03:00
Vadim Vetrov
2fd3107401 Fix memcpy 2024-09-19 22:48:25 +03:00
Vadim Vetrov
5415bc37ec Compatibility for kernel version 3 2024-09-19 21:55:15 +03:00
Vadim Vetrov
3187b3ca61 Delete mutexes from rawsocket
The program works in sync way with kernel
2024-09-19 16:47:18 +03:00
Vadim Vetrov
1cacac7adc Add notices about kernel module and openwrt sdk 2024-09-17 19:28:13 +03:00
Vadim Vetrov
6eaa0a67c8 Merge branch 'main' into kmod 2024-09-17 19:10:18 +03:00
Vadim Vetrov
edbfe120c5 Update README.md 2024-09-17 19:04:33 +03:00
Vadim Vetrov
7e71c5e9b8 Update README.md 2024-09-15 21:40:14 -07:00
Vadim Vetrov
1ade21aa22 Update README for kernel module 2024-09-16 00:28:10 +03:00
Vadim Vetrov
49a48c33cf Update kernel module arguments 2024-09-15 22:21:24 +03:00
Vadim Vetrov
5e28fe83c2 Allow allocate in user-space with malloc 2024-09-14 20:37:19 +03:00
Vadim Vetrov
d93763ac44 Merge branch 'main' into kmod 2024-09-14 20:17:25 +03:00
Vadim Vetrov
85d3843273 Update README.md 2024-09-14 04:23:33 -07:00
Vadim Vetrov
f0826606e3 Delete development branches 2024-09-14 12:27:37 +03:00
Vadim Vetrov
c2158a7450 Merge pull request #113 from Waujito/luci_upd
Openwrt LuCI support Part 2
2024-09-14 02:26:31 -07:00
Vadim Vetrov
740df8979f Add sections about restart after settings apply 2024-09-14 12:24:20 +03:00
Vadim Vetrov
7e73fa2613 Add documentation for LuCI and UCI 2024-09-14 11:39:10 +03:00
Vadim Vetrov
8c405b81df Log ip version for udp 2024-09-14 11:18:45 +03:00
Vadim Vetrov
2ff83c6030 Update firewall rules 2024-09-14 11:08:38 +03:00
Vadim Vetrov
9f5f194a37 Support for luci in actions 2024-09-13 21:14:01 +03:00
Vadim Vetrov
e38e0e7bd9 Add md5sum faking strategy 2024-09-13 19:11:17 +03:00
Vadim Vetrov
aef2b5b469 Merge pull request #108 from spvkgn/musl-cross
CI: Add MIPS
2024-09-10 07:06:25 -07:00
spvkgn
bbd9f29a67 CI: add armv7 static build 2024-09-10 14:23:35 +05:00
spvkgn
ec9f5bb20c CI: add job for MIPS arches 2024-09-10 14:23:35 +05:00
Vadim Vetrov
7919f82f4b Delete kmod from workflow
The systems and kernels are very various so we can't offer modules for
all the systems. It is just easier to simply delete it.
2024-09-07 16:25:11 +03:00
Vadim Vetrov
ed6979cbcd Merge branch 'main' into kmod 2024-09-07 15:52:31 +03:00
Vadim Vetrov
b3668f07ba Add flags for kernel module 2024-09-07 15:51:25 +03:00
Vadim Vetrov
31aa309198 Fix #104 Infinity loop with default parameters
Fixes infinity loop with default parameters for youtubeUnblock when
trying to connect not handled website. The commit is also related to
issue #100 where the support for --exclude-domains flag was added
2024-09-07 09:24:35 +03:00
Vadim Vetrov
7d01d0974d Update README.md 2024-09-03 21:46:47 +03:00
Vadim Vetrov
5f2e423dfa Add --exclude-domains flag. Fix #100 2024-09-03 21:23:29 +03:00
Vadim Vetrov
f96ac2252b CI devices 2024-09-02 14:29:02 +03:00
Vadim Vetrov
1e6a9496f6 Fix compilationg errors for some kernels 2024-09-02 13:41:25 +03:00
Vadim Vetrov
c0dc5d2652 CI for kernel module 2024-09-02 02:06:35 +03:00
Vadim Vetrov
8bb5368b85 Fix setsockopt (deleted it) 2024-09-02 01:48:23 +03:00
Vadim Vetrov
b249903ead CI for kmod 2024-09-02 01:29:09 +03:00
Vadim Vetrov
5870df44df Linearize instead of kmalloc 2024-09-02 00:11:58 +03:00
Vadim Vetrov
b20f15086e Kernel versions 2024-09-01 23:52:37 +03:00
Vadim Vetrov
5eeff9bc0d Use netfilter hook instead of iptables target
KISS principle is in action. No need to specify rules, just insmod
youtubeUnblock and it works!
2024-09-01 20:58:50 +03:00
Vadim Vetrov
5e327497bb Split raw socket logic from iptables kernel module, add udp over ipv6
support
2024-09-01 19:56:38 +03:00
Vadim Vetrov
731da0dd50 Delete redunant checksum setter 2024-09-01 16:53:11 +03:00
Vadim Vetrov
9c839a5094 IPv6 for kernel module 2024-09-01 16:52:41 +03:00
Vadim Vetrov
27629ba0cc Kernel module basic ipv4 with debug settings 2024-09-01 16:07:47 +03:00
Vadim Vetrov
3d50c00e4f Fix internet :)
Related to #96
2024-08-29 19:28:26 +03:00
Vadim Vetrov
0a679ea41c Update version grabber 2024-08-29 18:13:51 +03:00
Vadim Vetrov
cad262f201 Update docs for entware 2024-08-29 17:45:11 +03:00
Vadim Vetrov
8b23ab762d Fix issue with synfake and two youtubeUnblock instances one after another 2024-08-29 15:55:05 +03:00
Vadim Vetrov
3d9481d72d Allow to select synfake length 2024-08-29 15:49:01 +03:00
Vadim Vetrov
0f71d5f3c4 Add synfake option 2024-08-29 14:45:27 +03:00
Vadim Vetrov
33b0ca421b Update default value of frag-sni-pos
Related to #43 and probably other issues with some ISPs. Some providers
throws RST on 2 bytes tcp, but no RST on 1 byte
2024-08-29 12:21:34 +03:00
Vadim Vetrov
bc398cbd02 Merge branch 'main' of github.com:Waujito/youtubeUnblock 2024-08-29 09:10:51 +03:00
Vadim Vetrov
491d485260 Allow to change default mark
Related to #96
2024-08-29 09:09:57 +03:00
Vadim Vetrov
f273d9cc7a Update README.md 2024-08-28 15:54:37 +03:00
Vadim Vetrov
c101adcd07 entware for entware 2024-08-28 14:00:29 +03:00
Vadim Vetrov
725dc1a6d2 Allow tune randseq offsets.
May be useful for #94
2024-08-27 23:23:54 +03:00
Vadim Vetrov
3b5276c834 Merge pull request #93 from Waujito/ipv6
Support for ipv6
2024-08-27 13:03:38 -07:00
Vadim Vetrov
d16805871f Trace logs update 2024-08-27 21:21:33 +03:00
Vadim Vetrov
5a30ac427b Add option to disable ipv6, document ipv6 2024-08-27 20:01:34 +03:00
Vadim Vetrov
a3a497bc82 Merge branch 'main' into ipv6 2024-08-27 19:42:20 +03:00
Vadim Vetrov
d530dd26d1 Support for ipv6 2024-08-27 19:27:27 +03:00
Vadim Vetrov
564820ce38 Related to #86 2024-08-26 21:21:42 +03:00
Denis Strizhkin
de9b42ae46 add options of choosing to use system libs 2024-08-21 18:40:23 +03:00
Vadim Vetrov
c10393983a Fix bug with pastseq and frag-sni-faked 2024-08-21 12:25:13 +03:00
Vadim Vetrov
e62d76e1d6 pastseq by default
Pastseq is a way more stable than randseq since some providers just drop packets with invalid conntrack state.
2024-08-21 11:53:10 +03:00
Vadim Vetrov
a859472ef3 Merge branch 'zabbius-main' 2024-08-18 19:44:38 +03:00
Vadim Vetrov
71a6711b40 Merge branch 'main' of github.com:zabbius/youtubeUnblock into zabbius-main 2024-08-18 19:44:24 +03:00
Vadim Vetrov
78ed6a1d72 Merge branch 'dev' 2024-08-18 19:32:42 +03:00
Vadim Vetrov
e8d86b9df6 Do not delete all libraries on every clean 2024-08-18 18:32:43 +03:00
Sergey Zabodalov
c5e941a53b Merge branch 'Waujito:main' into main 2024-08-18 02:01:24 +03:00
Vadim Vetrov
551fb5d38d Update README.md 2024-08-17 12:55:08 +03:00
Vadim Vetrov
b434ef4b7f Add compatibility with v0.2.2 2024-08-17 12:51:53 +03:00
Vadim Vetrov
6cf2ec5504 Update README.md 2024-08-16 22:55:59 +03:00
Vadim Vetrov
a546e783c6 Add support for tcp_check and past sequence faking strategies 2024-08-16 22:47:55 +03:00
Vadim Vetrov
1c5d4e68d9 Add few logs, minor improvements 2024-08-16 22:23:55 +03:00
Vadim Vetrov
fa0552ba66 #71 2024-08-15 14:10:38 +03:00
Vadim Vetrov
51c21a89fd Fix endian source 2024-08-15 02:58:03 +03:00
Vadim Vetrov
af6e993c07 Merge branch 'main' into dev 2024-08-15 02:46:21 +03:00
Vadim Vetrov
044801efb9 Add support for bruteforce mode of parsing SNI from Client Hello. 2024-08-15 02:31:48 +03:00
Vadim Vetrov
7f340fb033 Merge branch 'quic' into dev 2024-08-15 01:50:52 +03:00
Vadim Vetrov
727e909db1 Add documentation for QUIC 2024-08-15 01:50:12 +03:00
Vadim Vetrov
460f392a91 Update README.md 2024-08-14 19:58:35 +03:00
Vadim Vetrov
b76cc5fcee Update names of outputs 2024-08-14 19:36:37 +03:00
Vadim Vetrov
b68052efa2 Merge pull request #66 from spvkgn/ci-workflow
CI workflow
2024-08-14 07:09:14 -07:00
spvkgn
9af85abc84 CI workflow 2024-08-14 17:54:29 +05:00
Vadim Vetrov
59d19646a6 Support for new firmware (#56) 2024-08-14 12:28:25 +03:00
Vadim Vetrov
bcdf1810c4 Merge branch 'main' into dev 2024-08-13 20:51:16 +03:00
Vadim Vetrov
0aef6a991b Merge branch 'main' into quic 2024-08-13 20:50:24 +03:00
Vadim Vetrov
f3db464b97 Add initial support for QUIC, improve logging capabilities.
Add TRACE logging mode
2024-08-13 20:48:35 +03:00
Vadim Vetrov
e8519b4973 Fix error on enable in init script openwrt
Check #56 and #37 for more details. Real commit made to openwrt branch. Pushing this to restart actions
2024-08-13 19:33:52 +03:00
Vadim Vetrov
dfc2277efc Merge pull request #62 from Viktor45/main
Update Readme.md
2024-08-13 03:55:44 -07:00
Viktor45
0160c26618 Update Readme.md
Normalize the document, make it more readable, correct some typos
2024-08-13 13:18:58 +03:00
Vadim Vetrov
4a8f0d18a9 Skeleton for quic initial message parser 2024-08-13 01:59:47 +03:00
Vadim Vetrov
d5db8c18e5 Types to distinct file common for the entire program 2024-08-13 01:59:04 +03:00
Vadim Vetrov
e6367c72bd Update README.md 2024-08-12 23:16:12 +03:00
Vadim Vetrov
aafa1a728a Merge #57 by @zabbius to dev
minor - removed duplicated code in args.c
2024-08-12 15:24:57 +03:00
Vadim Vetrov
219062aae2 Fix segfault bufs, update coding style 2024-08-12 15:22:04 +03:00
zabbius
24826f851d removed duplicated code in args.c 2024-08-12 04:52:03 +03:00
Vadim Vetrov
918ccc822d Update service files 2024-08-12 00:59:13 +03:00
Vadim Vetrov
e649ef5567 Add option to change TCP winsize 2024-08-12 00:45:30 +03:00
Vadim Vetrov
b2cff9699b Merge branch 'main' of github.com:Waujito/youtubeUnblock 2024-08-12 00:26:12 +03:00
Vadim Vetrov
569cfcf049 Merge PR #51
Enhance bypass strategies
2024-08-12 00:24:23 +03:00
Vadim Vetrov
86bada6ea7 Update internal APIs, defaults 2024-08-12 00:23:08 +03:00
Vadim Vetrov
e39bc9b059 Update README.md 2024-08-12 00:21:03 +03:00
Vadim Vetrov
7d571e6860 Verbosity, debug logs 2024-08-11 21:43:32 +03:00
Vadim Vetrov
05648cc7c2 fix --sni-domains=all 2024-08-11 21:34:21 +03:00
Vadim Vetrov
8ca048d9fd Merge pull request #55 from spvkgn/patch-1
Update README.md
2024-08-11 08:48:20 -07:00
spvkgn
fa631accb7 Update README.md
https://github.com/Waujito/youtubeUnblock/issues/54#issuecomment-2282490807
2024-08-11 20:18:39 +05:00
Vadim Vetrov
b4607d69f6 Update README.md 2024-08-11 16:59:41 +03:00
Vadim Vetrov
9c2d31f51d Merge branch 'main' into enhance_bypasses 2024-08-11 16:26:46 +03:00
Vadim Vetrov
74a9ae3eb1 Do not force user to specify queue number explicitly 2024-08-11 16:21:26 +03:00
Vadim Vetrov
6951c0319e Fix infinity recursion on reverse fragmentation 2024-08-11 15:34:58 +03:00
Vadim Vetrov
6df3b53d7a Comments for managing functions 2024-08-11 11:40:13 +03:00
Vadim Vetrov
e719c1319b Add new firmware #54 2024-08-11 02:14:10 +03:00
Vadim Vetrov
2e96aa150e Add multiple fooling options 2024-08-11 02:10:18 +03:00
Vadim Vetrov
d29177d783 Move args parsers to the separate file 2024-08-10 21:44:04 +03:00
Vadim Vetrov
0126e403fd Do not force user to specify queue number explicitly 2024-08-10 21:38:25 +03:00
Vadim Vetrov
80811a41e6 Merge remote-tracking branch 'origin/main' into actions-entware 2024-08-10 21:09:50 +03:00
Vadim Vetrov
c39e7d81c9 Update build-openwrt.yml 2024-08-10 18:44:52 +03:00
Vadim Vetrov
b6a8a45502 Update build-openwrt.yml 2024-08-10 18:40:24 +03:00
Vadim Vetrov
21be10caed Entware Workflow 2024-08-10 17:24:30 +03:00
Vadim Vetrov
d83e54701e Update README.md 2024-08-10 16:30:57 +03:00
Vadim Vetrov
75b7fe3011 Merge pull request #50 from spvkgn/actions-alpine-static
Alpine workflow
2024-08-10 05:50:18 -07:00
spvkgn
81fcdf41c0 Alpine workflow 2024-08-10 17:17:42 +05:00
Vadim Vetrov
ab402c573b Run build actions only for main branch 2024-08-10 11:42:48 +03:00
Vadim Vetrov
ff5bfc9037 Fix fragmentation strategy none
Related to #43
2024-08-10 02:55:06 +03:00
Vadim Vetrov
98e1c2f5d6 Merge #47 from @spvkgn
OpenWRT workflow
2024-08-10 02:37:23 +03:00
Vadim Vetrov
da10542edc Update OpenWRT Workflow 2024-08-10 02:31:11 +03:00
Vadim Vetrov
dc03bee64b Delete build logs, update names 2024-08-10 02:21:18 +03:00
Vadim Vetrov
34345b127b Update workflow 2024-08-10 02:16:00 +03:00
Vadim Vetrov
48d8f08957 Merge branch 'actions-openwrt' of github.com:spvkgn/youtubeUnblock into spvkgn-actions-openwrt 2024-08-10 00:48:37 +03:00
Vadim Vetrov
cee1b371fd Merge Pull Request #46 2024-08-10 00:42:04 +03:00
Vadim Vetrov
8e592d8957 Fix segfault on unrecognized option 2024-08-10 00:40:31 +03:00
Vadim Vetrov
6bbeae3876 Update version output 2024-08-10 00:35:36 +03:00
spvkgn
7b9e7b773b remove release job 2024-08-09 20:36:39 +05:00
Vadim Vetrov
8d4fb1f7ad Fix coding style of args parser 2024-08-09 16:03:45 +03:00
zabbius
4963258c0b const char* argv[] -> char* argv[] 2024-08-09 15:40:04 +03:00
zabbius
46e4231f7e minor 2024-08-09 15:31:04 +03:00
zabbius
916d575920 parsing args with getopt 2024-08-09 15:21:54 +03:00
Vadim Vetrov
7d60fd8854 Update list of blocked domains
https://habr.com/ru/news/834792/
2024-08-09 00:05:28 +03:00
Vadim Vetrov
0d43ce60f5 Fix all domains being mangled 2024-08-08 20:26:35 +03:00
Vadim Vetrov
8e3fa48510 Fix fake sni strategy ttl 2024-08-08 18:58:21 +03:00
spvkgn
4f9ab69b37 OpenWrt workflow 2024-08-08 20:55:20 +05:00
Vadim Vetrov
50933ee0d6 Fix last SNI detect 2024-08-08 18:22:45 +03:00
Vadim Vetrov
bb66ab13a8 Fix buildsystem targets 2024-08-08 18:22:45 +03:00
Vadim Vetrov
0c17702e9d Merge pull request #42 from Masha/reverte
revert bad Makefile changes
2024-08-08 07:32:52 -07:00
Miezhiko
b786d78d19 revert bad Makefile changes
Signed-off-by: Miezhiko <Miezhiko@gmail.com>
2024-08-08 18:13:46 +04:00
96 changed files with 19889 additions and 1995 deletions

View File

@@ -4,3 +4,7 @@ root = true
indent_style = tab indent_style = tab
indent_size = 8 indent_size = 8
tab_width = 8 tab_width = 8
[*.yml]
indent_style = space
indent_size = 2

42
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Bug report
description: Use this issue template when you are pretty sure here is a bug. Make sure the trouble you are experiencing haven't been already reported earlier and haven't been talked about in discussions.
body:
- type: markdown
attributes:
value: |
Use this issue template when you are pretty sure here is a bug.
Make sure the trouble you are experiencing haven't been already reported earlier and haven't been talked about in [discussions](https://github.com/Waujito/youtubeUnblock/discussions).
Note, that *bugs* are internal program errors: crashes, freezes and other types of undefined behavior. You may also report problems with routers infrastructure here, but **NOT** questions like *My router doesn't work help please*. Your questions and other stuff with custom routers setup should be discussed [here](https://github.com/Waujito/youtubeUnblock/discussions/172)
Discuss problems like *youtube doesn't unblock* [here](https://github.com/Waujito/youtubeUnblock/discussions/173)
- type: textarea
id: bug-report
attributes:
label: Bug description
validations:
required: true
- type: input
id: linux-distro
attributes:
label: Linux distribution
description: Pass here your linux distro e.g. OpenWRT, Entware, Merlin, Padavan, Ubuntu, Debian
validations:
required: false
- type: textarea
id: architecture
attributes:
label: Device architecture
description: Pass here the architecture of your device. (On openwrt do `cat /etc/openwrt_release`, on other systems `lscpu` or `cat /proc/cpuinfo`)
validations:
required: false
- type: textarea
id: configs
attributes:
label: Configuration
description: Pass here the configuration of youtubeUnblock being used. You may pass output of `cat /etc/config/youtubeUnblock` on OpenWRT or raw flags of youtubeUnblock.
validations:
required: false

View File

@@ -0,0 +1,10 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---

1
.github/builder_containers/README.md vendored Normal file
View File

@@ -0,0 +1 @@
This directory contains dockerfiles for large docker containers. This allows not to rebuild binaries every build and not to utilize cache.

View File

@@ -0,0 +1,6 @@
FROM waujito/entware_builder
RUN git clone --depth 1 https://github.com/Entware/Entware.git
WORKDIR /home/me/Entware
RUN make package/symlinks
RUN cp -v configs/aarch64-3.10.config .config
RUN make -j$(nproc) toolchain/install

View File

@@ -0,0 +1,6 @@
FROM waujito/entware_builder
RUN git clone --depth 1 https://github.com/Entware/Entware.git -b k2.6
WORKDIR /home/me/Entware
RUN make package/symlinks
RUN cp -v configs/armv7-2.6.config .config
RUN make -j$(nproc) toolchain/install

View File

@@ -0,0 +1,6 @@
FROM waujito/entware_builder
RUN git clone --depth 1 https://github.com/Entware/Entware.git
WORKDIR /home/me/Entware
RUN make package/symlinks
RUN cp -v configs/armv7-3.2.config .config
RUN make -j$(nproc) toolchain/install

View File

@@ -0,0 +1,6 @@
FROM waujito/entware_builder
RUN git clone --depth 1 https://github.com/Entware/Entware.git
WORKDIR /home/me/Entware
RUN make package/symlinks
RUN cp -v configs/mips-3.4.config .config
RUN make -j$(nproc) toolchain/install

View File

@@ -0,0 +1,6 @@
FROM waujito/entware_builder
RUN git clone --depth 1 https://github.com/Entware/Entware.git
WORKDIR /home/me/Entware
RUN make package/symlinks
RUN cp -v configs/mipsel-3.4.config .config
RUN make -j$(nproc) toolchain/install

View File

@@ -0,0 +1,6 @@
FROM waujito/entware_builder
RUN git clone --depth 1 https://github.com/Entware/Entware.git
WORKDIR /home/me/Entware
RUN make package/symlinks
RUN cp -v configs/x64-3.2.config .config
RUN make -j$(nproc) toolchain/install

View File

@@ -0,0 +1,6 @@
FROM waujito/entware_builder
RUN git clone --depth 1 https://github.com/Entware/Entware.git -b k2.6
WORKDIR /home/me/Entware
RUN make package/symlinks
RUN cp -v configs/x86-2.6.config .config
RUN make -j$(nproc) toolchain/install

View File

@@ -0,0 +1,12 @@
FROM ubuntu:14.04
RUN apt update && apt install -y build-essential flex bc bison libelf-dev elfutils libssl-dev wget
RUN wget https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.0.101.tar.xz -O kernel.tar.xz
RUN tar -xf kernel.tar.xz
RUN rm -f kernel.tar.xz
RUN /bin/bash -c "mv linux-* linux"
WORKDIR /linux
RUN make defconfig
RUN make -j$(nproc)

View File

@@ -0,0 +1,12 @@
FROM ubuntu:16.04
RUN apt update && apt install -y build-essential flex bc bison libelf-dev elfutils libssl-dev wget
RUN wget https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.10.108.tar.xz -O kernel.tar.xz
RUN tar -xf kernel.tar.xz
RUN rm -f kernel.tar.xz
RUN /bin/bash -c "mv linux-* linux"
WORKDIR /linux
RUN make defconfig
RUN make -j$(nproc)

View File

@@ -0,0 +1,12 @@
FROM ubuntu:24.04
RUN apt update && apt install -y build-essential flex bc bison libelf-dev elfutils libssl-dev wget
RUN wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.322.tar.xz -O kernel.tar.xz
RUN tar -xf kernel.tar.xz
RUN rm -f kernel.tar.xz
RUN /bin/bash -c "mv linux-* linux"
WORKDIR /linux
RUN make defconfig
RUN make -j$(nproc)

View File

@@ -0,0 +1,12 @@
FROM ubuntu:24.04
RUN apt update && apt install -y build-essential flex bc bison libelf-dev elfutils libssl-dev wget
RUN wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.302.tar.xz -O kernel.tar.xz
RUN tar -xf kernel.tar.xz
RUN rm -f kernel.tar.xz
RUN /bin/bash -c "mv linux-* linux"
WORKDIR /linux
RUN make defconfig
RUN make -j$(nproc)

View File

@@ -0,0 +1,12 @@
FROM ubuntu:24.04
RUN apt update && apt install -y build-essential flex bc bison libelf-dev elfutils libssl-dev wget
RUN wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.167.tar.xz -O kernel.tar.xz
RUN tar -xf kernel.tar.xz
RUN rm -f kernel.tar.xz
RUN /bin/bash -c "mv linux-* linux"
WORKDIR /linux
RUN make defconfig
RUN make -j$(nproc)

View File

@@ -0,0 +1,12 @@
FROM ubuntu:24.04
RUN apt update && apt install -y build-essential flex bc bison libelf-dev elfutils libssl-dev wget
RUN wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.284.tar.xz -O kernel.tar.xz
RUN tar -xf kernel.tar.xz
RUN rm -f kernel.tar.xz
RUN /bin/bash -c "mv linux-* linux"
WORKDIR /linux
RUN make defconfig
RUN make -j$(nproc)

View File

@@ -0,0 +1,12 @@
FROM ubuntu:24.04
RUN apt update && apt install -y build-essential flex bc bison libelf-dev elfutils libssl-dev wget
RUN wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.52.tar.xz -O kernel.tar.xz
RUN tar -xf kernel.tar.xz
RUN rm -f kernel.tar.xz
RUN /bin/bash -c "mv linux-* linux"
WORKDIR /linux
RUN make defconfig
RUN make -j$(nproc)

379
.github/workflows/build-ci.yml vendored Normal file
View File

@@ -0,0 +1,379 @@
name: CI
on:
push:
branches:
- main
paths-ignore:
- '.editorconfig'
- '.gitignore'
- 'LICENSE'
- 'README.md'
workflow_dispatch:
pull_request:
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.gh.outputs.version }}
release: ${{ steps.gh.outputs.release }}
sha: ${{ steps.gh.outputs.sha }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: GH
id: gh
env:
REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
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
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
name: build ${{ matrix.arch }}
runs-on: ubuntu-latest
strategy:
matrix:
arch: [x86_64, x86, aarch64, armhf, armv7]
branch: [latest-stable]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up ccache
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.ccache
key: ccache-${{ matrix.arch }}-${{ github.run_id }}
restore-keys: ccache-${{ matrix.arch }}-
- name: Set up Alpine Linux for ${{ matrix.arch }}
uses: jirutka/setup-alpine@v1
with:
arch: ${{ matrix.arch }}
branch: ${{ matrix.branch }}
packages: >
bash build-base ccache coreutils findutils gawk git grep tar wget xz
autoconf automake libtool pkgconf linux-headers
shell-name: alpine.sh
- name: Build inside chroot
id: build
env:
ARCH: ${{ matrix.arch }}
CCACHE_DIR: ${{ github.workspace }}/.ccache
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
shell: alpine.sh {0}
run: |
case $ARCH in
x86_64) PLATFORM=x86-64 ;;
x86) PLATFORM=x86 ;;
aarch64) PLATFORM=arm64 ;;
armhf) PLATFORM=arm ;;
*) PLATFORM=$ARCH ;;
esac
make -j$(nproc) CC="ccache gcc -static-libgcc -static" || exit 1
strip -s build/youtubeUnblock
cp -va build/youtubeUnblock .
tar -czvf youtubeUnblock-$VERSION-$RELEASE-$SHA-$PLATFORM-static.tar.gz youtubeUnblock youtubeUnblock.service README.md
ccache --show-stats
- name: Upload artifacts
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: youtubeUnblock-static-${{ matrix.arch }}
path: ./**/youtubeUnblock*.tar.gz
build-static-cross:
needs: prepare
name: build ${{ matrix.arch }}
runs-on: ubuntu-latest
strategy:
matrix:
include:
- arch: mips64el
tool: mips64el-unknown-linux-musl
- arch: mips64
tool: mips64-unknown-linux-musl
- arch: mipsel
tool: mipsel-unknown-linux-musl
- arch: mipselsf
tool: mipsel-unknown-linux-muslsf
- arch: mips
tool: mips-unknown-linux-musl
- arch: mipssf
tool: mips-unknown-linux-muslsf
- arch: armv7sf
tool: armv7-unknown-linux-musleabi
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up build tools
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: 'musl-cross/musl-cross'
TOOL: ${{ matrix.tool }}
run: |
mkdir -p $HOME/tools
gh api repos/$REPO/releases/latest --jq '.tag_name' |\
xargs -I{} wget -qO- https://github.com/$REPO/releases/download/{}/$TOOL.tar.xz | tar -C $HOME/tools -xJ || exit 1
[ -d "$HOME/tools/$TOOL/bin" ] && echo "$HOME/tools/$TOOL/bin" >> $GITHUB_PATH
- name: Build
id: build
env:
ARCH: ${{ matrix.arch }}
TOOL: ${{ matrix.tool }}
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
make -j$(nproc) \
CC="$TOOL-gcc -static-libgcc -static" \
LD=$TOOL-ld \
AR=$TOOL-ar \
NM=$TOOL-nm \
STRIP=$TOOL-strip \
CROSS_COMPILE_PLATFORM=$TOOL || exit 1
$TOOL-strip -s build/youtubeUnblock
cp -va build/youtubeUnblock .
tar -czvf youtubeUnblock-$VERSION-$RELEASE-$SHA-$ARCH-static.tar.gz youtubeUnblock youtubeUnblock.service README.md
- name: Upload artifacts
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: youtubeUnblock-static-${{ matrix.arch }}
path: ./**/youtubeUnblock*.tar.gz
build-openwrt:
needs: prepare
runs-on: ubuntu-latest
strategy:
matrix:
branch:
- openwrt-23.05
arch:
- aarch64_cortex-a53
- aarch64_cortex-a72
- aarch64_generic
- arm_arm1176jzf-s_vfp
- arm_arm926ej-s
- arm_cortex-a15_neon-vfpv4
- arm_cortex-a5_vfpv4
- arm_cortex-a7
- arm_cortex-a7_neon-vfpv4
- arm_cortex-a7_vfpv4
- arm_cortex-a8_vfpv3
- arm_cortex-a9
- arm_cortex-a9_neon
- arm_cortex-a9_vfpv3-d16
- arm_fa526
- arm_mpcore
- arm_xscale
- mips64_octeonplus
- mips_24kc
- mips_4kec
- mips_mips32
- mipsel_24kc
- mipsel_24kc_24kf
- mipsel_74kc
- mipsel_mips32
- x86_64
container:
image: openwrt/sdk:${{ matrix.arch }}-${{ matrix.branch }}
options: --user root
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: 'openwrt'
- name: Prepare build
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION-$RELEASE-$SHA/" youtubeUnblock/Makefile
- name: Initilalize SDK
id: init_sdk
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
working-directory: /builder
run: |
HOME=/builder ./setup.sh
- name: Build packages
id: build
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
working-directory: /builder
run: |
echo "src-link youtubeUnblock $GITHUB_WORKSPACE" >> feeds.conf
cat feeds.conf
./scripts/feeds update youtubeUnblock
./scripts/feeds install -a -p youtubeUnblock
make defconfig
make package/youtubeUnblock/compile V=s
mv $(find ./bin -type f -name 'youtubeUnblock*.ipk') ./youtubeUnblock-$VERSION-$RELEASE-$SHA-${{ matrix.arch }}-${{ matrix.branch }}.ipk
- name: Upload packages
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: youtubeUnblock-${{ matrix.branch }}-${{ matrix.arch }}
path: /builder/youtubeUnblock*.ipk
if-no-files-found: error
build-openwrt-luci:
needs: prepare
runs-on: ubuntu-latest
container:
image: openwrt/sdk:x86_64-openwrt-23.05
options: --user root
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: 'openwrt'
- name: Prepare build
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION-$RELEASE-$SHA/" youtubeUnblock/Makefile
- name: Initilalize SDK
id: init_sdk
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
working-directory: /builder
run: |
HOME=/builder ./setup.sh
- name: Build packages
id: build
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
working-directory: /builder
run: |
echo "src-link youtubeUnblock $GITHUB_WORKSPACE" >> feeds.conf
cat feeds.conf
./scripts/feeds update youtubeUnblock
./scripts/feeds install -a -p youtubeUnblock
make defconfig
make package/luci-app-youtubeUnblock/compile V=s
mv $(find ./bin -type f -name 'luci-app-youtubeUnblock*.ipk') ./luci-app-youtubeUnblock-$VERSION-$RELEASE-$SHA.ipk
- name: Upload packages
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: luci-app-youtubeUnblock
path: /builder/luci-app-youtubeUnblock*.ipk
if-no-files-found: error
build-entware:
needs: prepare
runs-on: ubuntu-latest
strategy:
matrix:
arch:
- aarch64-3.10
- armv7-3.2
- mips-3.4
- mipsel-3.4
- x64-3.2
- x86-2.6
- armv7-2.6
container:
image: waujito/entware_builder:${{ matrix.arch }}
options: --user root
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: 'openwrt'
- name: Prepare build
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
sed -i "s/PKG_REV:=.*$/PKG_REV:=$SHA/;s/PKG_VERSION:=.*$/PKG_VERSION:=$VERSION-$RELEASE-$SHA/" youtubeUnblockEntware/Makefile
- name: Build packages
id: build
working-directory: /home/me/Entware
env:
VERSION: ${{ needs.prepare.outputs.version }}
RELEASE: ${{ needs.prepare.outputs.release }}
SHA: ${{ needs.prepare.outputs.sha }}
run: |
echo "src-link youtubeUnblock $GITHUB_WORKSPACE" >> feeds.conf
cat feeds.conf
./scripts/feeds update youtubeUnblock
./scripts/feeds install -a -p youtubeUnblock
echo "CONFIG_PACKAGE_youtubeUnblockEntware=m" | tee -a .config
make package/youtubeUnblockEntware/compile V=s
mv $(find ./bin -type f -name 'youtubeUnblockEntware*.ipk') ./youtubeUnblock-$VERSION-$RELEASE-$SHA-entware-${{ matrix.arch }}.ipk
- name: Upload packages
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: youtubeUnblock-entware-${{ matrix.arch }}
path: /home/me/Entware/youtubeUnblock*.ipk
if-no-files-found: error
pre-release:
if: github.event_name != 'pull_request' && github.ref_name == 'main'
needs: [build-static, build-static-cross, build-openwrt, build-entware, build-openwrt-luci]
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Upload assets
uses: slord399/action-automatic-releases@v1.0.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
automatic_release_tag: 'continuous'
prerelease: true
draft: true
title: 'Development build'
files: |
./**/youtubeUnblock*.ipk
./**/youtubeUnblock*.tar.gz
./**/luci-app-youtubeUnblock*.ipk

130
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,130 @@
name: "youtubeUnblock build test"
on:
push:
branches:
- main
paths-ignore:
- '.editorconfig'
- '.gitignore'
- 'LICENSE'
- 'README.md'
workflow_dispatch:
pull_request:
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.gh.outputs.version }}
sha: ${{ steps.gh.outputs.sha }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: 'openwrt'
- name: GH
id: gh
env:
REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
echo "version=$(cat youtubeUnblock/Makefile | grep PKG_VERSION | sed 's/PKG_VERSION:=//')" >> $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
fi
build-static:
needs: prepare
name: build-static ${{ matrix.arch }}
runs-on: ubuntu-latest
strategy:
matrix:
arch: [x86_64]
branch: [latest-stable]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
id: build
env:
ARCH: ${{ matrix.arch }}
VERSION: ${{ needs.prepare.outputs.version }}
SHA: ${{ needs.prepare.outputs.sha }}
shell: bash
run: |
make -j$(nproc)
strip -s build/youtubeUnblock
cp -va build/youtubeUnblock .
tar -czvf static-youtubeUnblock-$VERSION-$SHA-$PLATFORM.tar.gz youtubeUnblock youtubeUnblock.service README.md
- name: Upload artifacts
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
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 }}
runs-on: ubuntu-latest
strategy:
matrix:
kernel_version:
- 6.6.52
- 5.15.167
- 5.4.284
- 4.19.322
- 4.4.302
- 3.10.108
- 3.0.101
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build kernel module
id: build
env:
VERSION: ${{ needs.prepare.outputs.version }}
SHA: ${{ needs.prepare.outputs.sha }}
shell: bash
run: |
docker run --rm -v ./:/youtubeUnblock -w /youtubeUnblock waujito/kernel-bins:${{ matrix.kernel_version }} make kmake KERNEL_BUILDER_MAKEDIR:=/linux
tar -czvf kmod-youtubeUnblock-$VERSION-$SHA-linux-${{ matrix.kernel_version }}.tar.gz kyoutubeUnblock.ko
- name: Upload artifacts
if: steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
with:
name: kmod-youtubeUnblock-linux-${{ matrix.kernel_version }}
path: ./**/kmod-youtubeUnblock*.tar.gz

3
.gitignore vendored
View File

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

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule ".github/builder_containers/entware_docker"]
path = .github/builder_containers/entware_docker
url = https://github.com/Entware/docker.git

6
Kbuild
View File

@@ -1,3 +1,3 @@
obj-m := ipt_YTUNBLOCK.o obj-m := kyoutubeUnblock.o
ipt_YTUNBLOCK-objs := iptk_YTUNBLOCK.o mangle.o kyoutubeUnblock-objs := src/kytunblock.o src/mangle.o src/quic.o src/quic_crypto.o src/utils.o src/tls.o src/getopt.o src/inet_ntop.o src/args.o src/trie.o deps/cyclone/aes.o deps/cyclone/cpu_endian.o deps/cyclone/ecb.o deps/cyclone/gcm.o deps/cyclone/hkdf.o deps/cyclone/hmac.o deps/cyclone/sha256.o
ccflags-y := -std=gnu11 -Wno-unused-variable -DKERNEL_SPACE -DDEBUG ccflags-y := -std=gnu99 -DKERNEL_SPACE -Wno-error -Wno-declaration-after-statement -I$(src)/src -I$(src)/deps/cyclone/include

View File

@@ -1,14 +1,32 @@
USPACE_TARGETS := default all install uninstall dev run_dev USPACE_TARGETS := default all install uninstall dev run_dev
KMAKE_TARGETS := kmake kload kunload kreload xmod xtclean KMAKE_TARGETS := kmake kload kunload kreload xmod xtclean
.PHONY: $(USPACE_TARGETS) $(KMAKE_TARGETS) clean PKG_VERSION := 1.0.0
PKG_RELEASE := 10
PKG_FULLVERSION := $(PKG_VERSION)-$(PKG_RELEASE)
export PKG_VERSION PKG_RELEASE PKG_FULLVERSION
.PHONY: $(USPACE_TARGETS) $(KMAKE_TARGETS) test build_test clean distclean kclean
$(USPACE_TARGETS): $(USPACE_TARGETS):
@$(MAKE) -ef uspace.mk $@ @$(MAKE) -f uspace.mk $@
$(KMAKE_TARGETS): $(KMAKE_TARGETS):
@$(MAKE) -ef kmake.mk $@ @$(MAKE) -f kmake.mk $@
build_test:
-@$(MAKE) -f uspace.mk build_test
test:
-@$(MAKE) -f uspace.mk test
clean: clean:
-@$(MAKE) -ef kmake.mk kclean -@$(MAKE) -f uspace.mk clean
@$(MAKE) -ef uspace.mk clean
distclean: clean
-@$(MAKE) -f uspace.mk distclean
kclean:
-@$(MAKE) -f kmake.mk kclean

30
Padavan.md Normal file
View File

@@ -0,0 +1,30 @@
## Padavan
На падаване есть раздел, доступный для записи (/etc/storage), и, докинув нужные модули, можно запустить youtubeUblock на уже установленной прошивке без USB. Установка самого youtubeUblock мало будет отличаться от классичкской установки. Наибольшая сложность заключается в получении модулей ядра специально для вашего роутера.
**Версия youtubeUblock должна быть не меньше v1.0.0-rc4.**
### Сборка прошивки с модулями
Необходимо собрать ядро с модулями nfqueue. Собирать можно у себя локально, а можно и в github actions (https://github.com/shvchk/padavan-builder-workflow)
Добавить строки ниже в `padavan-ng/trunk/configs/boards/TPLINK/TL_C5-V4/kernel-3.4.x.config` (вместо TPLINK/TL_C5-V4 нужно выбрать свою модель):
```sh
CONFIG_NETFILTER_NETLINK=m
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_IP_NF_QUEUE=m
CONFIG_IP6_NF_QUEUE=m
```
Сборка
```sh
cd padavan-ng/trunk
cp configs/templates/tplink/tl_c5-v4.config .config
./build_firmware.sh
```
Если финальный размер превышает максимум, то можно отключить что-нибудь в .config, например FTP.
После сборки необходимо установить прошивку на роутер. Подробнее в гитлабе падавана: https://gitlab.com/hadzhioglu/padavan-ng. Как устанавливать: https://4pda.to/forum/index.php?showtopic=975687&st=12980#Spoil-115912586-5
Далее скачать youtubeUnblock, закинуть его на роутер, добавить правила фаервола и запустить. Можно скачивать static бинарник и запускать вручную, а можно загрузить entware на usb или в память, и поставить соответствующую версию youtubeUblock.

504
README.md
View File

@@ -1,90 +1,494 @@
- [youtubeUnblock](#youtubeunblock)
- [Configuration](#configuration)
- [OpenWRT pre configuration](#openwrt-pre-configuration)
- [Entware](#entware)
- [PC configuration](#pc-configuration)
- [Firewall configuration](#firewall-configuration)
- [nftables rules](#nftables-rules)
- [Iptables rules](#iptables-rules)
- [IPv6](#ipv6)
- [Check it](#check-it)
- [Flags](#flags)
- [UDP/QUIC/Voice Chats](#udpquicvoice-chats)
- [Troubleshooting](#troubleshooting)
- [TV](#tv)
- [Troubleshooting EPERMS (Operation not permitted)](#troubleshooting-eperms-operation-not-permitted)
- [Conntrack](#conntrack-troubleshooting)
- [NAT Hardware/Software offloading](#nat-hardwaresoftware-offloading)
- [Compilation](#compilation)
- [OpenWRT case](#openwrt-case)
- [Building OpenWRT .ipk package](#building-openwrt-ipk-package)
- [Building with toolchain](#building-with-toolchain)
- [Kernel module](#kernel-module)
- [Building kernel module](#building-kernel-module)
- [Building on host system](#building-on-host-system)
- [Building on any kernel](#building-on-any-kernel)
- [Building with openwrt SDK](#building-with-openwrt-sdk)
- [Padavan](#padavan)
# youtubeUnblock # youtubeUnblock
Bypasses Googlevideo detection systems that relies on SNI. The package is for Linux only. The package is fully compatible with routers running OpenWRT. To learn how to build the package on OpenWRT, consult [this chapter](https://github.com/Waujito/youtubeUnblock?tab=readme-ov-file#openwrt-case).
For Windows use [GoodbyeDPI from ValdikSS](https://github.com/ValdikSS/GoodbyeDPI) (you can find how to use it for YouTube [here](https://github.com/ValdikSS/GoodbyeDPI/issues/378)) The same behavior is also implemented in [zapret package for linux](https://github.com/bol-van/zapret). Bypasses Deep Packet Inspection (DPI) systems that relies on SNI. The package is for Linux only. It is also fully compatible with routers running [OpenWRT](https://github.com/openwrt).
## How it works: The program was primarily developed to bypass YouTube Outage in Russia.
Lets look from the DPIses side of view: All they have is ip and tcp information, higher-level data is encrypted. So from the IP header only IP address might be helpful for them. In tcp here is basically nothing. So they may handle IP addresses and process it. What's wrong? Google servers are on the way: It is very hard to handle all that infrastracture. One server may host multiple websites and it is very bad if them block, say Google Search trying to block googlevideo. But even if googlevideo servers have their own ip for only googlevideo purposes, here is a problem about how large is Google infrastracture and how much servers are here. The DPIs can't even parse normally all the servers, because each video may live on it's cache server. So what's else? Let's take a look at a TLS level. All information here is encrypted. All... Except hello messages! They are used to initialize handshake connections and hold tons of helpful information. If we talk about TLS v1.3, it is optimized to transfer as less information as possible unencrypted. But here is only one thing that may point us which domain the user wants to connect, the SNI extension. It transfers all domain names unencrypted. Exactly what we need! And DPIs may use this thing to detect google video connections and slow down them (In fact they are corrupting a tcp connection with bad packets).
So we aims to somehow hide the SNI from them. How? ```
- We can alter the SNI name in the tls packet to something else. But what's wrong with this? The server also uses SNI name for certificates. And if we change it, the server will return an invalid certificate which browser can't normally process, which may turn out to the MITM problem. This program is free software: you can redistribute it and/or modify
- We can encrypt it. Here are a lot of investigations about SNI, but the server should support the technique. Also ISPs may block encrypted SNI. [Check this Wikipedia page](https://en.wikipedia.org/wiki/Server_Name_Indication) it under the terms of the GNU General Public License as published by
- So what else can we do with the SNI info? If we can't hide it, let's rely on DPIs weak spots. The DPI is an extremly high loaded machine that analyzes every single packet sent to the Internet. And every performance-impacted feature should be avoided for them. One of this features is IP packet fragmentation. We can split the packet in the middle of SNI message and post it. For DPI fragmentation involves too much overhead: they should store a very big mapping table which maps IP id, Source ip and Destination ip. Also note that some packets may be lost and DPI should support auto-clean of that table. So just imagine how much memory and CPU time will this cost for DPI. But fragments are ok for clients and hosts. And that's the base idea behind this package. I have to mention here that the idea isn't mine, I get in here after some research for this side. Here already was a solution for Windows, GoodbyeDPI. I just made an alternative for Linux. 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 may read further in an [yt-dlp issue page](https://github.com/yt-dlp/yt-dlp/issues/10443) and in [ntc party forum](https://ntc.party/t/%D0%BE%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B7%D0%B0%D0%BC%D0%B5%D0%B4%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-youtube-%D0%B2-%D1%80%D0%BE%D1%81%D1%81%D0%B8%D0%B8/8074). The program is distributed in two version:
- A userspace application works on top of nfnetlink queue which requires nfnetlink modules in the kernel and firewall rules. This approach is default and normally should be used but it has some limitations on embedded devices which may have no nfnetlink support. Also this solution may break down the internet speed and CPU load on your device because of jumps between userspace and kernelspace for each packet (this behavior may be fixed with connbytes but it also requires conntrack kernel module).
- A kernel module which integrates deeply within the netfilter stack and does not interact with the userspace firewall. The module requires only netfilter kernel support but it definetly present on every device connected to the Internet. The only difficulity is how to build it. I cannot provide modules within Github Actions for each single one kernel, even if we talk only about OpenWRT versions. If you want to learn more about the module, jump on [its section in the README](#kernel-module). Whats the benefits of the kernel module? The benefits come for some specific cases: the kernel module is the fastest thing that allows us to process every single packet sent to the linux network stack, while the normal youtubeUnblock requires connbytes to keep the internet speed. Speaking about connbytes, it also requires conntrack to operate, which may be a limitation on some transit-traffic machines. Also userspace youtubeUnblock requires modules for netlink queue, userspace firewall application and modules for it. The kernel module is much simpler and requires only the linux kernel with netfilter built in.
## How it processes packets The program is compatible with routers based on OpenWRT, Entware(Keenetic/ASUS) and host machines. The program offers binaries via Github Actions. The binaries are also available via [github releases](https://github.com/Waujito/youtubeUnblock/releases). Use the latest pre-release for the most up to date build. Check out [Github Actions](https://github.com/Waujito/youtubeUnblock/actions/workflows/build-ci.yml) if you want to see all the binaries compiled ever. You should know the arcitecture of your hardware to use binaries. On OpenWRT you can check it with command `grep ARCH /etc/openwrt_release`.
When the packet is joining the queue, the application checks sni payload to be googlevideo (right how the DPIs do), segmentates/fragmentates (both TCP and IP fragmentation techniques are supported) and posts the packet. Note that it is impossible to post two fragmented packets from one netfilter queue verdict. Instead, the application drops an original packet and makes another linux raw socket to post the packets in the network. To escape infinity loops the socket marks outgoing packets and the application automatically accepts it.
## Usage: On both OpenWRT and Entware install the program with opkg. If you got read-only filesystem error you may unpack the binary manually or specify opkg path `opkg -o <destdir>`.
Before compilation make sure `gcc`, `make`, `autoconf`, `automake`, `pkg-config` and `libtool` is installed. For Fedora `glibc-static` should be installed as well.
Compile with `make`. Install with `make install`. The package include libnetfilter_queue, libnfnetlink and libmnl as static dependencies. The package requires linux-headers and kernel built with netfilter nfqueue support.
You should also configure iptables for this to start working: For Windows use [GoodbyeDPI by ValdikSS](https://github.com/ValdikSS/GoodbyeDPI) (you can find how to use it for YouTube [here](https://github.com/ValdikSS/GoodbyeDPI/issues/378)) The same behavior is also implemented in [zapret package for linux](https://github.com/bol-van/zapret).
```iptables -A OUTPUT -p tcp --dport 443 -j NFQUEUE --queue-num 537 --queue-bypass``` (or do ```nft add rule ip mangle OUTPUT tcp dport 443 counter queue num 537 bypass``` for nftables.)
Here iptables serves every tcp packet, destinating port 443 for this userspace packet analyzer (via netfilter kernel module) queue-num may be any number from 0 to 65565. --queue-bypass allows traffic to pass if the application is down.
Also tips to explicitly accept all important outgoing raw packets from youtubeUnblock from [Troubleshooting EPERMS](https://github.com/Waujito/youtubeUnblock?tab=readme-ov-file#troubleshooting-eperms-operation-not-permitted) may be useful to avoid issues. ## Configuration
Run an application with `youtubeUnblock 537` where `537` stands for the queue-num (must be the same as in the iptables rule). ### OpenWRT pre configuration
Systemd daemon is also available. Do `systemctl enable --now youtubeUnblock.service` after installation (uses queue-num `537`). Please, note that systemd will configure iptables automatically. If you have troubles with it, delete ExecStartPre and ExecStop from youtubeUnblock.service and configure iptables manually (may be a useful case for nftables). When you got the release package, you should install it. Go to your router interface, to *System->Software*, do *Update lists* and install youtubeUnblock via *install_package* button. Then, you should go to *System-Startup* menu and reload the firewall (You may also do it within *Services->youtubeUnblock* menu).
If you don't want youtubeUnblock to log on each googlevideo request pass -DSILENT as CFLAGS. Since OpenWRT **main** branch switched to apk instead of opkg, but this is not released yet, here is not deploys for apk in **Releases**. But **apk is supported** in PR #196.
Also DNS over HTTPS (DOH) is preferred for additional anonimity. To make it work you should register an iptables rule and install required kernel modules. The list of modules depends on the version of OpenWRT and which firewall do you use (iptables or nftables). For most modern versions of OpenWRT (v23.x, v22.x) you should use nftables rules, for older ones it depends, but typically iptables.
The common dependency is
```text
kmod-nfnetlink-queue
```
but it is provided as dependency for another firewall packages.
So, if you are on **iptables** you should install:
```text
kmod-ipt-nfqueue
iptables-mod-nfqueue
kmod-ipt-conntrack-extra
iptables-mod-conntrack-extra
```
and of course, iptables user-space app should be available.
On **nftables** the dependencies are:
```text
kmod-nft-queue
kmod-nf-conntrack
```
Next step is to add required firewall rules.
For nftables on OpenWRT rules comes out-of-the-box and stored under `/usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft`. All you need is install requirements and do `/etc/init.d/firewall reload`. If no, go to [Firewall configuration](#firewall-configuration).
Now we go to the configuration. For OpenWRT here is configuration via [UCI](https://openwrt.org/docs/guide-user/base-system/uci) and [LuCI](https://openwrt.org/docs/guide-user/luci/start) available (CLI and GUI respectively).
For **LuCI** aka **GUI** aka **web-interface of router** you should install **luci-app-youtubeUnblock** package like you did it with the normal youtubeUnblock package. Note, that lists of official opkg feeds should be loaded (**Do it with Update lists option**).
If you got ` * pkg_hash_check_unresolved: cannot find dependency luci-lua-runtime for luci-app-youtubeUnblock` error, you are using old openwrt. Install [this dummy package](https://github.com/xiaorouji/openwrt-passwall/files/12605732/luci-lua-runtime_all_fake.zip). [Check this comment](https://github.com/Waujito/youtubeUnblock/issues/168#issuecomment-2449227547) for more details.
LuCI configuration lives in **Services->youtubeUnblock** section. It is self descriptive, with description for each flag. Note, that after you push `Save & Apply` button, the configuration is applied automatically and the service is restarted.
UCI configuration is available in /etc/config/youtubeUnblock file, in section `youtubeUnblock.youtubeUnblock`. You may pass any args as a string to parameter `args`, but before it disable interactive flags (You can configurate with it but it is a way harder and I recommend to use it only with `luci-app-youtubeUnblock`):
```sh
uci set youtubeUnblock.youtubeUnblock.conf_strat="args"
uci set youtubeUnblock.youtubeUnblock.args="--queue-num=537 --threads=1"
```
To save the configs you should do `uci commit` and then `reload_config` to restart youtubeUnblock
You can check the logs in CLI mode with `logread -l 200 | grep youtubeUnblock` command.
In CLI mode you will use youtubeUnblock as a normal init.d service:
for example, you can enable it with `/etc/init.d/youtubeUnblock enable`.
### Entware
For Entware on Keenetic here is an [installation guide (russian)](https://help.keenetic.com/hc/ru/articles/360021214160-%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B-%D0%BF%D0%B0%D0%BA%D0%B5%D1%82%D0%BE%D0%B2-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D1%8F-Entware-%D0%BD%D0%B0-USB-%D0%BD%D0%B0%D0%BA%D0%BE%D0%BF%D0%B8%D1%82%D0%B5%D0%BB%D1%8C).
Install the binary with `opkg install youtubeUnblock-*.ipk`. After installation, the binary in /opt/bin and the init script in /opt/etc/init.d/S51youtubeUnblock will be available. To run the youtubeUnblock, simply run `/opt/etc/init.d/S51youtubeUnblock start`
### NFNETLINK_QUEUE kernel modules
Note, that you should feed the target kernel with nfnetlink_queue kernel module. The module may be disabled or even not present. Entware S51youtubeUnblock will try to insert kmods any way but if they are not provided by software, you should install them manually. AFAIK on keenetics here is a repository with modules compiled by customer. You can find them somewhere in the web interface of your device. On other routers you may want to do deeper research in that case and find your kmods. If you can't find anything, you may ask the customer for GPL codes of linux kernel (and may be even OpenWRT) and compile kmods manually.
You should insert the module with (this step may be omitted on Entware and OpenWRT):
```sh
modprobe nfnetlink_queue
```
### PC configuration
On local host make sure to change **FORWARD** to **OUTPUT** chain in the following Firewall rulesets.
Copy `youtubeUnblock.service` to `/usr/lib/systemd/system` (you should change the path inside the file to the program position, for example `/usr/bin/youtubeUnblock`, also you may want to delete default iptables rule addition in systemd file to controll it manually). And run `systemctl start youtubeUnblock`.
### Firewall configuration
#### nftables rules
On nftables you should put next nftables rules:
```sh
nft add chain inet fw4 youtubeUnblock '{ type filter hook postrouting priority mangle - 1; policy accept; }'
nft add rule inet fw4 youtubeUnblock 'tcp dport 443 ct original packets < 20 counter queue num 537 bypass'
nft add rule inet fw4 youtubeUnblock 'meta l4proto udp ct original packets < 9 counter queue num 537 bypass'
nft insert rule inet fw4 output 'mark and 0x8000 == 0x8000 counter accept'
```
#### Iptables rules
On iptables you should put next iptables rules:
```sh
iptables -t mangle -N YOUTUBEUNBLOCK
iptables -t mangle -A YOUTUBEUNBLOCK -p tcp --dport 443 -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:19 -j NFQUEUE --queue-num 537 --queue-bypass
iptables -t mangle -A YOUTUBEUNBLOCK -p udp -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:8 -j NFQUEUE --queue-num 537 --queue-bypass
iptables -t mangle -A POSTROUTING -j YOUTUBEUNBLOCK
iptables -I OUTPUT -m mark --mark 32768/32768 -j ACCEPT
```
#### IPv6
For IPv6 on iptables you need to duplicate rules above for ip6tables:
```sh
ip6tables -t mangle -N YOUTUBEUNBLOCK
ip6tables -t mangle -A YOUTUBEUNBLOCK -p tcp --dport 443 -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:19 -j NFQUEUE --queue-num 537 --queue-bypass
ip6tables -t mangle -A YOUTUBEUNBLOCK -p udp -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:8 -j NFQUEUE --queue-num 537 --queue-bypass
ip6tables -t mangle -A POSTROUTING -j YOUTUBEUNBLOCK
ip6tables -I OUTPUT -m mark --mark 32768/32768 -j ACCEPT
```
Note that above rules use *conntrack* to route only first 20 packets from the connection to **youtubeUnblock**.
If you got some troubles with it, for example **youtubeUnblock** doesn't detect YouTube, try to delete *connbytes* from the rules. But it is an unlikely behavior and you should probably check your ruleset.
You can use `--queue-balance` with multiple instances of **youtubeUnblock** for performance. This behavior is supported via multithreading. Just pass `--threads=n` where n stands for an number of threads you want to be enabled. The n defaults to **1**. The maximum threads defaults to **16** but may be altered programmatically. Note, that if you are about to increase it, here is 100% chance that you are on the wrong way.
Also [DNS over HTTPS](https://github.com/curl/curl/wiki/DNS-over-HTTPS) is preferred for additional anonymity.
## Check it
Here is the command to test whether it working or not:
```sh
curl -o/dev/null -k --connect-to ::google.com -k -L -H Host:\ mirror.gcr.io https://test.googlevideo.com/v2/cimg/android/blobs/sha256:6fd8bdac3da660bde7bd0b6f2b6a46e1b686afb74b9a4614def32532b73f5eaa
```
It should return low speed without **youtubeUnblock** and faster with it. With **youtubeUnblock** the speed should be the same as fast with the next command:
```sh
curl -o/dev/null -k --connect-to ::google.com -k -L -H Host:\ mirror.gcr.io https://mirror.gcr.io/v2/cimg/android/blobs/sha256:6fd8bdac3da660bde7bd0b6f2b6a46e1b686afb74b9a4614def32532b73f5eaa
```
## Flags ## Flags
Put flags to the **BINARY**, not an init script. If you are on OpenWRT you should put the flags inside the script: open `/etc/init.d/youtubeUnblock` with any text editor, like vi or nano and put your flags after `procd_set_param command /usr/bin/youtubeUnblock` line.
Available flags: Available flags:
- `--sni-domains=<comma separated domain list>|all` - List of domains you want to be handled by sni. Use this string if you want to change default domains. Defaults to `googlevideo.com,youtube.com,ggpht.com,ytimg.com`. You can pass all if you want for every Client Hello to be handled. #### General flags
- `--seg2delay=<delay>` - This flag forces youtubeUnblock to wait little bit before send the 2nd part of the split packet. Flags that do not scoped to a specific section, used over all the youtubeUnblock
- `--fake-sni={ack,ttl, none}` This flag enables fake-sni which forces youtubeUnblock to send at least three packets instead of one with TLS ClientHello: Fake ClientHello, 1st part of original ClientHello, 2nd part of original ClientHello. This flag may be related to some Operation not permitted error messages, so befor open an issue refer to FAQ for EPERMS. Note, that this flag is set to `ack` by default. You may disable fake sni by setting it to `none`. Note, that your ISP may have conntrack drop on invalid state enabled, so this flag won't work. Use `ttl` to escape that.
- `--fake-sni-ttl=<ttl>` Tunes the time to live of fake sni messages. TTL is specified like that the packet will go through the TSPU and captured by it, but will not reach the destination server. Defaults to 8.
- `--no-gso` Disables support for Google Chrome fat packets which uses GSO. This feature is well tested now, so this flag probably won't fix anything.
- `--threads=<threads number>` Specifies the amount of threads you want to be running for your program. This defaults to 1 and shouldn't be edited for normal use. If you have performance issues, consult [performance chaptr](https://github.com/Waujito/youtubeUnblock?tab=readme-ov-file#performance)
- `--silent` - Disables Google video detected debug logs.
- `--frag={tcp,ip,none}` Specifies the fragmentation strategy for the packet. tcp is used by default. Ip fragmentation may be blocked by TSPU. None specifies no fragmentation. Probably this won't work, but may be will work for some fake sni strategies.
If you are on Chromium you may have to disable kyber (the feature that makes the TLS ClientHello very fat). I've got the problem with it on router, so to escape possibly errors it is better to just disable it: in chrome://flags search for kyber and switch it to disabled state. - `--queue-num=<number of netfilter queue>` The number of netfilter queue **youtubeUnblock** will be linked to. Defaults to **537**.
If your browser is using quic it may not work properly. Disable it in chrome in chrome://flags and in Firefox network.http.http{2,3}.enable(d) in about:config - `--silent` Disables verbose mode.
- `--trace` Maximum verbosity for debugging purposes.
- `--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.
- `--use-conntrack` Enables support for conntrack in youtubeUnblock. Disabled by default. Enabled in kernel module.
- `--no-ipv6` Disables support for ipv6. May be useful if you don't want for ipv6 socket to be opened.
- `--threads=<threads number>` Specifies the amount of threads you want to be running for your program. This defaults to **1** and shouldn't be edited for normal use. But if you really want multiple queue instances of youtubeUnblock, note that you should change --queue-num to --queue balance. For example, with 4 threads, use `--queue-balance 537:540` on iptables and `queue num 537-540` on nftables.
- `--connbytes-limit=<pkts>` **Kernel module only!** Specify how much packets of connection should be processed by kyoutubeUnblock. Pass 0 if you want for each packet to be processed. This flag may be useful for UDP traffic since unlimited youtubeUnblock may lead to traffic flood and unexpected bans. Defaults to 19. In most cases you don't want to change it.
- `--daemonize` Daemonizes the youtubeUnblock (forks and detaches it from the shell). Terminate the program with `killall youtubeUnblock`. If you want to track the logs of youtubeUnblock in logread or journalctl, use **--syslog** flag.
- `--syslog` Redirects logs to the system log. You can read it with `journalctl` or `logread`.
- `--noclose` Usable only with `--daemonize`. Will not redirect io streams to /dev/null.
- `--packet-mark=<mark>` Use this option if youtubeUnblock conflicts with other systems rely on packet mark. Note that you may want to change accept rule for iptables to follow the mark.
#### Section scoped flags
- `--fbegin` and `--fend` flags: youtubeUnblock supports multiple sets of strategies for specific filters. You may want to initiate a new set after the default one, like: `--sni-domains=googlevideo.com --faking-strategy=md5sum --fbegin --sni-domains=youtube.com --faking-strategy=tcp_check --fbegin --sni-domains=l.google.com --faking-strategy=pastseq`. Note, that the priority of these sets goes backwards: last is first, default (one that does not start with --fbegin) is last. If you start the new section, the default settings are implemented just like youtubeUnblock without any parameters. Note that the config above is just an example and won't work for you.
- `--tls={enabled|disabled}` Set it if you want not to process TLS traffic in current section. May be used if you want to set only UDP-based section. (Here section is a unit between `--fbegin` and `--fend` flags).
- `--fake-sni={0|1}` This flag enables fake-sni which forces **youtubeUnblock** to send at least three packets instead of one with TLS *ClientHello*: Fake *ClientHello*, 1st part of original *ClientHello*, 2nd part of original *ClientHello*. This flag may be related to some Operation not permitted error messages, so before open an issue refer to [Troubleshooting for EPERMS](#troubleshooting-eperms-operation-not-permitted). Defaults to **1**.
- `--fake-sni-seq-len=<length>` This flag specifies **youtubeUnblock** to build a complicated construction of fake client hello packets. length determines how much fakes will be sent. Defaults to **1**.
- `--fake-sni-type={default|custom|random}` This flag specifies which faking message type should be used for fake packets. For `random`, the message of random length and with random payload will be sent. For `default` the default payload (sni=www.google.com) is used. And for the `custom` option, the payload from `--fake-custom-payload` section utilized. Defaults to `default`.
- `--fake-custom-payload=<payload>` Useful with `--fake-sni-type=custom`. You should specify the payload for fake message manually. Use hex format: `--fake-custom-payload=0001020304` mean that 5 bytes sequence: `0x00`, `0x01`, `0x02`, `0x03`, `0x04` used as fake.
- `--fake-custom-payload-file=<binary file containing TLS message>` Same as `--fake-custom-payload` but binary file instead of hex. The file should contain raw binary TLS message (TCP payload).
- `--faking-strategy={randseq|ttl|tcp_check|pastseq|md5sum}` This flag determines the strategy of fake packets invalidation. Defaults to `randseq`
- `randseq` specifies that random sequence/acknowledgment random will be set. This option may be handled by provider which uses *conntrack* with drop on invalid *conntrack* state firewall rule enabled.
- `ttl` specifies that packet will be invalidated after `--faking-ttl=n` hops. `ttl` is better but may cause issues if unconfigured.
- `pastseq` is like `randseq` but sequence number is not random but references the packet sent in the past (before current).
- `tcp_check` will invalidate faking packet with invalid checksum. May be handled and dropped by some providers/TSPUs.
- `md5sum` will invalidate faking packet with invalid TCP md5sum. md5sum is a TCP option which is handled by the destination server but may be skipped by TSPU.
- `--faking-ttl=<ttl>` Tunes the time to live (TTL) of fake SNI messages. TTL is specified like that the packet will go through the DPI system and captured by it, but will not reach the destination server. Defaults to **8**.
- `--fake-seq-offset` Tunes the offset from original sequence number for fake packets. Used by randseq faking strategy. Defaults to 10000. If 0, random sequence number will be set.
- `--frag={tcp,ip,none}` Specifies the fragmentation strategy for the packet. tcp is used by default. Ip fragmentation may be blocked by DPI system. None specifies no fragmentation. Probably this won't work, but may be will work for some fake sni strategies.
- `--frag-sni-reverse={0|1}` Specifies **youtubeUnblock** to send *ClientHello* fragments in the reverse order. Defaults to **1**.
- `--frag-sni-faked={0|1}` Specifies **youtubeUnblock** to send fake packets near *ClientHello* (fills payload with zeroes). Defaults to **0**.
- `--frag-middle-sni={0|1}` With this options **youtubeUnblock** will split the packet in the middle of SNI data. Defaults to 1.
- `--frag-sni-pos=<pos>` With this option **youtubeUnblock** will split the packet at the position pos. Defaults to 1.
- `--fk-winsize=<winsize>` Specifies window size for the fragmented TCP packet. Applicable if you want for response to be fragmented. May slowdown connection initialization.
- `--synfake={1|0}` If 1, syn payload will be sent before each request. The idea is taken from syndata from zapret project. Syn payload will normally be discarded by endpoint but may be handled by TSPU. This option sends normal fake in that payload. Please note, that the option works for all the sites, so --sni-domains won't change anything.
- `--synfake-len=<len>` The fake packet sent in synfake may be too large. If you experience issues, lower up synfake-len. where len stands for how much bytes should be sent as syndata. Pass 0 if you want to send an entire fake packet. Defaults to 0
- `--sni-detection={parse|brute}` Specifies how to detect SNI. Parse will normally detect it by parsing the Client Hello message. Brute will go through the entire message and check possibility of SNI occurrence. Please note, that when `--sni-domains` option is not all brute will be O(nm) time complexity where n stands for length of the message and m is number of domains. Defaults to parse.
- `--seg2delay=<delay>` This flag forces **youtubeUnblock** to wait a little bit before send the 2nd part of the split packet.
- `--sni-domains=<comma separated domain list>|all` List of domains you want to be handled by SNI. Use this string if you want to change default domain list. Defaults to `googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com`. You can pass **all** if you want for every *ClientHello* to be handled. You can exclude some domains with `--exclude-domains` flag.
- `--exclude-domains=<comma separated domain list>` List of domains to be excluded from targeting.
- `--sni-domains-file=<file contains comma or new-line separated list>` Same as `--sni-domains` but accepts path to container file instead of inline domains list. The format is file may consist of both comma-separated domains list as well as new-line separated list.
- `--exclude-domains-file=<file contains comma or new-line separated list>` Same as `--exclude-domains` but accepts path to container file instead of inline domains list. The format is file may consist of both comma-separated domains list as well as new-line separated list.
- `--udp-mode={drop|fake}` This flag specifies udp handling strategy. If drop udp packets will be dropped (useful for quic when browser can fallback to tcp), if fake udp will be faked. Defaults to fake.
- `--udp-fake-seq-len=<amount of faking packets sent>` Specifies how much faking packets will be sent over the network. Defaults to 6.
- `--udp-fake-len=<size of udp fake>` Size of udp fake payload (typically payload is zeroes). Defaults to 64.
- `--udp-dport-filter=<5,6,200-500>` Filter the UDP destination ports. Defaults to no ports. Specifie the ports you want to be handled by youtubeUnblock.
- `--udp-faking-strategy={checksum|ttl|none}` Faking strategy for udp. `checksum` will fake UDP checksum, `ttl` won't fake but will make UDP content relatively small, `none` is no faking. Defaults to none.
- `--udp-filter-quic={disabled|all|parse}` Enables QUIC filtering for UDP handler. If disabled, quic won't be processed, if all, all quic initial packets will be handled. `parse` will decrypt and parse QUIC initial message and match it with `--sni-domains`. Defaults to disabled.
- `--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`.
- `--no-dport-filter` By default, youtubeUnblock will filter for TLS and QUIC 443. If you want to disable it, pass this flag. (this does not affect `--udp-dport-filter`)
## UDP/QUIC/Voice Chats
UDP 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 UDP faking in kernel module** Make sure to decrease `--connbytes-limit` up to 5. This will allow not to process additional packets and prevent network flood.
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
Check up [this issue](https://github.com/Waujito/youtubeUnblock/issues/148) for useful configs.
If you got troubles with some sites and you sure that they are blocked by SNI (youtube for example), use may play around with [flags](#flags) and their combinations. At first it is recommended to try `--faking-strategy` flag and `--frag-sni-faked=1`.
If you have troubles with some sites being proxied, you can play with flags values. For example, for someone `--faking-strategy=ttl` works. You should specify proper `--fake-sni-ttl=<ttl value>` where ttl is the amount of hops between you and DPI.
If you are on Chromium you may have to disable *kyber* (the feature that makes the TLS *ClientHello* very big). I've got the problem with it on router, so to escape possible errors, so it is better to disable it: in `chrome://flags` search for kyber and switch it to disabled state. Alternatively you may set `--sni-detection=brute` and probably adjust `--sni-domains` flag.
*Kyber* on firefox disables with `security.tls.enable_kyber` in `about:config`.
If your browser is using QUIC it may not work properly. Disable it in Chrome in `chrome://flags` and in Firefox `network.http.http{2,3}.enable(d)` in `about:config` option.
It seems like some TSPUs started to block wrongseq packets, so you should play around with faking strategies. I personally recommend to start with `md5sum` faking strategy.
#### youtube with `--sni-domains=all`
I know about this issue but it is **basically not an youtubeUnblock problem**. The problem is behind the large `*.googlevideo.com` domain name. All you want is to create a new configuration section for only youtube. It should go after section for all domains. For plain string arguments just `--fbegin` at the end of args list will work. In luci you can create section interactively.
### TV
Televisions are the biggest headache.
In [this issue](https://github.com/Waujito/youtubeUnblock/issues/59) the problem has been resolved. And now youtubeUnblock should work with default flags. If not, play around with faking strategies and other flags. Also you might be have to disable QUIC. To do it you may use `--quic-drop` [flag](#flags) with proper firewall configuration (check description of the flag). Note, that this flag won't disable gQUIC and some TVs may relay on it. To disable gQUIC you will need to block the entire 443 port for udp in firewall configuration:
For **nftables** do
```
nft insert rule inet fw4 forward ip saddr 192.168.. udp dport 443 counter drop
```
For **iptables**
```
iptables -I FORWARD --src 192.168.. -p udp --dport 443 -j DROP
```
Where you have to replace 192.168.. with ip of your television.
### Troubleshooting EPERMS (Operation not permitted) ### Troubleshooting EPERMS (Operation not permitted)
EPERM may occur in a lot of places but generally here are two: mnl_cb_run and when sending the packet via rawsocket (raw_frags_send and send fake sni).
- mnl_cb_run Operation not permitted indicates that another instance of youtubeUnblock is running on the specified queue-num. *EPERM* may occur in a lot of places but generally here are two: *mnl_cb_run* and when sending the packet via *rawsocket* (raw_frags_send and send fake sni).
- rawsocket Operation not permitted indicates that the packet is being dropped by nefilter rules. In fact this is a hint from the kernel that something wrong is going on and we should check the firewall rules. Before dive into the problem let's make it clean how the mangled packets are being sent. Nefilter queue provides us with the ability to mangle the packet on fly but that is not suitable for this program because we need to split the packet to at least two independent packets. So we are using [linux raw sockets](https://man7.org/linux/man-pages/man7/raw.7.html) which allows us to send any ipv4 packet. **The packet goes from the OUTPUT chain even when NFQUEUE is set up on FORWARD (suitable for OpenWRT).** So we need to escape packet rejects here.
- **mnl_cb_run** *Operation not permitted* indicates that another instance of youtubeUnblock is running on the specified queue-num.
- **rawsocket** *Operation not permitted* indicates that the packet is being dropped by nefilter rules. In fact this is a hint from the kernel that something wrong is going on and we should check the firewall rules. Before dive into the problem let's make it clean how the mangled packets are being sent. Nefilter queue provides us with the ability to mangle the packet on fly but that is not suitable for this program because we need to split the packet to at least two independent packets. So we are using [linux raw sockets](https://man7.org/linux/man-pages/man7/raw.7.html) which allows us to send any ipv4 packet. **The packet goes from the OUTPUT chain even when NFQUEUE is set up on FORWARD (suitable for OpenWRT).** So we need to escape packet rejects here.
* raw_frags_send EPERM: just make sure outgoing traffic is allowed (RELATED,ESTABLISHED should work, if not, go to step 3) * raw_frags_send EPERM: just make sure outgoing traffic is allowed (RELATED,ESTABLISHED should work, if not, go to step 3)
* 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. * 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`. * Step 3, ultimate solution. Use mark (don't confuse with connmark). The youtubeUnblock uses mark internally to avoid infinity packet loops (when the packet is sent by youtubeUnblock but on next step handled by itself). Currently it uses mark (1 << 15) = 32768. You should put iptables/nftables that ultimately accepts such marks at the very start of the filter OUTPUT chain: `iptables -I OUTPUT -m mark --mark 32768/32768 -j ACCEPT` or `nft insert rule inet fw4 output mark and 0x8000 == 0x8000 counter accept`.
## Performance ### Conntrack troubleshooting
If you have bad performance you can queue to youtubeUnblock only first, say, 20 packets from the connection. To do so, use nftables conntrack packets counter: `nft add rule inet fw4 mangle_forward tcp dport 443 ct original "packets < 20" counter queue num 537 bypass`. For my 1 CPU core device it worked pretty well. This works because we do care about only first packets with ClientHello. We don't need to process others.
The same behavior is also possible in iptables: `iptables -t mangle -A FORWARD -p tcp -m tcp --dport 443 -m connbytes --connbytes-dir original --connbytes-mode packets --connbytes 0:19 -j NFQUEUE --queue-num 537 --queue-bypass`. (The package iptables-mod-conntrack-extra is required for connbytes on OpenWRT) youtubeUnblock *optionally* depends on conntrack.
For hosts change FORWARD to OUTPUT. For kernel module, if conntrack breaks dependencies, compile it with `make kmake EXTRA_CFLAGS="-DNO_CONNTRACK"` to disable it completly.
You can use `--queue-balance` with multiple instances of youtubeUnblock. This behavior is supported via multithreading. Just pass -DTHREADS_NUM=n where n stands for an amount of threads you want to be enabled. The n defaults to 1. The maximum threads defaults to 16 but may be altered programatically. Note, that if you are about to increase it, here is 100% chance that you are on the wrong way. If you want to be able to use connbytes in custom stack where conntrack is broken, check #220 and #213 for possible references.
### NAT Hardware/Software offloading
youtubeUnblock will conflict with offloading. But hopefully youtubeUnblock need to process only a bunch of first packets in the connection. So, on some devices it is indeed possible to use youtubeUnblock alongside with offloading, especially on ones driven by nftables (OpenWRT 23+). Note, that this is not tested by me but [reported as a workaround](https://github.com/Waujito/youtubeUnblock/issues/199#issuecomment-2519418553) by users:
Edit `/usr/share/firewall4/templates/ruleset.uc` by replacing
```
meta l4proto { tcp, udp } flow offload @ft;
```
with
```
meta l4proto { tcp, udp } ct original packets ge 30 flow offload @ft;
```
And restart firewall with `service firewall restart`
## Compilation
Before compilation make sure `gcc`, `make`, `autoconf`, `automake`, `pkg-config` and `libtool` is installed. For Fedora `glibc-static` should be installed as well.
Compile with `make`. Install with `make install`. The package include `libnetfilter_queue`, `libnfnetlink` and `libmnl` as static dependencies. The package requires `linux-headers` and kernel built with netfilter nfqueue support.
## OpenWRT case ## OpenWRT case
The package is also compatible with routers. The router should be running by linux-based system such as [OpenWRT](https://openwrt.org/). The package is also compatible with routers. The router should be running by linux-based system such as [OpenWRT](https://openwrt.org/).
You can build under openwrt with two options: first - through the SDK, which is preferred way and second is cross-compile manually with openwrt toolchain.
You can build under OpenWRT with two options: first - through the SDK, which is preferred way and second is cross-compile manually with OpenWRT toolchain.
### Building OpenWRT .ipk package ### Building OpenWRT .ipk package
OpenWRT provides a high-level SDK for the package builds. OpenWRT provides a high-level SDK for the package builds.
First step is to download or compile OpenWRT SDK for your specific platform. The SDK can be compiled according to [this tutorial](https://openwrt.org/docs/guide-developer/toolchain/using_the_sdk). Beside of raw source code of SDK, OpenWRT also offers precompiled SDKs for your router. You can find it on the router page. For example, I have ramips/mt76x8 based router so for me the sdk is on https://downloads.openwrt.org/releases/23.05.3/targets/ramips/mt76x8/ and called `openwrt-sdk-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64`. You will need to [install sdk requirements on your system](https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem) If you have any problems, use docker ubuntu:24.04 image. Make sure to be a non-root user since some makesystem fails with it. Next, untar the SDK and cd into it. Do `echo "src-git youtubeUnblock https://github.com/Waujito/youtubeUnblock.git;openwrt" >> feeds.conf`, `./scripts/feeds update youtubeUnblock`, `./scripts/feeds install -a -p youtubeUnblock`, `make package/youtubeUnblock/compile`. Now the packet is built and you can import it to the router. Find it in `bin/packages/<target>/youtubeUnblock/youtubeUnblock-<version>.ipk`. Go to your router interface and put it in via System-Software-install_package. Now the package is on the router. Goto System-Startup, restart firewall and start youtubeUnblock. You are done!
First step is to download or compile OpenWRT SDK for your specific platform. The SDK can be compiled according to [this tutorial](https://openwrt.org/docs/guide-developer/toolchain/using_the_sdk).
Beside of raw source code of SDK, OpenWRT also offers precompiled SDKs for your router. You can find it on the router page. For example, I have ramips/mt76x8 based router so for me the sdk is on https://downloads.openwrt.org/releases/23.05.3/targets/ramips/mt76x8/ and called `openwrt-sdk-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64`.
You will need to [install sdk requirements on your system](https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem) If you have any problems, use docker ubuntu:24.04 image. Make sure to be a non-root user since some makesystem fails with it. Next, untar the SDK and cd into it.
Do
```sh
echo "src-git youtubeUnblock https://github.com/Waujito/youtubeUnblock.git;openwrt" >> feeds.conf
./scripts/feeds update youtubeUnblock
./scripts/feeds install -a -p youtubeUnblock
make package/youtubeUnblock/compile
```
Now the packet is built and you can import it to the router. Find it in `bin/packages/<target>/youtubeUnblock/youtubeUnblock-<version>.ipk`.
### Building with toolchain ### Building with toolchain
The precompiled toolchain located near the SDK. For me it is called `openwrt-toolchain-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64.tar.xz`. When you download the toolchain, untar it somewhere. Now we are ready for compilation. My cross gcc asked me to create a staging dir for it and pass it as an environment variable. Also you should notice toolsuite packages and replace my make command with yours. ```STAGING_DIR=temp make CC=/usr/bin/mipsel-openwrt-linux-gcc LD=/usr/bin/mipsel-openwrt-linux-ld AR=/usr/bin/mipsel-openwrt-linux-ar OBJDUMP=/usr/bin/mipsel-openwrt-linux-objdump NM=/usr/bin/mipsel-openwrt-linux-nm STRIP=/usr/bin/mipsel-openwrt-linux-strip CROSS_COMPILE_PLATFORM=mipsel-buildroot-linux-gnu```. Take a look at `CROSS_COMPILE_PLATFORM` It is required by autotools but I think it is not necessary. Anyways I put `mipsel-buildroot-linux-gnu` in here. For your model may be an [automake cross-compile manual](https://www.gnu.org/software/automake/manual/html_node/Cross_002dCompilation.html) will be helpful. When compilation is done, the binary file will be in build directory. Copy it to your router. Note that an ssh access is likely to be required to proceed. sshfs don't work on my model so I injected the application to the router via Software Upload Package page. It has given me an error, but also a `/tmp/upload.ipk` file which I copied in root directory, `chmod +x`-ed and run.
### Configuration The precompiled toolchain located near the SDK. For example it is called `openwrt-toolchain-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64.tar.xz`. When you download the toolchain, untar it somewhere. Now we are ready for compilation. My cross gcc asked me to create a staging dir for it and pass it as an environment variable. Also you should notice toolsuite packages and replace my make command with yours.
If you compiled the package via the SDK everything is preinstalled. But if you got any issues (suitable for routers with iptables instead of nftables), ssh into the router and check up everything manually.
For iptables: install a normal iptables user-space app: `xtables-legacy iptables-zz-legacy` and kernel/iptables nfqueue extensions: `iptables-mod-nfqueue kmod-ipt-nfqueue` and add `iptables -t mangle -A FORWARD -p tcp -m tcp --dport 443 -j NFQUEUE --queue-num 537 --queue-bypass` rule. ```
STAGING_DIR=temp make CC=/usr/bin/mipsel-openwrt-linux-gcc LD=/usr/bin/mipsel-openwrt-linux-ld AR=/usr/bin/mipsel-openwrt-linux-ar OBJDUMP=/usr/bin/mipsel-openwrt-linux-objdump NM=/usr/bin/mipsel-openwrt-linux-nm STRIP=/usr/bin/mipsel-openwrt-linux-strip CROSS_COMPILE_PLATFORM=mipsel-buildroot-linux-gnu
```
If you prefer nftables, this should work: `nft add rule inet fw4 mangle_forward tcp dport 443 counter queue num 537 bypass`. Note that `kmod-nft-queue` should be installed. Take a look at `CROSS_COMPILE_PLATFORM` It is required by autotools but I think it is not necessary. Anyways I put `mipsel-buildroot-linux-gnu` in here. For your router model name maybe an [automake cross-compile manual](https://www.gnu.org/software/automake/manual/html_node/Cross_002dCompilation.html) will be helpful.
Also you can copy `owrt/537-youtubeUnblock.nft` to `/usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft` and run `/etc/init.d/firewall reload`. This will reload the nftables ruleset and automatically link 537-youtubeUnblock.nft with it. When compilation is done, the binary file will be in build directory. Copy it to your router. Note that a ssh access is likely to be required to proceed. *sshfs* don't work on my model so I injected the application to the router via *Software Upload Package* page. It has given me an error, but also a `/tmp/upload.ipk` file which I copied in root directory, `chmod +x` it and run.
## Kernel module
This section describes the kernel module version of youtubeUnblock. The kernel module operates as a normal module inside the kernel and integrates within the netfilter stack to statelessly mangle the packets sent over the Internet.
You can configure the module with its flags:
```sh
insmod kyoutubeUnblock.ko
echo "--fake_sni=1 --exclude_domains=.ru --quic_drop" | sudo tee /sys/module/kyoutubeUnblock/parameters/parameters
```
You can also do
```sh
cat /sys/module/kyoutubeUnblock/parameters/parameters
```
and check all the parameters configured.
You can check up the statistics of youtubeUnblock with
```sh
sudo cat /proc/kyoutubeUnblock
```
### Building kernel module
#### Building on host system
To build the kernel module on your host system you should install `linux-headers` which will provide build essential tools and `gcc` compiler suite. On host system you may build the module with
```sh
make kmake
```
#### Building on any kernel
To build the module for external kernel you should build that kernel locally and point make to it. Use `KERNEL_BUILDER_MAKEDIR=~/linux` flag for make, for example:
```
make kmake KERNEL_BUILDER_MAKEDIR=~/linux
```
Note, that the kernel should be already configured and built. See linux kernel building manuals for more information about your specific case.
#### Building with openwrt SDK
Building with openwrt SDK is not such a hard thing. The only thing you should do is to obtain the sdk. You can find it by looking to your architecture and version of the openwrt currently used. You should use the exactly your version of openwrt since kernels there change often. You can find the sdk in two ways: by downloading it from their site or by using the openwrt sdk docker container (recommended).
If you decide to download the tar archive, follow next steps:
For me the archive lives in https://downloads.openwrt.org/releases/23.05.3/targets/ramips/mt76x8/ and called `openwrt-sdk-23.05.3-ramips-mt76x8_gcc-12.3.0_musl.Linux-x86_64`. You will need to [install sdk requirements on your system](https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem) If you have any problems, use docker ubuntu:24.04 image. Make sure to be a non-root user since some makesystem fails with it. Next, untar the SDK and cd into it.
Or you can obtain the docker image with sdk built-in: [https://hub.docker.com/u/openwrt/sdk](https://hub.docker.com/u/openwrt/sdk). In my case the image has tag `ramips-mt76x8-23.05.3`. A good thing here is that you don't need to install any dependencies inside the docker container. Also docker hub has a perfect search around tags if you don't sure which one corresponds to your device.
When you unpacked/installed the sdk, you is ready to start with building the kernel module.
Do
```sh
echo "src-git youtubeUnblock https://github.com/Waujito/youtubeUnblock.git;openwrt" >> feeds.conf
./scripts/feeds update youtubeUnblock
./scripts/feeds install -a -p youtubeUnblock
make defconfig
make package/kyoutubeUnblock/compile V=s
```
When the commands finish, the module is ready. Find it with `find bin -name "kmod-youtubeUnblock*.ipk"`, copy to your host and install to the router via gui software interface. The module should start immediately. If not, do `modprobe kyoutubeUnblock`.
## Padavan
YoutubeUnblock may also run on Padavan. [Check the manual here\[rus\]](Padavan.md)
>If you have any questions/suggestions/problems feel free to open an [issue](https://github.com/Waujito/youtubeUnblock/issues).
Next step is to daemonize the application in openwrt. Copy `owrt/youtubeUnblock.owrt` to `/etc/init.d/youtubeUnblock` and put the program into /usr/bin/. (Don't forget to `chmod +x` both). Now run `/etc/init.d/youtubeUnblock start`. You can alo run `/etc/init.d/youtubeUnblock enable` to force OpenWRT autostart the program on boot, but I don't recommend this since if the packet has bug you may lose access to the router (I think you will be able to reset it with reset settings tricks documented for your router).
## If you have any questions/suggestions/problems feel free to open an issue.

View File

@@ -1,73 +0,0 @@
struct config_t {
unsigned int queue_start_num;
int rawsocket;
int threads;
int use_gso;
int fragmentation_strategy;
unsigned char fake_sni_ttl;
int fake_sni_strategy;
int verbose;
unsigned int seg2_delay;
const char *domains_str;
unsigned int domains_strlen;
unsigned int all_domains;
};
extern struct config_t config;
#define MAX_THREADS 16
#ifndef THREADS_NUM
#define THREADS_NUM 1
#endif
#if THREADS_NUM > MAX_THREADS
#error "Too much threads"
#endif
#ifndef NOUSE_GSO
#define USE_GSO
#endif
#define FRAG_STRAT_TCP 0
#define FRAG_STRAT_IP 1
#define FRAG_STRAT_NONE 2
#ifndef FRAGMENTATION_STRATEGY
#define FRAGMENTATION_STRATEGY FRAG_STRAT_TCP
#endif
#define RAWSOCKET_MARK (1 << 15)
#ifdef USE_SEG2_DELAY
#define SEG2_DELAY 100
#endif
#define FAKE_SNI_TTL 8
// No fake SNI
#define FKSN_STRAT_NONE 0
// Will invalidate fake client hello by out-of-ack_seq out-of-seq request
#define FKSN_STRAT_ACK_SEQ 1
// Will assume that GGC server is located further than FAKE_SNI_TTL
// Thus, Fake Client Hello will be eliminated automatically.
#define FKSN_STRAT_TTL 2
#ifdef NO_FAKE_SNI
#define FAKE_SNI_STRATEGY FKSN_STRAT_NONE
#endif
#ifndef FAKE_SNI_STRATEGY
#define FAKE_SNI_STRATEGY FKSN_STRAT_ACK_SEQ
#endif
#if !defined(SILENT) && !defined(KERNEL_SPACE)
#define DEBUG
#endif
// The Maximum Transmission Unit size for rawsocket
// Larger packets will be fragmented. Applicable for Chrome's kyber.
#define AVAILABLE_MTU 1384
static const char defaul_snistr[] = "googlevideo.com,ggpht.com,ytimg.com,l.google.com,youtube.com,play.google.com";

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

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

@@ -0,0 +1,286 @@
/**
* @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);
#if !(defined(_SVID_SOURCE) || defined(_BSD_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE))
char *strtok_r(char *s, const char *delim, char **last);
#endif
//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

View File

@@ -1,6 +0,0 @@
#ifndef IPT_YTUNBLOCK_H
#define IPT_YTUNBLOCK_H
struct xt_ytunblock_tginfo {};
#endif /* IPT_YTUNBLOCK_H */

View File

@@ -1,341 +0,0 @@
#define _GNU_SOURCE
// Kernel module for youtubeUnblock.
// Make with make kmake && sudo iptables -t mangle -D OUTPUT 1 && sudo make kreload && sudo iptables -t mangle -I OUTPUT -p tcp -j YTUNBLOCK
#include <linux/module.h>
#include <linux/init.h>
#include <linux/printk.h>
#include <linux/mutex.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/netfilter/x_tables.h>
#include "ipt_YTUNBLOCK.h"
#include "mangle.h"
#include "config.h"
#include "raw_replacements.h"
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
MODULE_AUTHOR("Vadim Vetrov <vetrovvd@gmail.com>");
MODULE_DESCRIPTION("Linux kernel module for youtube unblock");
static int rsfd;
static struct socket *rawsocket;
DEFINE_MUTEX(rslock);
static int open_raw_socket(void) {
int ret = 0;
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
if (ret < 0) {
pr_alert("Unable to create raw socket\n");
goto err;
}
sockptr_t optval = {
.kernel = NULL,
.is_kernel = 1
};
int mark = RAWSOCKET_MARK;
optval.kernel = &mark;
ret = sock_setsockopt(rawsocket, SOL_SOCKET, SO_MARK, optval, sizeof(mark));
if (ret < 0)
{
pr_alert("setsockopt(SO_MARK, %d) failed\n", mark);
goto sr_err;
}
int one = 1;
optval.kernel = &one;
return 0;
sr_err:
sock_release(rawsocket);
err:
return ret;
}
static void close_raw_socket(void) {
sock_release(rawsocket);
}
#define AVAILABLE_MTU 1384
static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
if (pktlen > AVAILABLE_MTU) {
pr_warn("The packet is too big and may cause issues!");
__u32 buff1_size = pktlen;
__u32 buff2_size = pktlen;
__u8 *buff1 = kmalloc(pktlen, GFP_ATOMIC);
if (buff1 == NULL) return -1;
__u8 *buff2 = kmalloc(pktlen, GFP_ATOMIC);
if (buff2 == NULL) {
kfree(buff1);
return -1;
}
int ret;
#if defined(USE_TCP_SEGMENTATION) || defined(RAWSOCK_TCP_FSTRAT)
if ((ret = tcp4_frag(pkt, pktlen, AVAILABLE_MTU-128,
buff1, &buff1_size, buff2, &buff2_size)) < 0)
return ret;
#elif defined(USE_IP_FRAGMENTATION) || defined(RAWSOCK_IP_FSTRAT)
if ((ret = ip4_frag(pkt, pktlen, AVAILABLE_MTU-128,
buff1, &buff1_size, buff2, &buff2_size)) < 0)
return ret;
#else
pr_warn("send_raw_socket: Packet is too big but fragmentation is disabled! "
"Pass -DRAWSOCK_TCP_FSTRAT or -DRAWSOCK_IP_FSTRAT as CFLAGS "
"To enable it only for raw socket\n");
return -EINVAL;
#endif
int sent = 0;
ret = send_raw_socket(buff1, buff1_size);
if (ret >= 0) sent += ret;
else {
kfree(buff1);
kfree(buff2);
return ret;
}
kfree(buff1);
ret = send_raw_socket(buff2, buff2_size);
if (ret >= 0) sent += ret;
else {
kfree(buff2);
return ret;
}
kfree(buff2);
return sent;
}
struct iphdr *iph;
int ret;
if ((ret = ip4_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
return ret;
}
struct sockaddr_in daddr = {
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr = {
.s_addr = iph->daddr
}
};
struct msghdr msg;
struct kvec iov;
iov.iov_base = (__u8 *)pkt;
iov.iov_len = pktlen;
iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, 1);
msg.msg_flags = 0;
msg.msg_name = &daddr;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
mutex_lock(&rslock);
ret = kernel_sendmsg(rawsocket, &msg, &iov, 1, pktlen);
mutex_unlock(&rslock);
return ret;
}
static unsigned int ykb_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
if ((skb->mark & RAWSOCKET_MARK) == RAWSOCKET_MARK)
return XT_CONTINUE;
if (skb->head == NULL) return XT_CONTINUE;
// TODO: Mallocs are bad!
uint32_t buflen = skb->len;
__u8 *buf = kmalloc(skb->len, GFP_ATOMIC);
if (buf == NULL) {
pr_err("Cannot alloc enough buffer space");
goto accept;
}
if (skb_copy_bits(skb, 0, buf, skb->len) < 0) {
pr_err("Unable copy bits\n");
goto ac_fkb;
}
struct iphdr *iph;
uint32_t iph_len;
struct tcphdr *tcph;
uint32_t tcph_len;
__u8 *payload;
uint32_t plen;
int ret = tcp4_payload_split(buf, buflen, &iph, &iph_len,
&tcph, &tcph_len, &payload, &plen);
if (ret < 0)
goto ac_fkb;
struct verdict vrd = analyze_tls_data(payload, plen);
if (vrd.gvideo_hello) {
int ret;
pr_info("Googlevideo detected\n");
ip4_set_checksum(iph);
tcp4_set_checksum(tcph, iph);
uint32_t f1len = skb->len;
uint32_t f2len = skb->len;
__u8 *frag1 = kmalloc(f1len, GFP_ATOMIC);
if (!frag1) {
pr_err("Cannot alloc enough gv frag1 buffer space");
goto ac_fkb;
}
__u8 *frag2 = kmalloc(f2len, GFP_ATOMIC);
if (!frag2) {
pr_err("Cannot alloc enough gv frag1 buffer space");
kfree(frag1);
goto ac_fkb;
}
#ifdef FAKE_SNI
uint32_t fksn_len = FAKE_SNI_MAXLEN;
__u8 *fksn_buf = kmalloc(fksn_len, GFP_ATOMIC);
if (!fksn_buf) {
pr_err("Cannot alloc enough gksn buffer space");
goto fallback;
}
ret = gen_fake_sni(iph, tcph, fksn_buf, &fksn_len);
if (ret < 0) {
pr_err("Cannot alloc enough gksn buffer space");
goto fksn_fb;
}
#endif
#if defined(USE_TCP_SEGMENTATION)
size_t ipd_offset = vrd.sni_offset;
size_t mid_offset = ipd_offset + vrd.sni_len / 2;
if ((ret = tcp4_frag(buf, skb->len,
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
pr_err("tcp4_frag: %d", ret);
goto fksn_fb;
}
#elif defined(USE_IP_FRAGMENTATION)
size_t ipd_offset = tcph_len + vrd.sni_offset;
size_t mid_offset = ipd_offset + vrd.sni_len / 2;
mid_offset += 8 - mid_offset % 8;
if ((ret = ip4_frag(buf, skb->len,
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
pr_err("ip4_frag: %d", ret);
goto fksn_fb;
}
#endif
#ifdef FAKE_SNI
ret = send_raw_socket(fksn_buf, fksn_len);
if (ret < 0) {
pr_err("fksn_send: %d", ret);
goto fksn_fb;
}
#endif
#if defined(USE_NO_FRAGMENTATION)
#ifdef SEG2_DELAY
#error "SEG2_DELAY is incompatible with NO FRAGMENTATION"
#endif
ret = send_raw_socket(buf, buflen);
if (ret < 0) {
pr_err("nofrag_send: %d", ret);
}
goto fksn_fb;
#endif
ret = send_raw_socket(frag2, f2len);
if (ret < 0) {
pr_err("raw frag2 send: %d", ret);
goto fksn_fb;
}
#ifdef SEG2_DELAY
#error "Seg2 delay is unsupported yet for kmod"
#else
ret = send_raw_socket(frag1, f1len);
if (ret < 0) {
pr_err("raw frag1 send: %d", ret);
goto fksn_fb;
}
#endif
fksn_fb:
#ifdef FAKE_SNI
kfree(fksn_buf);
#endif
fallback:
#ifndef SEG2_DELAY
kfree(frag1);
#endif
kfree(frag2);
kfree(buf);
kfree_skb(skb);
return NF_STOLEN;
}
ac_fkb:
kfree(buf);
accept:
return XT_CONTINUE;
}
static int ykb_chk(const struct xt_tgchk_param *par) {
return 0;
}
static struct xt_target ykb_tg_reg __read_mostly = {
.name = "YTUNBLOCK",
.target = ykb_tg,
.table = "mangle",
.hooks = (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_FORWARD),
.targetsize = sizeof(struct xt_ytunblock_tginfo),
.proto = IPPROTO_TCP,
.family = NFPROTO_IPV4,
.checkentry = ykb_chk,
.me = THIS_MODULE,
};
static int __init ykb_init(void) {
int ret = 0;
ret = open_raw_socket();
if (ret < 0) goto err;
ret = xt_register_target(&ykb_tg_reg);
if (ret < 0) goto close_rawsocket;
pr_info("youtubeUnblock kernel module started.\n");
return 0;
close_rawsocket:
close_raw_socket();
err:
return ret;
}
static void __exit ykb_destroy(void) {
xt_unregister_target(&ykb_tg_reg);
close_raw_socket();
pr_info("youtubeUnblock kernel module destroyed.\n");
}
module_init(ykb_init);
module_exit(ykb_destroy);

View File

@@ -7,36 +7,25 @@ LD := ld
CFLAGS := CFLAGS :=
LDFLAGS := LDFLAGS :=
IPT_CFLAGS := -Wall -Wpedantic -O2 KERNEL_BUILDER_MAKEDIR:=/lib/modules/$(shell uname -r)/build
override EXTRA_CFLAGS += -DPKG_VERSION=\"$(PKG_FULLVERSION)\"
.PHONY: kmake kload kunload kreload kclean kmclean xclean .PHONY: kmake kload kunload kreload kclean kmclean xclean
kmake: kmod xmod kmake: kmod
kmod: kmod:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules $(MAKE) -C $(KERNEL_BUILDER_MAKEDIR) M=$(PWD) EXTRA_CFLAGS='$(EXTRA_CFLAGS)' modules
xmod: libipt_YTUNBLOCK.so
libipt_YTUNBLOCK.so: libipt_YTUNBLOCK.o
$(CCLD) -shared -fPIC ${IPT_CFLAGS} -o $@ $^;
libipt_YTUNBLOCK.o: libipt_YTUNBLOCK.c
$(CC) ${IPT_CFLAGS} -D_INIT=lib$*_init -fPIC -c -o $@ $<;
kload: kload:
insmod ipt_YTUNBLOCK.ko insmod kyoutubeUnblock.ko
cp ./libipt_YTUNBLOCK.so /usr/lib/xtables/
kunload: kunload:
-rmmod ipt_YTUNBLOCK -rmmod kyoutubeUnblock
-/bin/rm /usr/lib/xtables/libipt_YTUNBLOCK.so
kreload: kunload kload kreload: kunload kload
kclean: xtclean kmclean kclean: kmclean
kmclean: kmclean:
-$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean -$(MAKE) -C $(KERNEL_BUILDER_MAKEDIR) M=$(PWD) clean
xtclean:
-/bin/rm -f libipt_YTUNBLOCK.so libipt_YTUNBLOCK.o

View File

@@ -1,26 +0,0 @@
// Used to register target in iptables
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ipt_YTUNBLOCK.h"
#define _init __attribute__((constructor)) _INIT
#define __maybe_unused __attribute__((__unused__))
static void YTKB_help(void) {
printf("Youtube Unblock - bypass youtube slowdown DPI in Russia\n");
}
static struct xtables_target ykb_tg_reg = {
.name = "YTUNBLOCK",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_ytunblock_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_ytunblock_tginfo)),
.help = YTKB_help,
};
void _init(void) {
xtables_register_target(&ykb_tg_reg);
}

484
mangle.c
View File

@@ -1,484 +0,0 @@
#define _GNU_SOURCE
#include "mangle.h"
#include "raw_replacements.h"
#include "config.h"
#ifdef KERNEL_SPACE
#include <linux/printk.h>
#include <linux/ip.h>
#define printf pr_info
#define perror pr_err
#define lgerror(msg, ret) (pr_err(msg ": %d\n", ret))
#else
#include <stdio.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
typedef uint8_t __u8;
typedef uint32_t __u32;
typedef uint16_t __u16;
#define lgerror(msg, ret) __extension__ ({errno = -ret; perror(msg);})
#endif
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
{
#ifdef KERNEL_SPACE
uint32_t tcp_packet_len = ntohs(iph->tot_len) - (iph->ihl << 2);
tcph->check = 0;
tcph->check = csum_tcpudp_magic(
iph->saddr, iph->daddr, tcp_packet_len,
IPPROTO_TCP,
csum_partial(tcph, tcp_packet_len, 0));
#else
nfq_tcp_compute_checksum_ipv4(tcph, iph);
#endif
}
void ip4_set_checksum(struct iphdr *iph)
{
#ifdef KERNEL_SPACE
iph->check = 0;
iph->check = ip_fast_csum(iph, iph->ihl);
#else
nfq_ip_set_checksum(iph);
#endif
}
int ip4_payload_split(__u8 *pkt, __u32 buflen,
struct iphdr **iph, __u32 *iph_len,
__u8 **payload, __u32 *plen) {
if (pkt == NULL || buflen < sizeof(struct iphdr)) {
return -EINVAL;
}
struct iphdr *hdr = (struct iphdr *)pkt;
if (hdr->version != IPVERSION) return -EINVAL;
__u32 hdr_len = hdr->ihl * 4;
__u32 pktlen = ntohs(hdr->tot_len);
if (buflen < pktlen || hdr_len > pktlen) return -EINVAL;
if (iph)
*iph = hdr;
if (iph_len)
*iph_len = hdr_len;
if (payload)
*payload = pkt + hdr_len;
if (plen)
*plen = pktlen - hdr_len;
return 0;
}
int tcp4_payload_split(__u8 *pkt, __u32 buflen,
struct iphdr **iph, __u32 *iph_len,
struct tcphdr **tcph, __u32 *tcph_len,
__u8 **payload, __u32 *plen) {
struct iphdr *hdr;
__u32 hdr_len;
struct tcphdr *thdr;
__u32 thdr_len;
__u8 *tcph_pl;
__u32 tcph_plen;
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
&tcph_pl, &tcph_plen)){
return -EINVAL;
}
if (
hdr->protocol != IPPROTO_TCP ||
tcph_plen < sizeof(struct tcphdr)) {
return -EINVAL;
}
thdr = (struct tcphdr *)(tcph_pl);
thdr_len = thdr->doff * 4;
if (thdr_len > tcph_plen) {
return -EINVAL;
}
if (iph) *iph = hdr;
if (iph_len) *iph_len = hdr_len;
if (tcph) *tcph = thdr;
if (tcph_len) *tcph_len = thdr_len;
if (payload) *payload = tcph_pl + thdr_len;
if (plen) *plen = tcph_plen - thdr_len;
return 0;
}
// split packet to two ipv4 fragments.
int ip4_frag(const __u8 *pkt, __u32 buflen, __u32 payload_offset,
__u8 *frag1, __u32 *f1len,
__u8 *frag2, __u32 *f2len) {
struct iphdr *hdr;
const __u8 *payload;
__u32 plen;
__u32 hdr_len;
int ret;
if (!frag1 || !f1len || !frag2 || !f2len)
return -EINVAL;
if ((ret = ip4_payload_split(
(__u8 *)pkt, buflen,
&hdr, &hdr_len, (__u8 **)&payload, &plen)) < 0) {
lgerror("ipv4_frag: TCP Header extract error", ret);
return -EINVAL;
}
if (plen <= payload_offset) {
return -EINVAL;
}
if (payload_offset & ((1 << 3) - 1)) {
lgerror("ipv4_frag: Payload offset MUST be a multiply of 8!", -EINVAL);
return -EINVAL;
}
__u32 f1_plen = payload_offset;
__u32 f1_dlen = f1_plen + hdr_len;
__u32 f2_plen = plen - payload_offset;
__u32 f2_dlen = f2_plen + hdr_len;
if (*f1len < f1_dlen || *f2len < f2_dlen) {
return -ENOMEM;
}
*f1len = f1_dlen;
*f2len = f2_dlen;
memcpy(frag1, hdr, hdr_len);
memcpy(frag2, hdr, hdr_len);
memcpy(frag1 + hdr_len, payload, f1_plen);
memcpy(frag2 + hdr_len, payload + payload_offset, f2_plen);
struct iphdr *f1_hdr = (void *)frag1;
struct iphdr *f2_hdr = (void *)frag2;
__u16 f1_frag_off = ntohs(f1_hdr->frag_off);
__u16 f2_frag_off = ntohs(f2_hdr->frag_off);
f1_frag_off &= IP_OFFMASK;
f1_frag_off |= IP_MF;
if ((f2_frag_off & ~IP_OFFMASK) == IP_MF) {
f2_frag_off &= IP_OFFMASK;
f2_frag_off |= IP_MF;
} else {
f2_frag_off &= IP_OFFMASK;
}
f2_frag_off += (__u16)payload_offset / 8;
f1_hdr->frag_off = htons(f1_frag_off);
f1_hdr->tot_len = htons(f1_dlen);
f2_hdr->frag_off = htons(f2_frag_off);
f2_hdr->tot_len = htons(f2_dlen);
if (config.verbose)
printf("Packet split in portion %u %u\n", f1_plen, f2_plen);
ip4_set_checksum(f1_hdr);
ip4_set_checksum(f2_hdr);
return 0;
}
// split packet to two tcp-on-ipv4 segments.
int tcp4_frag(const __u8 *pkt, __u32 buflen, __u32 payload_offset,
__u8 *seg1, __u32 *s1len,
__u8 *seg2, __u32 *s2len) {
struct iphdr *hdr;
__u32 hdr_len;
struct tcphdr *tcph;
__u32 tcph_len;
__u32 plen;
const __u8 *payload;
int ret;
if (!seg1 || !s1len || !seg2 || !s2len)
return -EINVAL;
if ((ret = tcp4_payload_split((__u8 *)pkt, buflen,
&hdr, &hdr_len,
&tcph, &tcph_len,
(__u8 **)&payload, &plen)) < 0) {
lgerror("tcp4_frag: tcp4_payload_split", ret);
return -EINVAL;
}
if (
ntohs(hdr->frag_off) & IP_MF ||
ntohs(hdr->frag_off) & IP_OFFMASK) {
printf("tcp4_frag: frag value: %d\n",
ntohs(hdr->frag_off));
lgerror("tcp4_frag: ip fragmentation is set", -EINVAL);
return -EINVAL;
}
if (plen <= payload_offset) {
return -EINVAL;
}
__u32 s1_plen = payload_offset;
__u32 s1_dlen = s1_plen + hdr_len + tcph_len;
__u32 s2_plen = plen - payload_offset;
__u32 s2_dlen = s2_plen + hdr_len + tcph_len;
if (*s1len < s1_dlen || *s2len < s2_dlen)
return -ENOMEM;
*s1len = s1_dlen;
*s2len = s2_dlen;
memcpy(seg1, hdr, hdr_len);
memcpy(seg2, hdr, hdr_len);
memcpy(seg1 + hdr_len, tcph, tcph_len);
memcpy(seg2 + hdr_len, tcph, tcph_len);
memcpy(seg1 + hdr_len + tcph_len, payload, s1_plen);
memcpy(seg2 + hdr_len + tcph_len, payload + payload_offset, s2_plen);
struct iphdr *s1_hdr = (void *)seg1;
struct iphdr *s2_hdr = (void *)seg2;
struct tcphdr *s1_tcph = (void *)(seg1 + hdr_len);
struct tcphdr *s2_tcph = (void *)(seg2 + hdr_len);
s1_hdr->tot_len = htons(s1_dlen);
s2_hdr->tot_len = htons(s2_dlen);
s2_tcph->seq = htonl(ntohl(s2_tcph->seq) + payload_offset);
if (config.verbose)
printf("Packet split in portion %u %u\n", s1_plen, s2_plen);
tcp4_set_checksum(s1_tcph, s1_hdr);
tcp4_set_checksum(s2_tcph, s2_hdr);
return 0;
}
#define TLS_CONTENT_TYPE_HANDSHAKE 0x16
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
#define TLS_EXTENSION_SNI 0x0000
#define TLS_EXTENSION_CLIENT_HELLO_ENCRYPTED 0xfe0d
typedef __u8 uint8_t;
typedef __u32 uint32_t;
typedef __u16 uint16_t;
/**
* Processes tls payload of the tcp request.
*
* data Payload data of TCP.
* dlen Length of `data`.
*/
struct verdict analyze_tls_data(
const uint8_t *data,
uint32_t dlen)
{
struct verdict vrd = {0};
size_t i = 0;
const uint8_t *data_end = data + dlen;
while (i + 4 < dlen) {
const uint8_t *msgData = data + i;
uint8_t tls_content_type = *msgData;
uint8_t tls_vmajor = *(msgData + 1);
uint8_t tls_vminor = *(msgData + 2);
uint16_t message_length = ntohs(*(uint16_t *)(msgData + 3));
const uint8_t *message_length_ptr = msgData + 3;
if (i + 5 + message_length > dlen) break;
if (tls_content_type != TLS_CONTENT_TYPE_HANDSHAKE)
goto nextMessage;
const uint8_t *handshakeProto = msgData + 5;
if (handshakeProto + 1 >= data_end) break;
uint8_t handshakeType = *handshakeProto;
if (handshakeType != TLS_HANDSHAKE_TYPE_CLIENT_HELLO)
goto nextMessage;
const uint8_t *msgPtr = handshakeProto;
msgPtr += 1;
const uint8_t *handshakeProto_length_ptr = msgPtr + 1;
msgPtr += 3 + 2 + 32;
if (msgPtr + 1 >= data_end) break;
uint8_t sessionIdLength = *msgPtr;
msgPtr++;
msgPtr += sessionIdLength;
if (msgPtr + 2 >= data_end) break;
uint16_t ciphersLength = ntohs(*(uint16_t *)msgPtr);
msgPtr += 2;
msgPtr += ciphersLength;
if (msgPtr + 1 >= data_end) break;
uint8_t compMethodsLen = *msgPtr;
msgPtr++;
msgPtr += compMethodsLen;
if (msgPtr + 2 >= data_end) break;
uint16_t extensionsLen = ntohs(*(uint16_t *)msgPtr);
const uint8_t *extensionsLen_ptr = msgPtr;
msgPtr += 2;
const uint8_t *extensionsPtr = msgPtr;
const uint8_t *extensions_end = extensionsPtr + extensionsLen;
if (extensions_end > data_end) break;
while (extensionsPtr < extensions_end) {
const uint8_t *extensionPtr = extensionsPtr;
if (extensionPtr + 4 >= extensions_end) break;
uint16_t extensionType =
ntohs(*(uint16_t *)extensionPtr);
extensionPtr += 2;
uint16_t extensionLen =
ntohs(*(uint16_t *)extensionPtr);
const uint8_t *extensionLen_ptr = extensionPtr;
extensionPtr += 2;
if (extensionPtr + extensionLen > extensions_end)
break;
if (extensionType != TLS_EXTENSION_SNI)
goto nextExtension;
const uint8_t *sni_ext_ptr = extensionPtr;
if (sni_ext_ptr + 2 >= extensions_end) break;
uint16_t sni_ext_dlen = ntohs(*(uint16_t *)sni_ext_ptr);
const uint8_t *sni_ext_dlen_ptr = sni_ext_ptr;
sni_ext_ptr += 2;
const uint8_t *sni_ext_end = sni_ext_ptr + sni_ext_dlen;
if (sni_ext_end >= extensions_end) break;
if (sni_ext_ptr + 3 >= sni_ext_end) break;
uint8_t sni_type = *sni_ext_ptr++;
uint16_t sni_len = ntohs(*(uint16_t *)sni_ext_ptr);
sni_ext_ptr += 2;
if (sni_ext_ptr + sni_len > sni_ext_end) break;
char *sni_name = (char *)sni_ext_ptr;
vrd.sni_offset = (uint8_t *)sni_name - data;
vrd.sni_len = sni_len;
if (config.all_domains) {
vrd.target_sni = 1;
goto out;
}
unsigned int j = 0;
for (unsigned int i = 0; i < config.domains_strlen; i++) {
if (config.domains_str[i] == ',' || config.domains_str[i] == '\n') {
unsigned int domain_len = (i - j);
const char *sni_startp = sni_name + sni_len - domain_len;
const char *domain_startp = config.domains_str + j;
if (sni_len >= domain_len &&
sni_len < 128 &&
!strncmp(sni_startp,
domain_startp,
domain_len)) {
vrd.target_sni = 1;
}
j = i + 1;
}
}
nextExtension:
extensionsPtr += 2 + 2 + extensionLen;
}
nextMessage:
i += 5 + message_length;
}
out:
return vrd;
}
int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
uint8_t *buf, uint32_t *buflen) {
if (!iph || !tcph || !buf || !buflen)
return -EINVAL;
int ip_len = iph->ihl * 4;
size_t data_len = sizeof(fake_sni);
size_t dlen = data_len + ip_len;
if (*buflen < dlen)
return -ENOMEM;
*buflen = dlen;
memcpy(buf, iph, ip_len);
memcpy(buf + ip_len, fake_sni, data_len);
struct iphdr *niph = (struct iphdr *)buf;
niph->protocol = IPPROTO_TCP;
niph->tot_len = htons(dlen);
int ret = 0;
struct tcphdr *ntcph = (struct tcphdr *)(buf + ip_len);
#ifdef KERNEL_SPACE
ntcph->dest = tcph->dest;
ntcph->source = tcph->source;
#else
ntcph->th_dport = tcph->th_dport;
ntcph->th_sport = tcph->th_sport;
#if FAKE_SNI_STRATEGY == FKSN_STRAT_TTL
ntcph->ack = tcph->ack;
ntcph->ack_seq = tcph->ack_seq;
niph->ttl = FAKE_SNI_TTL;
#endif
#endif
ip4_set_checksum(niph);
tcp4_set_checksum(ntcph, niph);
return 0;
}

View File

@@ -1,66 +0,0 @@
#ifndef YU_MANGLE_H
#define YU_MANGLE_H
#ifdef KERNEL_SPACE
#include <linux/types.h>
typedef __u8 uint8_t;
typedef __u32 uint32_t;
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/stddef.h>
#include <linux/net.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <asm/byteorder.h>
/* from <netinet/ip.h> */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
#else
#define USER_SPACE
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
struct verdict {
int target_sni; /* google video hello packet */
int sni_offset; /* offset from start of tcp _payload_ */
int sni_len;
};
struct verdict analyze_tls_data(const uint8_t *data, uint32_t dlen);
int ip4_frag(const uint8_t *pkt, uint32_t pktlen,
uint32_t payload_offset,
uint8_t *frag1, uint32_t *f1len,
uint8_t *frag2, uint32_t *f2len);
int tcp4_frag(const uint8_t *pkt, uint32_t pktlen,
uint32_t payload_offset,
uint8_t *seg1, uint32_t *s1len,
uint8_t *seg2, uint32_t *s2len);
int ip4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
uint8_t **payload, uint32_t *plen);
int tcp4_payload_split(uint8_t *pkt, uint32_t buflen,
struct iphdr **iph, uint32_t *iph_len,
struct tcphdr **tcph, uint32_t *tcph_len,
uint8_t **payload, uint32_t *plen);
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph);
void ip4_set_checksum(struct iphdr *iph);
int gen_fake_sni(const struct iphdr *iph, const struct tcphdr *tcph,
uint8_t *buf, uint32_t *buflen);
#endif /* YU_MANGLE_H */

View File

@@ -1,5 +0,0 @@
#!/usr/sbin/nft -f
# This file
insert rule inet fw4 mangle_forward tcp dport 443 ct original packets < 20 counter queue num 537 bypass
insert rule inet fw4 output mark and 0x8000 == 0x8000 counter accept

View File

@@ -1,21 +0,0 @@
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=50
STOP=50
# Openwrt procd script: https://openwrt.org/docs/guide-developer/procd-init-script-example
# The program should be put into /usr/bin/
# This file should be put into /etc/init.d/
start_service() {
procd_open_instance
procd_set_param command /usr/bin/youtubeUnblock 537
procd_set_param nice -20
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}

View File

@@ -1,9 +0,0 @@
#ifndef RAW_REPLACEMENTS_H
#define RAW_REPLACEMENTS_H
#define FAKE_SNI_MAXLEN 1500
static const char fake_sni[] = "\276(\001\273\366\234|\335\213\222\023\330\200\030\001\366\350e\000\000\001\001\b\n}\355\267Hm/\217\347\026\003\001\004\316\001\000\004\312\003\003K+\272\314\340\306\374>dw%\f\223\346\225\270\270~\335\027\f\264\341H\267\357\303\216T\322[\371 \245\320\212V6\374\3706\232\0216B\325\273P\b\300>\0332>\362\323\033\322\301\204\022f8\223\214\000\"\023\001\023\003\023\002\300+\300/\314\251\314\250\300,\3000\300\n\300\t\300\023\300\024\000\234\000\235\000/\0005\001\000\004_\000\000\000\023\000\021\000\000\016www.google.com\000\027\000\000\377\001\000\001\000\000\n\000\016\000\f\000\035\000\027\000\030\000\031\001\000\001\001\000\v\000\002\001\000\000\020\000\v\000\t\bhttp/1.1\000\005\000\005\001\000\000\000\000\000\"\000\n\000\b\004\003\005\003\006\003\002\003\0003\000k\000i\000\035\000 \333C\212\234-\t\237#\202\\\231\311\022]\333\341t(\t\276U\373u\234\316J~,^|*Z\000\027\000A\004k\n\255\254\376X\226t\001;n~\033\034.\245\027\024\3762_\352$\374\346^f\fF,\201\275\263\336O\231\001\032\200\357dI\266y\031\323\311vR\232\004\r\366FT\004\335\326\356\256\230B\t\313\000*\000\000\000+\000\005\004\003\004\003\003\000\r\000\030\000\026\004\003\005\003\006\003\b\004\b\005\b\006\004\001\005\001\006\001\002\003\002\001\000-\000\002\001\001\000\034\000\002@\001\376\r\0029\000\000\001\000\003\344\000 \337\306\243\332Y\033\a\252\352\025\365Z\035\223\226\304\255\363\215G\356g\344%}7\217\033n\211^\201\002\017g\267\334\326OD}\336\341ZC\230\226'\225\313\357\211\\\242\273\030k\216\377U\315\206\2410\200\203\332Z\223\005\370\b\304\370f\017\200\023\241\223~?\270{\037b\312\001\270\227\366\356\352\002\314\351\006\237\241q\226\300\314\321o\247{\201\317\230}B\005T\3660\335\320\332r?S\217\tq\036\031\326I|\237]\311 c\f\024r\031\310W\373\257\314q)q\030\237\261\227\217Kd?\257'G\320\020\340\256ND\247\005\341\324\024OP>\370\350\270b\311wAj\t\311\213\365i\203\230x\207\354\245<\274\202\230c\v0Y\263\364\022\303a\200\022\031\314\271rl=\327\336\001\327\264\267\342\353\352=\354[u\224\260\257\034\004\232\023\226}\227\030e\221\"\350\207\027dId\324\305\362N:\035\307`\204\337\201;\221\320\266b\362hrH\345e\206\246%\006\020a4\3430\036\225\215\274\275\360Q&\271\237)\222uK\362\017o\220\226W\357\267#\357\v\023\354\213\2629\331\ad\005/~6k\000[\247\301\270\310qJ\004\303|m5\363\376Y\002\243}6\251x\024\331)GH\335\205rI\032\f\210\a\212\347]\271\030\347.\021\213\365\026\030\340/Ny\r\332\3577\3203\026iX}>\2507\327&XRXU!\017\270I\313\352\350^?\352Uss\017\266pF\222NI\245\307_\305#\361\352\243+-\266\317Q\036s\243\277\355{S&\023>\275\360\215\032V\237XOY\345u>\002\305\252T\354\035\327v{P\352M\233\366\221\270\377\251\261f+rF\201wL2W\266X\252\242X\2536I\337c\205uZ\254Fe\305h\t\371\376\216r\336Y\327h\347*\331\257-ZQ{(\336\226\206\017\037\036\021\341\027z\033\254\235\252\227\224\004?p\243\351\\\263\352\205\327#W\345\255\256\375\267bP\3047\363!*K\003t\212(\306\214P\215\3506j\025\375\213e\254s\000)\001\034\000\367\000\361\002\276W%\232?\326\223\277\211v\017\a\361\347\312N\226\024L\260v\210\271j\324[|\270\344\3773\321-\313b>~\310\253XIR\324)&;\033{g;)\344\255\226\370\347I\\y\020\324\360\211vC\310\226s\267|\273$\341\332\2045qh\245w\2255\214\316\030\255\301\326C\343\304=\245\231h`yd\000#s\002\370\374Z\0336\245\361\226\222\306\032k\2457\016h\314(R;\326T~EHH\352\307\023^\247\363\321`V\340\253Z\233\357\227I\373\337z\177\nv\261\252\371\017\226\223\345\005\315y4\b\236N0\2630\017\215c\305&L\260\346J\237\203Q(\335W\027|>\3553\275j\307?W5\3463kc\350\262C\361 \037w!\371}\214\"I\377|\331@a;\342\3566\312\272Z\327u7\204'\215YBLL\235\236\242\345\215\245T\211a\312\263\342\000! \221\202X$\302\317\203\246\207c{\231\330\264\324\\k\271\272\336\356\002|\261O\207\030+\367P\317\356";
#endif /*RAW_REPLACEMENTS_H*/

1280
src/args.c Normal file

File diff suppressed because it is too large Load Diff

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

345
src/config.h Normal file
View File

@@ -0,0 +1,345 @@
/*
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
#ifndef KERNEL_SPACE
#define USER_SPACE
#endif
#include "types.h"
#include "trie.h"
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, size_t data_len, unsigned int delay_ms);
struct instance_config_t {
raw_send_t send_raw_packet;
delayed_send_t send_delayed_packet;
};
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;
};
struct section_config_t {
int id;
struct section_config_t *next;
struct section_config_t *prev;
struct trie_container sni_domains;
struct trie_container exclude_sni_domains;
unsigned int all_domains;
int tls_enabled;
int fragmentation_strategy;
int frag_sni_reverse;
int frag_sni_faked;
int faking_strategy;
int frag_middle_sni;
int frag_sni_pos;
unsigned char faking_ttl;
int fake_sni;
unsigned int fake_sni_seq_len;
#define FAKE_PAYLOAD_RANDOM 0
#define FAKE_PAYLOAD_CUSTOM 1
// In default mode all other options will be skipped.
#define FAKE_PAYLOAD_DEFAULT 2
int fake_sni_type;
/* In milliseconds */
unsigned int seg2_delay;
int synfake;
unsigned int synfake_len;
const char *fake_sni_pkt;
unsigned int fake_sni_pkt_sz;
char *fake_custom_pkt;
unsigned int fake_custom_pkt_sz;
unsigned int fk_winsize;
int fakeseq_offset;
int dport_filter;
#define SNI_DETECTION_PARSE 0
#define SNI_DETECTION_BRUTE 1
int sni_detection;
int udp_mode;
unsigned int udp_fake_seq_len;
unsigned int udp_fake_len;
int udp_faking_strategy;
struct udp_dport_range *udp_dport_range;
int udp_dport_range_len;
int udp_filter_quic;
};
#define MAX_CONFIGLIST_LEN 64
struct config_t {
unsigned int queue_start_num;
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;
#define VERBOSE_INFO 0
#define VERBOSE_DEBUG 1
#define VERBOSE_TRACE 2
int verbose;
struct section_config_t *first_section;
struct section_config_t *last_section;
#ifdef KERNEL_SPACE
struct kref refcount;
#endif
};
#define ITER_CONFIG_SECTIONS(config, section) \
for (struct section_config_t *section = (config)->last_section; section != NULL; section = section->prev)
#define CONFIG_SECTION_NUMBER(section) ((section)->id)
#define MAX_THREADS 16
#ifndef THREADS_NUM
#define THREADS_NUM 1
#endif
#if THREADS_NUM > MAX_THREADS
#error "Too much threads"
#endif
#ifndef NOUSE_GSO
#define USE_GSO
#endif
#define FRAG_STRAT_TCP 0
#define FRAG_STRAT_IP 1
#define FRAG_STRAT_NONE 2
#ifndef FRAGMENTATION_STRATEGY
#define FRAGMENTATION_STRATEGY FRAG_STRAT_TCP
#endif
#define DEFAULT_RAWSOCKET_MARK (1 << 15)
#ifdef USE_SEG2_DELAY
#define SEG2_DELAY 100
#endif
#define FAKE_TTL 8
#define FAKE_STRAT_NONE 0
// Will invalidate fake packets by out-of-ack_seq out-of-seq request
#define FAKE_STRAT_RAND_SEQ (1 << 0)
// Will assume that GGC server is located further than FAKE_TTL
// Thus, Fake packet will be eliminated automatically.
#define FAKE_STRAT_TTL (1 << 1)
#define FAKE_STRAT_PAST_SEQ (1 << 2)
#define FAKE_STRAT_TCP_CHECK (1 << 3)
#define FAKE_STRAT_TCP_MD5SUM (1 << 4)
#define FAKE_STRAT_UDP_CHECK (1 << 5)
#define FAKE_STRAT_COUNT 6
/**
* This macros iterates through all faking strategies and executes code under it.
* destination strategy will be available under name of `strategy` variable.
*/
#define ITER_FAKE_STRAT(fake_bitmask, strategy) \
for (int strategy = 1; strategy <= (1 << FAKE_STRAT_COUNT); strategy <<= 1) \
if ((fake_bitmask) & strategy)
#ifndef FAKING_STRATEGY
#define FAKING_STRATEGY FAKE_STRAT_PAST_SEQ
#endif
#define MAX_FAKE_SIZE 1300
#if !defined(SILENT) && !defined(KERNEL_SPACE)
#define DEBUG
#endif
// The Maximum Transmission Unit size for rawsocket
// Larger packets will be fragmented. Applicable for Chrome's kyber.
#define AVAILABLE_MTU 1400
#define DEFAULT_QUEUE_NUM 537
#define MAX_PACKET_SIZE (1 << 16)
#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;
enum {
UDP_MODE_DROP,
UDP_MODE_FAKE,
};
enum {
UDP_FILTER_QUIC_DISABLED,
UDP_FILTER_QUIC_ALL,
UDP_FILTER_QUIC_PARSED,
};
#define default_section_config { \
.sni_domains = {0}, \
.exclude_sni_domains = {0}, \
.all_domains = 0, \
.tls_enabled = 1, \
.frag_sni_reverse = 1, \
.frag_sni_faked = 0, \
.fragmentation_strategy = FRAGMENTATION_STRATEGY, \
.faking_strategy = FAKING_STRATEGY, \
.faking_ttl = FAKE_TTL, \
.fake_sni = 1, \
.fake_sni_seq_len = 1, \
.fake_sni_type = FAKE_PAYLOAD_DEFAULT, \
.fake_custom_pkt = NULL, \
.fake_custom_pkt_sz = 0, \
.frag_middle_sni = 1, \
.frag_sni_pos = 1, \
.fakeseq_offset = 10000, \
.synfake = 0, \
.synfake_len = 0, \
\
.dport_filter = 1, \
.seg2_delay = 0, \
\
.sni_detection = SNI_DETECTION_PARSE, \
\
.udp_mode = UDP_MODE_FAKE, \
.udp_fake_seq_len = 6, \
.udp_fake_len = 64, \
.udp_faking_strategy = FAKE_STRAT_NONE, \
.udp_dport_range = NULL, \
.udp_dport_range_len = 0, \
.udp_filter_quic = UDP_FILTER_QUIC_DISABLED, \
\
.prev = NULL, \
.next = NULL, \
.id = 0, \
}
#define default_config_set { \
.threads = THREADS_NUM, \
.queue_start_num = DEFAULT_QUEUE_NUM, \
.mark = DEFAULT_RAWSOCKET_MARK, \
.use_ipv6 = 1, \
.connbytes_limit = 19, \
\
.verbose = VERBOSE_DEBUG, \
.use_gso = 1, \
.use_conntrack = 0, \
\
.first_section = NULL, \
.last_section = NULL, \
\
.daemonize = 0, \
.noclose = 0, \
.syslog = 0, \
.instaflush = 0, \
}
#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;
};
struct statistics_data {
unsigned long all_packet_counter;
unsigned long packet_counter;
unsigned long target_counter;
unsigned long sent_counter;
};
extern struct statistics_data global_stats;
#endif /* YTB_CONFIG_H */

228
src/getopt.c Normal file
View File

@@ -0,0 +1,228 @@
/*
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"
char *optarg;
int optind=1, opterr=1, optopt, __optpos, optreset=0;
#define optpos __optpos
static void __getopt_msg(const char *b, const char *c, size_t l)
{
lgerr("%s %.*s", b, (int)l, c);
}
int getopt(int argc, char * const argv[], const char *optstring)
{
int i, c, d;
int k, l;
char *optchar;
if (!optind || optreset) {
optreset = 0;
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind])
return -1;
if (argv[optind][0] != '-') {
if (optstring[0] == '-') {
optarg = argv[optind++];
return 1;
}
return -1;
}
if (!argv[optind][1])
return -1;
if (argv[optind][1] == '-' && !argv[optind][2])
return optind++, -1;
if (!optpos) optpos++;
c = argv[optind][optpos], k = 1;
optchar = argv[optind]+optpos;
optopt = c;
optpos += k;
if (!argv[optind][optpos]) {
optind++;
optpos = 0;
}
if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
i = 0;
d = 0;
do {
d = optstring[i], l = 1;
if (l>0) i+=l; else i++;
} while (l && d != c);
if (d != c) {
if (optstring[0] != ':' && opterr)
__getopt_msg("Unrecognized option: ", optchar, k);
return '?';
}
if (optstring[i] == ':') {
if (optstring[i+1] == ':') optarg = 0;
else if (optind >= argc) {
if (optstring[0] == ':') return ':';
if (opterr) __getopt_msg("Option requires an argument: ",
optchar, k);
return '?';
}
if (optstring[i+1] != ':' || optpos) {
optarg = argv[optind++] + optpos;
optpos = 0;
}
}
return c;
}
static void permute(char *const *argv, int dest, int src)
{
char **av = (char **)argv;
char *tmp = av[src];
int i;
for (i=src; i>dest; i--)
av[i] = av[i-1];
av[dest] = tmp;
}
static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{
optarg = 0;
if (longopts && argv[optind][0] == '-' &&
((longonly && argv[optind][1] && argv[optind][1] != '-') ||
(argv[optind][1] == '-' && argv[optind][2])))
{
int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
int i, cnt, match = -1;
char *opt;
for (cnt=i=0; longopts[i].name; i++) {
const char *name = longopts[i].name;
opt = argv[optind]+1;
if (*opt == '-') opt++;
for (; *name && *name == *opt; name++, opt++);
if (*opt && *opt != '=') continue;
match = i;
if (!*name) {
cnt = 1;
break;
}
cnt++;
}
if (cnt==1) {
i = match;
optind++;
optopt = longopts[i].val;
if (*opt == '=') {
if (!longopts[i].has_arg) {
if (colon || !opterr)
return '?';
__getopt_msg(
"Option does not take an argument: ",
longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optarg = opt+1;
} else if (longopts[i].has_arg == required_argument) {
if (!(optarg = argv[optind])) {
if (colon) return ':';
if (!opterr) return '?';
__getopt_msg(
"Option requires an argument: ",
longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optind++;
}
if (idx) *idx = i;
if (longopts[i].flag) {
*longopts[i].flag = longopts[i].val;
return 0;
}
return longopts[i].val;
}
if (argv[optind][1] == '-') {
if (!colon && opterr)
__getopt_msg(cnt ?
"Option is ambiguous: " :
"Unrecognized option: ",
argv[optind]+2,
strlen(argv[optind]+2));
optind++;
return '?';
}
}
return getopt(argc, argv, optstring);
}
static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{
int ret, skipped, resumed;
if (!optind || optreset) {
optreset = 0;
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind]) return -1;
skipped = optind;
if (optstring[0] != '+' && optstring[0] != '-') {
int i;
for (i=optind; ; i++) {
if (i >= argc || !argv[i]) return -1;
if (argv[i][0] == '-' && argv[i][1]) break;
}
optind = i;
}
resumed = optind;
ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
if (resumed > skipped) {
int i, cnt = optind-resumed;
for (i=0; i<cnt; i++)
permute(argv, skipped, optind-1);
optind = skipped + cnt;
}
return ret;
}
int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}
int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
}

45
src/getopt.h Normal file
View File

@@ -0,0 +1,45 @@
/*
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.
*/
#ifndef _GETOPT_H
#define _GETOPT_H
int getopt(int, char * const [], const char *);
extern char *optarg;
extern int optind, opterr, optopt, optreset;
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long(int, char *const *, const char *, const struct option *, int *);
int getopt_long_only(int, char *const *, const char *, const struct option *, int *);
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#endif

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;
}

714
src/kytunblock.c Normal file
View File

@@ -0,0 +1,714 @@
/*
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/proc_fs.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;
}
++global_stats.sent_counter;
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);
++global_stats.all_packet_counter;
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);
++global_stats.packet_counter;
switch(vrd) {
case PKT_ACCEPT:
nf_verdict = NF_ACCEPT;
break;
case PKT_DROP:
++global_stats.target_counter;
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) */
#ifdef CONFIG_PROC_FS
static int proc_stats_show(struct seq_file *s, void *v) {
seq_printf(s, "youtubeUnblock stats: \n"
"\tCatched: %ld packets\n"
"\tProcessed: %ld packets\n"
"\tTargetted: %ld packets\n"
"\tSent over socket %ld packets\n",
global_stats.all_packet_counter, global_stats.packet_counter,
global_stats.target_counter, global_stats.sent_counter);
return 0;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0)
static int proc_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_stats_show, NULL);
}
static const struct file_operations proc_stats_operations = {
.open = proc_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif /* KERNEL_VERSION */
#endif /* CONFIG_PROC_FS */
static int __init ykb_init(void) {
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 */
#ifdef CONFIG_PROC_FS
if (!
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0)
proc_create_single("kyoutubeUnblock", 0, NULL, proc_stats_show)
#else
proc_create("kyoutubeUnblock", 0, NULL, &proc_stats_operations)
#endif
) {
lgwarning("kyoutubeUnblock procfs entry creation failed");
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
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
#ifdef CONFIG_PROC_FS
remove_proc_entry("kyoutubeUnblock", NULL);
#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 */

767
src/mangle.c Normal file
View File

@@ -0,0 +1,767 @@
/*
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"
#include "config.h"
#include "utils.h"
#include "quic.h"
#include "logging.h"
#include "tls.h"
#ifndef KERNEL_SPACE
#include <stdlib.h>
#else
#include "linux/inet.h"
#endif
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;
size_t iph_len;
const uint8_t *ip_payload;
size_t ip_payload_len;
const char *bpt;
int transport_proto = -1;
int ipver = netproto_version(raw_payload, raw_payload_len);
int ret;
lgtrace_start();
lgtrace_wr("IPv%d ", ipver);
if (ipver == IP4VERSION) {
ret = ip4_payload_split((uint8_t *)raw_payload, raw_payload_len,
(struct iphdr **)&iph, &iph_len,
(uint8_t **)&ip_payload, &ip_payload_len);
if (ret < 0)
goto accept;
transport_proto = iph->protocol;
}
#ifndef NO_IPV6
else if (ipver == IP6VERSION && config->use_ipv6) {
ret = ip6_payload_split((uint8_t *)raw_payload, raw_payload_len,
(struct ip6_hdr **)&ip6h, &iph_len,
(uint8_t **)&ip_payload, &ip_payload_len);
if (ret < 0)
goto accept;
transport_proto = ip6h->ip6_nxt;
}
#endif
else {
lgtrace("Unknown layer 3 protocol version: %d", ipver);
goto accept;
}
if (LOG_LEVEL >= VERBOSE_TRACE) {
bpt = inet_ntop(
ipver == IP4VERSION ? AF_INET : AF_INET6,
ipver == IP4VERSION ? (void *)(&iph->saddr) :
(void *)(&ip6h->ip6_src),
ylgh_curptr, ylgh_leftbuf);
if (bpt != NULL) {
ret = strnlen(bpt, ylgh_leftbuf);
ylgh_leftbuf -= ret;
ylgh_curptr += ret;
}
lgtrace_wr(" => ");
bpt = inet_ntop(
ipver == IP4VERSION ? AF_INET : AF_INET6,
ipver == IP4VERSION ? (void *)(&iph->daddr) :
(void *)(&ip6h->ip6_dst),
ylgh_curptr, ylgh_leftbuf);
if (bpt != NULL) {
ret = strnlen(bpt, ylgh_leftbuf);
ylgh_leftbuf -= ret;
ylgh_curptr += ret;
}
lgtrace_wr(" ");
const uint8_t *transport_payload = NULL;
size_t transport_payload_len = 0;
int sport = -1, dport = -1;
if (transport_proto == IPPROTO_TCP) {
lgtrace_wr("TCP ");
const struct tcphdr *tcph;
ret = tcp_payload_split((uint8_t *)raw_payload, raw_payload_len,
NULL, NULL,
(struct tcphdr **)&tcph, NULL,
(uint8_t **)&transport_payload, &transport_payload_len);
if (ret == 0) {
sport = ntohs(tcph->source);
dport = ntohs(tcph->dest);
}
} else if (transport_proto == IPPROTO_UDP) {
lgtrace_wr("UDP ");
const struct udphdr *udph = ((const struct udphdr *)ip_payload);
ret = udp_payload_split((uint8_t *)raw_payload, raw_payload_len,
NULL, NULL,
(struct udphdr **)&udph,
(uint8_t **)&transport_payload, &transport_payload_len);
if (ret == 0) {
sport = ntohs(udph->source);
dport = ntohs(udph->dest);
}
}
lgtrace_wr("%d => %d ", sport, dport);
lgtrace_write();
lgtrace_wr("Transport payload: [ ");
for (int i = 0; i < min((int)16, (int)transport_payload_len); i++) {
lgtrace_wr("%02x ", transport_payload[i]);
}
lgtrace_wr("]");
lgtrace_write();
}
int verdict = PKT_CONTINUE;
ITER_CONFIG_SECTIONS(config, section) {
lgtrace_wr("Section #%d: ", CONFIG_SECTION_NUMBER(section));
switch (transport_proto) {
case IPPROTO_TCP:
verdict = process_tcp_packet(section, raw_payload, raw_payload_len);
break;
case IPPROTO_UDP:
verdict = process_udp_packet(section, raw_payload, raw_payload_len);
break;
}
if (verdict == PKT_CONTINUE) {
lgtrace_wr("continue_flow");
lgtrace_write();
continue;
}
lgtrace_write();
goto ret_verdict;
}
accept:
verdict = PKT_ACCEPT;
ret_verdict:
switch (verdict) {
case PKT_ACCEPT:
lgtrace_wr("accept");
break;
case PKT_DROP:
lgtrace_wr("drop");
break;
default:
lgtrace_wr("unknown verdict: %d", verdict);
}
lgtrace_end();
return verdict;
}
int process_tcp_packet(const struct section_config_t *section, const uint8_t *raw_payload, size_t raw_payload_len) {
const void *ipxh;
size_t iph_len;
const struct tcphdr *tcph;
size_t tcph_len;
const uint8_t *data;
size_t dlen;
int ipxv = netproto_version(raw_payload, raw_payload_len);
int ret = tcp_payload_split((uint8_t *)raw_payload, raw_payload_len,
(void *)&ipxh, &iph_len,
(struct tcphdr **)&tcph, &tcph_len,
(uint8_t **)&data, &dlen);
if (ret < 0) {
return PKT_ACCEPT;
}
// As defined by TLS standard.
if (section->dport_filter && ntohs(tcph->dest) != 443) {
return PKT_ACCEPT;
}
if (tcph->syn && section->synfake) {
lgtrace_addp("TCP syn alter");
size_t fake_len = section->fake_sni_pkt_sz;
if (section->synfake_len)
fake_len = min((int)section->synfake_len, (int)fake_len);
size_t payload_len = iph_len + tcph_len + fake_len;
uint8_t *payload = malloc(payload_len);
if (payload == NULL) {
lgerror(-ENOMEM, "Allocation error");
return PKT_ACCEPT;
}
memcpy(payload, ipxh, iph_len);
memcpy(payload + iph_len, tcph, tcph_len);
memcpy(payload + iph_len + tcph_len, section->fake_sni_pkt, fake_len);
struct tcphdr *tcph = (struct tcphdr *)(payload + iph_len);
if (ipxv == IP4VERSION) {
struct iphdr *iph = (struct iphdr *)payload;
iph->tot_len = htons(iph_len + tcph_len + fake_len);
set_ip_checksum(payload, iph_len);
set_tcp_checksum(tcph, iph, iph_len);
} else if (ipxv == IP6VERSION) {
struct ip6_hdr *ip6h = (struct ip6_hdr *)payload;
ip6h->ip6_plen = ntohs(tcph_len + fake_len);
set_ip_checksum(ip6h, iph_len);
set_tcp_checksum(tcph, ip6h, iph_len);
}
ret = instance_config.send_raw_packet(payload, payload_len);
if (ret < 0) {
lgerror(ret, "send_syn_altered");
free(payload);
return PKT_ACCEPT;
}
free(payload);
return PKT_DROP;
}
if (tcph->syn)
return PKT_CONTINUE;
if (!section->tls_enabled)
return PKT_CONTINUE;
struct tls_verdict vrd = analyze_tls_data(section, data, dlen);
lgtrace_addp("TLS analyzed");
if (vrd.sni_len != 0) {
lgtrace_addp("SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
}
if (vrd.target_sni) {
lgdebug("Target SNI detected: %.*s", vrd.sni_len, vrd.sni_ptr);
size_t target_sni_offset = vrd.target_sni_ptr - data;
size_t payload_len = raw_payload_len;
uint8_t *payload = malloc(raw_payload_len);
if (payload == NULL) {
lgerror(-ENOMEM, "Allocation error");
return PKT_ACCEPT;
}
memcpy(payload, raw_payload, raw_payload_len);
void *iph;
size_t iph_len;
struct tcphdr *tcph;
size_t tcph_len;
uint8_t *data;
size_t dlen;
int ret = tcp_payload_split(payload, payload_len,
&iph, &iph_len, &tcph, &tcph_len,
&data, &dlen);
if (ret < 0) {
lgerror(ret, "tcp_payload_split in targ_sni");
goto accept_lc;
}
if (section->fk_winsize) {
tcph->window = htons(section->fk_winsize);
set_tcp_checksum(tcph, iph, iph_len);
}
/*
if (0) {
int delta = 2;
ret = seqovl_packet(payload, &payload_len, delta);
int ret = tcp_payload_split(payload, payload_len,
&iph, &iph_len, &tcph, &tcph_len,
&data, &dlen);
if (ret < 0) {
lgerror(ret, "seqovl_packet delta %d", delta);
}
}
*/
if (dlen > AVAILABLE_MTU) {
lgdebug("WARNING! Client Hello packet is too big and may cause issues!");
}
if (section->fake_sni) {
post_fake_sni(args_default_fake_type(section), iph, iph_len, tcph, tcph_len);
}
size_t ipd_offset;
size_t mid_offset;
switch (section->fragmentation_strategy) {
case FRAG_STRAT_TCP:
{
ipd_offset = target_sni_offset;
mid_offset = ipd_offset + vrd.target_sni_len / 2;
size_t poses[2];
int cnt = 0;
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
poses[cnt++] = section->frag_sni_pos;
}
if (section->frag_middle_sni) {
poses[cnt++] = mid_offset;
}
if (cnt > 1 && poses[0] > poses[1]) {
size_t tmp = poses[0];
poses[0] = poses[1];
poses[1] = tmp;
}
ret = send_tcp_frags(section, payload, payload_len, poses, cnt, 0);
if (ret < 0) {
lgerror(ret, "tcp4 send frags");
goto accept_lc;
}
goto drop_lc;
}
break;
case FRAG_STRAT_IP:
if (ipxv == IP4VERSION) {
ipd_offset = ((char *)data - (char *)tcph) + target_sni_offset;
mid_offset = ipd_offset + vrd.target_sni_len / 2;
mid_offset += 8 - mid_offset % 8;
size_t poses[2];
int cnt = 0;
if (section->frag_sni_pos && dlen > section->frag_sni_pos) {
poses[cnt] = section->frag_sni_pos + ((char *)data - (char *)tcph);
poses[cnt] += 8 - poses[cnt] % 8;
cnt++;
}
if (section->frag_middle_sni) {
poses[cnt++] = mid_offset;
}
if (cnt > 1 && poses[0] > poses[1]) {
size_t tmp = poses[0];
poses[0] = poses[1];
poses[1] = tmp;
}
ret = send_ip4_frags(section, payload, payload_len, poses, cnt, 0);
if (ret < 0) {
lgerror(ret, "ip4 send frags");
goto accept_lc;
}
goto drop_lc;
} else {
lginfo("WARNING: IP fragmentation is supported only for IPv4");
goto default_send;
}
break;
}
default_send:
ret = instance_config.send_raw_packet(payload, payload_len);
if (ret < 0) {
lgerror(ret, "raw pack send");
goto accept_lc;
}
goto drop_lc;
accept_lc:
free(payload);
return PKT_ACCEPT;
drop_lc:
free(payload);
return PKT_DROP;
}
return PKT_CONTINUE;
}
int process_udp_packet(const struct section_config_t *section, const uint8_t *pkt, size_t pktlen) {
const void *iph;
size_t iph_len;
const struct udphdr *udph;
const uint8_t *data;
size_t dlen;
int ret = udp_payload_split((uint8_t *)pkt, pktlen,
(void **)&iph, &iph_len,
(struct udphdr **)&udph,
(uint8_t **)&data, &dlen);
if (ret < 0) {
lgtrace_addp("undefined");
goto accept;
}
if (!detect_udp_filtered(section, pkt, pktlen))
goto continue_flow;
if (section->udp_mode == UDP_MODE_DROP)
goto drop;
else if (section->udp_mode == UDP_MODE_FAKE) {
for (int i = 0; i < section->udp_fake_seq_len; i++) {
uint8_t *fake_udp;
size_t fake_udp_len;
struct udp_fake_type fake_type = {
.fake_len = section->udp_fake_len,
.strategy = {
.strategy = section->udp_faking_strategy,
.faking_ttl = section->faking_ttl,
},
};
ret = gen_fake_udp(fake_type, iph, iph_len, udph, &fake_udp, &fake_udp_len);
if (ret < 0) {
lgerror(ret, "gen_fake_udp");
goto erret;
}
lgtrace_addp("post fake udp #%d", i + 1);
ret = instance_config.send_raw_packet(fake_udp, fake_udp_len);
if (ret < 0) {
lgerror(ret, "send fake udp");
goto erret_lc;
}
free(fake_udp);
continue;
erret_lc:
free(fake_udp);
erret:
goto accept;
}
ret = instance_config.send_raw_packet(pkt, pktlen);
goto drop;
}
continue_flow:
return PKT_CONTINUE;
accept:
return PKT_ACCEPT;
drop:
return PKT_DROP;
}
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) {
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
return instance_config.send_delayed_packet(
packet, pktlen, section->seg2_delay);
} else {
return instance_config.send_raw_packet(
packet, pktlen);
}
} else {
size_t f1len = pktlen;
uint8_t *frag1 = malloc(f1len);
if (frag1 == NULL) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
size_t f2len = pktlen;
uint8_t *frag2 = malloc(f2len);
if (frag2 == NULL) {
lgerror(-ENOMEM, "Allocation error");
free(frag1);
return -ENOMEM;
}
int ret;
if (dvs > poses[0]) {
lgerror(-EINVAL, "send_frags: Recursive dvs(%zu) is more than poses0(%zu)", dvs, poses[0]);
ret = -EINVAL;
goto erret_lc;
}
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 %zu, position: %zu, recursive dvs: %zu", pktlen, poses[0], dvs);
goto erret_lc;
}
if (section->frag_sni_reverse)
goto send_frag2;
send_frag1:
ret = send_ip4_frags(section, frag1, f1len, NULL, 0, 0);
if (ret < 0) {
goto erret_lc;
}
if (section->frag_sni_reverse)
goto out_lc;
send_frag2:
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_frag1;
out_lc:
free(frag1);
free(frag2);
goto out;
erret_lc:
free(frag1);
free(frag2);
return ret;
}
out:
return 0;
}
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) {
lgtrace_addp("raw send packet of %zu bytes with %zu dvs", pktlen, dvs);
if (section->seg2_delay && ((dvs > 0) ^ section->frag_sni_reverse)) {
return instance_config.send_delayed_packet(
packet, pktlen, section->seg2_delay);
} else {
return instance_config.send_raw_packet(
packet, pktlen);
}
} else {
size_t f1len = pktlen;
uint8_t *frag1 = malloc(f1len);
if (frag1 == NULL) {
lgerror(-ENOMEM, "Allocation error");
return -ENOMEM;
}
size_t f2len = pktlen;
uint8_t *frag2 = malloc(f2len);
if (frag2 == NULL) {
lgerror(-ENOMEM, "Allocation error");
free(frag1);
return -ENOMEM;
}
int ret;
if (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 %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 %zu, position: %zu", pktlen, poses[0]);
goto erret_lc;
}
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;
send_fake:
if (section->frag_sni_faked) {
size_t iphfl, tcphfl;
void *iph;
struct tcphdr *tcph;
ret = tcp_payload_split(frag2, f2len, &iph, &iphfl, &tcph, &tcphfl, NULL, NULL);
struct fake_type f_type = args_default_fake_type(section);
if ((f_type.strategy.strategy & FAKE_STRAT_PAST_SEQ) == FAKE_STRAT_PAST_SEQ) {
f_type.strategy.strategy ^= FAKE_STRAT_PAST_SEQ;
f_type.strategy.strategy |= FAKE_STRAT_RAND_SEQ;
f_type.strategy.randseq_offset = dvs;
}
f_type.seg2delay = section->seg2_delay;
post_fake_sni(f_type, iph, iphfl, tcph, tcphfl);
}
if (section->frag_sni_reverse)
goto send_frag1;
send_frag2:
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:
free(frag1);
free(frag2);
goto out;
erret_lc:
free(frag1);
free(frag2);
return ret;
}
out:
return 0;
}
int post_fake_sni(struct fake_type f_type,
const void *iph, unsigned int iph_len,
const struct tcphdr *tcph, unsigned int tcph_len) {
uint8_t rfsiph[128];
uint8_t rfstcph[60];
int ret;
int ipxv = netproto_version(iph, iph_len);
memcpy(rfsiph, iph, iph_len);
memcpy(rfstcph, tcph, tcph_len);
void *fsiph = (void *)rfsiph;
struct tcphdr *fstcph = (void *)rfstcph;
ITER_FAKE_STRAT(f_type.strategy.strategy, strategy) {
struct fake_type fake_seq_type = f_type;
fake_seq_type.strategy.strategy = strategy;
// one goes for default fake
for (int i = 0; i < fake_seq_type.sequence_len; i++) {
uint8_t *fake_sni;
size_t fake_sni_len;
ret = gen_fake_sni(
fake_seq_type,
fsiph, iph_len, fstcph, tcph_len,
&fake_sni, &fake_sni_len);
if (ret < 0) {
lgerror(ret, "gen_fake_sni");
return ret;
}
lgtrace_addp("post fake sni #%d", i + 1);
if (f_type.seg2delay) {
ret = instance_config.send_delayed_packet(fake_sni, fake_sni_len, f_type.seg2delay);
} else {
ret = instance_config.send_raw_packet(fake_sni, fake_sni_len);
}
if (ret < 0) {
lgerror(ret, "send fake sni");
goto erret_lc;
}
size_t iph_len;
size_t tcph_len;
size_t plen;
ret = tcp_payload_split(
fake_sni, fake_sni_len,
&fsiph, &iph_len,
&fstcph, &tcph_len,
NULL, &plen);
if (ret < 0) {
lgtrace_addp("continue fake seq");
goto erret_lc;
}
if (!(strategy == FAKE_STRAT_PAST_SEQ ||
strategy == FAKE_STRAT_RAND_SEQ)) {
fstcph->seq = htonl(ntohl(fstcph->seq) + plen);
}
if (ipxv == IP4VERSION) {
((struct iphdr *)fsiph)->id = htons(ntohs(((struct iphdr *)fsiph)->id) + 1);
}
memcpy(rfsiph, fsiph, iph_len);
memcpy(rfstcph, fstcph, tcph_len);
fsiph = (void *)rfsiph;
fstcph = (void *)rfstcph;
free(fake_sni);
continue;
erret_lc:
free(fake_sni);
return ret;
}
}
return 0;
}

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 (ret < 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
);
if (ret < 0) {
lgerror(ret, "quic_parse_data");
goto error_nfr;
}
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;
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;
}

10
src/raw_replacements.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef RAW_REPLACEMENTS_H
#define RAW_REPLACEMENTS_H
#define FAKE_SNI_MAXLEN 1500
static const char fake_sni[] = "\026\003\001\002\000\001\000\001\374\003\003\323[\345\201f\362\200:B\356Uq\355X\315i\235*\021\367\331\272\a>\233\254\355\307/\342\372\265 \275\2459l&r\222\313\361\3729`\376\256\233\333O\001\373\33050\r\260f,\231\035 \324^\000>\023\002\023\003\023\001\300,\3000\000\237\314\251\314\250\314\252\300+\300/\000\236\300$\300(\000k\300#\300'\000g\300\n\300\024\0009\300\t\300\023\0003\000\235\000\234\000=\000<\0005\000/\000\377\001\000\001u\000\000\000\023\000\021\000\000\016www.google.com\000\v\000\004\003\000\001\002\000\n\000\026\000\024\000\035\000\027\000\036\000\031\000\030\001\000\001\001\001\002\001\003\001\004\000\020\000\016\000\f\002h2\bhttp/1.1\000\026\000\000\000\027\000\000\0001\000\000\000\r\0000\000.\004\003\005\003\006\003\b\a\b\b\b\032\b\033\b\034\b\t\b\n\b\v\b\004\b\005\b\006\004\001\005\001\006\001\003\003\003\001\003\002\004\002\005\002\006\002\000+\000\005\004\003\004\003\003\000-\000\002\001\001\0003\000&\000$\000\035\000 \004\224\206\021\256\f\222\266\3435\216\202\342\2573\341\3503\2107\341\023\016\240r|6\000^K\310s\000\025\000\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
static const char fake_sni_old[] = "\026\003\001\004\316\001\000\004\312\003\003K+\272\314\340\306\374>dw%\f\223\346\225\270\270~\335\027\f\264\341H\267\357\303\216T\322[\371 \245\320\212V6\374\3706\232\0216B\325\273P\b\300>\0332>\362\323\033\322\301\204\022f8\223\214\000\"\023\001\023\003\023\002\300+\300/\314\251\314\250\300,\3000\300\n\300\t\300\023\300\024\000\234\000\235\000/\0005\001\000\004_\000\000\000\023\000\021\000\000\016www.google.com\000\027\000\000\377\001\000\001\000\000\n\000\016\000\f\000\035\000\027\000\030\000\031\001\000\001\001\000\v\000\002\001\000\000\020\000\v\000\t\bhttp/1.1\000\005\000\005\001\000\000\000\000\000\"\000\n\000\b\004\003\005\003\006\003\002\003\0003\000k\000i\000\035\000 \333C\212\234-\t\237#\202\\\231\311\022]\333\341t(\t\276U\373u\234\316J~,^|*Z\000\027\000A\004k\n\255\254\376X\226t\001;n~\033\034.\245\027\024\3762_\352$\374\346^f\fF,\201\275\263\336O\231\001\032\200\357dI\266y\031\323\311vR\232\004\r\366FT\004\335\326\356\256\230B\t\313\000*\000\000\000+\000\005\004\003\004\003\003\000\r\000\030\000\026\004\003\005\003\006\003\b\004\b\005\b\006\004\001\005\001\006\001\002\003\002\001\000-\000\002\001\001\000\034\000\002@\001\376\r\0029\000\000\001\000\003\344\000 \337\306\243\332Y\033\a\252\352\025\365Z\035\223\226\304\255\363\215G\356g\344%}7\217\033n\211^\201\002\017g\267\334\326OD}\336\341ZC\230\226'\225\313\357\211\\\242\273\030k\216\377U\315\206\2410\200\203\332Z\223\005\370\b\304\370f\017\200\023\241\223~?\270{\037b\312\001\270\227\366\356\352\002\314\351\006\237\241q\226\300\314\321o\247{\201\317\230}B\005T\3660\335\320\332r?S\217\tq\036\031\326I|\237]\311 c\f\024r\031\310W\373\257\314q)q\030\237\261\227\217Kd?\257'G\320\020\340\256ND\247\005\341\324\024OP>\370\350\270b\311wAj\t\311\213\365i\203\230x\207\354\245<\274\202\230c\v0Y\263\364\022\303a\200\022\031\314\271rl=\327\336\001\327\264\267\342\353\352=\354[u\224\260\257\034\004\232\023\226}\227\030e\221\"\350\207\027dId\324\305\362N:\035\307`\204\337\201;\221\320\266b\362hrH\345e\206\246%\006\020a4\3430\036\225\215\274\275\360Q&\271\237)\222uK\362\017o\220\226W\357\267#\357\v\023\354\213\2629\331\ad\005/~6k\000[\247\301\270\310qJ\004\303|m5\363\376Y\002\243}6\251x\024\331)GH\335\205rI\032\f\210\a\212\347]\271\030\347.\021\213\365\026\030\340/Ny\r\332\3577\3203\026iX}>\2507\327&XRXU!\017\270I\313\352\350^?\352Uss\017\266pF\222NI\245\307_\305#\361\352\243+-\266\317Q\036s\243\277\355{S&\023>\275\360\215\032V\237XOY\345u>\002\305\252T\354\035\327v{P\352M\233\366\221\270\377\251\261f+rF\201wL2W\266X\252\242X\2536I\337c\205uZ\254Fe\305h\t\371\376\216r\336Y\327h\347*\331\257-ZQ{(\336\226\206\017\037\036\021\341\027z\033\254\235\252\227\224\004?p\243\351\\\263\352\205\327#W\345\255\256\375\267bP\3047\363!*K\003t\212(\306\214P\215\3506j\025\375\213e\254s\000)\001\034\000\367\000\361\002\276W%\232?\326\223\277\211v\017\a\361\347\312N\226\024L\260v\210\271j\324[|\270\344\3773\321-\313b>~\310\253XIR\324)&;\033{g;)\344\255\226\370\347I\\y\020\324\360\211vC\310\226s\267|\273$\341\332\2045qh\245w\2255\214\316\030\255\301\326C\343\304=\245\231h`yd\000#s\002\370\374Z\0336\245\361\226\222\306\032k\2457\016h\314(R;\326T~EHH\352\307\023^\247\363\321`V\340\253Z\233\357\227I\373\337z\177\nv\261\252\371\017\226\223\345\005\315y4\b\236N0\2630\017\215c\305&L\260\346J\237\203Q(\335W\027|>\3553\275j\307?W5\3463kc\350\262C\361 \037w!\371}\214\"I\377|\331@a;\342\3566\312\272Z\327u7\204'\215YBLL\235\236\242\345\215\245T\211a\312\263\342\000! \221\202X$\302\317\203\246\207c{\231\330\264\324\\k\271\272\336\356\002|\261O\207\030+\367P\317\356";
#endif /*RAW_REPLACEMENTS_H*/

380
src/tls.c Normal file
View File

@@ -0,0 +1,380 @@
/*
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
) {
size_t offset, offlen;
int ret;
*vrd = (struct tls_verdict){0};
if (dlen <= 1) {
return 0;
}
if (section->all_domains) {
vrd->target_sni = 1;
vrd->sni_len = 0;
vrd->sni_ptr = data + dlen / 2;
vrd->target_sni_ptr = vrd->sni_ptr;
vrd->target_sni_len = vrd->sni_len;
return 0;
}
// It is safe for multithreading, so dp mutability is ok
ret = trie_process_str((struct trie_container *)&section->sni_domains, data, dlen, 0, &offset, &offlen);
if (ret) {
vrd->target_sni = 1;
vrd->sni_len = offlen;
vrd->sni_ptr = data + offset;
vrd->target_sni_ptr = vrd->sni_ptr;
vrd->target_sni_len = vrd->sni_len;
}
return 0;
}
static int analyze_sni_str(
const struct section_config_t *section,
const char *sni_name, int sni_len,
struct tls_verdict *vrd
) {
int ret;
size_t offset, offlen;
if (section->all_domains) {
vrd->target_sni = 1;
goto check_domain;
}
// It is safe for multithreading, so dp mutability is ok
ret = trie_process_str((struct trie_container *)&section->sni_domains,
(const uint8_t *)sni_name, sni_len, TRIE_OPT_MAP_TO_END, &offset, &offlen);
if (ret) {
vrd->target_sni = 1;
vrd->target_sni_ptr = (const uint8_t *)sni_name + offset;
vrd->target_sni_len = offlen;
}
check_domain:
if (vrd->target_sni == 1) {
// It is safe for multithreading, so dp mutability is ok
ret = trie_process_str((struct trie_container *)&section->exclude_sni_domains,
(const uint8_t *)sni_name, sni_len, TRIE_OPT_MAP_TO_END, &offset, &offlen);
if (ret) {
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 */

197
src/trie.c Normal file
View File

@@ -0,0 +1,197 @@
/*
youtubeUnblock - https://github.com/Waujito/youtubeUnblock
Copyright (C) 2024-2025 Vadim Vetrov <vetrovvd@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* This is slightly optimized Aho-Corasick implementation
*
* Big thanks to e-maxx http://e-maxx.ru/algo/aho_corasick
* for the best description and reference code samples
*/
#include "trie.h"
int trie_init(struct trie_container *trie) {
void *vx = malloc(sizeof(struct trie_vertex) * TRIE_STARTSZ);
if (vx == NULL) {
return -ENOMEM;
}
trie->vx = vx;
trie->arrsz = TRIE_STARTSZ;
trie->sz = 1;
struct trie_vertex *trx = trie->vx;
trx->p = trx->link = -1;
trx->leaf = 0;
trx->depth = 0;
trx->pch = 0;
memset(trx->go, 0xff, sizeof(trie->vx[0].go));
return 0;
}
void trie_destroy(struct trie_container *trie) {
trie->arrsz = 0;
trie->sz = 0;
free(trie->vx);
trie->vx = NULL;
}
/**
*
* Increases trie vertex container size.
* Returns new vertex index or ret < 0 on error
*
*/
static int trie_push_vertex(struct trie_container *trie) {
if (trie->sz == NMAX - 1) {
return -EINVAL;
}
if (trie->arrsz == trie->sz) { // realloc
void *pt = realloc(trie->vx,
sizeof(struct trie_vertex) * trie->arrsz * 2);
if (pt == NULL) {
return -ENOMEM;
}
trie->arrsz *= 2;
trie->vx = pt;
}
return trie->sz++;
}
int trie_add_string(struct trie_container *trie,
const uint8_t *str, size_t strlen) {
if (trie == NULL || trie->vx == NULL) {
return -EINVAL;
}
int v = 0;
int nv;
for (size_t i = 0; i < strlen; ++i) {
uint8_t c = str[i];
if (c >= TRIE_ALPHABET) {
return -EINVAL;
}
if (trie->vx[v].go[c] == -1) {
nv = trie_push_vertex(trie);
if (nv < 0) {
return nv;
}
struct trie_vertex *tvx = trie->vx + nv;
memset(tvx->go, 0xff, sizeof(tvx->go));
tvx->link = -1;
tvx->p = v;
tvx->depth = trie->vx[v].depth + 1;
tvx->leaf = 0;
tvx->pch = c;
trie->vx[v].go[c] = nv;
}
v = trie->vx[v].go[c];
}
if (v != 0) {
trie->vx[v].leaf = 1;
}
return 0;
}
static int trie_go(struct trie_container *trie,
int v, uint8_t c);
static int trie_get_link(struct trie_container *trie,
int v) {
struct trie_vertex *tvx = trie->vx + v;
if (tvx->link == -1) {
if (v == 0 || tvx->p == 0) {
tvx->link = 0;
} else {
tvx->link = trie_go(trie,
trie_get_link(trie, tvx->p), tvx->pch);
}
}
return tvx->link;
}
static int trie_go(struct trie_container *trie, int v, uint8_t c) {
struct trie_vertex *tvx = trie->vx + v;
if (tvx->go[c] == -1) {
tvx->go[c] = v == 0 ? 0 :
trie_go(trie, trie_get_link(trie, v), c);
}
return tvx->go[c];
}
int trie_process_str(
struct trie_container *trie,
const uint8_t *str, size_t strlen,
int flags,
size_t *offset, size_t *offlen
) {
if (trie == NULL || trie->vx == NULL) {
return 0;
}
int v = 0;
size_t i = 0;
uint8_t c;
int len;
for (; i < strlen; ++i) {
c = str[i];
if (c >= TRIE_ALPHABET) {
v = 0;
continue;
}
v = trie->vx[v].go[c] != -1 ? trie->vx[v].go[c] :
trie_go(trie, v, str[i]);
if (trie->vx[v].leaf &&
((flags & TRIE_OPT_MAP_TO_END) != TRIE_OPT_MAP_TO_END ||
i == strlen - 1)
) {
++i;
break;
}
}
len = trie->vx[v].depth;
if ( trie->vx[v].leaf &&
i >= len
) {
size_t sp = i - len;
*offset = sp;
*offlen = len;
return 1;
}
return 0;
}

92
src/trie.h Normal file
View File

@@ -0,0 +1,92 @@
/*
youtubeUnblock - https://github.com/Waujito/youtubeUnblock
Copyright (C) 2024-2025 Vadim Vetrov <vetrovvd@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* This is slightly optimized Aho-Corasick implementation
*
* Big thanks to e-maxx http://e-maxx.ru/algo/aho_corasick
* for the best description and reference code samples
*
*/
/**
*
* This algorithm allows us to search inside the string
* for a list of patterns in the linear time.
*
* The algorithm will lazily initialize itself while
* youtubeUnblock works. Lazy initializations considered
* safe for multithreading and operate without atomicity
* or synchronization primitives.
*
*/
#ifndef TRIE_H
#define TRIE_H
#include "types.h"
// ASCII alphabet
#define TRIE_ALPHABET 128
// Maximum of vertexes in the trie
#define NMAX ((1 << 15) - 1)
struct trie_vertex {
int leaf; // boolean flag
int depth; // depth of tree (length of substring)
int p; // parent
uint8_t pch; // vertex char
int link; // sufflink
int16_t go[TRIE_ALPHABET]; // dynamically filled pushes
};
struct trie_container {
struct trie_vertex *vx;
size_t arrsz;
size_t sz;
};
#define TRIE_STARTSZ 32
int trie_init(struct trie_container *trie);
void trie_destroy(struct trie_container *trie);
int trie_add_string(struct trie_container *trie,
const uint8_t *str, size_t strlen);
/**
* Aligns the pattern to the end
*/
#define TRIE_OPT_MAP_TO_END (1 << 1)
/**
* Searches the string for the patterns.
* flags is TRIE_OPT binary mask with options for search.
* offset, offlen are destination variables with
* offset of the given string and length of target.
*
* returns 1 if target found, 0 otherwise
*/
int trie_process_str(
struct trie_container *trie,
const uint8_t *str, size_t strlen,
int flags,
size_t *offset, size_t *offlen
);
#endif

147
src/types.h Normal file
View File

@@ -0,0 +1,147 @@
/*
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
#include <asm/byteorder.h>
#ifdef KERNEL_SPACE
#include <linux/errno.h> // IWYU pragma: export
#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))
#if !_NO_GETRANDOM
#include <sys/random.h> // IWYU pragma: export
#endif
#endif /* SPACES */
// Network specific structures
#ifdef KERNEL_SPACE
#include <linux/stddef.h> // IWYU pragma: export
#include <linux/net.h> // IWYU pragma: export
#include <linux/in.h> // IWYU pragma: export
#include <linux/ip.h> // IWYU pragma: export
#include <linux/ipv6.h> // IWYU pragma: export
#include <linux/tcp.h> // IWYU pragma: export
#include <linux/version.h>
#define free kfree
#define malloc(size) kmalloc((size), GFP_KERNEL)
#define realloc(pt, size) krealloc((pt), (size), GFP_KERNEL)
#define calloc(n, size) kcalloc((n), (size), GFP_KERNEL)
#define ip6_hdr ipv6hdr
/* from <netinet/ip.h> */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
#ifdef __LITTLE_ENDIAN
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN
#elif defined(__BIG_ENDIAN)
#define __LITTLE_ENDIAN 1234
#define __BYTE_ORDER __BIG_ENDIAN
#else
#error "Unsupported endian"
#endif
#define ip6_plen payload_len
#define ip6_nxt nexthdr
#define ip6_hops hop_limit
#define ip6_hlim hop_limit
#define ip6_src saddr
#define ip6_dst daddr
#else /* USER_SPACE */
#include <arpa/inet.h> // IWYU pragma: export
#include <netinet/ip.h> // IWYU pragma: export
#include <netinet/ip6.h> // IWYU pragma: export
#include <netinet/tcp.h> // IWYU pragma: export
#include <netinet/udp.h> // IWYU pragma: export
#endif
#define SFREE(item) do { \
free((item)); \
(item) = NULL; \
} while (0)
#ifndef KERNEL_SPACE
#define max(a,b)__extension__\
({ \
__typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; \
})
#define min(a,b)__extension__\
({ \
__typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; \
})
#endif /* not a KERNEL_SPACE */
static inline int randint(void) {
int rnd;
#ifdef KERNEL_SPACE
get_random_bytes(&rnd, sizeof(rnd));
#else
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 */

753
src/utils.c Normal file
View File

@@ -0,0 +1,753 @@
/*
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"
#ifndef KERNEL_SPACE
#include <stdlib.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv6.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#else
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24))
#include <net/ip6_checksum.h>
#include <net/checksum.h>
#else
#include <net/checksum.h>
#endif
#endif
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph)
{
#ifdef KERNEL_SPACE
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,
IPPROTO_TCP,
csum_partial(tcph, tcp_packet_len, 0));
#else
nfq_tcp_compute_checksum_ipv4(tcph, iph);
#endif
}
void udp4_set_checksum(struct udphdr *udph, struct iphdr *iph)
{
#ifdef KERNEL_SPACE
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,
IPPROTO_UDP,
csum_partial(udph, udp_packet_len, 0));
#else
nfq_udp_compute_checksum_ipv4(udph, iph);
#endif
}
void ip4_set_checksum(struct iphdr *iph)
{
#ifdef KERNEL_SPACE
iph->check = 0;
iph->check = ip_fast_csum(iph, iph->ihl);
#else
nfq_ip_set_checksum(iph);
#endif
}
void tcp6_set_checksum(struct tcphdr *tcph, struct ip6_hdr *iph) {
#ifdef KERNEL_SPACE
tcph->check = 0;
tcph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr,
ntohs(iph->ip6_plen), IPPROTO_TCP,
csum_partial(tcph, ntohs(iph->ip6_plen), 0));
#else
nfq_tcp_compute_checksum_ipv6(tcph, iph);
#endif
}
void udp6_set_checksum(struct udphdr *udph, struct ip6_hdr *iph) {
#ifdef KERNEL_SPACE
udph->check = 0;
udph->check = csum_ipv6_magic(&iph->saddr, &iph->daddr,
ntohs(iph->ip6_plen), IPPROTO_UDP,
csum_partial(udph, ntohs(iph->ip6_plen), 0));
#else
nfq_udp_compute_checksum_ipv6(udph, iph);
#endif
}
int set_ip_checksum(void *iph, size_t iphb_len) {
int ipvx = netproto_version(iph, iphb_len);
if (ipvx == IP4VERSION) {
ip4_set_checksum(iph);
} else if (ipvx == IP6VERSION) { // IP6 has no checksums
} else
return -1;
return 0;
}
int set_tcp_checksum(struct tcphdr *tcph, void *iph, size_t iphb_len) {
int ipvx = netproto_version(iph, iphb_len);
if (ipvx == IP4VERSION) {
tcp4_set_checksum(tcph, iph);
} else if (ipvx == IP6VERSION) {
tcp6_set_checksum(tcph, iph);
} else
return -1;
return 0;
}
int set_udp_checksum(struct udphdr *udph, void *iph, size_t iphb_len) {
int ipvx = netproto_version(iph, iphb_len);
if (ipvx == IP4VERSION) {
udp4_set_checksum(udph, iph);
} else if (ipvx == IP6VERSION) {
udp6_set_checksum(udph, iph);
} else {
return -1;
}
return 0;
}
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;
}
struct iphdr *hdr = (struct iphdr *)pkt;
if (netproto_version(pkt, buflen) != IP4VERSION) {
lgerror(-EINVAL, "ip4_payload_split: ipversion");
return -EINVAL;
}
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: "
"buflen = %zu pktlen = %zu hdr_len = %zu",
buflen, pktlen, hdr_len);
return -EINVAL;
}
if (iph)
*iph = hdr;
if (iph_len)
*iph_len = hdr_len;
if (payload)
*payload = pkt + hdr_len;
if (plen)
*plen = pktlen - hdr_len;
return 0;
}
int tcp4_payload_split(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;
size_t hdr_len;
struct tcphdr *thdr;
size_t thdr_len;
uint8_t *tcph_pl;
size_t tcph_plen;
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
&tcph_pl, &tcph_plen)){
return -EINVAL;
}
if (
hdr->protocol != IPPROTO_TCP ||
tcph_plen < sizeof(struct tcphdr)) {
return -EINVAL;
}
thdr = (struct tcphdr *)(tcph_pl);
thdr_len = thdr->doff * 4;
if (thdr_len > tcph_plen) {
return -EINVAL;
}
if (iph) *iph = hdr;
if (iph_len) *iph_len = hdr_len;
if (tcph) *tcph = thdr;
if (tcph_len) *tcph_len = thdr_len;
if (payload) *payload = tcph_pl + thdr_len;
if (plen) *plen = tcph_plen - thdr_len;
return 0;
}
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;
}
struct ip6_hdr *hdr = (struct ip6_hdr *)pkt;
if (netproto_version(pkt, buflen) != 6) {
lgerror(-EINVAL, "ip6_payload_split: ip6version");
return -EINVAL;
}
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: "
"buflen = %zu pktlen = %zu", buflen, pktlen);
return -EINVAL;
}
if (iph)
*iph = hdr;
if (iph_len)
*iph_len = hdr_len;
if (payload)
*payload = pkt + hdr_len;
if (plen)
*plen = pktlen;
return 0;
}
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;
size_t hdr_len;
struct tcphdr *thdr;
size_t thdr_len;
uint8_t *tcph_pl;
size_t tcph_plen;
if (ip6_payload_split(pkt, buflen, &hdr, &hdr_len,
&tcph_pl, &tcph_plen)){
return -EINVAL;
}
if (
hdr->ip6_nxt != IPPROTO_TCP ||
tcph_plen < sizeof(struct tcphdr)) {
return -EINVAL;
}
thdr = (struct tcphdr *)(tcph_pl);
thdr_len = thdr->doff * 4;
if (thdr_len > tcph_plen) {
return -EINVAL;
}
if (iph) *iph = hdr;
if (iph_len) *iph_len = hdr_len;
if (tcph) *tcph = thdr;
if (tcph_len) *tcph_len = thdr_len;
if (payload) *payload = tcph_pl + thdr_len;
if (plen) *plen = tcph_plen - thdr_len;
return 0;
}
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);
} else if (netvers == IP6VERSION) {
return tcp6_payload_split(pkt, buflen, (struct ip6_hdr **)iph, iph_len, tcph, tcph_len, payload, plen);
} else {
lgerror(-EINVAL, "Internet Protocol version is unsupported");
return -EINVAL;
}
}
int udp4_payload_split(uint8_t *pkt, size_t buflen,
struct iphdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, size_t *plen) {
struct iphdr *hdr;
size_t hdr_len;
struct udphdr *uhdr;
uint8_t *ip_ph;
size_t ip_phlen;
if (ip4_payload_split(pkt, buflen, &hdr, &hdr_len,
&ip_ph, &ip_phlen)){
return -EINVAL;
}
if (
hdr->protocol != IPPROTO_UDP ||
ip_phlen < sizeof(struct udphdr)) {
return -EINVAL;
}
uhdr = (struct udphdr *)(ip_ph);
if (uhdr->len != 0 && ntohs(uhdr->len) != ip_phlen) {
return -EINVAL;
}
if (iph) *iph = hdr;
if (iph_len) *iph_len = hdr_len;
if (udph) *udph = uhdr;
if (payload) *payload = ip_ph + sizeof(struct udphdr);
if (plen) *plen = ip_phlen - sizeof(struct udphdr);
return 0;
}
int udp6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, size_t *plen) {
struct ip6_hdr *hdr;
size_t hdr_len;
struct udphdr *uhdr;
uint8_t *ip_ph;
size_t ip_phlen;
if (ip6_payload_split(pkt, buflen, &hdr, &hdr_len,
&ip_ph, &ip_phlen)){
return -EINVAL;
}
if (
hdr->ip6_nxt != IPPROTO_UDP ||
ip_phlen < sizeof(struct udphdr)) {
return -EINVAL;
}
uhdr = (struct udphdr *)(ip_ph);
if (uhdr->len != 0 && ntohs(uhdr->len) != ip_phlen) {
return -EINVAL;
}
if (iph) *iph = hdr;
if (iph_len) *iph_len = hdr_len;
if (udph) *udph = uhdr;
if (payload) *payload = ip_ph + sizeof(struct udphdr);
if (plen) *plen = ip_phlen - sizeof(struct udphdr);
return 0;
}
int udp_payload_split(uint8_t *pkt, size_t buflen,
void **iph, size_t *iph_len,
struct udphdr **udph,
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);
} else if (netvers == IP6VERSION) {
return udp6_payload_split(pkt, buflen, (struct ip6_hdr **)iph, iph_len, udph, payload, plen);
} else {
lgerror(-EINVAL, "Internet Protocol version is unsupported");
return -EINVAL;
}
}
// split packet to two ipv4 fragments.
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;
size_t plen;
size_t hdr_len;
int ret;
if (!frag1 || !f1len || !frag2 || !f2len)
return -EINVAL;
if ((ret = ip4_payload_split(
(uint8_t *)pkt, buflen,
&hdr, &hdr_len, (uint8_t **)&payload, &plen)) < 0) {
lgerror(ret, "ipv4_frag: TCP Header extract error");
return -EINVAL;
}
if (plen <= payload_offset) {
return -EINVAL;
}
if (payload_offset & ((1 << 3) - 1)) {
lgerror(-EINVAL, "ipv4_frag: Payload offset MUST be a multiply of 8!");
return -EINVAL;
}
size_t f1_plen = payload_offset;
size_t f1_dlen = f1_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;
}
*f1len = f1_dlen;
*f2len = f2_dlen;
memcpy(frag1, hdr, hdr_len);
memcpy(frag2, hdr, hdr_len);
memcpy(frag1 + hdr_len, payload, f1_plen);
memcpy(frag2 + hdr_len, payload + payload_offset, f2_plen);
struct iphdr *f1_hdr = (void *)frag1;
struct iphdr *f2_hdr = (void *)frag2;
uint16_t f1_frag_off = ntohs(f1_hdr->frag_off);
uint16_t f2_frag_off = ntohs(f2_hdr->frag_off);
f1_frag_off &= IP_OFFMASK;
f1_frag_off |= IP_MF;
if ((f2_frag_off & ~IP_OFFMASK) == IP_MF) {
f2_frag_off &= IP_OFFMASK;
f2_frag_off |= IP_MF;
} else {
f2_frag_off &= IP_OFFMASK;
}
f2_frag_off += (uint16_t)payload_offset / 8;
f1_hdr->frag_off = htons(f1_frag_off);
f1_hdr->tot_len = htons(f1_dlen);
f2_hdr->frag_off = htons(f2_frag_off);
f2_hdr->tot_len = htons(f2_dlen);
ip4_set_checksum(f1_hdr);
ip4_set_checksum(f2_hdr);
return 0;
}
// split packet to two tcp-on-ipv4 segments.
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;
size_t hdr_len;
struct tcphdr *tcph;
size_t tcph_len;
size_t plen;
const uint8_t *payload;
int ret;
if (!seg1 || !s1len || !seg2 || !s2len)
return -EINVAL;
if ((ret = tcp_payload_split((uint8_t *)pkt, buflen,
&hdr, &hdr_len,
&tcph, &tcph_len,
(uint8_t **)&payload, &plen)) < 0) {
lgerror(ret, "tcp_frag: tcp_payload_split");
return -EINVAL;
}
int ipvx = netproto_version(pkt, buflen);
if (ipvx == IP4VERSION) {
struct iphdr *iphdr = hdr;
if (
ntohs(iphdr->frag_off) & IP_MF ||
ntohs(iphdr->frag_off) & IP_OFFMASK) {
lgdebug("tcp_frag: ip4: frag value: %d",
ntohs(iphdr->frag_off));
lgerror(-EINVAL, "tcp_frag: ip4: ip fragmentation is set");
return -EINVAL;
}
}
if (plen <= payload_offset) {
return -EINVAL;
}
size_t s1_plen = payload_offset;
size_t s1_dlen = s1_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;
*s1len = s1_dlen;
*s2len = s2_dlen;
memcpy(seg1, hdr, hdr_len);
memcpy(seg2, hdr, hdr_len);
memcpy(seg1 + hdr_len, tcph, tcph_len);
memcpy(seg2 + hdr_len, tcph, tcph_len);
memcpy(seg1 + hdr_len + tcph_len, payload, s1_plen);
memcpy(seg2 + hdr_len + tcph_len, payload + payload_offset, s2_plen);
if (ipvx == IP4VERSION) {
struct iphdr *s1_hdr = (void *)seg1;
struct iphdr *s2_hdr = (void *)seg2;
s1_hdr->tot_len = htons(s1_dlen);
s2_hdr->tot_len = htons(s2_dlen);
s1_hdr->id = randint();
s2_hdr->id = randint();
set_ip_checksum(s1_hdr, sizeof(struct iphdr));
set_ip_checksum(s2_hdr, sizeof(struct iphdr));
} else {
struct ip6_hdr *s1_hdr = (void *)seg1;
struct ip6_hdr *s2_hdr = (void *)seg2;
s1_hdr->ip6_plen = htons(s1_dlen - hdr_len);
s2_hdr->ip6_plen = htons(s2_dlen - hdr_len);
}
struct tcphdr *s1_tcph = (void *)(seg1 + hdr_len);
struct tcphdr *s2_tcph = (void *)(seg2 + hdr_len);
s2_tcph->seq = htonl(ntohl(s2_tcph->seq) + payload_offset);
set_tcp_checksum(s1_tcph, seg1, hdr_len);
set_tcp_checksum(s2_tcph, seg2, hdr_len);
return 0;
}
void z_function(const char *str, int *zbuf, size_t len) {
zbuf[0] = len;
int lh = 0, rh = 1;
for (int i = 1; i < (int)len; i++) {
zbuf[i] = 0;
if (i < rh) {
zbuf[i] = zbuf[i - lh];
if (rh - i < zbuf[i])
zbuf[i] = rh - i;
}
while (i + zbuf[i] < len && str[zbuf[i]] == str[i + zbuf[i]])
zbuf[i]++;
if (i + zbuf[i] > rh) {
lh = i;
rh = i + zbuf[i];
}
}
}
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;
for (size_t i = dlen + 1; i > 0; i--) {
*ndptr = *dptr;
--ndptr, --dptr;
}
for (size_t i = 0; i < delta; i++) {
*ndlptr++ = 0;
}
}
#define TCP_MD5SIG_LEN 16
#define TCP_MD5SIG_KIND 19
struct tcp_md5sig_opt {
uint8_t kind;
uint8_t len;
uint8_t sig[TCP_MD5SIG_LEN];
};
#define TCP_MD5SIG_OPT_LEN (sizeof(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, size_t *plen, size_t avail_buflen) {
void *iph;
size_t iph_len;
struct tcphdr *tcph;
size_t tcph_len;
uint8_t *data;
size_t dlen;
int ret;
ret = tcp_payload_split(payload, *plen,
&iph, &iph_len, &tcph, &tcph_len,
&data, &dlen);
int ipxv = netproto_version(payload, *plen);
if (ret < 0) {
return ret;
}
if (strategy.strategy == FAKE_STRAT_RAND_SEQ) {
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
tcph->seq = htonl(ntohl(tcph->seq) - (strategy.randseq_offset + dlen));
lgtrace_addp("%u", ntohl(tcph->seq));
} else if (strategy.strategy == FAKE_STRAT_PAST_SEQ) {
lgtrace_wr("fake seq: %u -> ", ntohl(tcph->seq));
tcph->seq = htonl(ntohl(tcph->seq) - dlen);
lgtrace_addp("%u", ntohl(tcph->seq));
} else 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;
}
} else if (strategy.strategy == FAKE_STRAT_TCP_MD5SUM) {
int optp_len = tcph_len - sizeof(struct tcphdr);
int delta = TCP_MD5SIG_OPT_RLEN - optp_len;
lgtrace_addp("Incr delta %d: %d -> %d", delta, optp_len, optp_len + delta);
if (delta > 0) {
if (avail_buflen - *plen < delta) {
return -1;
}
shift_data(data, dlen, delta);
data += delta;
tcph_len = tcph_len + delta;
tcph->doff = tcph_len >> 2;
if (ipxv == IP4VERSION) {
((struct iphdr *)iph)->tot_len = htons(ntohs(((struct iphdr *)iph)->tot_len) + delta);
} else if (ipxv == IP6VERSION) {
((struct ip6_hdr *)iph)->ip6_plen = htons(ntohs(((struct ip6_hdr *)iph)->ip6_plen) + delta);
} else {
lgerror(-EINVAL, "fail_packet: IP version is unsupported");
return -EINVAL;
}
optp_len += delta;
*plen += delta;
}
uint8_t *optplace = (uint8_t *)tcph + sizeof(struct tcphdr);
struct tcp_md5sig_opt *mdopt = (void *)optplace;
mdopt->kind = TCP_MD5SIG_KIND;
mdopt->len = TCP_MD5SIG_OPT_LEN;
optplace += sizeof(struct tcp_md5sig_opt);
optp_len -= sizeof(struct tcp_md5sig_opt);
while (optp_len-- > 0) {
*optplace++ = 0x01;
}
}
if (ipxv == IP4VERSION) {
((struct iphdr *)iph)->frag_off = 0;
}
set_ip_checksum(iph, iph_len);
set_tcp_checksum(tcph, iph, iph_len);
if (strategy.strategy == FAKE_STRAT_TCP_CHECK) {
lgtrace_addp("break fake tcp checksum");
tcph->check += 1;
}
return 0;
}
int seqovl_packet(uint8_t *payload, size_t *plen, size_t seq_delta) {
int ipxv = netproto_version(payload, *plen);
void *iph;
size_t iph_len;
struct tcphdr *tcph;
size_t tcph_len;
uint8_t *data;
size_t dlen;
int ret = tcp_payload_split(payload, *plen,
&iph, &iph_len, &tcph, &tcph_len,
&data, &dlen);
if (ret < 0) {
return -1;
}
if (ipxv == IP4VERSION) {
struct iphdr *ip4h = iph;
ip4h->tot_len = htons(ntohs(ip4h->tot_len) + seq_delta);
} else if (ipxv == IP6VERSION) {
struct ip6_hdr *ip6h = iph;
ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + seq_delta);
} else {
return -1;
}
tcph->seq = htons(ntohs(tcph->seq) - seq_delta);
shift_data(data, dlen, seq_delta);
*plen += seq_delta;
set_ip_checksum(iph, iph_len);
set_tcp_checksum(tcph, iph, iph_len);
return 0;
}

229
src/utils.h Normal file
View File

@@ -0,0 +1,229 @@
/*
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
#include "types.h"
#include "config.h"
#define IP4VERSION 4
#define IP6VERSION 6
/**
* Splits the packet to two IP fragments on position payload_offset.
* payload_offset indicates the position relatively to start of IP payload
* (start of transport header)
*/
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, 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, 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, size_t buflen) {
if (pkt == NULL || buflen == 0)
return -1;
return (*pkt) >> 4;
}
/**
* Splits the raw packet payload to ip header, tcp header and tcp payload.
*/
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, 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, 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, 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, size_t buflen,
struct iphdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, size_t *plen);
int udp6_payload_split(uint8_t *pkt, size_t buflen,
struct ip6_hdr **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, size_t *plen);
int udp_payload_split(uint8_t *pkt, size_t buflen,
void **iph, size_t *iph_len,
struct udphdr **udph,
uint8_t **payload, size_t *plen);
void tcp4_set_checksum(struct tcphdr *tcph, struct iphdr *iph);
void ip4_set_checksum(struct iphdr *iph);
void ip6_set_checksum(struct ip6_hdr *iph);
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, 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, size_t dlen, size_t delta);
struct failing_strategy {
unsigned int strategy;
uint8_t faking_ttl;
size_t randseq_offset;
};
struct fake_type {
#define FAKE_PAYLOAD_RANDOM 0
#define FAKE_PAYLOAD_DATA 1
// In default mode all other options will be skipped.
#define FAKE_PAYLOAD_DEFAULT 2
int type;
// Length of the final fake message.
// Pass 0 in RANDOM mode to make it random
uint16_t fake_len;
// Payload of the fake message of fake_len length.
// Will be omitted in RANDOM mode.
const char *fake_data;
unsigned int sequence_len;
// If non-0 the packet send will be delayed for n milliseconds
unsigned int seg2delay;
// faking strategy of the fake packet.
// Does not support bitmask, pass standalone strategy.
// Pass 0 if you don't want any faking procedures.
struct failing_strategy strategy;
};
struct udp_failing_strategy {
unsigned int strategy;
uint8_t faking_ttl;
};
struct udp_fake_type {
uint16_t fake_len;
// faking strategy of the fake packet.
// Does not support bitmask, pass standalone strategy.
// Pass 0 if you don't want any faking procedures.
struct udp_failing_strategy strategy;
};
/**
* Invalidates the raw packet. The function aims to invalid the packet
* in such way as it will be accepted by DPI, but dropped by target server
*
* Does not support bitmask, pass standalone strategy.
*/
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, size_t *plen, size_t seq_delta);
static inline struct failing_strategy args_default_failing_strategy(const struct section_config_t *section) {
struct failing_strategy fl_strat = {
.strategy = (unsigned int)section->faking_strategy,
.faking_ttl = section->faking_ttl,
.randseq_offset = (size_t)section->fakeseq_offset
};
return fl_strat;
}
static inline struct fake_type args_default_fake_type(const struct section_config_t *section) {
struct fake_type f_type = {
.sequence_len = section->fake_sni_seq_len,
.strategy = args_default_failing_strategy(section),
};
switch (section->fake_sni_type) {
case FAKE_PAYLOAD_RANDOM:
f_type.type = FAKE_PAYLOAD_RANDOM;
break;
case FAKE_PAYLOAD_CUSTOM:
f_type.type = FAKE_PAYLOAD_CUSTOM;
f_type.fake_data = section->fake_custom_pkt;
f_type.fake_len = section->fake_custom_pkt_sz;
break;
default:
f_type.type = FAKE_PAYLOAD_CUSTOM;
f_type.fake_data = section->fake_sni_pkt;
f_type.fake_len = section->fake_sni_pkt_sz;
}
return f_type;
}
#endif /* UTILS_H */

990
src/youtubeUnblock.c Normal file
View File

@@ -0,0 +1,990 @@
/*
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!"
#endif
#ifdef KERNEL_SPACE
#error "The build aims to the kernel, not userspace"
#endif
#include <stdio.h>
#include <stdlib.h>
/* Warning is ok, use this for Entware */
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <linux/if_ether.h>
#include <linux/netfilter.h>
#include <pthread.h>
#include <sys/socket.h>
#include <signal.h>
#include "config.h"
#include "mangle.h"
#include "args.h"
#include "utils.h"
#include "logging.h"
pthread_mutex_t rawsocket_lock;
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);
if (nl == NULL) {
lgerror(-errno, "mnl_socket_open");
return -1;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
lgerror(-errno, "mnl_socket_bind");
mnl_socket_close(nl);
return -1;
}
*_nl = nl;
return 0;
}
static int close_socket(struct mnl_socket **_nl) {
struct mnl_socket *nl = *_nl;
if (nl == NULL) return 1;
if (mnl_socket_close(nl) < 0) {
lgerror(-errno, "mnl_socket_close");
return -1;
}
*_nl = NULL;
return 0;
}
static int open_raw_socket(void) {
if (rawsocket != -2) {
errno = EALREADY;
lgerror(-errno, "Raw socket is already opened");
return -1;
}
rawsocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (rawsocket == -1) {
lgerror(-errno, "Unable to create raw socket");
return -1;
}
int mark = cur_config->mark;
if (setsockopt(rawsocket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
{
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", mst);
close(rawsocket);
errno = mst;
return -1;
}
return rawsocket;
}
static int close_raw_socket(void) {
if (rawsocket < 0) {
errno = EALREADY;
lgerror(-errno, "Raw socket is not set");
return -1;
}
if (close(rawsocket)) {
lgerror(-errno, "Unable to close raw socket");
pthread_mutex_destroy(&rawsocket_lock);
return -1;
}
pthread_mutex_destroy(&rawsocket_lock);
rawsocket = -2;
return 0;
}
static int open_raw6_socket(void) {
if (raw6socket != -2) {
errno = EALREADY;
lgerror(-errno, "Raw socket is already opened");
return -1;
}
raw6socket = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
if (rawsocket == -1) {
lgerror(-errno, "Unable to create raw socket");
return -1;
}
int mark = cur_config->mark;
if (setsockopt(raw6socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
{
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", mst);
close(raw6socket);
return -1;
}
return raw6socket;
}
static int close_raw6_socket(void) {
if (raw6socket < 0) {
errno = EALREADY;
lgerror(-errno, "Raw socket is not set");
return -1;
}
if (close(raw6socket)) {
lgerror(-errno, "Unable to close raw socket");
pthread_mutex_destroy(&rawsocket_lock);
return -1;
}
pthread_mutex_destroy(&raw6socket_lock);
raw6socket = -2;
return 0;
}
/*
* libnetfilter_conntrack
* (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
*/
enum ctattr_counters {
CTA_COUNTERS_UNSPEC,
CTA_COUNTERS_PACKETS, /* 64bit counters */
CTA_COUNTERS_BYTES, /* 64bit counters */
CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */
CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */
CTA_COUNTERS_PAD,
__CTA_COUNTERS_MAX
};
#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
enum ctattr_type {
CTA_UNSPEC,
CTA_TUPLE_ORIG,
CTA_TUPLE_REPLY,
CTA_STATUS,
CTA_PROTOINFO,
CTA_HELP,
CTA_NAT_SRC,
#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */
CTA_TIMEOUT,
CTA_MARK,
CTA_COUNTERS_ORIG,
CTA_COUNTERS_REPLY,
CTA_USE,
CTA_ID,
CTA_NAT_DST,
CTA_TUPLE_MASTER,
CTA_SEQ_ADJ_ORIG,
CTA_NAT_SEQ_ADJ_ORIG = CTA_SEQ_ADJ_ORIG,
CTA_SEQ_ADJ_REPLY,
CTA_NAT_SEQ_ADJ_REPLY = CTA_SEQ_ADJ_REPLY,
CTA_SECMARK, /* obsolete */
CTA_ZONE,
CTA_SECCTX,
CTA_TIMESTAMP,
CTA_MARK_MASK,
CTA_LABELS,
CTA_LABELS_MASK,
CTA_SYNPROXY,
CTA_FILTER,
CTA_STATUS_MASK,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
enum {
__DIR_ORIG,
__DIR_REPL
};
static int
yct_parse_counters_attr_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0)
return MNL_CB_OK;
switch(type) {
case CTA_COUNTERS_PACKETS:
case CTA_COUNTERS_BYTES:
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0)
return MNL_CB_ERROR;
break;
case CTA_COUNTERS32_PACKETS:
case CTA_COUNTERS32_BYTES:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
return MNL_CB_ERROR;
break;
}
tb[type] = attr;
return MNL_CB_OK;
}
static int
yct_parse_counters(const struct nlattr *attr, struct ytb_conntrack *yct,
int dir)
{
struct nlattr *tb[CTA_COUNTERS_MAX+1] = {0};
if (mnl_attr_parse_nested(attr, yct_parse_counters_attr_cb, tb) < 0)
return -1;
if (tb[CTA_COUNTERS_PACKETS] || tb[CTA_COUNTERS32_PACKETS]) {
uint64_t packets_counter;
if (tb[CTA_COUNTERS32_PACKETS]) {
packets_counter =
ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_PACKETS]));
}
if (tb[CTA_COUNTERS_PACKETS]) {
packets_counter =
be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS]));
}
switch(dir) {
case __DIR_ORIG:
yct->orig_packets = packets_counter;
yct_set_mask_attr(YCTATTR_ORIG_PACKETS, yct);
break;
case __DIR_REPL:
yct->repl_packets = packets_counter;
yct_set_mask_attr(YCTATTR_REPL_PACKETS, yct);
break;
}
}
if (tb[CTA_COUNTERS_BYTES] || tb[CTA_COUNTERS32_BYTES]) {
uint64_t bytes_counter;
if (tb[CTA_COUNTERS32_BYTES]) {
bytes_counter =
ntohl(mnl_attr_get_u32(tb[CTA_COUNTERS32_BYTES]));
}
if (tb[CTA_COUNTERS_BYTES]) {
bytes_counter =
be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES]));
}
switch(dir) {
case __DIR_ORIG:
yct->orig_bytes = bytes_counter;
yct_set_mask_attr(YCTATTR_ORIG_BYTES, yct);
break;
case __DIR_REPL:
yct->repl_bytes = bytes_counter;
yct_set_mask_attr(YCTATTR_REPL_BYTES, yct);
break;
}
}
return 0;
}
static int
yct_parse_conntrack_attr_cb(const struct nlattr *attr, void *data){
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
return MNL_CB_OK;
switch(type) {
case CTA_TUPLE_ORIG:
case CTA_TUPLE_REPLY:
case CTA_TUPLE_MASTER:
case CTA_NAT_SEQ_ADJ_ORIG:
case CTA_NAT_SEQ_ADJ_REPLY:
case CTA_PROTOINFO:
case CTA_COUNTERS_ORIG:
case CTA_COUNTERS_REPLY:
case CTA_HELP:
case CTA_SECCTX:
case CTA_TIMESTAMP:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
return MNL_CB_ERROR;
break;
case CTA_STATUS:
case CTA_TIMEOUT:
case CTA_MARK:
case CTA_SECMARK:
case CTA_USE:
case CTA_ID:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
return MNL_CB_ERROR;
break;
case CTA_ZONE:
if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
return MNL_CB_ERROR;
break;
case CTA_NAT_SRC:
case CTA_NAT_DST:
/* deprecated */
break;
}
tb[type] = attr;
return MNL_CB_OK;
}
static int
yct_payload_parse(const void *payload, size_t payload_len,
uint16_t l3num, struct ytb_conntrack *yct)
{
struct nlattr *tb[CTA_MAX+1] = {0};
if (mnl_attr_parse_payload(payload, payload_len,
yct_parse_conntrack_attr_cb, tb) < 0)
return -1;
if (tb[CTA_MARK]) {
yct->connmark = ntohl(mnl_attr_get_u32(tb[CTA_MARK]));
yct_set_mask_attr(YCTATTR_CONNMARK, yct);
}
if (tb[CTA_COUNTERS_ORIG]) {
if (yct_parse_counters(tb[CTA_COUNTERS_ORIG],
yct, __DIR_ORIG) < 0)
return -1;
}
if (tb[CTA_ID]) {
yct->id = ntohl(mnl_attr_get_u32(tb[CTA_ID]));
yct_set_mask_attr(YCTATTR_CONNID, yct);
}
if (tb[CTA_COUNTERS_REPLY]) {
if (yct_parse_counters(tb[CTA_COUNTERS_REPLY],
yct, __DIR_REPL) < 0)
return -1;
}
return 0;
}
static int send_raw_ipv4(const uint8_t *pkt, size_t pktlen) {
int ret;
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
struct iphdr *iph;
if ((ret = ip4_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
errno = -ret;
return ret;
}
struct sockaddr_in daddr = {
.sin_family = AF_INET,
/* Always 0 for raw socket */
.sin_port = 0,
.sin_addr = {
.s_addr = iph->daddr
}
};
if (cur_config->threads != 1)
pthread_mutex_lock(&rawsocket_lock);
int sent = sendto(rawsocket,
pkt, pktlen, MSG_DONTWAIT,
(struct sockaddr *)&daddr, sizeof(daddr));
if (cur_config->threads != 1)
pthread_mutex_unlock(&rawsocket_lock);
/* The function will return -errno on error as well as errno value set itself */
if (sent < 0) sent = -errno;
return sent;
}
static int send_raw_ipv6(const uint8_t *pkt, size_t pktlen) {
int ret;
if (pktlen > AVAILABLE_MTU) return -ENOMEM;
struct ip6_hdr *iph;
if ((ret = ip6_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
errno = -ret;
return ret;
}
struct sockaddr_in6 daddr = {
.sin6_family = AF_INET6,
/* Always 0 for raw socket */
.sin6_port = 0,
.sin6_addr = iph->ip6_dst
};
if (cur_config->threads != 1)
pthread_mutex_lock(&rawsocket_lock);
int sent = sendto(raw6socket,
pkt, pktlen, MSG_DONTWAIT,
(struct sockaddr *)&daddr, sizeof(daddr));
lgtrace_addp("rawsocket sent %d", sent);
if (cur_config->threads != 1)
pthread_mutex_unlock(&rawsocket_lock);
/* The function will return -errno on error as well as errno value set itself */
if (sent < 0) sent = -errno;
return sent;
}
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;
}
++global_stats.sent_counter;
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;
}
// Per-queue data. Passed to queue_cb.
struct queue_data {
struct mnl_socket **_nl;
int queue_num;
};
/**
* Used to accept unsupported packets (GSOs)
*/
static int fallback_accept_packet(uint32_t id, struct queue_data qdata) {
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *verdnlh;
verdnlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qdata.queue_num);
nfq_nlmsg_verdict_put(verdnlh, id, NF_ACCEPT);
if (mnl_socket_sendto(*qdata._nl, verdnlh, verdnlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
return MNL_CB_ERROR;
}
return MNL_CB_OK;
}
struct dps_t {
uint8_t *pkt;
size_t pktlen;
// Time for the packet in milliseconds
uint32_t timer;
};
// Note that the thread will automatically release dps_t and pkt_buff
void *delay_packet_send_fn(void *data) {
struct dps_t *dpdt = data;
uint8_t *pkt = dpdt->pkt;
size_t pktlen = dpdt->pktlen;
usleep(dpdt->timer * 1000);
int ret = send_raw_socket(pkt, pktlen);
if (ret < 0) {
errno = -ret;
lgerror(-errno, "send delayed raw packet");
}
free(pkt);
free(dpdt);
return NULL;
}
int delay_packet_send(const unsigned char *data, size_t data_len, unsigned int delay_ms) {
int ret;
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
if (dpdt == NULL) {
return -ENOMEM;
}
*dpdt = (struct dps_t){0};
dpdt->pkt = malloc(data_len);
if (dpdt->pkt == NULL) {
free(dpdt);
return -ENOMEM;
}
memcpy(dpdt->pkt, data, data_len);
dpdt->pktlen = data_len;
dpdt->timer = delay_ms;
pthread_t thr = {0};
ret = pthread_create(&thr, NULL, delay_packet_send_fn, dpdt);
if (ret != 0) {
free(dpdt->pkt);
free(dpdt);
return -ret;
}
ret = pthread_detach(thr);
lgtrace_addp("Scheduled packet send after %d ms", delay_ms);
return 0;
}
static int queue_cb(const struct nlmsghdr *nlh, void *data) {
char buf[MNL_SOCKET_BUFFER_SIZE];
struct queue_data *qdata = 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;
++global_stats.all_packet_counter;
if (nfq_nlmsg_parse(nlh, attr) < 0) {
lgerror(-errno, "Attr parse");
return MNL_CB_ERROR;
}
if (attr[NFQA_PACKET_HDR] == NULL) {
errno = ENODATA;
lgerror(-errno, "Metaheader not set");
return MNL_CB_ERROR;
}
nfg = mnl_nlmsg_get_payload(nlh);
l3num = nfg->nfgen_family;
ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]);
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!");
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])) & 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");
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);
ret = process_packet(cur_config, &packet);
++global_stats.packet_counter;
switch (ret) {
case PKT_DROP:
++global_stats.target_counter;
nfq_nlmsg_verdict_put(verdnlh, id, NF_DROP);
break;
default:
nfq_nlmsg_verdict_put(verdnlh, id, NF_ACCEPT);
break;
}
if (mnl_socket_sendto(*qdata->_nl, verdnlh, verdnlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
return MNL_CB_ERROR;
}
return MNL_CB_OK;
}
#define BUF_SIZE (0xffff + (MNL_SOCKET_BUFFER_SIZE / 2))
int init_queue(int queue_num) {
struct mnl_socket *nl;
if (open_socket(&nl)) {
lgerror(-errno, "Unable to open socket");
return -1;
}
uint32_t portid = mnl_socket_get_portid(nl);
struct nlmsghdr *nlh;
char *buf = malloc(BUF_SIZE);
if (buf == NULL) {
lgerror(-ENOMEM, "Allocation error");
goto die_alloc;
}
/* Support for kernels versions < 3.8 */
// Obsolete and ignored in kernel version 3.8
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0360ae412d09bc6f4864c801effcb20bfd84520e
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, PF_INET, NFQNL_CFG_CMD_PF_UNBIND);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
goto die;
}
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, PF_INET, NFQNL_CFG_CMD_PF_BIND);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
goto die;
}
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);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
goto die;
}
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, PF_INET6, NFQNL_CFG_CMD_PF_BIND);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
goto die;
}
}
/* End of support for kernel versions < 3.8 */
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
lgerror(-errno, "mnl_socket_send");
goto die;
}
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff);
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");
goto die;
}
/* ENOBUFS is signalled to userspace when packets were lost
* on kernel side. In most cases, userspace isn't interested
* in this information, so turn it off.
*/
int ret = 1;
mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &ret, sizeof(int));
struct queue_data qdata = {
._nl = &nl,
.queue_num = queue_num
};
lginfo("Queue %d started", qdata.queue_num);
while (1) {
ret = mnl_socket_recvfrom(nl, buf, BUF_SIZE);
if (ret == -1) {
lgerror(-errno, "mnl_socket_recvfrom");
goto die;
}
ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, &qdata);
if (ret < 0) {
lgerror(ret, "mnl_cb_run");
if (ret == -EPERM) {
lgerr("Probably another instance of youtubeUnblock with the same queue number is running");
} else {
lgerr("Make sure the nfnetlink_queue kernel module is loaded");
}
goto die;
}
}
free(buf);
close_socket(&nl);
return 0;
die:
free(buf);
die_alloc:
close_socket(&nl);
return -1;
}
// Per-queue config. Used to initialize a queue. Passed to wrapper
struct queue_conf {
uint16_t i;
int queue_num;
};
struct queue_res {
int status;
};
static struct queue_res defqres = {0};
static struct queue_res threads_reses[MAX_THREADS];
void *init_queue_wrapper(void *qdconf) {
struct queue_conf *qconf = qdconf;
struct queue_res *thres = threads_reses + qconf->i;
thres->status = init_queue(qconf->queue_num);
lgerror(thres->status, "Thread %d exited with status %d", qconf->i, thres->status);
return thres;
}
struct instance_config_t instance_config = {
.send_raw_packet = send_raw_socket,
.send_delayed_packet = delay_packet_send,
};
void sigint_handler(int s) {
lginfo("youtubeUnblock stats: catched %ld packets, "
"processed %ld packets, "
"targetted %ld packets, sent over socket %ld packets",
global_stats.all_packet_counter, global_stats.packet_counter,
global_stats.target_counter, global_stats.sent_counter);
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[]) {
int ret;
struct config_t config;
if ((ret = yparse_args(&config, argc, argv)) != 0) {
if (ret < 0) {
lgerror(-errno, "Unable to parse args");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
print_version();
print_welcome(&config);
parse_global_lgconf(&config);
cur_config = &config;
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
if (open_raw_socket() < 0) {
lgerror(-errno, "Unable to open raw socket");
exit(EXIT_FAILURE);
}
if (config.use_ipv6) {
if (open_raw6_socket() < 0) {
lgerror(-errno, "Unable to open raw socket for ipv6");
close_raw_socket();
exit(EXIT_FAILURE);
}
}
if (config.daemonize) {
daemon(0, config.noclose);
}
struct queue_res *qres = &defqres;
if (config.threads == 1) {
struct queue_conf tconf = {
.i = 0,
.queue_num = config.queue_start_num
};
qres = init_queue_wrapper(&tconf);
} else {
lginfo("%d threads wil be used", config.threads);
struct queue_conf thread_confs[MAX_THREADS];
pthread_t threads[MAX_THREADS];
for (int i = 0; i < config.threads; i++) {
struct queue_conf *tconf = thread_confs + i;
pthread_t *thr = threads + i;
tconf->queue_num = config.queue_start_num + i;
tconf->i = i;
pthread_create(thr, NULL, init_queue_wrapper, tconf);
}
void *res;
for (int i = 0; i < config.threads; i++) {
pthread_join(threads[i], &res);
qres = res;
}
}
close_raw_socket();
if (config.use_ipv6)
close_raw6_socket();
return -qres->status;
}

19
test/main_fn.c Normal file
View File

@@ -0,0 +1,19 @@
#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);
RUN_TEST_GROUP(TrieTest);
}
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)
}

58
test/tls.c Normal file
View File

@@ -0,0 +1,58 @@
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 trie_container trie;
int ret;
ret = trie_init(&trie);
ret = trie_add_string(&trie, (uint8_t *)"youtube.com", 11);
sconf.sni_domains = trie;
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);
trie_destroy(&trie);
}
TEST_GROUP_RUNNER(TLSTest)
{
RUN_TEST_CASE(TLSTest, Test_CHLO_message_detect);
RUN_TEST_CASE(TLSTest, Test_Bruteforce_detects);
}

147
test/trie.c Normal file
View File

@@ -0,0 +1,147 @@
#include "unity.h"
#include "unity_fixture.h"
#include "trie.h"
TEST_GROUP(TrieTest);
TEST_SETUP(TrieTest)
{
}
TEST_TEAR_DOWN(TrieTest)
{
}
const char ASTR[] = "abacaba";
const char BSTR[] = "BABABABA";
const char CSTR[] = "abracadabra";
const char tstr[] = "aBABABABDADAabacabracadabraabbbabacabaaaaaabacaba";
TEST(TrieTest, Trie_string_adds)
{
int ret;
size_t offset;
size_t offlen;
struct trie_container trie;
ret = trie_init(&trie);
TEST_ASSERT_EQUAL(0, ret);
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
TEST_ASSERT_EQUAL(0, ret);
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
TEST_ASSERT_EQUAL(0, ret);
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
TEST_ASSERT_EQUAL(0, ret);
TEST_ASSERT_EQUAL(25, trie.sz);
trie_destroy(&trie);
}
TEST(TrieTest, Trie_string_finds)
{
int ret;
size_t offset;
size_t offlen;
struct trie_container trie;
ret = trie_init(&trie);
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
ret = trie_process_str(&trie,
(uint8_t *)tstr, sizeof(tstr) - 1,
0, &offset, &offlen
);
TEST_ASSERT_EQUAL(1, ret);
TEST_ASSERT_EQUAL(11, offlen);
TEST_ASSERT_EQUAL_STRING_LEN("abracadabra", tstr + offset, offlen);
trie_destroy(&trie);
}
TEST(TrieTest, Trie_string_finds_opt_end)
{
int ret;
size_t offset;
size_t offlen;
struct trie_container trie;
ret = trie_init(&trie);
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
ret = trie_add_string(&trie, (uint8_t *)BSTR, sizeof(BSTR) - 1);
ret = trie_add_string(&trie, (uint8_t *)CSTR, sizeof(CSTR) - 1);
ret = trie_process_str(&trie,
(uint8_t *)tstr, sizeof(tstr) - 1,
TRIE_OPT_MAP_TO_END,
&offset, &offlen
);
TEST_ASSERT_EQUAL(1, ret);
TEST_ASSERT_EQUAL(7, offlen);
TEST_ASSERT_EQUAL_STRING_LEN("abacaba", tstr + offset, offlen);
ret = trie_process_str(&trie,
(uint8_t *)tstr, sizeof(tstr),
TRIE_OPT_MAP_TO_END,
&offset, &offlen
);
TEST_ASSERT_EQUAL(0, ret);
trie_destroy(&trie);
}
TEST(TrieTest, Trie_single_vertex)
{
int ret;
size_t offset;
size_t offlen;
struct trie_container trie;
ret = trie_init(&trie);
ret = trie_process_str(&trie,
(uint8_t *)tstr, sizeof(tstr) - 1,
0,
&offset, &offlen
);
TEST_ASSERT_EQUAL(0, ret);
trie_destroy(&trie);
}
TEST(TrieTest, Trie_uninitialized)
{
int ret;
size_t offset;
size_t offlen;
struct trie_container trie = {0};
// ret = trie_init(&trie);
ret = trie_add_string(&trie, (uint8_t *)ASTR, sizeof(ASTR) - 1);
TEST_ASSERT_EQUAL(-EINVAL, ret);
ret = trie_process_str(&trie,
(uint8_t *)tstr, sizeof(tstr) - 1,
0,
&offset, &offlen
);
TEST_ASSERT_EQUAL(0, ret);
}
TEST_GROUP_RUNNER(TrieTest)
{
RUN_TEST_CASE(TrieTest, Trie_string_adds);
RUN_TEST_CASE(TrieTest, Trie_string_finds);
RUN_TEST_CASE(TrieTest, Trie_string_finds_opt_end);
RUN_TEST_CASE(TrieTest, Trie_single_vertex);
RUN_TEST_CASE(TrieTest, Trie_uninitialized);
}

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

View File

@@ -1,12 +1,23 @@
#Check for using system libs
USE_SYS_LIBS := no
#Userspace app makes here #Userspace app makes here
BUILD_DIR := $(CURDIR)/build BUILD_DIR := $(CURDIR)/build
DEPSDIR := $(BUILD_DIR)/deps DEPSDIR := $(BUILD_DIR)/deps
INCLUDE_DIR := $(CURDIR)/src
SRC_DIR := $(CURDIR)/src
CC:=gcc CC:=gcc
CCLD:=$(CC) CCLD:=$(CC)
LD:=ld LD:=ld
override CFLAGS += -Wall -Wpedantic -Wno-unused-variable -I$(DEPSDIR)/include
override LDFLAGS += -L$(DEPSDIR)/lib ifeq ($(USE_SYS_LIBS), no)
override CFLAGS += -I$(DEPSDIR)/include
override LDFLAGS += -L$(DEPSDIR)/lib
REQ = $(LIBNETFILTER_QUEUE) $(LIBMNL) $(LIBCRYPTO)
endif
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_CFLAGS := -I$(DEPSDIR)/include
LIBNFNETLINK_LIBS := -L$(DEPSDIR)/lib LIBNFNETLINK_LIBS := -L$(DEPSDIR)/lib
@@ -21,20 +32,28 @@ endif
export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CFLAGS LIBMNL_LIBS export CC CCLD LD CFLAGS LDFLAGS LIBNFNETLINK_CFLAGS LIBNFNETLINK_LIBS LIBMNL_CFLAGS LIBMNL_LIBS
APP:=$(BUILD_DIR)/youtubeUnblock APP:=$(BUILD_DIR)/youtubeUnblock
TEST_APP:=$(BUILD_DIR)/testYoutubeUnblock
SRCS := youtubeUnblock.c mangle.c SRCS := mangle.c args.c utils.c quic.c tls.c getopt.c quic_crypto.c inet_ntop.c trie.c
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o) OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
APP_EXEC := youtubeUnblock.c
LIBNFNETLINK := $(DEPSDIR)/lib/libnfnetlink.a APP_OBJ := $(APP_EXEC:%.c=$(BUILD_DIR)/%.o)
LIBMNL := $(DEPSDIR)/lib/libmnl.a
LIBNETFILTER_QUEUE := $(DEPSDIR)/lib/libnetfilter_queue.a
.PHONY: default all dev dev_attrs prepare_dirs 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
LIBCYCLONE := $(DEPSDIR)/lib/libcyclone.a
.PHONY: default all test build_test dev dev_attrs prepare_dirs
default: all default: all
run_dev: dev run_dev: dev
bash -c "sudo $(APP) 537" bash -c "sudo $(APP)"
dev: dev_attrs all dev: dev_attrs all
@@ -43,10 +62,22 @@ dev_attrs:
all: prepare_dirs $(APP) all: prepare_dirs $(APP)
build_test: prepare_dirs $(TEST_APP)
test: build_test
$(TEST_APP)
prepare_dirs: prepare_dirs:
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)
mkdir -p $(BUILD_DIR)/crypto
mkdir -p $(BUILD_DIR)/test
mkdir -p $(BUILD_DIR)/test/unity
mkdir -p $(DEPSDIR) mkdir -p $(DEPSDIR)
$(LIBCYCLONE):
$(MAKE) -C deps/cyclone CFLAGS="$(CFLAGS)"
mkdir -p $(DEPSDIR)/lib
cp deps/cyclone/libcyclone.a $(DEPSDIR)/lib/libcyclone.a
$(LIBNFNETLINK): $(LIBNFNETLINK):
cd deps/libnfnetlink && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared cd deps/libnfnetlink && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
$(MAKE) -C deps/libnfnetlink $(MAKE) -C deps/libnfnetlink
@@ -57,19 +88,27 @@ $(LIBMNL):
$(MAKE) -C deps/libmnl $(MAKE) -C deps/libmnl
$(MAKE) install -C deps/libmnl $(MAKE) install -C deps/libmnl
$(LIBNETFILTER_QUEUE): $(LIBNFNETLINK) $(LIBMNL) $(LIBNETFILTER_QUEUE): $(LIBNFNETLINK) $(LIBMNL)
cd deps/libnetfilter_queue && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared cd deps/libnetfilter_queue && ./autogen.sh && ./configure --prefix=$(DEPSDIR) $(if $(CROSS_COMPILE_PLATFORM),--host=$(CROSS_COMPILE_PLATFORM),) --enable-static --disable-shared
$(MAKE) -C deps/libnetfilter_queue $(MAKE) -C deps/libnetfilter_queue
$(MAKE) install -C deps/libnetfilter_queue $(MAKE) install -C deps/libnetfilter_queue
$(APP): $(OBJS) $(LIBNETFILTER_QUEUE) $(LIBMNL) $(APP): $(OBJS) $(APP_OBJ) $(REQ) $(LIBCYCLONE)
@echo 'CCLD $(APP)' @echo 'CCLD $(APP)'
$(CCLD) $(OBJS) -o $(APP) $(LDFLAGS) -lmnl -lnetfilter_queue $(CCLD) $(OBJS) $(APP_OBJ) -o $(APP) $(LDFLAGS) -lmnl -lnetfilter_queue -lpthread -lcyclone
$(BUILD_DIR)/%.o: %.c $(LIBNETFILTER_QUEUE) $(LIBMNL) 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 $@' @echo 'CC $@'
$(CC) -c $(CFLAGS) $(LDFLAGS) $< -o $@ $(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: all
install -d $(DESTDIR)$(PREFIX)/bin/ install -d $(DESTDIR)$(PREFIX)/bin/
install -m 755 $(APP) $(DESTDIR)$(PREFIX)/bin/ install -m 755 $(APP) $(DESTDIR)$(PREFIX)/bin/
@@ -84,8 +123,13 @@ uninstall:
-systemctl disable youtubeUnblock.service -systemctl disable youtubeUnblock.service
clean: clean:
find $(BUILD_DIR) -maxdepth 1 -type f | xargs rm -rf
distclean: clean
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)
ifeq ($(USE_SYS_LIBS), no)
$(MAKE) distclean -C deps/libnetfilter_queue || true $(MAKE) distclean -C deps/libnetfilter_queue || true
$(MAKE) distclean -C deps/libmnl || true $(MAKE) distclean -C deps/libmnl || true
$(MAKE) distclean -C deps/libnfnetlink || true $(MAKE) distclean -C deps/libnfnetlink || true
endif
$(MAKE) clean -C deps/cyclone || true

View File

@@ -1,871 +0,0 @@
#define _GNU_SOURCE
#ifndef __linux__
#error "The package is linux only!"
#endif
#ifdef KERNEL_SPACE
#error "The build aims to the kernel, not userspace"
#endif
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
#include <stdio.h>
#include <stdlib.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <linux/if_ether.h>
#include <linux/netfilter.h>
#include <pthread.h>
#include <sys/socket.h>
#include "config.h"
#include "mangle.h"
pthread_mutex_t rawsocket_lock;
struct config_t config = {
.rawsocket = -2,
.threads = THREADS_NUM,
.fragmentation_strategy = FRAGMENTATION_STRATEGY,
.fake_sni_strategy = FAKE_SNI_STRATEGY,
.fake_sni_ttl = FAKE_SNI_TTL,
#ifdef SEG2_DELAY
.seg2_delay = SEG2_DELAY,
#else
.seg2_delay = 0,
#endif
#ifdef USE_GSO
.use_gso = true,
#else
.use_gso = false,
#endif
#ifdef DEBUG
.verbose = true,
#else
.verbose = false,
#endif
.domains_str = defaul_snistr,
.domains_strlen = sizeof(defaul_snistr),
};
const char* get_value(const char *option, const char *prefix)
{
errno = 0;
size_t prefix_len = strlen(prefix);
size_t option_len = strlen(option);
if (option_len <= prefix_len || strncmp(prefix, option, prefix_len)) {
return NULL;
}
return option + prefix_len;
}
int parse_bool_option(const char *value) {
errno = 0;
if (strcmp(value, "1") == 0) {
return 1;
}
else if (strcmp(value, "0") == 0) {
return 0;
}
errno = EINVAL;
return -1;
}
long parse_numeric_option(const char* value) {
errno = 0;
char* end;
long result = strtol(value, &end, 10);
if (*end != '\0') {
errno = EINVAL;
return 0;
}
return result;
}
int parse_option(const char* option) {
const char* value;
int ret;
if (!strcmp(option, "--no-gso")) {
config.use_gso = 0;
goto out;
}
if (!strcmp(option, "--silent")) {
config.verbose = 0;
goto out;
}
if ((value = get_value(option, "--sni-domains")) != 0) {
if (!value) {
goto err;
}
if (strcmp(value, "all")) {
config.all_domains = 1;
}
config.domains_str = value;
config.domains_strlen = strlen(value);
goto out;
}
if ((value = get_value(option, "--frag=")) != 0) {
if (!value) {
goto err;
}
if (strcmp(value, "tcp") == 0) {
config.fragmentation_strategy = FRAG_STRAT_TCP;
} else if (strcmp(value, "ip") == 0) {
config.fragmentation_strategy = FRAG_STRAT_IP;
} else if (strcmp(value, "none") == 0) {
config.fragmentation_strategy = FRAG_STRAT_NONE;
} else {
goto err;
}
goto out;
}
if ((value = get_value(option, "--fake-sni=")) != 0) {
if (strcmp(value, "ack") == 0) {
config.fake_sni_strategy = FKSN_STRAT_ACK_SEQ;
} else if (strcmp(value, "ttl") == 0) {
config.fake_sni_strategy = FKSN_STRAT_TTL;
}
else if (strcmp(value, "none") == 0) {
config.fake_sni_strategy = FKSN_STRAT_NONE;
} else {
goto err;
}
goto out;
}
if ((value = get_value(option, "--seg2delay=")) != 0) {
long num = parse_numeric_option(value);
if (errno != 0 ||
num < 0)
goto err;
config.seg2_delay = num;
goto out;
}
if ((value = get_value(option, "--threads=")) != 0) {
long num = parse_numeric_option(value);
if (errno != 0 ||
num < 0 ||
num > MAX_THREADS) {
errno = EINVAL;
goto err;
}
config.threads = num;
goto out;
}
if ((value = get_value(option, "--fake-sni-ttl=")) != 0) {
long num = parse_numeric_option(value);
if (errno != 0 ||
num < 0 ||
num > 255) {
goto err;
}
config.fake_sni_ttl = num;
goto out;
}
err:
errno = EINVAL;
return -1;
out:
errno = 0;
return 0;
}
static int parse_args(int argc, const char *argv[]) {
int err;
char *end;
if (argc < 2) {
errno = EINVAL;
goto errormsg_help;
}
config.queue_start_num = parse_numeric_option(argv[1]);
if (errno != 0) goto errormsg_help;
for (int i = 2; i < argc; i++) {
if (parse_option(argv[i])) {
printf("Invalid option %s\n", argv[i]);
goto errormsg_help;
}
}
return 0;
errormsg_help:
err = errno;
printf("Usage: %s <queue_num> [OPTIONS]\n", argv[0]);
printf("Options:\n");
printf("\t--sni-domains=<comma separated domain list>|all\n");
printf("\t--fake-sni={ack,ttl,none}\n");
printf("\t--fake-sni-ttl=<ttl>\n");
printf("\t--frag={tcp,ip,none}\n");
printf("\t--seg2delay=<delay>\n");
printf("\t--threads=<threads number>\n");
printf("\t--silent\n");
printf("\t--no-gso\n");
errno = err;
if (errno == 0) errno = EINVAL;
return -1;
}
static int open_socket(struct mnl_socket **_nl) {
struct mnl_socket *nl = NULL;
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
return -1;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
mnl_socket_close(nl);
return -1;
}
*_nl = nl;
return 0;
}
static int close_socket(struct mnl_socket **_nl) {
struct mnl_socket *nl = *_nl;
if (nl == NULL) return 1;
if (mnl_socket_close(nl) < 0) {
perror("mnl_socket_close");
return -1;
}
*_nl = NULL;
return 0;
}
static int open_raw_socket(void) {
if (config.rawsocket != -2) {
errno = EALREADY;
perror("Raw socket is already opened");
return -1;
}
config.rawsocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (config.rawsocket == -1) {
perror("Unable to create raw socket");
return -1;
}
int mark = RAWSOCKET_MARK;
if (setsockopt(config.rawsocket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
{
fprintf(stderr, "setsockopt(SO_MARK, %d) failed\n", mark);
return -1;
}
int mst = pthread_mutex_init(&rawsocket_lock, NULL);
if (mst) {
fprintf(stderr, "Mutex err: %d\n", mst);
close(config.rawsocket);
errno = mst;
return -1;
}
return config.rawsocket;
}
static int close_raw_socket(void) {
if (config.rawsocket < 0) {
errno = EALREADY;
perror("Raw socket is not set");
return -1;
}
if (close(config.rawsocket)) {
perror("Unable to close raw socket");
pthread_mutex_destroy(&rawsocket_lock);
return -1;
}
pthread_mutex_destroy(&rawsocket_lock);
config.rawsocket = -2;
return 0;
}
static int send_raw_socket(const uint8_t *pkt, uint32_t pktlen) {
int ret;
if (pktlen > AVAILABLE_MTU) {
if (config.verbose)
printf("Split packet!\n");
uint8_t buff1[MNL_SOCKET_BUFFER_SIZE];
uint32_t buff1_size = MNL_SOCKET_BUFFER_SIZE;
uint8_t buff2[MNL_SOCKET_BUFFER_SIZE];
uint32_t buff2_size = MNL_SOCKET_BUFFER_SIZE;
switch (config.fragmentation_strategy) {
case FRAG_STRAT_TCP:
if ((ret = tcp4_frag(pkt, pktlen, AVAILABLE_MTU-128,
buff1, &buff1_size, buff2, &buff2_size)) < 0) {
errno = -ret;
return ret;
}
break;
case FRAG_STRAT_IP:
if ((ret = ip4_frag(pkt, pktlen, AVAILABLE_MTU-128,
buff1, &buff1_size, buff2, &buff2_size)) < 0) {
errno = -ret;
return ret;
}
break;
default:
errno = EINVAL;
printf("send_raw_socket: Packet is too big but fragmentation is disabled!\n");
return -EINVAL;
}
int sent = 0;
int status = send_raw_socket(buff1, buff1_size);
if (status >= 0) sent += status;
else {
return status;
}
status = send_raw_socket(buff2, buff2_size);
if (status >= 0) sent += status;
else {
return status;
}
return sent;
}
struct iphdr *iph;
if ((ret = ip4_payload_split(
(uint8_t *)pkt, pktlen, &iph, NULL, NULL, NULL)) < 0) {
errno = -ret;
return ret;
}
struct sockaddr_in daddr = {
.sin_family = AF_INET,
/* Always 0 for raw socket */
.sin_port = 0,
.sin_addr = {
.s_addr = iph->daddr
}
};
pthread_mutex_lock(&rawsocket_lock);
int sent = sendto(config.rawsocket,
pkt, pktlen, 0,
(struct sockaddr *)&daddr, sizeof(daddr));
pthread_mutex_unlock(&rawsocket_lock);
/* The function will return -errno on error as well as errno value set itself */
if (sent < 0) sent = -errno;
return sent;
}
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 {
struct mnl_socket **_nl;
int queue_num;
};
/**
* Used to accept unsupported packets (GSOs)
*/
static int fallback_accept_packet(uint32_t id, struct queue_data qdata) {
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *verdnlh;
verdnlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qdata.queue_num);
nfq_nlmsg_verdict_put(verdnlh, id, NF_ACCEPT);
if (mnl_socket_sendto(*qdata._nl, verdnlh, verdnlh->nlmsg_len) < 0) {
perror("mnl_socket_send");
return MNL_CB_ERROR;
}
return MNL_CB_OK;
}
struct dps_t {
uint8_t *pkt;
uint32_t pktlen;
// Time for the packet in milliseconds
uint32_t timer;
};
// Note that the thread will automatically release dps_t and pkt_buff
void *delay_packet_send(void *data) {
struct dps_t *dpdt = data;
uint8_t *pkt = dpdt->pkt;
uint32_t pktlen = dpdt->pktlen;
usleep(dpdt->timer * 1000);
int ret = send_raw_socket(pkt, pktlen);
if (ret < 0) {
errno = -ret;
perror("send delayed raw packet");
}
free(pkt);
free(dpdt);
return NULL;
}
static int process_packet(const struct packet_data packet, struct queue_data qdata) {
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *verdnlh;
#ifdef DEBUG_LOGGING
printf("packet received (id=%u hw=0x%04x hook=%u, payload len %u)\n",
packet.id, packet.hw_proto, packet.hook, packet.payload_len);
#endif
if (packet.hw_proto != ETH_P_IP) {
return fallback_accept_packet(packet.id, qdata);
}
const int family = AF_INET;
const uint8_t *raw_payload = packet.payload;
size_t raw_payload_len = packet.payload_len;
const struct iphdr *iph;
uint32_t iph_len;
const struct tcphdr *tcph;
uint32_t tcph_len;
const uint8_t *data;
uint32_t dlen;
int ret = tcp4_payload_split((uint8_t *)raw_payload, raw_payload_len,
(struct iphdr **)&iph, &iph_len, (struct tcphdr **)&tcph, &tcph_len,
(uint8_t **)&data, &dlen);
if (ret < 0) {
goto fallback;
}
struct verdict vrd = analyze_tls_data(data, dlen);
verdnlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qdata.queue_num);
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_ACCEPT);
if (vrd.target_sni) {
if (config.verbose)
printf("SNI target detected\n");
if (dlen > 1480) {
if (config.verbose)
fprintf(stderr, "WARNING! Google video packet is too big and may cause issues!\n");
}
uint8_t frag1[MNL_SOCKET_BUFFER_SIZE];
uint8_t frag2[MNL_SOCKET_BUFFER_SIZE];
uint32_t f1len = MNL_SOCKET_BUFFER_SIZE;
uint32_t f2len = MNL_SOCKET_BUFFER_SIZE;
nfq_nlmsg_verdict_put(verdnlh, packet.id, NF_DROP);
int ret = 0;
nfq_ip_set_checksum((struct iphdr *)iph);
nfq_tcp_compute_checksum_ipv4(
(struct tcphdr *)tcph, (struct iphdr *)iph);
if (config.fake_sni_strategy != FKSN_STRAT_NONE) {
uint8_t fake_sni[MNL_SOCKET_BUFFER_SIZE];
uint32_t fsn_len = MNL_SOCKET_BUFFER_SIZE;
ret = gen_fake_sni(iph, tcph, fake_sni, &fsn_len);
if (ret < 0) {
errno = -ret;
perror("gen_fake_sni");
goto fallback;
}
ret = send_raw_socket(fake_sni, fsn_len);
if (ret < 0) {
errno = -ret;
perror("send fake sni");
goto fallback;
}
}
size_t ipd_offset;
size_t mid_offset;
switch (config.fragmentation_strategy) {
case FRAG_STRAT_TCP:
ipd_offset = vrd.sni_offset;
mid_offset = ipd_offset + vrd.sni_len / 2;
if ((ret = tcp4_frag(raw_payload, raw_payload_len,
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
errno = -ret;
perror("tcp4_frag");
goto fallback;
}
break;
case FRAG_STRAT_IP:
ipd_offset = ((char *)data - (char *)tcph) + vrd.sni_offset;
mid_offset = ipd_offset + vrd.sni_len / 2;
mid_offset += 8 - mid_offset % 8;
if ((ret = ip4_frag(raw_payload, raw_payload_len,
mid_offset, frag1, &f1len, frag2, &f2len)) < 0) {
errno = -ret;
perror("ip4_frag");
goto fallback;
}
break;
default:
ret = send_raw_socket(raw_payload, raw_payload_len);
if (ret < 0) {
errno = -ret;
perror("raw pack send");
}
goto fallback;
}
ret = send_raw_socket(frag2, f2len);
if (ret < 0) {
errno = -ret;
perror("raw frags send: frag2");
goto fallback;
}
if (config.seg2_delay) {
struct dps_t *dpdt = malloc(sizeof(struct dps_t));
dpdt->pkt = malloc(f1len);
memcpy(dpdt->pkt, frag1, f1len);
dpdt->pktlen = f1len;
dpdt->timer = config.seg2_delay;
pthread_t thr;
pthread_create(&thr, NULL, delay_packet_send, dpdt);
pthread_detach(thr);
} else {
ret = send_raw_socket(frag1, f1len);
if (ret < 0) {
errno = -ret;
perror("raw frags send: frag1");
goto fallback;
}
}
}
/*
if (pktb_mangled(pktb)) {
if (config.versose)
printf("Mangled!\n");
nfq_nlmsg_verdict_put_pkt(
verdnlh, pktb_data(pktb), pktb_len(pktb));
}
*/
send_verd:
if (mnl_socket_sendto(*qdata._nl, verdnlh, verdnlh->nlmsg_len) < 0) {
perror("mnl_socket_send");
goto error;
}
return MNL_CB_OK;
fallback:
return fallback_accept_packet(packet.id, qdata);
error:
return MNL_CB_ERROR;
}
static int queue_cb(const struct nlmsghdr *nlh, void *data) {
struct queue_data *qdata = data;
struct nfqnl_msg_packet_hdr *ph = NULL;
struct nlattr *attr[NFQA_MAX+1] = {0};
struct packet_data packet = {0};
if (nfq_nlmsg_parse(nlh, attr) < 0) {
perror("Attr parse");
return MNL_CB_ERROR;
}
if (attr[NFQA_PACKET_HDR] == NULL) {
errno = ENODATA;
perror("Metaheader not set");
return MNL_CB_ERROR;
}
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;
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) {
fprintf(stderr, "The packet was truncated! Skip!\n");
return fallback_accept_packet(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])) & RAWSOCKET_MARK) ==
RAWSOCKET_MARK) {
return fallback_accept_packet(packet.id, *qdata);
}
}
return process_packet(packet, *qdata);
}
#define BUF_SIZE (0xffff + (MNL_SOCKET_BUFFER_SIZE / 2))
int init_queue(int queue_num) {
struct mnl_socket *nl;
if (open_socket(&nl)) {
perror("Unable to open socket");
return -1;
}
uint32_t portid = mnl_socket_get_portid(nl);
struct nlmsghdr *nlh;
char buf[BUF_SIZE];
nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_send");
goto die;
}
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));
}
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_send");
goto die;
}
/* ENOBUFS is signalled to userspace when packets were lost
* on kernel side. In most cases, userspace isn't interested
* in this information, so turn it off.
*/
int ret = 1;
mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &ret, sizeof(int));
struct queue_data qdata = {
._nl = &nl,
.queue_num = queue_num
};
printf("Queue %d started!\n", qdata.queue_num);
while (1) {
ret = mnl_socket_recvfrom(nl, buf, BUF_SIZE);
if (ret == -1) {
perror("mnl_socket_recvfrom");
continue;
}
ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, &qdata);
if (ret < 0) {
perror("mnl_cb_run");
}
}
close_socket(&nl);
return 0;
die:
close_socket(&nl);
return -1;
}
// Per-queue config. Used to initialize a queue. Passed to wrapper
struct queue_conf {
uint16_t i;
int queue_num;
};
struct queue_res {
int status;
};
static struct queue_res defqres = {0};
static struct queue_res threads_reses[MAX_THREADS];
void *init_queue_wrapper(void *qdconf) {
struct queue_conf *qconf = qdconf;
struct queue_res *thres = threads_reses + qconf->i;
thres->status = init_queue(qconf->queue_num);
fprintf(stderr, "Thread %d exited with status %d\n", qconf->i, thres->status);
return thres;
}
int main(int argc, const char *argv[]) {
if (parse_args(argc, argv)) {
perror("Unable to parse args");
exit(EXIT_FAILURE);
}
switch (config.fragmentation_strategy) {
case FRAG_STRAT_TCP:
printf("Using TCP segmentation\n");
break;
case FRAG_STRAT_IP:
printf("Using IP fragmentation\n");
break;
default:
printf("SNI fragmentation is disabled\n");
break;
}
if (config.seg2_delay) {
printf("Some outgoing googlevideo request segments will be delayed for %d ms as of seg2_delay define\n", config.seg2_delay);
}
switch (config.fake_sni_strategy) {
case FKSN_STRAT_TTL:
printf("Fake SNI will be sent before each googlevideo request, TTL strategy will be used with TTL %d\n", config.fake_sni_ttl);
break;
case FRAG_STRAT_IP:
printf("Fake SNI will be sent before each googlevideo request, Ack-Seq strategy will be used\n");
break;
default:
printf("SNI fragmentation is disabled\n");
break;
}
if (config.use_gso) {
printf("GSO is enabled\n");
}
if (open_raw_socket() < 0) {
perror("Unable to open raw socket");
exit(EXIT_FAILURE);
}
struct queue_res *qres = &defqres;
if (config.threads == 1) {
struct queue_conf tconf = {
.i = 0,
.queue_num = config.queue_start_num
};
qres = init_queue_wrapper(&tconf);
} else {
printf("%d threads wil be used\n", config.threads);
struct queue_conf thread_confs[MAX_THREADS];
pthread_t threads[MAX_THREADS];
for (int i = 0; i < config.threads; i++) {
struct queue_conf *tconf = thread_confs + i;
pthread_t *thr = threads + i;
tconf->queue_num = config.queue_start_num + i;
tconf->i = i;
pthread_create(thr, NULL, init_queue_wrapper, tconf);
}
void *res;
for (int i = 0; i < config.threads; i++) {
pthread_join(threads[i], &res);
qres = res;
}
}
if (close_raw_socket() < 0) {
perror("Unable to close raw socket");
exit(EXIT_FAILURE);
}
return qres->status;
}

View File

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