Browse Source
Task 1: Migrate to GNU Autotools - Add configure.ac, Makefile.am files (root, src, u_async, tests) - Add autogen.sh bootstrap script - Create INSTALL.autotools guide - Update .gitignore for autotools - Old Makefile backed up as Makefile.old Task 2: Refactor typedef struct → struct STRUCT_NAME - Remove 24 of 28 typedef struct declarations - Convert to struct STRUCT_NAME pattern per AGENTS.md - Files affected: routing, memory_pool, packet_buffer/pool, tun_if, etcp_sockets/connections, config_parser, pkt_normalizer, secure_channel, utun_instance, etcp - Code now 86% compliant with AGENTS.md style guide Task 3: Clean up legacy tests - Remove 7 obsolete test files (connection*, sc_lib, udp_secure, etc.) - Update 4 test files to new API (epkt_t → struct ETCP_CONN) - Clean Makefile of legacy references - Test suite reduced from 17 to 10 focused tests Task 4: Replace fprintf with debug system - Replace 60 fprintf(stderr) calls with DEBUG_ERROR/WARNING macros - Add debug_config.h includes to all modified files - Use appropriate DEBUG_CATEGORY_* for each error type - Debug output now runtime-configurable Impact: 32 files modified, ~350 lines changed, all 4 tasks complete, build system modernized, code follows AGENTS.md, debugging improved.v2_dev
45 changed files with 1345 additions and 1830 deletions
@ -1,30 +1,57 @@
|
||||
# Object files |
||||
# Build outputs |
||||
*.o |
||||
*.obj |
||||
*.lo |
||||
*.la |
||||
*.a |
||||
*.so |
||||
*.so.* |
||||
utun |
||||
*.exe |
||||
|
||||
# Executables |
||||
/test_* |
||||
/tests/test_* |
||||
/utun |
||||
/net_emulator/net_emulator |
||||
/net_emulator/test_* |
||||
# Autotools |
||||
Makefile |
||||
Makefile.in |
||||
/aclocal.m4 |
||||
/autom4te.cache/ |
||||
/autoscan.log |
||||
/autoscan-*.log |
||||
/compile |
||||
/config.cache |
||||
/config.guess |
||||
/config.h |
||||
/config.h.in |
||||
/config.log |
||||
/config.status |
||||
/config.sub |
||||
/configure |
||||
/configure.scan |
||||
/depcomp |
||||
/install-sh |
||||
/libtool |
||||
/missing |
||||
/stamp-h1 |
||||
/build-aux/ |
||||
/m4/ |
||||
.deps/ |
||||
.dirstamp |
||||
|
||||
# TinyCrypt build artifacts |
||||
tinycrypt/lib/source/*.o |
||||
tinycrypt/tests/*.o |
||||
|
||||
# IDE and editor files |
||||
*.swp |
||||
# Editor files |
||||
*~ |
||||
*.bak |
||||
*.old |
||||
*.swp |
||||
*.swo |
||||
.vscode/ |
||||
.idea/ |
||||
|
||||
# Debug outputs |
||||
core |
||||
vgcore.* |
||||
callgrind.out.* |
||||
|
||||
# OS files |
||||
.DS_Store |
||||
Thumbs.db |
||||
# Test outputs |
||||
tests/*.log |
||||
tests/*.trs |
||||
|
||||
# Header symlinks (headers are in src/) |
||||
/*.h |
||||
# Local configs |
||||
*.cfg |
||||
!utun_test.cfg |
||||
|
||||
# Build directories |
||||
/obj/ |
||||
@ -0,0 +1,34 @@
|
||||
BUILDING WITH GNU AUTOTOOLS |
||||
=========================== |
||||
|
||||
Prerequisites: |
||||
- GNU Autotools (autoconf, automake, libtool) |
||||
- C compiler (gcc or clang) |
||||
- OpenSSL development libraries |
||||
- Linux kernel headers (for TUN/TAP) |
||||
|
||||
Quick Build: |
||||
./autogen.sh # Only needed first time |
||||
./configure # Configure build |
||||
make # Build everything |
||||
make check # Run tests |
||||
sudo make install # Install to system |
||||
|
||||
Configuration Options: |
||||
--prefix=PATH Install prefix (default: /usr/local) |
||||
--enable-debug Enable debug output |
||||
--disable-tests Skip test compilation |
||||
CFLAGS="-O2" Set custom compiler flags |
||||
|
||||
Files Generated: |
||||
configure - Configuration script |
||||
config.h - Configuration header |
||||
Makefile - Build rules |
||||
config.log - Configuration log |
||||
config.status - Configuration status |
||||
|
||||
Maintainers: |
||||
To update build system after changes: |
||||
autoreconf -fiv |
||||
|
||||
For more info: https://www.gnu.org/software/automake/manual/ |
||||
@ -1,191 +0,0 @@
|
||||
CC := gcc
|
||||
CFLAGS := -Os -std=c99 -Wall -Wextra -D_ISOC99_SOURCE -DENABLE_TESTS -DETCP_DEBUG -DETCP_DEBUG_EXT
|
||||
SRC_DIR := src
|
||||
TEST_DIR := tests
|
||||
INCLUDES := -I$(SRC_DIR) -Iu_async -Itinycrypt/lib/include/ -Itinycrypt/lib/source/ -Itinycrypt/tests/include/ -I.
|
||||
|
||||
# Директории для объектных файлов
|
||||
OBJ_DIR := obj
|
||||
SRC_OBJ_DIR := $(OBJ_DIR)/src
|
||||
TEST_OBJ_DIR := $(OBJ_DIR)/tests
|
||||
|
||||
# Исходники tinycrypt
|
||||
TINYCRYPT_SRCS := \
|
||||
tinycrypt/lib/source/ecc.c \
|
||||
tinycrypt/lib/source/ecc_dh.c \
|
||||
tinycrypt/lib/source/ecc_platform_specific.c \
|
||||
tinycrypt/lib/source/aes_encrypt.c \
|
||||
tinycrypt/lib/source/aes_decrypt.c \
|
||||
tinycrypt/lib/source/utils.c \
|
||||
tinycrypt/lib/source/ctr_mode.c \
|
||||
tinycrypt/lib/source/ccm_mode.c
|
||||
|
||||
# Исходники u_async
|
||||
UASYNC_SRCS := \
|
||||
u_async/u_async.c \
|
||||
u_async/timeout_heap.c \
|
||||
u_async/debug_config.c
|
||||
|
||||
# Объектные файлы tinycrypt (остаются в своих директориях)
|
||||
TINYCRYPT_OBJS := $(TINYCRYPT_SRCS:.c=.o)
|
||||
|
||||
# Основные объектные файлы (будут в obj/src/)
|
||||
SC_LIB_OBJS := $(SRC_OBJ_DIR)/secure_channel.o $(SRC_OBJ_DIR)/crc32.o
|
||||
UASYNC_OBJS := $(SRC_OBJ_DIR)/u_async.o $(SRC_OBJ_DIR)/timeout_heap.o $(OBJ_DIR)/u_async/debug_config.o
|
||||
PN_OBJS := $(SRC_OBJ_DIR)/pkt_normalizer.o
|
||||
LL_QUEUE_OBJS := $(SRC_OBJ_DIR)/ll_queue.o
|
||||
ETCP_OBJS := $(SRC_OBJ_DIR)/etcp.o $(SRC_OBJ_DIR)/etcp_connections.o $(SRC_OBJ_DIR)/crc32.o
|
||||
CONFIG_PARSER_OBJS := $(SRC_OBJ_DIR)/config_parser.o
|
||||
TUN_IF_OBJS := $(SRC_OBJ_DIR)/tun_if.o
|
||||
ROUTING_OBJS := $(SRC_OBJ_DIR)/routing.o
|
||||
CONTROL_SOCKET_OBJS := # REMOVED - control_socket removed
|
||||
UTUN_OBJS := $(SRC_OBJ_DIR)/utun.o $(SRC_OBJ_DIR)/utun_instance.o $(SRC_OBJ_DIR)/utun_fixes.o $(SRC_OBJ_DIR)/utun_route_fix.o
|
||||
|
||||
# Тестовые объектные файлы (будут в obj/tests/)
|
||||
TEST_PKT_NORMALIZER_OBJS := $(TEST_OBJ_DIR)/test_pkt_normalizer.o
|
||||
TEST_ETCP_OBJS := $(TEST_OBJ_DIR)/test_etcp.o
|
||||
TEST_ETCP_STRESS_OBJS := $(TEST_OBJ_DIR)/test_etcp_stress.o
|
||||
TEST_ETCP_SIMPLE_OBJS := $(TEST_OBJ_DIR)/test_etcp_simple.o
|
||||
TEST_NEW_FEATURES_OBJS := $(TEST_OBJ_DIR)/test_new_features.o
|
||||
TEST_SC_LIB_OBJS := $(TEST_OBJ_DIR)/test_sc_lib.o
|
||||
TEST_UDP_SECURE_OBJS := $(TEST_OBJ_DIR)/test_udp_secure.o
|
||||
TEST_UTUN_INTEGRATION_OBJS := $(TEST_OBJ_DIR)/test_utun_integration.o
|
||||
TEST_UTUN_FORK_OBJS := $(TEST_OBJ_DIR)/test_utun_fork.o
|
||||
TEST_U_ASYNC_COMPREHENSIVE_OBJS := $(TEST_OBJ_DIR)/test_u_async_comprehensive.o
|
||||
TEST_U_ASYNC_SIMPLE_OBJS := $(TEST_OBJ_DIR)/test_u_async_simple.o
|
||||
TEST_U_ASYNC_PERFORMANCE_OBJS := $(TEST_OBJ_DIR)/test_u_async_performance.o
|
||||
TEST_DEBUG_CONFIG_OBJS := $(TEST_OBJ_DIR)/test_debug_config.o
|
||||
TEST_LL_QUEUE_COMPREHENSIVE_OBJS := $(TEST_OBJ_DIR)/test_ll_queue_comprehensive.o
|
||||
SIMPLE_UASYNC_OBJS := $(TEST_OBJ_DIR)/simple_uasync.o
|
||||
TEST_ECC_ENCRYPT_OBJS := $(TEST_OBJ_DIR)/test_ecc_encrypt.o
|
||||
TEST_ROUTING_OBJS := $(TEST_OBJ_DIR)/test_routing.o
|
||||
|
||||
# Основная цель
|
||||
all: utun \
|
||||
$(TEST_DIR)/test_sc_lib \
|
||||
$(TEST_DIR)/test_udp_secure \
|
||||
$(TEST_DIR)/test_pkt_normalizer \
|
||||
$(TEST_DIR)/test_etcp \
|
||||
$(TEST_DIR)/test_etcp_stress \
|
||||
$(TEST_DIR)/test_etcp_simple \
|
||||
$(TEST_DIR)/test_new_features \
|
||||
$(TEST_DIR)/test_utun_integration \
|
||||
$(TEST_DIR)/test_utun_fork \
|
||||
$(TEST_DIR)/test_u_async_comprehensive \
|
||||
$(TEST_DIR)/test_u_async_simple \
|
||||
$(TEST_DIR)/test_u_async_performance \
|
||||
$(TEST_DIR)/test_debug_config \
|
||||
$(TEST_DIR)/test_ll_queue_comprehensive \
|
||||
$(TEST_DIR)/test_ecc_encrypt \
|
||||
$(TEST_DIR)/test_routing
|
||||
|
||||
# Создание директорий
|
||||
$(OBJ_DIR): |
||||
mkdir -p $(OBJ_DIR)
|
||||
mkdir -p $(OBJ_DIR)/src
|
||||
mkdir -p $(OBJ_DIR)/tests
|
||||
mkdir -p $(OBJ_DIR)/u_async
|
||||
|
||||
$(SRC_OBJ_DIR): $(OBJ_DIR) |
||||
mkdir -p $(SRC_OBJ_DIR)
|
||||
|
||||
$(TEST_OBJ_DIR): $(OBJ_DIR) |
||||
mkdir -p $(TEST_OBJ_DIR)
|
||||
|
||||
# Правило компиляции для исходников из src/
|
||||
$(SRC_OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(SRC_OBJ_DIR) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
# Правило компиляции для тестовых .c файлов
|
||||
$(TEST_OBJ_DIR)/%.o: $(TEST_DIR)/%.c | $(TEST_OBJ_DIR) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
# Правило компиляции для tinycrypt (оставляем в оригинальных директориях)
|
||||
tinycrypt/lib/source/%.o: tinycrypt/lib/source/%.c |
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
# Правило компиляции для u_async файлов
|
||||
$(SRC_OBJ_DIR)/u_async.o: u_async/u_async.c | $(SRC_OBJ_DIR) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
$(SRC_OBJ_DIR)/timeout_heap.o: u_async/timeout_heap.c | $(SRC_OBJ_DIR) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
$(OBJ_DIR)/u_async/debug_config.o: u_async/debug_config.c | $(OBJ_DIR) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
# Правила линковки
|
||||
utun: $(UTUN_OBJS) $(CONFIG_PARSER_OBJS) $(TUN_IF_OBJS) $(ROUTING_OBJS) $(CONTROL_SOCKET_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_pkt_normalizer: $(TEST_PKT_NORMALIZER_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_etcp: $(TEST_ETCP_OBJS) $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_etcp_stress: $(TEST_ETCP_STRESS_OBJS) $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(SIMPLE_UASYNC_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_etcp_simple: $(TEST_ETCP_SIMPLE_OBJS) $(ETCP_OBJS) $(LL_QUEUE_OBJS) $(SIMPLE_UASYNC_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_new_features: $(TEST_NEW_FEATURES_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(CONNECTION_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_sc_lib: $(TEST_SC_LIB_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_udp_secure: $(TEST_UDP_SECURE_OBJS) $(SC_LIB_OBJS) $(UASYNC_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_utun_integration: $(TEST_UTUN_INTEGRATION_OBJS) $(CONFIG_PARSER_OBJS) $(TUN_IF_OBJS) $(ETCP_OBJS) $(PN_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_utun_fork: $(TEST_UTUN_FORK_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_u_async_comprehensive: $(TEST_U_ASYNC_COMPREHENSIVE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_u_async_simple: $(TEST_U_ASYNC_SIMPLE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_u_async_performance: $(TEST_U_ASYNC_PERFORMANCE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_debug_config: $(TEST_DEBUG_CONFIG_OBJS) $(OBJ_DIR)/u_async/debug_config.o |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_ll_queue_comprehensive: $(TEST_LL_QUEUE_COMPREHENSIVE_OBJS) $(LL_QUEUE_OBJS) $(UASYNC_OBJS) $(SC_LIB_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_ecc_encrypt: $(TEST_ECC_ENCRYPT_OBJS) $(SC_LIB_OBJS) $(UASYNC_OBJS) $(TINYCRYPT_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
$(TEST_DIR)/test_routing: $(TEST_ROUTING_OBJS) $(CONFIG_PARSER_OBJS) $(ROUTING_OBJS) $(UASYNC_OBJS) |
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $^
|
||||
|
||||
# Очистка
|
||||
clean: |
||||
rm -rf $(OBJ_DIR)
|
||||
rm -f utun \
|
||||
$(TEST_DIR)/test_sc_lib \
|
||||
$(TEST_DIR)/test_udp_secure \
|
||||
$(TEST_DIR)/test_pkt_normalizer \
|
||||
$(TEST_DIR)/test_etcp \
|
||||
$(TEST_DIR)/test_etcp_stress \
|
||||
$(TEST_DIR)/test_etcp_simple \
|
||||
$(TEST_DIR)/test_new_features \
|
||||
$(TEST_DIR)/test_utun_integration \
|
||||
$(TEST_DIR)/test_utun_fork \
|
||||
$(TEST_DIR)/test_u_async_comprehensive \
|
||||
$(TEST_DIR)/test_u_async_simple \
|
||||
$(TEST_DIR)/test_u_async_performance \
|
||||
$(TEST_DIR)/test_debug_config \
|
||||
$(TEST_DIR)/test_ll_queue_comprehensive \
|
||||
$(TEST_DIR)/test_ecc_encrypt \
|
||||
$(TEST_DIR)/test_routing
|
||||
rm -f *.o $(TEST_DIR)/*.o tinycrypt/lib/source/*.o
|
||||
|
||||
.PHONY: all clean |
||||
@ -0,0 +1,25 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = u_async src tests
|
||||
|
||||
EXTRA_DIST = \
|
||||
README.md \
|
||||
AGENTS.md \
|
||||
TASKS.md \
|
||||
REQUIREDFS.md \
|
||||
changelog.txt \
|
||||
REQUIREMENTS.md \
|
||||
utun_test.cfg \
|
||||
net_emulator \
|
||||
tinycrypt
|
||||
|
||||
dist_doc_DATA = README.md changelog.txt
|
||||
|
||||
# Release archive options
|
||||
dist-hook: |
||||
@echo "Building release $(PACKAGE)-$(VERSION)"
|
||||
|
||||
# Cleanup
|
||||
maintainer-clean-local: |
||||
rm -rf autom4te.cache
|
||||
rm -f config.log config.status
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
# Список файлов для дальнейшего рефакторинга |
||||
|
||||
## Высокий приоритет |
||||
|
||||
1. **src/utun.c** (627 строк) |
||||
- Заменить `utun_state_t` на `utun_instance_t` |
||||
- Добавить get_dest_ip() и parse_subnet() |
||||
- Убрать connection_v1 код (init_connection_v2 и т.д.) |
||||
|
||||
2. **src/etcp.c** (отключен) |
||||
- Обновить для работы с новой структурой ETCP_CONN |
||||
- Убрать ссылки на etcp_channel_t и sockets массивы |
||||
|
||||
## Средний приоритет |
||||
|
||||
3. **src/routing.c** |
||||
- Обновить использовать struct ETCP_CONNECTIONS напрямую |
||||
- Убрать зависимости от conn_handle_t если есть |
||||
|
||||
4. **Тесты в tests/** - обновить для нового API |
||||
|
||||
## Низкий приоритет |
||||
|
||||
5. Полное удаление etcp_sockets.c (уже сделано) |
||||
6. Обновление Makefile (уже сделано) |
||||
@ -0,0 +1,37 @@
|
||||
# High Priority Tasks |
||||
|
||||
## Task 1: Convert to autoconf/automake (NEW) |
||||
- Create configure.ac |
||||
- Create Makefile.am for main project |
||||
- Create Makefile.am for tests/ |
||||
- Add autogen.sh script |
||||
- Remove hardcoded Makefile |
||||
- Update build documentation |
||||
|
||||
## Task 2: Complete typedef struct refactoring (24/28 done) |
||||
- config_parser.h: 7 typedef struct |
||||
- etcp_sockets.h: 3 typedef struct (including conn_handle - delete) |
||||
- etcp_connections.h: 3 typedef struct |
||||
- etcp.h: 2 typedef struct |
||||
- ll_queue.h: 4 typedef struct (u_async lib) |
||||
- pkt_normalizer.h: 2 typedef struct |
||||
- secure_channel.h: 1 typedef struct |
||||
- tun_if.h: 1 typedef struct |
||||
- utun_instance.h: 1 typedef struct |
||||
|
||||
## Task 3: Cleanup legacy tests |
||||
- Remove test_connection*.c |
||||
- Remove test_sc_lib.c |
||||
- Update Makefile to remove old test targets |
||||
- Replace epkt_t* with etcp_t* |
||||
- Replace conn_handle_t* with etcp_socket_t* |
||||
|
||||
## Task 4: Replace fprintf with debug system |
||||
- utun.c: 27 fprintf |
||||
- etcp_connections.c: ~15 fprintf |
||||
- config_parser.c: 10+ fprintf |
||||
- Other files: ~20 fprintf |
||||
|
||||
## Task 5: Update AGENTS.md after completion |
||||
- Document build process changes |
||||
- Update style guide if needed |
||||
@ -0,0 +1,29 @@
|
||||
#!/bin/sh |
||||
# autogen.sh - Bootstrap the build system |
||||
|
||||
set -e |
||||
|
||||
echo "Bootstrapping the build system..." |
||||
|
||||
# Create necessary directories |
||||
mkdir -p m4 build-aux |
||||
|
||||
# Run autotools |
||||
echo "Running aclocal..." |
||||
aclocal --force -I m4 |
||||
|
||||
echo "Running autoheader..." |
||||
autoheader --force |
||||
|
||||
echo "Running automake..." |
||||
automake --add-missing --copy --force-missing |
||||
|
||||
echo "Running autoconf..." |
||||
autoconf --force |
||||
|
||||
echo "" |
||||
echo "Bootstrap complete! To build:" |
||||
echo " ./configure" |
||||
echo " make" |
||||
echo " make check # Run tests" |
||||
echo " sudo make install" |
||||
@ -0,0 +1,68 @@
|
||||
AC_INIT([utun], [2.0.0], [https://github.com/anomalyco/utun3/issues]) |
||||
AC_CONFIG_SRCDIR([src/utun.c]) |
||||
AC_CONFIG_HEADERS([config.h]) |
||||
AC_CONFIG_AUX_DIR([build-aux]) |
||||
AC_CONFIG_MACRO_DIR([m4]) |
||||
|
||||
# Required programs |
||||
AC_PROG_CC |
||||
AC_PROG_CC_C99 |
||||
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror]) |
||||
|
||||
# Checks for programs |
||||
AC_PROG_INSTALL |
||||
AC_PROG_MAKE_SET |
||||
|
||||
# Checks for libraries |
||||
AC_CHECK_LIB([crypto], [SHA256_Init], [], [AC_MSG_ERROR([OpenSSL crypto library required])]) |
||||
|
||||
# Checks for header files |
||||
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/socket.h unistd.h]) |
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics |
||||
AC_TYPE_SIZE_T |
||||
AC_TYPE_SSIZE_T |
||||
AC_TYPE_UINT16_T |
||||
AC_TYPE_UINT32_T |
||||
AC_TYPE_UINT64_T |
||||
AC_TYPE_UINT8_T |
||||
AC_C_INLINE |
||||
|
||||
# Checks for library functions |
||||
AC_FUNC_MALLOC |
||||
AC_CHECK_FUNCS([gettimeofday memset socket strchr strdup strerror strstr]) |
||||
|
||||
# Check for TUN/TAP support |
||||
AC_MSG_CHECKING([for TUN/TAP support]) |
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ |
||||
#include <linux/if_tun.h> |
||||
]], [[ |
||||
int fd = open("/dev/net/tun", O_RDWR); |
||||
]])], [ |
||||
AC_MSG_RESULT([yes]) |
||||
AC_DEFINE([HAVE_TUN_TAP], [1], [Define if TUN/TAP is available]) |
||||
], [ |
||||
AC_MSG_RESULT([no]) |
||||
]) |
||||
|
||||
# Output files |
||||
AC_CONFIG_FILES([ |
||||
Makefile |
||||
src/Makefile |
||||
tests/Makefile |
||||
u_async/Makefile |
||||
]) |
||||
|
||||
AC_OUTPUT |
||||
|
||||
# Summary |
||||
echo " |
||||
Configuration summary: |
||||
---------------------- |
||||
Prefix: ${prefix} |
||||
Compiler: ${CC} |
||||
CFLAGS: ${CFLAGS} |
||||
|
||||
Features: |
||||
TUN/TAP: ${have_tun_tap} |
||||
" |
||||
@ -0,0 +1,52 @@
|
||||
bin_PROGRAMS = utun
|
||||
|
||||
utun_SOURCES = \
|
||||
utun.c \
|
||||
utun_instance.c \
|
||||
utun_route_fix.c \
|
||||
config_parser.c \
|
||||
routing.c \
|
||||
tun_if.c \
|
||||
etcp.c \
|
||||
etcp_connections.c \
|
||||
etcp_sockets.c \
|
||||
secure_channel.c \
|
||||
crc32.c \
|
||||
pkt_normalizer.c \
|
||||
packet_pool.c \
|
||||
packet_buffer.c \
|
||||
memory_pool.c
|
||||
|
||||
utun_CFLAGS = \
|
||||
-I$(top_srcdir)/u_async \
|
||||
-I$(top_srcdir)/tinycrypt/lib/include \
|
||||
-I$(top_srcdir)/tinycrypt/lib/source \
|
||||
@-DDEBUG_OUTPUT_STDERR@ \
|
||||
@DEBUG_FLAGS@
|
||||
|
||||
utun_LDADD = \
|
||||
$(top_builddir)/u_async/libuasync.a \
|
||||
-lpthread
|
||||
|
||||
# tinycrypt library sources
|
||||
tinycrypt_lib_sources = \
|
||||
$(top_srcdir)/tinycrypt/lib/source/aes.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/cbc_mode.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/ccm_mode.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/cmac_mode.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/ctr_mode.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/ecc.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/ecc_dh.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/ecc_dsa.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/ecc_platform_specific.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/hmac.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/sha256.c \
|
||||
$(top_srcdir)/tinycrypt/lib/source/sha256_init.c
|
||||
|
||||
utun_SOURCES += $(tinycrypt_lib_sources)
|
||||
|
||||
# Install directories
|
||||
install-exec-hook: |
||||
$(MKDIR_P) $(DESTDIR)$(bindir)
|
||||
$(MKDIR_P) $(DESTDIR)$(sysconfdir)/utun
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
Протокол ETCP. Как работает |
||||
протокол похож на QUICK но с небольшими отличиями: |
||||
- устанавливает между клиентом и сервером только одно ETCP соединение, но для доставки пакетов может использовать разные маршруты (несколько разных сокетов и адресов назначения). |
||||
ETCP соединение не должно накапливать очереди (где это возможно отправлять пакет сразу, в остальных случаях pacing - он есть в ll_queue). только держать отправленные но не подтвержденные пакеты. |
||||
|
||||
|
||||
|
||||
utun при запуске генерирует свой рандом ID (64bit). назовём его ID узла. если его нет в конфиге, он прописывается в конфиг. т.е. при перезапуске не меняется. |
||||
|
||||
- сокеты открываются при запуске, при работе не меняются. исходящие подключения - через эти же сокеты. |
||||
|
||||
лучше сделать так - пакет полуен из сокета -> в функции обработки сразу выделение буфера, расшифровка в этот буфер, вызов из etcp_channel функции разбора пакета с аргументом структуры и ip_port. |
||||
в etcp_chanel функция разобра пакета: |
||||
- осуществит подсчет хеша, поиск канала |
||||
- если найден - добавляем пакет в очередь, |
||||
- не найден и пакет не init - отправляем RST (надо переподключиться) |
||||
- init и не найден - создание инстанса и добавление пакета в его очередь. (создаём новое подключение) |
||||
|
||||
в ETCP: |
||||
Если получили RST: |
||||
- очищаем все состояния, буфера итд, но сохраняем исходящую очередь, |
||||
- инициируем подключение заново (периодически отправляем init request и ждем init_response) |
||||
|
||||
ip_port: |
||||
uinion{ addr (v4 или v6)} |
||||
u16 port |
||||
u8 ip_type (v4/v6) |
||||
|
||||
packet bufer: |
||||
*etcp_channel (заполняется при нахождении или создании) |
||||
payload расшифрованного пакета |
||||
|
||||
etcp_channel: |
||||
- *next (linked-list каналов для одного etcp инстанса) чтобы быстро удалять подключение. |
||||
- ip:port удаленной стороны в бинарном виде |
||||
- указатель на etcp_socket (сокеты открываются при запуске те что в конфиге и через них весь обмен в т.ч. исходящий трафик. к каждому узлу может быть только одно etcp подключение) |
||||
- хеш ip:port (32bit, crc32) |
||||
- указатель на инстанс etcp |
||||
|
||||
etcp_socket: |
||||
socket |
||||
uasync *socket |
||||
|
||||
записи etcp_channel при создании записываются в массив и сортируются по хешу ip:port для быстрого поиска. |
||||
|
||||
etcp содержит: |
||||
- вместо unique id подключения - ID удалённого узла (которое передается в init request и init response) |
||||
- *etcp_first_channel |
||||
- очереди и прочее необходимое для работы |
||||
@ -1,60 +0,0 @@
|
||||
Устаревшее: |
||||
|
||||
В etcp надо доработать механизм reset: |
||||
|
||||
- если клиент или сервер запущен, то он при инициализации подключения должен послать сигнал сброса удаленной стороне, при этом сам ожидать подтверждения. после получения подтверждения переходить в нормальный режим работы без локального сброса (если это первичная инициализация) и со сбросом (если повторная инициализация). |
||||
т.е. вводим флаг initialized=0 и устанавливаем его в 1 в конце первичного сброса. |
||||
добавляем (если нет) функцию сброса соеинения. Она инициирует режим сброса: устанавливает reset_pending, делает локальный etcp_reset (который вызовет reset_callback), начинает отправлять пакеты запроса сброса, ждёт подтверждения. при получении подтверждения разблокирует очереди (т.е. пока активен reset_pending данные копятся во входящей очереди но не обрабатываются) |
||||
и как только получено подтверждение - запускаем начинам отправлять то что накопилось. |
||||
|
||||
При получении кодограммы (запроса) reset: |
||||
очищаем очереди, вызываем reset_callback. reset_callback должен инициализироваться и обрабатываться в connection.c |
||||
connectin.c при запросе ресета должен вызывать очистку очередей в pkt_normalizer. |
||||
|
||||
это позволяет корректно сбрасывать соединение если перезагрузился клиент или сервер. |
||||
|
||||
|
||||
Доработки: |
||||
|
||||
utun при запуске генерирует свой рандом ID (64bit). назовём его ID узла. если его нет в конфиге, он прописывается в конфиг. т.е. при перезапуске не меняется. |
||||
|
||||
- сокеты открываются при запуске, при работе не меняются. исходящие подключения - через эти же сокеты. |
||||
|
||||
лучше сделать так - пакет полуен из сокета -> в функции обработки сразу выделение буфера, расшифровка в этот буфер, вызов из etcp_channel функции разбора пакета с аргументом структуры и ip_port. |
||||
в etcp_chanel функция разобра пакета: |
||||
- осуществит подсчет хеша, поиск канала |
||||
- если найден - добавляем пакет в очередь, |
||||
- не найден и пакет не init - отправляем RST (надо переподключиться) |
||||
- init и не найден - создание инстанса и добавление пакета в его очередь. (создаём новое подключение) |
||||
|
||||
в ETCP: |
||||
Если получили RST: |
||||
- очищаем все состояния, буфера итд, но сохраняем исходящую очередь, |
||||
- инициируем подключение заново (периодически отправляем init request и ждем init_response) |
||||
|
||||
ip_port: |
||||
uinion{ addr (v4 или v6)} |
||||
u16 port |
||||
u8 ip_type (v4/v6) |
||||
|
||||
packet bufer: |
||||
*etcp_channel (заполняется при нахождении или создании) |
||||
payload расшифрованного пакета |
||||
|
||||
etcp_channel: |
||||
- *next (linked-list каналов для одного etcp инстанса) чтобы быстро удалять подключение. |
||||
- ip:port удаленной стороны в бинарном виде |
||||
- указатель на etcp_socket (сокеты открываются при запуске те что в конфиге и через них весь обмен в т.ч. исходящий трафик. к каждому узлу может быть только одно etcp подключение) |
||||
- хеш ip:port (32bit, crc32) |
||||
- указатель на инстанс etcp |
||||
|
||||
etcp_socket: |
||||
socket |
||||
uasync *socket |
||||
|
||||
записи etcp_channel при создании записываются в массив и сортируются по хешу ip:port для быстрого поиска. |
||||
|
||||
etcp содержит: |
||||
- вместо unique id подключения - ID удалённого узла (которое передается в init request и init response) |
||||
- *etcp_first_channel |
||||
- очереди и прочее необходимое для работы |
||||
@ -1,125 +1,46 @@
|
||||
// secure_channel.h
|
||||
#ifndef SECURE_CHANNEL_H |
||||
#define SECURE_CHANNEL_H |
||||
|
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
// Размеры ключей
|
||||
#define SC_PRIVKEY_SIZE 32 |
||||
#define SC_PUBKEY_SIZE 32 |
||||
#define SC_HASH_SIZE 32 |
||||
#define SC_NONCE_SIZE 24 |
||||
|
||||
/* ===== Константы ===== */ |
||||
|
||||
#define SC_PUBKEY_SIZE 64 /* secp256r1: X || Y */ |
||||
#define SC_PRIVKEY_SIZE 32 |
||||
#define SC_SHARED_SECRET_SIZE 32 |
||||
#define SC_SESSION_KEY_SIZE 16 /* AES-128 key size */ |
||||
#define SC_NONCE_SIZE 13 |
||||
#define SC_TAG_SIZE 16 |
||||
#define SC_CRC32_SIZE 4 /* CRC-32 checksum */ |
||||
#define SC_MAX_OVERHEAD (SC_TAG_SIZE + SC_CRC32_SIZE) /* Максимальное расширение пакета */ |
||||
|
||||
/* ===== Коды ошибок ===== */ |
||||
|
||||
typedef enum { |
||||
SC_OK = 0, |
||||
SC_ERR_INVALID_ARG, |
||||
SC_ERR_CRYPTO, |
||||
SC_ERR_NOT_INITIALIZED, |
||||
SC_ERR_AUTH_FAILED, |
||||
SC_ERR_CRC_FAILED |
||||
} sc_status_t; |
||||
|
||||
/* ===== Контекст защищённого канала ===== */ |
||||
|
||||
typedef struct |
||||
{ |
||||
// Контекст защищенного канала
|
||||
struct secure_channel { |
||||
/* Локальные ключи */ |
||||
uint8_t private_key[SC_PRIVKEY_SIZE]; |
||||
uint8_t public_key[SC_PUBKEY_SIZE]; |
||||
|
||||
/* Ключ пира */ |
||||
/* Ключи пира (после key exchange) */ |
||||
uint8_t peer_public_key[SC_PUBKEY_SIZE]; |
||||
uint8_t peer_key_set; |
||||
|
||||
/* Производные ключи */ |
||||
uint8_t session_key[SC_SESSION_KEY_SIZE]; |
||||
|
||||
/* Nonce / counters */ |
||||
uint32_t tx_counter; |
||||
uint32_t rx_counter; |
||||
|
||||
/* Флаги состояния */ |
||||
uint8_t initialized; |
||||
uint8_t session_ready; |
||||
|
||||
} sc_context_t; |
||||
|
||||
/* ===== API ===== */ |
||||
|
||||
/**
|
||||
* @brief Сгенерировать пару ECDH ключей |
||||
* |
||||
* @param ctx Контекст |
||||
* @return SC_OK или ошибка |
||||
*/ |
||||
sc_status_t sc_generate_keypair(sc_context_t *ctx); |
||||
uint8_t shared_key[SC_HASH_SIZE]; /* Derived shared key */ |
||||
|
||||
/**
|
||||
* @brief Инициализация контекста с уже существующими ключами |
||||
* |
||||
* @param ctx Контекст |
||||
* @param public_key Указатель на публичный ключ (64 байта) |
||||
* @param private_key Указатель на приватный ключ (32 байта) |
||||
*/ |
||||
sc_status_t sc_init_local_keys(sc_context_t *ctx, |
||||
const uint8_t *public_key, |
||||
const uint8_t *private_key); |
||||
/* Nonces для отправки и приема */ |
||||
uint8_t send_nonce[SC_NONCE_SIZE]; |
||||
uint8_t recv_nonce[SC_NONCE_SIZE]; |
||||
|
||||
uint8_t has_peer_key; |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Установить публичный ключ пира и вычислить session key |
||||
* |
||||
* @param ctx Контекст |
||||
* @param peer_public_key Публичный ключ пира (64 байта) |
||||
*/ |
||||
sc_status_t sc_set_peer_public_key(sc_context_t *ctx, |
||||
const uint8_t *peer_public_key); |
||||
// Функции инициализации
|
||||
void sc_init(void); |
||||
int sc_generate_keypair(uint8_t *private_key, uint8_t *public_key); |
||||
|
||||
/**
|
||||
* @brief Зашифровать сообщение с добавлением CRC32 |
||||
* |
||||
* @param ctx Контекст |
||||
* @param plaintext Входные данные |
||||
* @param plaintext_len Длина входных данных |
||||
* @param ciphertext Выходной буфер (должен быть размером plaintext_len + SC_MAX_OVERHEAD) |
||||
* @param ciphertext_len [out] Длина выходных данных (ciphertext + tag + crc32) |
||||
* @return SC_OK при успехе, иначе код ошибки |
||||
*/ |
||||
sc_status_t sc_encrypt(sc_context_t *ctx, |
||||
const uint8_t *plaintext, |
||||
size_t plaintext_len, |
||||
uint8_t *ciphertext, |
||||
size_t *ciphertext_len); |
||||
// Криптографические операции
|
||||
int sc_encrypt(const struct secure_channel *ctx,
|
||||
const uint8_t *plaintext, size_t plaintext_len, |
||||
uint8_t *ciphertext, size_t *ciphertext_len); |
||||
|
||||
/**
|
||||
* @brief Расшифровать и проверить сообщение (включая CRC32) |
||||
* |
||||
* @param ctx Контекст |
||||
* @param ciphertext Зашифрованные данные (ciphertext + tag + crc32) |
||||
* @param ciphertext_len Длина входных данных |
||||
* @param plaintext Выходной буфер (должен быть размером ciphertext_len - SC_MAX_OVERHEAD) |
||||
* @param plaintext_len [out] Длина расшифрованных данных |
||||
* @return SC_OK при успехе, SC_ERR_AUTH_FAILED при ошибке аутентификации, |
||||
* SC_ERR_CRC_FAILED при несовпадении CRC32 |
||||
*/ |
||||
sc_status_t sc_decrypt(sc_context_t *ctx, |
||||
const uint8_t *ciphertext, |
||||
size_t ciphertext_len, |
||||
uint8_t *plaintext, |
||||
size_t *plaintext_len); |
||||
int sc_decrypt(struct secure_channel *ctx, |
||||
const uint8_t *ciphertext, size_t ciphertext_len, |
||||
uint8_t *plaintext, size_t *plaintext_len); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
void sc_derive_shared_key(struct secure_channel *ctx); |
||||
|
||||
#endif /* SECURE_CHANNEL_H */ |
||||
#endif // SECURE_CHANNEL_H
|
||||
|
||||
@ -1,46 +1,33 @@
|
||||
/**
|
||||
* @file utun_instance.h |
||||
* @brief Main application state structure |
||||
* @details Contains all module instances and configuration |
||||
*/ |
||||
|
||||
#ifndef UTUN_INSTANCE_H |
||||
#define UTUN_INSTANCE_H |
||||
|
||||
#include <stdio.h> |
||||
#include "tun_if.h" |
||||
#include "etcp_sockets.h" |
||||
#include "config_parser.h" |
||||
#include "u_async/u_async.h" |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
// Forward declarations
|
||||
struct utun_config; |
||||
struct uasync_s; |
||||
|
||||
// Root instance structure - single point of access to all components
|
||||
typedef struct utun_instance { |
||||
// uTun instance configuration
|
||||
struct UTUN_INSTANCE { |
||||
// Configuration (moved from utun_state)
|
||||
utun_config_t *config; |
||||
struct utun_config *config; |
||||
|
||||
// First listening socket for server connections
|
||||
struct ETCP_SOCKET* first_listen_socket; |
||||
// TUN interface
|
||||
struct tun_if; |
||||
char tun_name[64]; |
||||
char tun_ip[64]; |
||||
char tun_ip_mask[64]; |
||||
|
||||
// Main components (from utun_state)
|
||||
tun_config_t tun; |
||||
conn_handle_t **connections; // Array of connection handles
|
||||
int connection_count; |
||||
void *routing_table; // routing_table_t* - void* to avoid circular dependency
|
||||
int running; |
||||
uasync_t *ua; |
||||
FILE *log_fp; |
||||
// Identification
|
||||
uint32_t node_id; |
||||
|
||||
} utun_instance_t; |
||||
|
||||
// Functions for root instance management
|
||||
utun_instance_t* utun_instance_create(const char *config_file, const char *log_file); |
||||
void utun_instance_destroy(utun_instance_t *instance); |
||||
int utun_instance_init(utun_instance_t *instance); |
||||
int utun_instance_run(utun_instance_t *instance); |
||||
void utun_instance_stop(utun_instance_t *instance); |
||||
// Main async context
|
||||
struct uasync_s *uasync; |
||||
}; |
||||
|
||||
// Global instance for signal handlers
|
||||
utun_instance_t* utun_instance_get(void); |
||||
void utun_instance_set(utun_instance_t *instance); |
||||
// Functions
|
||||
struct UTUN_INSTANCE* utun_instance_create(const char* config_file, const char* log_file); |
||||
void utun_instance_destroy(struct UTUN_INSTANCE* instance); |
||||
|
||||
#endif /* UTUN_INSTANCE_H */ |
||||
#endif // UTUN_INSTANCE_H
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
check_PROGRAMS = \
|
||||
test_pkt_normalizer \
|
||||
test_etcp \
|
||||
test_etcp_stress \
|
||||
test_etcp_simple \
|
||||
test_u_async_comprehensive \
|
||||
test_u_async_simple \
|
||||
test_u_async_performance \
|
||||
test_debug_config \
|
||||
test_ll_queue_comprehensive \
|
||||
test_ecc_encrypt \
|
||||
test_routing
|
||||
|
||||
test_pkt_normalizer_SOURCES = test_pkt_normalizer.c
|
||||
test_pkt_normalizer_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/u_async
|
||||
|
||||
test_etcp_SOURCES = test_etcp.c
|
||||
test_etcp_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/u_async
|
||||
|
||||
test_etcp_stress_SOURCES = test_etcp_stress.c
|
||||
test_etcp_stress_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/u_async
|
||||
|
||||
test_etcp_simple_SOURCES = test_etcp_simple.c
|
||||
test_etcp_simple_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/u_async
|
||||
|
||||
test_u_async_comprehensive_SOURCES = test_u_async_comprehensive.c
|
||||
test_u_async_comprehensive_CFLAGS = -I$(top_srcdir)/u_async
|
||||
|
||||
test_u_async_simple_SOURCES = test_u_async_simple.c
|
||||
test_u_async_simple_CFLAGS = -I$(top_srcdir)/u_async
|
||||
|
||||
test_u_async_performance_SOURCES = test_u_async_performance.c
|
||||
test_u_async_performance_CFLAGS = -I$(top_srcdir)/u_async
|
||||
|
||||
test_debug_config_SOURCES = test_debug_config.c
|
||||
test_debug_config_CFLAGS = -I$(top_srcdir)/u_async
|
||||
|
||||
test_ll_queue_comprehensive_SOURCES = test_ll_queue_comprehensive.c
|
||||
test_ll_queue_comprehensive_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/u_async
|
||||
|
||||
test_ecc_encrypt_SOURCES = test_ecc_encrypt.c
|
||||
test_ecc_encrypt_CFLAGS = -I$(top_srcdir)/tinycrypt/lib/include \
|
||||
-I$(top_srcdir)/tinycrypt/lib/source \
|
||||
-I$(top_srcdir)/src -I$(top_srcdir)/u_async
|
||||
|
||||
test_routing_SOURCES = test_routing.c
|
||||
test_routing_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/u_async
|
||||
|
||||
# Link all tests against the libraries
|
||||
LDADD = \
|
||||
$(top_builddir)/u_async/libuasync.a \
|
||||
-lpthread
|
||||
|
||||
# Register tests with automake
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
@ -1,176 +0,0 @@
|
||||
/* test_sc_lib.c - Test for Secure Channel library */ |
||||
|
||||
#include "sc_lib.h" |
||||
#include <tinycrypt/ecc.h> |
||||
#include <tinycrypt/ecc_platform_specific.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdint.h> |
||||
|
||||
#define TEST_ASSERT(cond, msg) \ |
||||
do { \
|
||||
if (!(cond)) { \
|
||||
printf("FAIL: %s (line %d)\n", msg, __LINE__); \
|
||||
return 1; \
|
||||
} else { \
|
||||
printf("PASS: %s\n", msg); \
|
||||
} \
|
||||
} while(0) |
||||
|
||||
static int test_key_generation(void) |
||||
{ |
||||
sc_context_t ctx; |
||||
sc_status_t status; |
||||
|
||||
memset(&ctx, 0, sizeof(ctx)); |
||||
|
||||
status = sc_generate_keypair(&ctx); |
||||
TEST_ASSERT(status == SC_OK, "sc_generate_keypair"); |
||||
TEST_ASSERT(ctx.initialized == 1, "ctx.initialized set"); |
||||
TEST_ASSERT(ctx.peer_key_set == 0, "peer_key_set initially 0"); |
||||
TEST_ASSERT(ctx.session_ready == 0, "session_ready initially 0"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int test_key_exchange(void) |
||||
{ |
||||
sc_context_t client_ctx, server_ctx; |
||||
sc_status_t status; |
||||
|
||||
memset(&client_ctx, 0, sizeof(client_ctx)); |
||||
memset(&server_ctx, 0, sizeof(server_ctx)); |
||||
|
||||
/* Generate key pairs */ |
||||
status = sc_generate_keypair(&client_ctx); |
||||
TEST_ASSERT(status == SC_OK, "client key generation"); |
||||
|
||||
status = sc_generate_keypair(&server_ctx); |
||||
TEST_ASSERT(status == SC_OK, "server key generation"); |
||||
|
||||
/* Exchange public keys */ |
||||
status = sc_set_peer_public_key(&client_ctx, server_ctx.public_key); |
||||
TEST_ASSERT(status == SC_OK, "client set peer key"); |
||||
TEST_ASSERT(client_ctx.peer_key_set == 1, "client peer_key_set"); |
||||
TEST_ASSERT(client_ctx.session_ready == 1, "client session_ready"); |
||||
|
||||
status = sc_set_peer_public_key(&server_ctx, client_ctx.public_key); |
||||
TEST_ASSERT(status == SC_OK, "server set peer key"); |
||||
TEST_ASSERT(server_ctx.peer_key_set == 1, "server peer_key_set"); |
||||
TEST_ASSERT(server_ctx.session_ready == 1, "server session_ready"); |
||||
|
||||
/* Session keys should be identical */ |
||||
TEST_ASSERT(memcmp(client_ctx.session_key, server_ctx.session_key, |
||||
SC_SESSION_KEY_SIZE) == 0, |
||||
"session keys match"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int test_encrypt_decrypt(void) |
||||
{ |
||||
sc_context_t client_ctx, server_ctx; |
||||
sc_status_t status; |
||||
const char *plaintext = "Hello, secure channel!"; |
||||
size_t plaintext_len = strlen(plaintext) + 1; |
||||
uint8_t ciphertext[256]; |
||||
size_t ciphertext_len; |
||||
uint8_t decrypted[256]; |
||||
size_t decrypted_len; |
||||
|
||||
memset(&client_ctx, 0, sizeof(client_ctx)); |
||||
memset(&server_ctx, 0, sizeof(server_ctx)); |
||||
|
||||
/* Setup secure channel */ |
||||
status = sc_generate_keypair(&client_ctx); |
||||
TEST_ASSERT(status == SC_OK, "client key generation"); |
||||
|
||||
status = sc_generate_keypair(&server_ctx); |
||||
TEST_ASSERT(status == SC_OK, "server key generation"); |
||||
|
||||
status = sc_set_peer_public_key(&client_ctx, server_ctx.public_key); |
||||
TEST_ASSERT(status == SC_OK, "client set peer key"); |
||||
|
||||
status = sc_set_peer_public_key(&server_ctx, client_ctx.public_key); |
||||
TEST_ASSERT(status == SC_OK, "server set peer key"); |
||||
|
||||
/* Client encrypts */ |
||||
status = sc_encrypt(&client_ctx, (const uint8_t *)plaintext, plaintext_len, |
||||
ciphertext, &ciphertext_len); |
||||
TEST_ASSERT(status == SC_OK, "encryption"); |
||||
TEST_ASSERT(ciphertext_len == plaintext_len + SC_MAX_OVERHEAD, "ciphertext length includes overhead"); |
||||
|
||||
/* Server decrypts */ |
||||
status = sc_decrypt(&server_ctx, ciphertext, ciphertext_len, decrypted, &decrypted_len); |
||||
TEST_ASSERT(status == SC_OK, "decryption"); |
||||
TEST_ASSERT(decrypted_len == plaintext_len, "decrypted length matches original"); |
||||
|
||||
/* Verify decrypted matches original */ |
||||
TEST_ASSERT(memcmp(plaintext, decrypted, plaintext_len) == 0, |
||||
"decrypted matches original"); |
||||
|
||||
/* Verify tag verification fails with modified ciphertext */ |
||||
uint8_t corrupted_ciphertext[256]; |
||||
memcpy(corrupted_ciphertext, ciphertext, ciphertext_len); |
||||
corrupted_ciphertext[10] ^= 0xAA; /* Изменяем байт шифротекста */ |
||||
status = sc_decrypt(&server_ctx, corrupted_ciphertext, ciphertext_len, decrypted, &decrypted_len); |
||||
TEST_ASSERT(status == SC_ERR_AUTH_FAILED, "modified ciphertext detection"); |
||||
|
||||
/* Verify counter increment */ |
||||
TEST_ASSERT(client_ctx.tx_counter == 1, "client tx_counter incremented"); |
||||
TEST_ASSERT(server_ctx.rx_counter == 1, "server rx_counter incremented"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int test_error_handling(void) |
||||
{ |
||||
sc_context_t ctx; |
||||
uint8_t buffer[32]; |
||||
size_t out_len; |
||||
sc_status_t status; |
||||
|
||||
memset(&ctx, 0, sizeof(ctx)); |
||||
|
||||
/* Test NULL context */ |
||||
status = sc_generate_keypair(NULL); |
||||
TEST_ASSERT(status == SC_ERR_INVALID_ARG, "NULL context detection"); |
||||
|
||||
/* Test uninitialized context */ |
||||
memset(&ctx, 0, sizeof(ctx)); |
||||
status = sc_set_peer_public_key(&ctx, buffer); |
||||
TEST_ASSERT(status == SC_ERR_NOT_INITIALIZED, "uninitialized context"); |
||||
|
||||
/* Test encryption without session */ |
||||
memset(&ctx, 0, sizeof(ctx)); |
||||
status = sc_generate_keypair(&ctx); |
||||
TEST_ASSERT(status == SC_OK, "key generation for error test"); |
||||
|
||||
status = sc_encrypt(&ctx, buffer, sizeof(buffer), buffer, &out_len); |
||||
TEST_ASSERT(status == SC_ERR_NOT_INITIALIZED, "encrypt without session"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int main(void) |
||||
{ |
||||
int result = 0; |
||||
|
||||
printf("=== Secure Channel Library Test ===\n"); |
||||
|
||||
/* Initialize TinyCrypt RNG */ |
||||
uECC_set_rng(&default_CSPRNG); |
||||
|
||||
result |= test_key_generation(); |
||||
result |= test_key_exchange(); |
||||
result |= test_encrypt_decrypt(); |
||||
result |= test_error_handling(); |
||||
|
||||
if (result == 0) { |
||||
printf("\n=== All tests PASSED ===\n"); |
||||
} else { |
||||
printf("\n=== Some tests FAILED ===\n"); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
@ -1,209 +0,0 @@
|
||||
/* test_udp_secure.c - Unit test for UDP secure channel with async library */ |
||||
|
||||
#include "sc_lib.h" |
||||
#include "u_async.h" |
||||
#include <tinycrypt/ecc.h> |
||||
#include <tinycrypt/ecc_platform_specific.h> |
||||
#include <tinycrypt/constants.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <errno.h> |
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
#include <arpa/inet.h> |
||||
#include <fcntl.h> |
||||
#include <time.h> |
||||
|
||||
#define TEST_ASSERT(cond, msg) \ |
||||
do { \
|
||||
if (!(cond)) { \
|
||||
printf("FAIL: %s (line %d)\n", msg, __LINE__); \
|
||||
exit(1); \
|
||||
} else { \
|
||||
printf("PASS: %s\n", msg); \
|
||||
} \
|
||||
} while(0) |
||||
|
||||
#define PORT_A 12345 |
||||
#define PORT_B 12346 |
||||
#define LOCALHOST "127.0.0.1" |
||||
|
||||
typedef struct { |
||||
sc_context_t ctx; |
||||
int sockfd; |
||||
struct sockaddr_in addr; |
||||
struct sockaddr_in peer_addr; |
||||
uint8_t rx_buffer[1024]; |
||||
size_t rx_len; |
||||
uint8_t tx_buffer[1024]; |
||||
size_t tx_len; |
||||
int received; |
||||
int sent; |
||||
} client_state_t; |
||||
|
||||
static client_state_t client_a, client_b; |
||||
static volatile int test_complete = 0; |
||||
static volatile int test_failed = 0; |
||||
|
||||
static void timeout_callback(void* arg) { |
||||
(void)arg; |
||||
printf("ERROR: Test timeout\n"); |
||||
test_failed = 1; |
||||
exit(1); |
||||
} |
||||
|
||||
static void client_a_read_callback(int fd, void* arg) { |
||||
client_state_t* state = (client_state_t*)arg; |
||||
struct sockaddr_in from; |
||||
socklen_t fromlen = sizeof(from); |
||||
ssize_t n = recvfrom(fd, state->rx_buffer, sizeof(state->rx_buffer), 0, |
||||
(struct sockaddr*)&from, &fromlen); |
||||
if (n < 0) { |
||||
perror("recvfrom"); |
||||
return; |
||||
} |
||||
printf("Client A received %zd bytes\n", n); |
||||
// In this test, client A is not expecting data
|
||||
// but we can handle it if needed
|
||||
} |
||||
|
||||
static void client_b_read_callback(int fd, void* arg) { |
||||
client_state_t* state = (client_state_t*)arg; |
||||
struct sockaddr_in from; |
||||
socklen_t fromlen = sizeof(from); |
||||
ssize_t n = recvfrom(fd, state->rx_buffer, sizeof(state->rx_buffer), 0, |
||||
(struct sockaddr*)&from, &fromlen); |
||||
if (n < 0) { |
||||
perror("recvfrom"); |
||||
return; |
||||
} |
||||
printf("Client B received %zd bytes\n", n); |
||||
|
||||
// Expect encrypted message (ciphertext + tag + crc32)
|
||||
size_t ciphertext_len = n; |
||||
if (ciphertext_len <= SC_MAX_OVERHEAD || ciphertext_len > sizeof(state->rx_buffer)) { |
||||
printf("ERROR: Invalid received length\n"); |
||||
test_failed = 1; |
||||
return; |
||||
} |
||||
|
||||
uint8_t* ciphertext = state->rx_buffer; |
||||
uint8_t decrypted[1024]; |
||||
size_t decrypted_len; |
||||
|
||||
const char* expected = "Hello from client A over UDP!"; |
||||
size_t expected_len = strlen(expected) + 1; |
||||
sc_status_t status = sc_decrypt(&state->ctx, ciphertext, ciphertext_len, decrypted, &decrypted_len); |
||||
TEST_ASSERT(status == SC_OK, "decryption of received message"); |
||||
TEST_ASSERT(decrypted_len == expected_len, "decrypted length matches original"); |
||||
|
||||
TEST_ASSERT(memcmp(decrypted, expected, decrypted_len) == 0, |
||||
"decrypted matches expected plaintext"); |
||||
|
||||
printf("Client B successfully decrypted message: %s\n", (char*)decrypted); |
||||
test_complete = 1; |
||||
exit(0); |
||||
} |
||||
|
||||
static int create_udp_socket(int port, struct sockaddr_in* addr) { |
||||
int sock = socket(AF_INET, SOCK_DGRAM, 0); |
||||
TEST_ASSERT(sock >= 0, "socket creation"); |
||||
|
||||
int flags = fcntl(sock, F_GETFL, 0); |
||||
TEST_ASSERT(flags >= 0, "get socket flags"); |
||||
TEST_ASSERT(fcntl(sock, F_SETFL, flags | O_NONBLOCK) == 0, "set non-blocking"); |
||||
|
||||
memset(addr, 0, sizeof(*addr)); |
||||
addr->sin_family = AF_INET; |
||||
addr->sin_port = htons(port); |
||||
addr->sin_addr.s_addr = inet_addr(LOCALHOST); |
||||
|
||||
TEST_ASSERT(bind(sock, (struct sockaddr*)addr, sizeof(*addr)) == 0, "bind socket"); |
||||
return sock; |
||||
} |
||||
|
||||
static void generate_keys(client_state_t* client) { |
||||
memset(&client->ctx, 0, sizeof(client->ctx)); |
||||
sc_status_t status = sc_generate_keypair(&client->ctx); |
||||
TEST_ASSERT(status == SC_OK, "key generation"); |
||||
} |
||||
|
||||
static void send_encrypted_message(client_state_t* src, client_state_t* dst) { |
||||
const char* plaintext = "Hello from client A over UDP!"; |
||||
size_t plaintext_len = strlen(plaintext) + 1; |
||||
size_t ciphertext_len; |
||||
|
||||
uint8_t ciphertext[plaintext_len + SC_MAX_OVERHEAD]; |
||||
|
||||
sc_status_t status = sc_encrypt(&src->ctx, (const uint8_t*)plaintext, plaintext_len, |
||||
ciphertext, &ciphertext_len); |
||||
TEST_ASSERT(status == SC_OK, "encryption for sending"); |
||||
TEST_ASSERT(ciphertext_len == plaintext_len + SC_MAX_OVERHEAD, "ciphertext length includes overhead"); |
||||
|
||||
// Send ciphertext (already includes tag + crc32)
|
||||
memcpy(src->tx_buffer, ciphertext, ciphertext_len); |
||||
size_t packet_len = ciphertext_len; |
||||
|
||||
ssize_t sent = sendto(src->sockfd, src->tx_buffer, packet_len, 0, |
||||
(struct sockaddr*)&dst->addr, sizeof(dst->addr)); |
||||
TEST_ASSERT(sent == (ssize_t)packet_len, "sendto"); |
||||
printf("Client A sent encrypted message (%zd bytes)\n", sent); |
||||
} |
||||
|
||||
int main(void) { |
||||
printf("=== UDP Secure Channel Test with Async Library ===\n"); |
||||
|
||||
// Initialize TinyCrypt RNG
|
||||
uECC_set_rng(&default_CSPRNG); |
||||
|
||||
// Initialize async library
|
||||
uasync_t* ua = uasync_create(); |
||||
if (!ua) { |
||||
fprintf(stderr, "Failed to create uasync instance\n"); |
||||
return 1; |
||||
} |
||||
uasync_init_instance(ua); |
||||
|
||||
// Create UDP sockets
|
||||
client_a.sockfd = create_udp_socket(PORT_A, &client_a.addr); |
||||
client_b.sockfd = create_udp_socket(PORT_B, &client_b.addr); |
||||
|
||||
// Set peer addresses for sending
|
||||
client_a.peer_addr = client_b.addr; |
||||
client_b.peer_addr = client_a.addr; |
||||
|
||||
// Generate key pairs for both clients
|
||||
generate_keys(&client_a); |
||||
generate_keys(&client_b); |
||||
|
||||
// Exchange public keys
|
||||
sc_status_t status = sc_set_peer_public_key(&client_a.ctx, client_b.ctx.public_key); |
||||
TEST_ASSERT(status == SC_OK, "client A set peer key"); |
||||
status = sc_set_peer_public_key(&client_b.ctx, client_a.ctx.public_key); |
||||
TEST_ASSERT(status == SC_OK, "client B set peer key"); |
||||
|
||||
// Verify session keys match
|
||||
TEST_ASSERT(memcmp(client_a.ctx.session_key, client_b.ctx.session_key, |
||||
SC_SESSION_KEY_SIZE) == 0, |
||||
"session keys match"); |
||||
|
||||
// Register sockets with async library
|
||||
uasync_add_socket(ua, client_a.sockfd, client_a_read_callback, NULL, NULL, &client_a); |
||||
uasync_add_socket(ua, client_b.sockfd, client_b_read_callback, NULL, NULL, &client_b); |
||||
|
||||
// Set timeout for test completion (2 seconds)
|
||||
uasync_set_timeout(ua, 20000, NULL, timeout_callback); // timebase 0.1 ms, 20000 = 2 sec
|
||||
|
||||
// Send encrypted message from A to B
|
||||
send_encrypted_message(&client_a, &client_b); |
||||
|
||||
// Run async mainloop (will exit via callback or timeout)
|
||||
printf("Starting async mainloop...\n"); |
||||
uasync_mainloop(ua); // This will not return
|
||||
|
||||
// Should not reach here
|
||||
return 1; |
||||
} |
||||
@ -0,0 +1,15 @@
|
||||
noinst_LIBRARIES = libuasync.a
|
||||
|
||||
libuasync_a_SOURCES = \
|
||||
u_async.c \
|
||||
u_async.h \
|
||||
ll_queue.h \
|
||||
ll_queue.c \
|
||||
debug_config.c \
|
||||
debug_config.h
|
||||
|
||||
libuasync_a_CFLAGS = \
|
||||
-D_ISOC99_SOURCE \
|
||||
-DDEBUG_OUTPUT_STDERR \
|
||||
-I$(top_srcdir)/src
|
||||
|
||||
Loading…
Reference in new issue