From 3f7fd9f8ada9c78bb50781a6ad2b2c382ac5ee18 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Mon, 19 Jan 2026 23:10:44 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B5=D0=B5=20?= =?UTF-8?q?=D1=81=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D0=B5=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B4=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BA=D0=BE=D0=BC=D0=BF?= =?UTF-8?q?=D0=B8=D0=BB=D1=8F=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1 | 5 + AGENTS.md | 30 - build.sh | 2 + build/config.h | 153 +++++ build/config.log | 323 +++++++++ build/config.status | 1200 ++++++++++++++++++++++++++++++++++ build/lib/tinycrypt | 1 + build/stamp-h1 | 1 + build_errors.txt | 293 +++++++++ configure.ac | 3 +- lib/Makefile.am | 6 +- {src => lib}/ll_queue.c | 48 +- {src => lib}/ll_queue.h | 15 +- lib/memory_pool.c | 87 +++ lib/memory_pool.h | 23 + lib/u_async.c | 55 +- lib/u_async.h | 40 +- log | 53 ++ src/Makefile.am | 2 - src/config_parser.c | 454 +++++++++---- src/config_parser.h | 78 +-- src/config_updater.c | 17 +- src/config_updater.h | 5 + src/etcp.c | 474 +++++++++++++- src/etcp.h | 103 ++- src/etcp.h.demo | 5 - src/etcp_connections.c | 1072 +++++++++++------------------- src/etcp_connections.h | 100 ++- src/etcp_protocol.txt | 16 +- src/etcp_sockets.h | 31 - src/memory_pool.c | 62 -- src/memory_pool.h | 36 - src/packet_buffer.h | 76 --- src/packet_pool.c | 85 --- src/packet_pool.h | 35 - src/secure_channel.c | 47 +- src/secure_channel.h | 28 +- src/tun_if.c | 79 +++ src/tun_if.h | 2 + src/utun.c | 34 +- src/utun_fixes.c | 52 -- src/utun_instance.c | 208 ++---- src/utun_instance.h | 26 +- test_invalid_keys.conf | 19 + test_no_keys.conf | 16 + tests/test_etcp_crypto | Bin 0 -> 360432 bytes tests/test_etcp_crypto.c | 213 ++++++ tests/test_etcp_crypto_fix | Bin 0 -> 360616 bytes tests/test_etcp_crypto_fix.c | 219 +++++++ utun_test_backup.conf | 42 ++ 50 files changed, 4237 insertions(+), 1737 deletions(-) create mode 100644 1 delete mode 100755 AGENTS.md create mode 100755 build.sh create mode 100644 build/config.h create mode 100644 build/config.log create mode 100755 build/config.status create mode 120000 build/lib/tinycrypt create mode 100644 build/stamp-h1 create mode 100644 build_errors.txt rename {src => lib}/ll_queue.c (91%) rename {src => lib}/ll_queue.h (92%) create mode 100644 lib/memory_pool.c create mode 100644 lib/memory_pool.h create mode 100644 log delete mode 100644 src/etcp.h.demo delete mode 100644 src/etcp_sockets.h delete mode 100644 src/memory_pool.c delete mode 100644 src/memory_pool.h delete mode 100644 src/packet_buffer.h delete mode 100644 src/packet_pool.c delete mode 100644 src/packet_pool.h delete mode 100644 src/utun_fixes.c create mode 100644 test_invalid_keys.conf create mode 100644 test_no_keys.conf create mode 100755 tests/test_etcp_crypto create mode 100644 tests/test_etcp_crypto.c create mode 100755 tests/test_etcp_crypto_fix create mode 100644 tests/test_etcp_crypto_fix.c create mode 100755 utun_test_backup.conf diff --git a/1 b/1 new file mode 100644 index 00000000..03869222 --- /dev/null +++ b/1 @@ -0,0 +1,5 @@ +In file included from src/etcp_connections.c:1: +src/etcp_connections.h:6:10: fatal error: etcp_sockets.h: Нет такого файла или каталога + 6 | #include "etcp_sockets.h" + | ^~~~~~~~~~~~~~~~ +compilation terminated. diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100755 index 776d9261..00000000 --- a/AGENTS.md +++ /dev/null @@ -1,30 +0,0 @@ -# AGENTS.md - uTun Development Guide - -This document provides essential information for agentic coding assistants working on the uTun VPN tunnel project. -Совместимость со станым при доработках сохранять не надо. при переделке старые хвосты надо удалять. - -Если не работает - добавляй отладочную информацию чтобы быстрее найти проблемное место и не рушить работающий код. -если отладочная информация будет флудить сделай ее отключаемой или подумай как ограничить ее вывод по возможности сохраняя информативность. -Добавляй в код структуры для статистики (например суммируй число ошибок, вызовов и других потенциально нужных для анализа при ошибках метрик). -добавляй в тест подсчет времени сколько каждый этап длился для лучшего понимания оптимизации -перед запуском тестов не забывай их пересобирать - -веди changelog.txt: дата время: что поменялось -задача протокола - обеспечивать минимальную задержку при большом трафике. т.е. держать необходимый минимум данных в очередях. -дизайн - однопоточный асинхронный. -все ожидающие операции - через сокеты(дескрипторы) и таймауты -> u_async -все очереди через ll_queue -главный модуль обслуживания подключения - connection -unit-tests: для каждого теста в начале файла теста описывай что и как он тестирует - кратко но указыая на нюансы если они есть. -Если код не собирается и в этом месте написано #указание <текст> - то это указание надо выполнить в приоритетном порядке. - -не используй shell для редактирования - много ошибок допускаешь. есть встроенные инструменты. - -## Code Style Guidelines - -комменты в коде на русском -используй по возможности структуры а не typedef, пример: struct STRUCT_NAME {...}; - прототипы структур ЗАГЛАВНЫМИ БУКВАМИ - -Приоритет - простое (логически понятное, минималистичное api, но функциональное). Всегда надо думать как сделать проще и красивее. не надо нагромождать лишнего - сперва подумай действительно ли оно нужно. - -рассуждай на английском, остальное лучше на русском (отчёты, дальшейшие шаги и ответы на запросы всегда на русском) diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..2bc3a930 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/bin/bash +make 2> build_errors.txt diff --git a/build/config.h b/build/config.h new file mode 100644 index 00000000..4f4d27bd --- /dev/null +++ b/build/config.h @@ -0,0 +1,153 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#define HAVE_LIBCRYPTO 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strstr' function. */ +#define HAVE_STRSTR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if TUN/TAP is available */ +/* #undef HAVE_TUN_TAP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "utun" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "https://github.com/anomalyco/utun3/issues" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "utun" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "utun 2.0.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "utun" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.0.0" + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "2.0.0" + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT32_T */ + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT64_T */ + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +/* #undef _UINT8_T */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint16_t */ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint32_t */ + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint64_t */ + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +/* #undef uint8_t */ diff --git a/build/config.log b/build/config.log new file mode 100644 index 00000000..7ecfd49c --- /dev/null +++ b/build/config.log @@ -0,0 +1,323 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by utun configure 2.0.0, which was +generated by GNU Autoconf 2.71. Invocation command line was + + $ ../configure --no-create --no-recursion + +## --------- ## +## Platform. ## +## --------- ## + +hostname = user-Standard-PC-i440FX-PIIX-1996 +uname -m = x86_64 +uname -r = 6.14.0-37-generic +uname -s = Linux +uname -v = #37~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Nov 20 10:25:38 UTC 2 + +/usr/bin/uname -p = x86_64 +/bin/uname -X = unknown + +/bin/arch = x86_64 +/usr/bin/arch -k = unknown +/usr/convex/getsysinfo = unknown +/usr/bin/hostinfo = unknown +/bin/machine = unknown +/usr/bin/oslevel = unknown +/bin/universe = unknown + +PATH: /home/vnc1/.cargo/bin/ +PATH: /usr/local/sbin/ +PATH: /usr/local/bin/ +PATH: /usr/sbin/ +PATH: /usr/bin/ +PATH: /sbin/ +PATH: /bin/ +PATH: /usr/games/ +PATH: /usr/local/games/ +PATH: /snap/bin/ +PATH: /snap/bin/ + + +## ----------- ## +## Core tests. ## +## ----------- ## + +configure:2453: looking for aux files: config.guess config.sub missing install-sh ar-lib compile +configure:2466: trying ../build-aux/ +configure:2495: ../build-aux/config.guess found +configure:2495: ../build-aux/config.sub found +configure:2495: ../build-aux/missing found +configure:2477: ../build-aux/install-sh found +configure:2495: ../build-aux/ar-lib found +configure:2495: ../build-aux/compile found +configure:2675: checking for gcc +configure:2696: found /usr/bin/gcc +configure:2707: result: gcc +configure:3060: checking for C compiler version +configure:3069: gcc --version >&5 +gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 +Copyright (C) 2023 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +configure:3080: $? = 0 +configure:3069: gcc -v >&5 +Using built-in specs. +COLLECT_GCC=gcc +COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper +OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa +OFFLOAD_TARGET_DEFAULT=1 +Target: x86_64-linux-gnu +Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 +Thread model: posix +Supported LTO compression algorithms: zlib zstd +gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04) +... rest of stderr output deleted ... +configure:3080: $? = 0 +configure:3069: gcc -V >&5 +gcc: error: unrecognized command-line option '-V' +gcc: fatal error: no input files +compilation terminated. +configure:3080: $? = 1 +configure:3069: gcc -qversion >&5 +gcc: error: unrecognized command-line option '-qversion'; did you mean '--version'? +gcc: fatal error: no input files +compilation terminated. +configure:3080: $? = 1 +configure:3069: gcc -version >&5 +gcc: error: unrecognized command-line option '-version' +gcc: fatal error: no input files +compilation terminated. +configure:3080: $? = 1 +configure:3100: checking whether the C compiler works +configure:3122: gcc conftest.c >&5 +configure:3126: $? = 0 +configure:3176: result: yes +configure:3179: checking for C compiler default output file name +configure:3181: result: a.out +configure:3187: checking for suffix of executables +configure:3194: gcc -o conftest conftest.c >&5 +configure:3198: $? = 0 +configure:3221: result: +configure:3243: checking whether we are cross compiling +configure:3251: gcc -o conftest conftest.c >&5 +configure:3255: $? = 0 +configure:3262: ./conftest +configure:3266: $? = 0 +configure:3281: result: no +configure:3286: checking for suffix of object files +configure:3309: gcc -c conftest.c >&5 +configure:3313: $? = 0 +configure:3335: result: o +configure:3339: checking whether the compiler supports GNU C +configure:3359: gcc -c conftest.c >&5 +configure:3359: $? = 0 +configure:3369: result: yes +configure:3380: checking whether gcc accepts -g +configure:3401: gcc -c -g conftest.c >&5 +configure:3401: $? = 0 +configure:3445: result: yes +configure:3465: checking for gcc option to enable C11 features +configure:3480: gcc -c -g -O2 conftest.c >&5 +configure:3480: $? = 0 +configure:3498: result: none needed +configure:3619: checking whether gcc understands -c and -o together +configure:3642: gcc -c conftest.c -o conftest2.o +configure:3645: $? = 0 +configure:3642: gcc -c conftest.c -o conftest2.o +configure:3645: $? = 0 +configure:3657: result: yes +configure:3722: checking for ranlib +configure:3743: found /usr/bin/ranlib +configure:3754: result: ranlib +configure:3832: checking for ar +configure:3853: found /usr/bin/ar +configure:3864: result: ar +configure:3890: checking the archiver (ar) interface +configure:3907: gcc -c -g -O2 conftest.c >&5 +configure:3907: $? = 0 +configure:3910: ar cru libconftest.a conftest.o >&5 +ar: `u' modifier ignored since `D' is the default (see `U') +configure:3913: $? = 0 +configure:3941: result: ar +configure:3978: checking for a BSD-compatible install +configure:4051: result: /usr/bin/install -c +configure:4062: checking whether build environment is sane +configure:4117: result: yes +configure:4272: checking for a race-free mkdir -p +configure:4316: result: /usr/bin/mkdir -p +configure:4323: checking for gawk +configure:4358: result: no +configure:4323: checking for mawk +configure:4344: found /usr/bin/mawk +configure:4355: result: mawk +configure:4366: checking whether make sets $(MAKE) +configure:4389: result: yes +configure:4411: checking whether make supports the include directive +configure:4426: make -f confmf.GNU && cat confinc.out +make[1]: Entering directory '/home/vnc1/proj/utun3/build' +make[1]: Leaving directory '/home/vnc1/proj/utun3/build' +this is the am__doit target +configure:4429: $? = 0 +configure:4448: result: yes (GNU style) +configure:4483: checking whether make supports nested variables +configure:4501: result: yes +configure:4518: error: source directory already configured; run "make distclean" there first + +## ---------------- ## +## Cache variables. ## +## ---------------- ## + +ac_cv_c_compiler_gnu=yes +ac_cv_env_CC_set= +ac_cv_env_CC_value= +ac_cv_env_CFLAGS_set= +ac_cv_env_CFLAGS_value= +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_LDFLAGS_set= +ac_cv_env_LDFLAGS_value= +ac_cv_env_LIBS_set= +ac_cv_env_LIBS_value= +ac_cv_env_build_alias_set= +ac_cv_env_build_alias_value= +ac_cv_env_host_alias_set= +ac_cv_env_host_alias_value= +ac_cv_env_target_alias_set= +ac_cv_env_target_alias_value= +ac_cv_objext=o +ac_cv_path_install='/usr/bin/install -c' +ac_cv_path_mkdir=/usr/bin/mkdir +ac_cv_prog_AWK=mawk +ac_cv_prog_ac_ct_AR=ar +ac_cv_prog_ac_ct_CC=gcc +ac_cv_prog_ac_ct_RANLIB=ranlib +ac_cv_prog_cc_c11= +ac_cv_prog_cc_g=yes +ac_cv_prog_cc_stdc= +ac_cv_prog_make_make_set=yes +am_cv_ar_interface=ar +am_cv_make_support_nested_variables=yes +am_cv_prog_cc_c_o=yes + +## ----------------- ## +## Output variables. ## +## ----------------- ## + +ACLOCAL='' +AMDEPBACKSLASH='\' +AMDEP_FALSE='#' +AMDEP_TRUE='' +AMTAR='' +AM_BACKSLASH='\' +AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +AM_DEFAULT_VERBOSITY='1' +AM_V='$(V)' +AR='ar' +AUTOCONF='' +AUTOHEADER='' +AUTOMAKE='' +AWK='mawk' +CC='gcc' +CCDEPMODE='' +CFLAGS='-g -O2' +CPPFLAGS='' +CSCOPE='' +CTAGS='' +CYGPATH_W='' +DEFS='' +DEPDIR='.deps' +ECHO_C='' +ECHO_N='-n' +ECHO_T='' +ETAGS='' +EXEEXT='' +INSTALL_DATA='${INSTALL} -m 644' +INSTALL_PROGRAM='${INSTALL}' +INSTALL_SCRIPT='${INSTALL}' +INSTALL_STRIP_PROGRAM='$(install_sh) -c -s' +LDFLAGS='' +LIBOBJS='' +LIBS='' +LTLIBOBJS='' +MAKEINFO='' +MKDIR_P='/usr/bin/mkdir -p' +OBJEXT='o' +PACKAGE='' +PACKAGE_BUGREPORT='https://github.com/anomalyco/utun3/issues' +PACKAGE_NAME='utun' +PACKAGE_STRING='utun 2.0.0' +PACKAGE_TARNAME='utun' +PACKAGE_URL='' +PACKAGE_VERSION='2.0.0' +PATH_SEPARATOR=':' +RANLIB='ranlib' +SET_MAKE='' +SHELL='/bin/bash' +STRIP='' +VERSION='' +ac_ct_AR='ar' +ac_ct_CC='gcc' +am__EXEEXT_FALSE='' +am__EXEEXT_TRUE='' +am__fastdepCC_FALSE='' +am__fastdepCC_TRUE='' +am__include='include' +am__isrc=' -I$(srcdir)' +am__leading_dot='.' +am__nodep='_no' +am__quote='' +am__tar='' +am__untar='' +bindir='${exec_prefix}/bin' +build='' +build_alias='' +build_cpu='' +build_os='' +build_vendor='' +datadir='${datarootdir}' +datarootdir='${prefix}/share' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +dvidir='${docdir}' +exec_prefix='NONE' +host='' +host_alias='' +host_cpu='' +host_os='' +host_vendor='' +htmldir='${docdir}' +includedir='${prefix}/include' +infodir='${datarootdir}/info' +install_sh='${SHELL} /home/vnc1/proj/utun3/build-aux/install-sh' +libdir='${exec_prefix}/lib' +libexecdir='${exec_prefix}/libexec' +localedir='${datarootdir}/locale' +localstatedir='${prefix}/var' +mandir='${datarootdir}/man' +mkdir_p='' +oldincludedir='/usr/include' +pdfdir='${docdir}' +prefix='NONE' +program_transform_name='s,x,x,' +psdir='${docdir}' +runstatedir='${localstatedir}/run' +sbindir='${exec_prefix}/sbin' +sharedstatedir='${prefix}/com' +sysconfdir='${prefix}/etc' +target_alias='' + +## ----------- ## +## confdefs.h. ## +## ----------- ## + +/* confdefs.h */ +#define PACKAGE_NAME "utun" +#define PACKAGE_TARNAME "utun" +#define PACKAGE_VERSION "2.0.0" +#define PACKAGE_STRING "utun 2.0.0" +#define PACKAGE_BUGREPORT "https://github.com/anomalyco/utun3/issues" +#define PACKAGE_URL "" + +configure: exit 1 diff --git a/build/config.status b/build/config.status new file mode 100755 index 00000000..6025e15e --- /dev/null +++ b/build/config.status @@ -0,0 +1,1200 @@ +#! /bin/bash +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=${CONFIG_SHELL-/bin/bash} +export SHELL +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +as_nop=: +if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 +then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else $as_nop + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. +as_nl=' +' +export as_nl +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi + +# The user is always right. +if ${PATH_SEPARATOR+false} :; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + printf "%s\n" "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null +then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else $as_nop + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else $as_nop + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by utun $as_me 2.0.0, which was +generated by GNU Autoconf 2.71. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +# Files that config.status was made for. +config_files=" Makefile src/Makefile tests/Makefile lib/Makefile" +config_headers=" config.h" +config_commands=" depfiles" + +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +ac_cs_config='' +ac_cs_version="\ +utun config.status 2.0.0 +configured by ../configure, generated by GNU Autoconf 2.71, + with options \"$ac_cs_config\" + +Copyright (C) 2021 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='/home/vnc1/proj/utun3/build' +srcdir='..' +INSTALL='/usr/bin/install -c' +MKDIR_P='/usr/bin/mkdir -p' +AWK='mawk' +test -n "$AWK" || AWK=awk +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + printf "%s\n" "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + printf "%s\n" "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + printf "%s\n" "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +if $ac_cs_recheck; then + set X /bin/bash '../configure' $ac_configure_extra_args --no-create --no-recursion + shift + \printf "%s\n" "running CONFIG_SHELL=/bin/bash $*" >&6 + CONFIG_SHELL='/bin/bash' + export CONFIG_SHELL + exec "$@" +fi + +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + printf "%s\n" "$ac_log" +} >&5 + +# +# INIT-COMMANDS +# +AMDEP_TRUE="" MAKE="make" + + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; + "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers + test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +cat >>"$ac_tmp/subs1.awk" <<\_ACAWK && +S["am__EXEEXT_FALSE"]="" +S["am__EXEEXT_TRUE"]="#" +S["LTLIBOBJS"]="" +S["LIBOBJS"]="" +S["host_os"]="linux-gnu" +S["host_vendor"]="pc" +S["host_cpu"]="x86_64" +S["host"]="x86_64-pc-linux-gnu" +S["build_os"]="linux-gnu" +S["build_vendor"]="pc" +S["build_cpu"]="x86_64" +S["build"]="x86_64-pc-linux-gnu" +S["AM_BACKSLASH"]="\\" +S["AM_DEFAULT_VERBOSITY"]="1" +S["AM_DEFAULT_V"]="$(AM_DEFAULT_VERBOSITY)" +S["AM_V"]="$(V)" +S["CSCOPE"]="cscope" +S["ETAGS"]="etags" +S["CTAGS"]="ctags" +S["am__fastdepCC_FALSE"]="#" +S["am__fastdepCC_TRUE"]="" +S["CCDEPMODE"]="depmode=gcc3" +S["am__nodep"]="_no" +S["AMDEPBACKSLASH"]="\\" +S["AMDEP_FALSE"]="#" +S["AMDEP_TRUE"]="" +S["am__include"]="include" +S["DEPDIR"]=".deps" +S["am__untar"]="$${TAR-tar} xf -" +S["am__tar"]="$${TAR-tar} chof - \"$$tardir\"" +S["AMTAR"]="$${TAR-tar}" +S["am__leading_dot"]="." +S["SET_MAKE"]="" +S["AWK"]="mawk" +S["mkdir_p"]="$(MKDIR_P)" +S["MKDIR_P"]="/usr/bin/mkdir -p" +S["INSTALL_STRIP_PROGRAM"]="$(install_sh) -c -s" +S["STRIP"]="" +S["install_sh"]="${SHELL} /home/vnc1/proj/utun3/build-aux/install-sh" +S["MAKEINFO"]="${SHELL} '/home/vnc1/proj/utun3/build-aux/missing' makeinfo" +S["AUTOHEADER"]="${SHELL} '/home/vnc1/proj/utun3/build-aux/missing' autoheader" +S["AUTOMAKE"]="${SHELL} '/home/vnc1/proj/utun3/build-aux/missing' automake-1.16" +S["AUTOCONF"]="${SHELL} '/home/vnc1/proj/utun3/build-aux/missing' autoconf" +S["ACLOCAL"]="${SHELL} '/home/vnc1/proj/utun3/build-aux/missing' aclocal-1.16" +S["VERSION"]="2.0.0" +S["PACKAGE"]="utun" +S["CYGPATH_W"]="echo" +S["am__isrc"]=" -I$(srcdir)" +S["INSTALL_DATA"]="${INSTALL} -m 644" +S["INSTALL_SCRIPT"]="${INSTALL}" +S["INSTALL_PROGRAM"]="${INSTALL}" +S["ac_ct_AR"]="ar" +S["AR"]="ar" +S["RANLIB"]="ranlib" +S["OBJEXT"]="o" +S["EXEEXT"]="" +S["ac_ct_CC"]="gcc" +S["CPPFLAGS"]="" +S["LDFLAGS"]="" +S["CFLAGS"]="-g -O2" +S["CC"]="gcc" +S["target_alias"]="" +S["host_alias"]="" +S["build_alias"]="" +S["LIBS"]="-lcrypto " +S["ECHO_T"]="" +S["ECHO_N"]="-n" +S["ECHO_C"]="" +S["DEFS"]="-DHAVE_CONFIG_H" +S["mandir"]="${datarootdir}/man" +S["localedir"]="${datarootdir}/locale" +S["libdir"]="${exec_prefix}/lib" +S["psdir"]="${docdir}" +S["pdfdir"]="${docdir}" +S["dvidir"]="${docdir}" +S["htmldir"]="${docdir}" +S["infodir"]="${datarootdir}/info" +S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" +S["oldincludedir"]="/usr/include" +S["includedir"]="${prefix}/include" +S["runstatedir"]="${localstatedir}/run" +S["localstatedir"]="${prefix}/var" +S["sharedstatedir"]="${prefix}/com" +S["sysconfdir"]="${prefix}/etc" +S["datadir"]="${datarootdir}" +S["datarootdir"]="${prefix}/share" +S["libexecdir"]="${exec_prefix}/libexec" +S["sbindir"]="${exec_prefix}/sbin" +S["bindir"]="${exec_prefix}/bin" +S["program_transform_name"]="s,x,x," +S["prefix"]="/usr/local" +S["exec_prefix"]="${prefix}" +S["PACKAGE_URL"]="" +S["PACKAGE_BUGREPORT"]="https://github.com/anomalyco/utun3/issues" +S["PACKAGE_STRING"]="utun 2.0.0" +S["PACKAGE_VERSION"]="2.0.0" +S["PACKAGE_TARNAME"]="utun" +S["PACKAGE_NAME"]="utun" +S["PATH_SEPARATOR"]=":" +S["SHELL"]="/bin/bash" +S["am__quote"]="" +_ACAWK +cat >>"$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +D["PACKAGE_NAME"]=" \"utun\"" +D["PACKAGE_TARNAME"]=" \"utun\"" +D["PACKAGE_VERSION"]=" \"2.0.0\"" +D["PACKAGE_STRING"]=" \"utun 2.0.0\"" +D["PACKAGE_BUGREPORT"]=" \"https://github.com/anomalyco/utun3/issues\"" +D["PACKAGE_URL"]=" \"\"" +D["PACKAGE"]=" \"utun\"" +D["VERSION"]=" \"2.0.0\"" +D["HAVE_LIBCRYPTO"]=" 1" +D["HAVE_STDIO_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_STRINGS_H"]=" 1" +D["HAVE_SYS_STAT_H"]=" 1" +D["HAVE_SYS_TYPES_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["STDC_HEADERS"]=" 1" +D["HAVE_ARPA_INET_H"]=" 1" +D["HAVE_FCNTL_H"]=" 1" +D["HAVE_LIMITS_H"]=" 1" +D["HAVE_NETINET_IN_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_SYS_IOCTL_H"]=" 1" +D["HAVE_SYS_SOCKET_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_MALLOC"]=" 1" +D["HAVE_GETTIMEOFDAY"]=" 1" +D["HAVE_MEMSET"]=" 1" +D["HAVE_SOCKET"]=" 1" +D["HAVE_STRCHR"]=" 1" +D["HAVE_STRDUP"]=" 1" +D["HAVE_STRERROR"]=" 1" +D["HAVE_STRSTR"]=" 1" + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*([\t (]|$)/ { + line = $ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`printf "%s\n" "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + ac_datarootdir_hack=' + s&@datadir@&${datarootdir}&g + s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g + s&@infodir@&${datarootdir}/info&g + s&@localedir@&${datarootdir}/locale&g + s&@mandir@&${datarootdir}/man&g + s&\${datarootdir}&${prefix}/share&g' ;; +esac +ac_sed_extra=" + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + printf "%s\n" "/* $configure_input */" >&1 \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +printf "%s\n" "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$am_mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? + done + if test $am_rc -ne 0; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE=\"gmake\" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See \`config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk +} + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 diff --git a/build/lib/tinycrypt b/build/lib/tinycrypt new file mode 120000 index 00000000..d9529048 --- /dev/null +++ b/build/lib/tinycrypt @@ -0,0 +1 @@ +../tinycrypt/lib \ No newline at end of file diff --git a/build/stamp-h1 b/build/stamp-h1 new file mode 100644 index 00000000..4547fe1b --- /dev/null +++ b/build/stamp-h1 @@ -0,0 +1 @@ +timestamp for config.h diff --git a/build_errors.txt b/build_errors.txt new file mode 100644 index 00000000..75b7cb6e --- /dev/null +++ b/build_errors.txt @@ -0,0 +1,293 @@ +etcp_connections.c: In function ‘etcp_encrypt_send’: +etcp_connections.c:250:24: error: incompatible types when initializing type ‘sc_context_t *’ {aka ‘struct secure_channel *’} using type ‘struct secure_channel’ + 250 | sc_context_t* sc = dgram->link->etcp->crypto_ctx; + | ^~~~~ +etcp_connections.c:252:59: warning: ‘return’ with no value, in function returning non-void + 252 | if (len<=0 || len>1480) { dgram->link->send_errors++; return; } + | ^~~~~~ +etcp_connections.c:248:5: note: declared here + 248 | int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { + | ^~~~~~~~~~~~~~~~~ +etcp_connections.c:255:38: warning: passing argument 4 of ‘sc_encrypt’ from incompatible pointer type [-Wincompatible-pointer-types] + 255 | sc_encrypt(sc, dgram->data, len, &enc_buf, &enc_buf_len); + | ^~~~~~~~ + | | + | uint8_t (*)[1600] {aka unsigned char (*)[1600]} +In file included from etcp_connections.h:4, + from etcp_connections.c:1: +secure_channel.h:61:102: note: expected ‘uint8_t *’ {aka ‘unsigned char *’} but argument is of type ‘uint8_t (*)[1600]’ {aka ‘unsigned char (*)[1600]’} + 61 | sc_status_t sc_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len); + | ~~~~~~~~~^~~~~~~~~~ +etcp_connections.c:256:82: warning: ‘return’ with no value, in function returning non-void + 256 | if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; return; } + | ^~~~~~ +etcp_connections.c:248:5: note: declared here + 248 | int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { + | ^~~~~~~~~~~~~~~~~ +etcp_connections.c:259:35: error: incompatible types when initializing type ‘struct sockaddr_storage *’ using type ‘struct sockaddr_storage’ + 259 | struct sockaddr_storage* addr=dgram->link->remote_addr; + | ^~~~~ +etcp_connections.c:260:27: error: ‘to_addr’ undeclared (first use in this function); did you mean ‘in_addr’? + 260 | socklen_t addr_len = (to_addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + | ^~~~~~~ + | in_addr +etcp_connections.c:260:27: note: each undeclared identifier is reported only once for each function it appears in +etcp_connections.c:261:67: warning: passing argument 5 of ‘sendto’ from incompatible pointer type [-Wincompatible-pointer-types] + 261 | ssize_t sent = sendto(dgram->link->conn->fd, enc_buf, len, 0, addr, addr_len); + | ^~~~ + | | + | struct sockaddr_storage * +In file included from etcp_connections.h:7: +/usr/include/x86_64-linux-gnu/sys/socket.h:153:58: note: expected ‘const struct sockaddr *’ but argument is of type ‘struct sockaddr_storage *’ + 153 | int __flags, __CONST_SOCKADDR_ARG __addr, + | ^ +etcp_connections.c: In function ‘etcp_connections_read_callback’: +etcp_connections.c:311:33: error: ‘pkt’ undeclared (first use in this function) + 311 | socklen_t addr_len = sizeof(pkt->metadata.remote_addr); + | ^~~ +etcp_connections.c:314:15: error: redefinition of ‘addr_len’ + 314 | socklen_t addr_len=sizeof(addr); + | ^~~~~~~~ +etcp_connections.c:311:15: note: previous definition of ‘addr_len’ with type ‘socklen_t’ {aka ‘unsigned int’} + 311 | socklen_t addr_len = sizeof(pkt->metadata.remote_addr); + | ^~~~~~~~ +etcp_connections.c:322:48: warning: passing argument 1 of ‘memory_pool_alloc’ from incompatible pointer type [-Wincompatible-pointer-types] + 322 | struct ETCP_DGRAM* pkt = memory_pool_alloc(&e_sock->instance->pkt_pool); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | + | struct memory_pool ** +In file included from utun_instance.h:7, + from etcp_connections.h:5: +../lib/memory_pool.h:18:45: note: expected ‘struct memory_pool *’ but argument is of type ‘struct memory_pool **’ + 18 | void* memory_pool_alloc(struct memory_pool* pool); + | ~~~~~~~~~~~~~~~~~~~~^~~~ +etcp_connections.c:327:51: error: expected expression before ‘struct’ + 327 | struct ETCP_LINK* link=etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, &addr); + | ^~~~~~ +etcp_connections.c:327:28: error: too few arguments to function ‘etcp_link_find_by_addr’ + 327 | struct ETCP_LINK* link=etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, &addr); + | ^~~~~~~~~~~~~~~~~~~~~~ +etcp_connections.c:105:26: note: declared here + 105 | static struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr) { + | ^~~~~~~~~~~~~~~~~~~~~~ +etcp_connections.c:360:41: error: invalid type argument of ‘->’ (have ‘struct secure_channel’) + 360 | if (memcmp(&conn->crypto_ctx->peer_public_key, &sc.peer_public_key, SC_PUBKEY_SIZE)) { errorcode=5; goto ec_fr; }// коллизия - peer id совпал а ключи разные. + | ^~ +etcp_connections.c:362:48: error: ‘etcp’ undeclared (first use in this function) + 362 | struct ETCP_LINK* link = etcp_link_new(etcp, e_sock, addr, 1); + | ^~~~ +etcp_connections.c:362:62: error: incompatible type for argument 3 of ‘etcp_link_new’ + 362 | struct ETCP_LINK* link = etcp_link_new(etcp, e_sock, addr, 1); + | ^~~~ + | | + | struct sockaddr_storage +etcp_connections.c:209:108: note: expected ‘struct sockaddr_storage *’ but argument is of type ‘struct sockaddr_storage’ + 209 | struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~ +etcp_connections.c:376:49: error: invalid type argument of ‘->’ (have ‘struct global_config’) + 376 | int mtu=e_sock->instance->config->global->mtu; + | ^~ +etcp_connections.c:383:9: warning: implicit declaration of function ‘packet_pool_free’ [-Wimplicit-function-declaration] + 383 | packet_pool_free(&e_sock->instance->pkt_pool, pkt); + | ^~~~~~~~~~~~~~~~ +etcp_connections.c:392:5: warning: implicit declaration of function ‘etcp_input’; did you mean ‘etcp_conn_input’? [-Wimplicit-function-declaration] + 392 | etcp_input(pkt, conns); + | ^~~~~~~~~~ + | etcp_conn_input +etcp_connections.c:392:21: error: ‘conns’ undeclared (first use in this function); did you mean ‘confstr’? + 392 | etcp_input(pkt, conns); + | ^~~~~ + | confstr +etcp_connections.c: In function ‘etcp_input’: +etcp_connections.c:405:18: error: ‘e_sock’ undeclared (first use in this function) + 405 | if (!pkt || !e_sock) return -1; + | ^~~~~~ +etcp_connections.c:408:21: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 408 | size_t len = pkt->metadata.data_len; + | ^~ +etcp_connections.c:417:75: error: ‘struct ETCP_CONN’ has no member named ‘has_peer_key’ + 417 | if (header != ETCP_INIT_REQUEST && header != ETCP_CHANNEL_INIT && etcp->has_peer_key) { + | ^~ +etcp_connections.c:419:28: error: incompatible types when initializing type ‘sc_context_t *’ {aka ‘struct secure_channel *’} using type ‘struct secure_channel’ + 419 | sc_context_t* sc = etcp->crypto_ctx; + | ^~~~ +etcp_connections.c:431:83: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 431 | struct ETCP_LINK* link = etcp_link_find_by_addr(e_sock, (struct sockaddr*)&pkt->metadata.remote_addr, + | ^~ +etcp_connections.c:432:63: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 432 | sizeof(pkt->metadata.remote_addr)); + | ^~ +etcp_connections.c:431:30: error: too many arguments to function ‘etcp_link_find_by_addr’ + 431 | struct ETCP_LINK* link = etcp_link_find_by_addr(e_sock, (struct sockaddr*)&pkt->metadata.remote_addr, + | ^~~~~~~~~~~~~~~~~~~~~~ +etcp_connections.c:105:26: note: declared here + 105 | static struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr) { + | ^~~~~~~~~~~~~~~~~~~~~~ +etcp_connections.c:437:70: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 437 | link = etcp_link_new(etcp, e_sock, (struct sockaddr*)&pkt->metadata.remote_addr, + | ^~ +etcp_connections.c:438:44: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 438 | sizeof(pkt->metadata.remote_addr)); + | ^~ +etcp_connections.c:443:13: warning: implicit declaration of function ‘etcp_connections_send’; did you mean ‘etcp_connection_create’? [-Wimplicit-function-declaration] + 443 | etcp_connections_send(e_sock, reset_pkt, 1, (struct sockaddr*)&pkt->metadata.remote_addr, sizeof(pkt->metadata.remote_addr)); + | ^~~~~~~~~~~~~~~~~~~~~ + | etcp_connection_create +etcp_connections.c:443:79: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 443 | etcp_connections_send(e_sock, reset_pkt, 1, (struct sockaddr*)&pkt->metadata.remote_addr, sizeof(pkt->metadata.remote_addr)); + | ^~ +etcp_connections.c:443:113: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 443 | etcp_connections_send(e_sock, reset_pkt, 1, (struct sockaddr*)&pkt->metadata.remote_addr, sizeof(pkt->metadata.remote_addr)); + | ^~ +etcp_connections.c:459:20: error: ‘struct ETCP_CONN’ has no member named ‘peer_public_key’ + 459 | memcpy(etcp->peer_public_key, peer_pubkey, SC_PUBKEY_SIZE); + | ^~ +etcp_connections.c:460:13: error: ‘struct ETCP_CONN’ has no member named ‘has_peer_key’ + 460 | etcp->has_peer_key = 1; + | ^~ +etcp_connections.c:461:36: error: incompatible type for argument 1 of ‘sc_set_peer_public_key’ + 461 | sc_set_peer_public_key(etcp->crypto_ctx, peer_pubkey); + | ~~~~^~~~~~~~~~~~ + | | + | struct secure_channel +secure_channel.h:58:50: note: expected ‘sc_context_t *’ {aka ‘struct secure_channel *’} but argument is of type ‘struct secure_channel’ + 58 | sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key, int mode);// mode: 0-bin 1-hex key format + | ~~~~~~~~~~~~~~^~~ +etcp_connections.c:461:9: error: too few arguments to function ‘sc_set_peer_public_key’ + 461 | sc_set_peer_public_key(etcp->crypto_ctx, peer_pubkey); + | ^~~~~~~~~~~~~~~~~~~~~~ +secure_channel.h:58:13: note: declared here + 58 | sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key, int mode);// mode: 0-bin 1-hex key format + | ^~~~~~~~~~~~~~~~~~~~~~ +etcp_connections.c:478:12: error: ‘struct ETCP_DGRAM’ has no member named ‘metadata’ + 478 | pkt->metadata.channel = link; // Or etcp_channel if separate + | ^~ +etcp_connections.c:483:5: warning: implicit declaration of function ‘packet_pool_put’ [-Wimplicit-function-declaration] + 483 | packet_pool_put(&etcp->packet_pool, pkt); + | ^~~~~~~~~~~~~~~ +etcp_connections.c:483:26: error: ‘struct ETCP_CONN’ has no member named ‘packet_pool’ + 483 | packet_pool_put(&etcp->packet_pool, pkt); + | ^~ +etcp_connections.c: In function ‘init_connections’: +etcp_connections.c:490:29: warning: initialization of ‘struct config *’ from incompatible pointer type ‘struct utun_config *’ [-Wincompatible-pointer-types] + 490 | struct config* config = instance->config; + | ^~~~~~~~ +etcp_connections.c:491:42: error: invalid use of undefined type ‘struct config’ + 491 | instance->connections = calloc(config->server_count, sizeof(struct ETCP_CONN)); + | ^~ +etcp_connections.c:494:15: error: ‘struct UTUN_INSTANCE’ has no member named ‘connection_count’; did you mean ‘connections’? + 494 | instance->connection_count = 0; + | ^~~~~~~~~~~~~~~~ + | connections +etcp_connections.c:496:39: error: invalid use of undefined type ‘struct config’ + 496 | struct CFG_SERVER* server = config->servers; + | ^~ +etcp_connections.c:500:34: warning: implicit declaration of function ‘etcp_connection_add’; did you mean ‘etcp_connection_create’? [-Wimplicit-function-declaration] + 500 | struct ETCP_CONN* conn = etcp_connection_add(instance, server->ip, server->netif_index, server->so_mark, server->type); + | ^~~~~~~~~~~~~~~~~~~ + | etcp_connection_create +etcp_connections.c:500:34: warning: initialization of ‘struct ETCP_CONN *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion] +etcp_connections.c:503:26: error: ‘etcp’ undeclared (first use in this function) + 503 | etcp_destroy(etcp); + | ^~~~ +etcp_connections.c:508:36: error: ‘struct CFG_SERVER’ has no member named ‘addr’ + 508 | server->name, server->addr, e_sock->num_channels); + | ^~ +etcp_connections.c:508:44: error: ‘e_sock’ undeclared (first use in this function) + 508 | server->name, server->addr, e_sock->num_channels); + | ^~~~~~ +etcp_connections.c:513:31: error: invalid use of undefined type ‘struct config’ + 513 | for (int j = 0; j < config->client_count; j++) { + | ^~ +etcp_connections.c:514:47: error: invalid use of undefined type ‘struct config’ + 514 | struct client_config* client = &config->clients[j]; + | ^~ +etcp_connections.c:517:26: error: invalid use of undefined type ‘struct client_config’ + 517 | if (strcmp(client->from, server->name) != 0) { + | ^~ +etcp_connections.c:525:31: error: ‘struct ETCP_CONN’ has no member named ‘ctx’ + 525 | sc_init_ctx(&etcp_conn->ctx, &instance->my_keys); + | ^~ +etcp_connections.c:526:26: error: invalid use of undefined type ‘struct client_config’ + 526 | if (strlen(client->peer_public_key_hex) > 0) { + | ^~ +etcp_connections.c:528:17: warning: implicit declaration of function ‘hex_to_binary’ [-Wimplicit-function-declaration] + 528 | if (hex_to_binary(client->peer_public_key_hex, peer_key_bin, SC_PUBKEY_SIZE) == 0) { + | ^~~~~~~~~~~~~ +etcp_connections.c:528:37: error: invalid use of undefined type ‘struct client_config’ + 528 | if (hex_to_binary(client->peer_public_key_hex, peer_key_bin, SC_PUBKEY_SIZE) == 0) { + | ^~ +etcp_connections.c:529:33: error: ‘struct ETCP_CONN’ has no member named ‘peer_public_key’ + 529 | memcpy(etcp_conn->peer_public_key, peer_key_bin, SC_PUBKEY_SIZE); + | ^~ +etcp_connections.c:530:26: error: ‘struct ETCP_CONN’ has no member named ‘has_peer_key’ + 530 | etcp_conn->has_peer_key = 1; + | ^~ +etcp_connections.c:531:49: error: incompatible type for argument 1 of ‘sc_set_peer_public_key’ + 531 | sc_set_peer_public_key(etcp_conn->crypto_ctx, peer_key_bin); + | ~~~~~~~~~^~~~~~~~~~~~ + | | + | struct secure_channel +secure_channel.h:58:50: note: expected ‘sc_context_t *’ {aka ‘struct secure_channel *’} but argument is of type ‘struct secure_channel’ + 58 | sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key, int mode);// mode: 0-bin 1-hex key format + | ~~~~~~~~~~~~~~^~~ +etcp_connections.c:531:17: error: too few arguments to function ‘sc_set_peer_public_key’ + 531 | sc_set_peer_public_key(etcp_conn->crypto_ctx, peer_key_bin); + | ^~~~~~~~~~~~~~~~~~~~~~ +secure_channel.h:58:13: note: declared here + 58 | sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key, int mode);// mode: 0-bin 1-hex key format + | ^~~~~~~~~~~~~~~~~~~~~~ +etcp_connections.c:537:16: error: variable ‘cl’ has initializer but incomplete type + 537 | struct client_link cl=client->links; + | ^~~~~~~~~~~ +etcp_connections.c:537:37: error: invalid use of undefined type ‘struct client_config’ + 537 | struct client_link cl=client->links; + | ^~ +etcp_connections.c:537:28: error: storage size of ‘cl’ isn’t known + 537 | struct client_link cl=client->links; + | ^~ +etcp_connections.c:539:13: error: ‘conn’ undeclared (first use in this function) + 539 | conn= (надо найти) + | ^~~~ +etcp_connections.c:539:20: error: ‘надо’ undeclared (first use in this function) + 539 | conn= (надо найти) + | ^~~~ +etcp_connections.c:539:24: error: expected ‘)’ before ‘найти’ + 539 | conn= (надо найти) + | ~ ^~~~~~ + | ) +etcp_connections.c:539:31: error: expected ‘;’ before ‘struct’ + 539 | conn= (надо найти) + | ^ + | ; +...... + 542 | struct ETCP_LINK* link = etcp_link_new(etcp, conn, cl->remote_sockaddr, sizeof(struct sockaddr_storage)); + | ~~~~~~ +In file included from etcp_connections.c:8: +etcp_connections.c:544:95: error: invalid use of undefined type ‘struct client_config’ + 544 | DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create link for client %s", client->name); + | ^~ +../lib/debug_config.h:114:92: note: in definition of macro ‘DEBUG_ERROR’ + 114 | debug_output(DEBUG_LEVEL_ERROR, category, __FUNCTION__, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + | ^~~~~~~~~~~ +etcp_connections.c:550:51: error: invalid use of undefined type ‘struct client_config’ + 550 | printf(" Added client %s -> %s\n", client->name, client->to_addr); + | ^~ +etcp_connections.c:550:65: error: invalid use of undefined type ‘struct client_config’ + 550 | printf(" Added client %s -> %s\n", client->name, client->to_addr); + | ^~ +etcp_connections.c:554:19: error: ‘struct UTUN_INSTANCE’ has no member named ‘connection_count’; did you mean ‘connections’? + 554 | if (instance->connection_count == 0) { + | ^~~~~~~~~~~~~~~~ + | connections +etcp_connections.c:561:54: error: ‘struct UTUN_INSTANCE’ has no member named ‘connection_count’; did you mean ‘connections’? + 561 | printf("Initialized %d connections\n", instance->connection_count); + | ^~~~~~~~~~~~~~~~ + | connections +etcp_connections.c: At top level: +etcp_connections.c:26:12: warning: ‘etcp_link_send_init_response’ used but never defined + 26 | static int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ +make[2]: *** [Makefile:619: utun-etcp_connections.o] Ошибка 1 +make[1]: *** [Makefile:433: all-recursive] Ошибка 1 +make: *** [Makefile:353: all] Ошибка 2 diff --git a/configure.ac b/configure.ac index 9066fd20..f55b17b2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([utun], [2.0.0], [https://github.com/anomalyco/utun3/issues]) +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]) @@ -6,7 +6,6 @@ AC_CONFIG_MACRO_DIR([m4]) # Required programs AC_PROG_CC -AC_PROG_CC_C99 AC_PROG_RANLIB AM_PROG_AR AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror]) diff --git a/lib/Makefile.am b/lib/Makefile.am index 807704d2..7d41d561 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -3,12 +3,14 @@ noinst_LIBRARIES = libuasync.a libuasync_a_SOURCES = \ u_async.c \ u_async.h \ - $(top_srcdir)/src/ll_queue.h \ - $(top_srcdir)/src/ll_queue.c \ + ll_queue.h \ + ll_queue.c \ debug_config.c \ debug_config.h \ timeout_heap.c \ timeout_heap.h \ + memory_pool.c \ + memory_pool.h \ sha256.c \ sha256.h diff --git a/src/ll_queue.c b/lib/ll_queue.c similarity index 91% rename from src/ll_queue.c rename to lib/ll_queue.c index bb1a5d4f..7676a8d3 100644 --- a/src/ll_queue.c +++ b/lib/ll_queue.c @@ -1,10 +1,10 @@ -#include "ll_queue.h" #include #include #include #include -#include "../lib/u_async.h" -#include "../lib/debug_config.h" +#include "ll_queue.h" +#include "u_async.h" +#include "debug_config.h" // Предварительное объявление для отложенного возобновления static void queue_resume_timeout_cb(void* arg); @@ -31,8 +31,8 @@ static void check_waiters(struct ll_queue* q) { waiter->callback(q, waiter->callback_arg); // Удалить waiter из списка *pprev = next; - if (q->use_pools) { - memory_pool_free(&q->waiter_pool, waiter); + if (q->pool) { + memory_pool_free(q->pool, waiter); } else { free(waiter); } @@ -50,7 +50,7 @@ static void check_waiters(struct ll_queue* q) { // ==================== Управление очередью ==================== -struct ll_queue* queue_new_with_pools(struct uasync_s* ua, int use_pools) { +struct ll_queue* queue_new(struct UASYNC* ua, struct memory_pool* pool) { struct ll_queue* q = calloc(1, sizeof(struct ll_queue)); if (!q) return NULL; @@ -65,20 +65,9 @@ struct ll_queue* queue_new_with_pools(struct uasync_s* ua, int use_pools) { q->resume_timeout_id = NULL; q->ua = ua; q->waiters = NULL; - q->use_pools = use_pools; - - // Инициализировать пулы памяти - if (use_pools) { - memory_pool_init(&q->waiter_pool, sizeof(struct queue_waiter)); - // Для entry_pool будем использовать фиксированный размер, так как размер данных может варьироваться - // Вместо этого оптимизируем через специализированные функции - } - - return q; -} + q->pool=pool; -struct ll_queue* queue_new(struct uasync_s* ua) { - return queue_new_with_pools(ua, 0); // По умолчанию без пулов для обратной совместимости + return q; } void queue_free(struct ll_queue* q) { @@ -104,8 +93,8 @@ void queue_free(struct ll_queue* q) { while (waiter) { struct queue_waiter* next = waiter->next; DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_free: freeing waiter %p (waiter %d)", waiter, waiter_count++); - if (q->use_pools) { - memory_pool_free(&q->waiter_pool, waiter); + if (q->pool) { + memory_pool_free(q->pool, waiter); } else { free(waiter); } @@ -118,11 +107,6 @@ void queue_free(struct ll_queue* q) { uasync_cancel_timeout(q->ua, q->resume_timeout_id); } - // Очистить пулы памяти - if (q->use_pools) { - memory_pool_destroy(&q->waiter_pool); - } - DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_free: freeing queue structure %p", q); free(q); } @@ -347,8 +331,8 @@ struct queue_waiter* queue_wait_threshold(struct ll_queue* q, int max_packets, s // Создать новый waiter struct queue_waiter* waiter; - if (q->use_pools) { - waiter = (struct queue_waiter*)memory_pool_alloc(&q->waiter_pool); + if (q->pool) { + waiter = (struct queue_waiter*)memory_pool_alloc(q->pool); } else { waiter = malloc(sizeof(struct queue_waiter)); } @@ -391,8 +375,8 @@ void queue_cancel_wait(struct ll_queue* q, struct queue_waiter* waiter) { while (w) { if (w == waiter) { *pprev = w->next; - if (q->use_pools) { - memory_pool_free(&q->waiter_pool, w); + if (q->pool) { + memory_pool_free(q->pool, w); } else { free(w); } @@ -406,11 +390,11 @@ void queue_cancel_wait(struct ll_queue* q, struct queue_waiter* waiter) { // ==================== Статистика и метрики ==================== void queue_get_pool_stats(struct ll_queue* q, size_t* waiter_allocations, size_t* waiter_reuse) { - if (!q || !q->use_pools) { + if (!q || !q->pool) { if (waiter_allocations) *waiter_allocations = 0; if (waiter_reuse) *waiter_reuse = 0; return; } - memory_pool_get_stats(&q->waiter_pool, waiter_allocations, waiter_reuse); + memory_pool_get_stats(q->pool, waiter_allocations, waiter_reuse); } diff --git a/src/ll_queue.h b/lib/ll_queue.h similarity index 92% rename from src/ll_queue.h rename to lib/ll_queue.h index 30404e6a..93af3045 100644 --- a/src/ll_queue.h +++ b/lib/ll_queue.h @@ -6,7 +6,6 @@ // Предварительные объявления struct ll_queue; -struct uasync_s; struct ll_entry; struct queue_waiter; struct memory_pool; @@ -46,25 +45,21 @@ struct ll_queue { int callback_suspended; // 1 если коллбэки приостановлены (во время обработки) void* resume_timeout_id; // ID таймаута uasync для отложенного возобновления - struct uasync_s* ua; // Экземпляр uasync для таймеров + struct UASYNC* ua; // Экземпляр uasync для таймеров struct queue_waiter* waiters; // Список ожидающих коллбэков // Пулы памяти для оптимизации аллокаций - struct memory_pool waiter_pool; // Пул для структур struct queue_waiter - int use_pools; // Флаг использования пулов (включается при частых аллокациях) + struct memory_pool* pool; // Пул для структур struct queue_waiter }; // ==================== Управление очередью ==================== // Создать новую пустую очередь // ua - экземпляр uasync для таймеров (обязательный параметр) -// use_pools - использовать пулы памяти для оптимизации (1) или нет (0) -// Возвращает: указатель на очередь или NULL при ошибке выделения памяти -struct ll_queue* queue_new_with_pools(struct uasync_s* ua, int use_pools); - -// Создать новую пустую очередь (обратная совместимость) -struct ll_queue* queue_new(struct uasync_s* ua); +// pool - если не null то использовать этот пул памяти +// Возвращает: указатель на очередь или NULL при ошибке выделения памяти (see memory_pool.c/h) +struct ll_queue* queue_new(struct UASYNC* ua, struct memory_pool* pool); // Освободить очередь и все её элементы // Также отменяет отложенное возобновление если оно запланировано diff --git a/lib/memory_pool.c b/lib/memory_pool.c new file mode 100644 index 00000000..140f64e4 --- /dev/null +++ b/lib/memory_pool.c @@ -0,0 +1,87 @@ +// memory_pool.c +#include "memory_pool.h" +#include +#include + +// Инициализировать пул памяти +struct memory_pool* memory_pool_init(size_t object_size) { + struct memory_pool* pool = calloc(1, sizeof(struct memory_pool)); + if (!pool) { + return NULL; + } + pool->free_head = NULL; + pool->object_size = object_size; + pool->free_count = 0; + pool->allocations = 0; + pool->reuse_count = 0; + return pool; +} + +// Выделить объект из пула или из malloc +void* memory_pool_alloc(struct memory_pool* pool) { + if (!pool) { + return NULL; + } + + if (pool->free_head) { + void* obj = pool->free_head; + pool->free_head = *(void**)obj; // Извлекаем next из начала блока + pool->free_count--; + pool->reuse_count++; + memset(obj, 0, pool->object_size); // Опционально: очищаем память для безопасности + return obj; + } + + pool->allocations++; + return calloc(1, pool->object_size); // Используем calloc для инициализации нулями +} + +// Освободить объект в пул или в free +void memory_pool_free(struct memory_pool* pool, void* obj) { + if (!pool || !obj) { + return; + } + + // Если пул не заполнен, сохранить объект для повторного использования + if (pool->free_count < MEMORY_POOL_MAX_FREE) { + *(void**)obj = pool->free_head; // Сохраняем next в начало блока + pool->free_head = obj; + pool->free_count++; + return; + } + + // Иначе освободить через free + free(obj); +} + +// Получить статистику пула +void memory_pool_get_stats(struct memory_pool* pool, size_t* allocations, size_t* reuse_count) { + if (!pool) { + return; + } + if (allocations) { + *allocations = pool->allocations; + } + if (reuse_count) { + *reuse_count = pool->reuse_count; + } +} + +// Очистить пул памяти +void memory_pool_destroy(struct memory_pool* pool) { + if (!pool) { + return; + } + + // Освободить все объекты в пуле + void* obj = pool->free_head; + while (obj) { + void* next = *(void**)obj; + free(obj); + obj = next; + } + + pool->free_head = NULL; + pool->free_count = 0; + free(pool); +} diff --git a/lib/memory_pool.h b/lib/memory_pool.h new file mode 100644 index 00000000..fa0bb50d --- /dev/null +++ b/lib/memory_pool.h @@ -0,0 +1,23 @@ +// memory_pool.h +#ifndef MEMORY_POOL_H +#define MEMORY_POOL_H + +#include + +#define MEMORY_POOL_MAX_FREE 64 // Максимальное количество свободных объектов в пуле (чтобы не накапливать слишком много) + +struct memory_pool { + void* free_head; // Голова linked list свободных блоков (next хранится в начале каждого блока) + int free_count; // Количество свободных блоков + size_t object_size; // Размер объектов в пуле + size_t allocations; // Общее количество аллокаций (включая новые malloc) + size_t reuse_count; // Количество повторных использований из пула +}; + +struct memory_pool* memory_pool_init(size_t object_size); +void* memory_pool_alloc(struct memory_pool* pool); +void memory_pool_free(struct memory_pool* pool, void* obj); +void memory_pool_get_stats(struct memory_pool* pool, size_t* allocations, size_t* reuse_count); +void memory_pool_destroy(struct memory_pool* pool); + +#endif // MEMORY_POOL_H diff --git a/lib/u_async.c b/lib/u_async.c index ae014ca1..de95b9bb 100644 --- a/lib/u_async.c +++ b/lib/u_async.c @@ -1,7 +1,6 @@ // uasync.c #include "u_async.h" -#include "timeout_heap.h" #include "debug_config.h" #include #include @@ -19,7 +18,7 @@ struct timeout_node { void* arg; timeout_callback_t callback; uint64_t expiration_ms; // absolute expiration time in milliseconds - uasync_t* ua; // Pointer back to uasync instance for counter updates + struct UASYNC* ua; // Pointer back to uasync instance for counter updates int cancelled; // Cancellation flag }; @@ -50,21 +49,7 @@ static int socket_array_remove(struct socket_array* sa, int fd); static struct socket_node* socket_array_get(struct socket_array* sa, int fd); static int socket_array_build_pollfd(struct socket_array* sa, struct pollfd* fds, int max_fds); -// Uasync instance structure -struct uasync_s { - TimeoutHeap* timeout_heap; // Heap for timeout management - struct socket_array* sockets; // Array-based socket management - // Debug counters for memory allocation tracking - size_t timer_alloc_count; - size_t timer_free_count; - size_t socket_alloc_count; - size_t socket_free_count; - // Wakeup pipe for interrupting poll - int wakeup_pipe[2]; // [0] read, [1] write - int wakeup_initialized; -}; - -// No global instance - each module must use its own uasync_t instance +// No global instance - each module must use its own struct UASYNC instance // Array-based socket management implementation static struct socket_array* socket_array_create(int initial_capacity) { @@ -219,7 +204,7 @@ static int socket_array_build_pollfd(struct socket_array* sa, struct pollfd* fds // Callback to free timeout node and update counters static void timeout_node_free_callback(void* user_data, void* data) { - uasync_t* ua = (uasync_t*)user_data; + struct UASYNC* ua = (struct UASYNC*)user_data; struct timeout_node* node = (struct timeout_node*)data; (void)node; // Not used directly, but keep for consistency ua->timer_free_count++; @@ -234,7 +219,7 @@ static void get_current_time(struct timeval* tv) { // Drain wakeup pipe - read all available bytes -static void drain_wakeup_pipe(uasync_t* ua) { +static void drain_wakeup_pipe(struct UASYNC* ua) { if (!ua || !ua->wakeup_initialized) return; char buf[64]; @@ -261,7 +246,7 @@ static uint64_t timeval_to_ms(const struct timeval* tv) { // Simplified timeout handling without reference counting // Process expired timeouts with safe cancellation -static void process_timeouts(struct uasync_s* ua) { +static void process_timeouts(struct UASYNC* ua) { if (!ua || !ua->timeout_heap) return; struct timeval now_tv; @@ -291,7 +276,7 @@ static void process_timeouts(struct uasync_s* ua) { } // Compute time to next timeout -static void get_next_timeout(struct uasync_s* ua, struct timeval* tv) { +static void get_next_timeout(struct UASYNC* ua, struct timeval* tv) { if (!ua || !ua->timeout_heap) { tv->tv_sec = 0; tv->tv_usec = 0; @@ -326,7 +311,7 @@ static void get_next_timeout(struct uasync_s* ua, struct timeval* tv) { // Instance version -void* uasync_set_timeout(uasync_t* ua, int timeout_tb, void* arg, timeout_callback_t callback) { +void* uasync_set_timeout(struct UASYNC* ua, int timeout_tb, void* arg, timeout_callback_t callback) { if (!ua || timeout_tb < 0 || !callback) return NULL; if (!ua->timeout_heap) return NULL; @@ -358,7 +343,7 @@ void* uasync_set_timeout(uasync_t* ua, int timeout_tb, void* arg, timeout_callba // Instance version -err_t uasync_cancel_timeout(uasync_t* ua, void* t_id) { +err_t uasync_cancel_timeout(struct UASYNC* ua, void* t_id) { if (!ua || !t_id || !ua->timeout_heap) return ERR_FAIL; struct timeout_node* node = (struct timeout_node*)t_id; @@ -381,7 +366,7 @@ err_t uasync_cancel_timeout(uasync_t* ua, void* t_id) { // Instance version -void* uasync_add_socket(uasync_t* ua, int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_data) { +void* uasync_add_socket(struct UASYNC* ua, int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_data) { if (!ua || fd < 0 || fd >= FD_SETSIZE) return NULL; // Bounds check int index = socket_array_add(ua->sockets, fd, read_cbk, write_cbk, except_cbk, user_data); @@ -396,7 +381,7 @@ void* uasync_add_socket(uasync_t* ua, int fd, socket_callback_t read_cbk, socket // Instance version -err_t uasync_remove_socket(uasync_t* ua, void* s_id) { +err_t uasync_remove_socket(struct UASYNC* ua, void* s_id) { if (!ua || !s_id) return ERR_FAIL; struct socket_node* node = (struct socket_node*)s_id; @@ -411,14 +396,14 @@ err_t uasync_remove_socket(uasync_t* ua, void* s_id) { -void uasync_mainloop(uasync_t* ua) { +void uasync_mainloop(struct UASYNC* ua) { while (1) { uasync_poll(ua, -1); /* infinite timeout */ } } // Instance version -void uasync_poll(uasync_t* ua, int timeout_tb) { +void uasync_poll(struct UASYNC* ua, int timeout_tb) { if (!ua) return; /* Process expired timeouts */ @@ -585,7 +570,7 @@ void uasync_poll(uasync_t* ua, int timeout_tb) { // ========== Instance management functions ========== -uasync_t* uasync_create(void) { +struct UASYNC* uasync_create(void) { // Initialize debug system on first use static int debug_initialized = 0; if (!debug_initialized) { @@ -593,10 +578,10 @@ uasync_t* uasync_create(void) { debug_initialized = 1; } - uasync_t* ua = malloc(sizeof(struct uasync_s)); + struct UASYNC* ua = malloc(sizeof(struct UASYNC)); if (!ua) return NULL; - memset(ua, 0, sizeof(struct uasync_s)); + memset(ua, 0, sizeof(struct UASYNC)); ua->wakeup_pipe[0] = -1; ua->wakeup_pipe[1] = -1; ua->wakeup_initialized = 0; @@ -643,7 +628,7 @@ uasync_t* uasync_create(void) { return ua; } -void uasync_destroy(uasync_t* ua) { +void uasync_destroy(struct UASYNC* ua) { if (!ua) return; // Check for potential memory leaks @@ -699,7 +684,7 @@ void uasync_destroy(uasync_t* ua) { free(ua); } -void uasync_init_instance(uasync_t* ua) { +void uasync_init_instance(struct UASYNC* ua) { if (!ua) return; // Initialize socket array if not present @@ -716,7 +701,7 @@ void uasync_init_instance(uasync_t* ua) { } // Debug statistics -void uasync_get_stats(uasync_t* ua, size_t* timer_alloc, size_t* timer_free, size_t* socket_alloc, size_t* socket_free) { +void uasync_get_stats(struct UASYNC* ua, size_t* timer_alloc, size_t* timer_free, size_t* socket_alloc, size_t* socket_free) { if (!ua) return; if (timer_alloc) *timer_alloc = ua->timer_alloc_count; if (timer_free) *timer_free = ua->timer_free_count; @@ -727,7 +712,7 @@ void uasync_get_stats(uasync_t* ua, size_t* timer_alloc, size_t* timer_free, siz // Get global instance for backward compatibility // Wakeup mechanism -int uasync_wakeup(uasync_t* ua) { +int uasync_wakeup(struct UASYNC* ua) { if (!ua || !ua->wakeup_initialized) return -1; char byte = 0; @@ -739,7 +724,7 @@ int uasync_wakeup(uasync_t* ua) { return 0; } -int uasync_get_wakeup_fd(uasync_t* ua) { +int uasync_get_wakeup_fd(struct UASYNC* ua) { if (!ua || !ua->wakeup_initialized) return -1; return ua->wakeup_pipe[1]; } diff --git a/lib/u_async.h b/lib/u_async.h index f760375d..c207373d 100644 --- a/lib/u_async.h +++ b/lib/u_async.h @@ -7,6 +7,7 @@ #include #include +#include "timeout_heap.h" typedef void (*timeout_callback_t)(void* user_arg);// передаёт user_arg из uasync_set_timeout typedef void (*socket_callback_t)(int fd, void* user_arg);// передаёт user_arg из uasync_add_socket @@ -18,33 +19,44 @@ typedef int err_t; #define ERR_OK 0 #define ERR_FAIL -1 -// Opaque uasync instance handle -typedef struct uasync_s uasync_t; +// Uasync instance structure +struct UASYNC { + TimeoutHeap* timeout_heap; // Heap for timeout management + struct socket_array* sockets; // Array-based socket management + // Debug counters for memory allocation tracking + size_t timer_alloc_count; + size_t timer_free_count; + size_t socket_alloc_count; + size_t socket_free_count; + // Wakeup pipe for interrupting poll + int wakeup_pipe[2]; // [0] read, [1] write + int wakeup_initialized; +}; // Instance API - основной API для работы с uasync -uasync_t* uasync_create(void); -void uasync_destroy(uasync_t* ua); -void uasync_init_instance(uasync_t* ua); +struct UASYNC* uasync_create(void); +void uasync_destroy(struct UASYNC* ua); +void uasync_init_instance(struct UASYNC* ua); // Timeouts, timebase = 0.1 mS -void* uasync_set_timeout(uasync_t* ua, int timeout_tb, void* user_arg, timeout_callback_t callback); -err_t uasync_cancel_timeout(uasync_t* ua, void* t_id); +void* uasync_set_timeout(struct UASYNC* ua, int timeout_tb, void* user_arg, timeout_callback_t callback); +err_t uasync_cancel_timeout(struct UASYNC* ua, void* t_id); // Sockets -void* uasync_add_socket(uasync_t* ua, int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_arg); -err_t uasync_remove_socket(uasync_t* ua, void* s_id); +void* uasync_add_socket(struct UASYNC* ua, int fd, socket_callback_t read_cbk, socket_callback_t write_cbk, socket_callback_t except_cbk, void* user_arg); +err_t uasync_remove_socket(struct UASYNC* ua, void* s_id); // Single iteration of event loop with timeout (timebase units) -void uasync_poll(uasync_t* ua, int timeout_tb); +void uasync_poll(struct UASYNC* ua, int timeout_tb); // Mainloop (бесконечный цикл, __noreturn) -void uasync_mainloop(uasync_t* ua); +void uasync_mainloop(struct UASYNC* ua); // Debug statistics -void uasync_get_stats(uasync_t* ua, size_t* timer_alloc, size_t* timer_free, size_t* socket_alloc, size_t* socket_free); +void uasync_get_stats(struct UASYNC* ua, size_t* timer_alloc, size_t* timer_free, size_t* socket_alloc, size_t* socket_free); // Wakeup mechanism for interrupting poll -int uasync_wakeup(uasync_t* ua); -int uasync_get_wakeup_fd(uasync_t* ua); // returns write fd for wakeup pipe (for signal handlers) +int uasync_wakeup(struct UASYNC* ua); +int uasync_get_wakeup_fd(struct UASYNC* ua); // returns write fd for wakeup pipe (for signal handlers) #endif // UASYNC_H diff --git a/log b/log new file mode 100644 index 00000000..e0051096 --- /dev/null +++ b/log @@ -0,0 +1,53 @@ +ar: модификатор «u» игнорируется, так как по умолчанию используется «D» (смотрите «U») +utun_instance.c: In function ‘utun_instance_destroy’: +utun_instance.c:98:17: warning: implicit declaration of function ‘conn_destroy’; did you mean ‘uasync_destroy’? [-Wimplicit-function-declaration] + 98 | conn_destroy(instance->connections[i]); + | ^~~~~~~~~~~~ + | uasync_destroy +utun_instance.c: In function ‘tun_read_callback’: +utun_instance.c:237:21: warning: implicit declaration of function ‘conn_send’ [-Wimplicit-function-declaration] + 237 | if (conn_send(route.next_hop, buffer, nread) < 0) { + | ^~~~~~~~~ +utun_instance.c: In function ‘utun_instance_unregister_sockets’: +utun_instance.c:276:57: warning: passing argument 2 of ‘uasync_remove_socket’ makes pointer from integer without a cast [-Wint-conversion] + 276 | uasync_remove_socket(instance->ua, instance->tun.fd); + | ~~~~~~~~~~~~~^~~ + | | + | int +In file included from utun_instance.c:8: +../lib/u_async.h:35:48: note: expected ‘void *’ but argument is of type ‘int’ + 35 | err_t uasync_remove_socket(uasync_t* ua, void* s_id); + | ~~~~~~^~~~ +etcp_connections.c: In function ‘etcp_link_send_init’: +etcp_connections.c:223:5: warning: implicit declaration of function ‘sc_get_public_key’; did you mean ‘sc_set_peer_public_key’? [-Wimplicit-function-declaration] + 223 | sc_get_public_key(sc, pubkey); + | ^~~~~~~~~~~~~~~~~ + | sc_set_peer_public_key +etcp_connections.c: In function ‘init_connections’: +etcp_connections.c:432:29: warning: initialization of ‘struct config *’ from incompatible pointer type ‘struct utun_config *’ [-Wincompatible-pointer-types] + 432 | struct config* config = instance->config; + | ^~~~~~~~ +etcp_connections.c:433:42: error: invalid use of undefined type ‘struct config’ + 433 | instance->connections = calloc(config->server_count, sizeof(conn_handle_t*)); + | ^~ +etcp_connections.c:438:31: error: invalid use of undefined type ‘struct config’ + 438 | for (int i = 0; i < config->server_count; i++) { + | ^~ +etcp_connections.c:439:47: error: invalid use of undefined type ‘struct config’ + 439 | struct server_config* server = &config->servers[i]; + | ^~ +etcp_connections.c:442:30: warning: implicit declaration of function ‘parse_ip_port’ [-Wimplicit-function-declaration] + 442 | uint16_t bind_port = parse_ip_port(server->addr, bind_ip_str, sizeof(bind_ip_str)); + | ^~~~~~~~~~~~~ +etcp_connections.c:485:43: warning: assignment to ‘struct ETCP_SOCKET *’ from incompatible pointer type ‘struct ETCP_CONNECTIONS *’ [-Wincompatible-pointer-types] + 485 | instance->first_listen_socket = conns; + | ^ +etcp_connections.c:489:35: error: invalid use of undefined type ‘struct config’ + 489 | for (int j = 0; j < config->client_count; j++) { + | ^~ +etcp_connections.c:490:51: error: invalid use of undefined type ‘struct config’ + 490 | struct client_config* client = &config->clients[j]; + | ^~ +make[2]: *** [Makefile:626: utun-etcp_connections.o] Ошибка 1 +make[1]: *** [Makefile:433: all-recursive] Ошибка 1 +make: *** [Makefile:353: all] Ошибка 2 diff --git a/src/Makefile.am b/src/Makefile.am index e454a011..a7cb15c4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,8 +12,6 @@ utun_SOURCES = \ secure_channel.c \ crc32.c \ pkt_normalizer.c \ - packet_pool.c \ - memory_pool.c \ $(top_srcdir)/tinycrypt/lib/source/aes_encrypt.c \ $(top_srcdir)/tinycrypt/lib/source/aes_decrypt.c \ $(top_srcdir)/tinycrypt/lib/source/cbc_mode.c \ diff --git a/src/config_parser.c b/src/config_parser.c index fc3d9186..67dcc094 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -1,31 +1,25 @@ -// config_parser.c - Configuration parser for utun application (simplified) +// config_parser.c - Configuration parser for utun application (updated for new structures) #define _POSIX_C_SOURCE 200809L #include "config_parser.h" #include #include #include #include -#include "debug_config.h" +#include "../lib/debug_config.h" #include #include +#include +#include +#include #define MAX_LINE_LEN 1024 #define INITIAL_ARRAY_CAPACITY 8 -void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len) { - if (!bytes || !hex_str || hex_len < len * 2 + 1) return; - for (size_t i = 0; i < len; i++) { - snprintf(hex_str + i * 2, hex_len - i * 2, "%02x", bytes[i]); - } - hex_str[len * 2] = '\0'; -} - typedef enum { SECTION_UNKNOWN, SECTION_GLOBAL, SECTION_SERVER, SECTION_CLIENT, - SECTION_CONNECTION, SECTION_ROUTING } section_type_t; @@ -57,87 +51,215 @@ static int parse_key_value(const char *line, char *key, size_t key_len, char *va return 0; } -static int ensure_capacity(void **array, int *capacity, int item_size) { - if (!array || !capacity) return -1; - - int new_capacity = *capacity == 0 ? INITIAL_ARRAY_CAPACITY : *capacity * 2; - void *new_array = realloc(*array, new_capacity * item_size); - if (!new_array) return -1; - - *array = new_array; - *capacity = new_capacity; - return 0; -} - static int assign_string(char *dest, size_t dest_size, const char *src) { if (!dest || !src || strlen(src) >= dest_size) return -1; strcpy(dest, src); return 0; } -static int add_server(struct utun_config *cfg, const struct server_config *srv) { - if (cfg->server_count >= cfg->server_capacity) { - if (ensure_capacity((void**)&cfg->servers, &cfg->server_capacity, sizeof(struct server_config)) < 0) return -1; +static int parse_ip_with_netmask(const char *str, struct IP *ip, uint8_t *netmask) { + char ip_str[64]; + strncpy(ip_str, str, sizeof(ip_str) - 1); + ip_str[sizeof(ip_str) - 1] = '\0'; + + char *slash = strchr(ip_str, '/'); + if (slash) { + *slash = '\0'; + *netmask = atoi(slash + 1); + } else { + *netmask = 32; // Default IPv4 netmask } - memcpy(&cfg->servers[cfg->server_count++], srv, sizeof(struct server_config)); - return 0; + + // Try IPv4 first + struct in_addr addr4; + if (inet_pton(AF_INET, ip_str, &addr4) == 1) { + ip->family = AF_INET; + ip->addr.v4 = addr4; + return 0; + } + + // Try IPv6 + struct in6_addr addr6; + if (inet_pton(AF_INET6, ip_str, &addr6) == 1) { + ip->family = AF_INET6; + ip->addr.v6 = addr6; + if (*netmask == 32) *netmask = 128; // Default IPv6 netmask + return 0; + } + + return -1; } -static int add_client(struct utun_config *cfg, const struct client_config *cli) { - if (cfg->client_count >= cfg->client_capacity) { - if (ensure_capacity((void**)&cfg->clients, &cfg->client_capacity, sizeof(struct client_config)) < 0) return -1; +static int parse_sockaddr(const char *addr_str, const char *port_str, struct sockaddr_storage *sockaddr) { + struct addrinfo hints = {0}; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + struct addrinfo *result; + if (getaddrinfo(addr_str, port_str, &hints, &result) != 0) { + return -1; } - memcpy(&cfg->clients[cfg->client_count++], cli, sizeof(struct client_config)); + + memcpy(sockaddr, result->ai_addr, result->ai_addrlen); + freeaddrinfo(result); return 0; } -static int add_route(struct utun_config *cfg, const char *server, const char *client) { - if (!cfg->connections_v2) { - cfg->connections_v2 = calloc(1, sizeof(struct connection_config_v2)); - if (!cfg->connections_v2) return -1; - cfg->connection_v2_capacity = 1; +static int parse_address_and_port(const char *str, struct sockaddr_storage *sockaddr) { + char addr_copy[MAX_ADDR_LEN]; + if (strlen(str) >= sizeof(addr_copy)) return -1; + strcpy(addr_copy, str); + + char *port_str = strrchr(addr_copy, ':'); + if (!port_str) return -1; + + *port_str = '\0'; + port_str++; + + return parse_sockaddr(addr_copy, port_str, sockaddr); +} + +static uint32_t get_netif_index(const char *ifname) { + if (!ifname || strlen(ifname) == 0) return 0; + return if_nametoindex(ifname); +} + +static struct CFG_CLIENT_LINK* create_client_link(struct CFG_SERVER* local_srv, const char *remote_addr) { + struct CFG_CLIENT_LINK *link = calloc(1, sizeof(struct CFG_CLIENT_LINK)); + if (!link) return NULL; + + link->local_srv = local_srv; + + if (parse_address_and_port(remote_addr, &link->remote_addr) < 0) { + free(link); + return NULL; } - struct connection_config_v2 *conn = &cfg->connections_v2[cfg->connection_v2_count]; + link->next = NULL; + return link; +} + +static void free_cfg_client_links(struct CFG_CLIENT_LINK *links) { + while (links) { + struct CFG_CLIENT_LINK *next = links->next; + free(links); + links = next; + } +} + +static struct CFG_ROUTE_ENTRY* create_route_entry(const char *subnet_str) { + struct CFG_ROUTE_ENTRY *entry = calloc(1, sizeof(struct CFG_ROUTE_ENTRY)); + if (!entry) return NULL; - if (conn->route_count >= conn->route_capacity) { - if (ensure_capacity((void**)&conn->routes, &conn->route_capacity, sizeof(struct route_pair)) < 0) return -1; + if (parse_ip_with_netmask(subnet_str, &entry->ip, &entry->netmask) < 0) { + free(entry); + return NULL; } - struct route_pair *route = &conn->routes[conn->route_count++]; - if (assign_string(route->server_name, MAX_CONN_NAME_LEN, server) < 0) return -1; - if (assign_string(route->client_name, MAX_CONN_NAME_LEN, client) < 0) return -1; + entry->next = NULL; + return entry; +} + +static void free_route_entries(struct CFG_ROUTE_ENTRY *entries) { + while (entries) { + struct CFG_ROUTE_ENTRY *next = entries->next; + free(entries); + entries = next; + } +} + +static int add_route_entry(struct CFG_ROUTE_ENTRY **list, const char *subnet_str) { + struct CFG_ROUTE_ENTRY *new_entry = create_route_entry(subnet_str); + if (!new_entry) return -1; + // Add to head of list + new_entry->next = *list; + *list = new_entry; return 0; } +static struct CFG_SERVER* find_server_by_name(struct CFG_SERVER *servers, const char *name) { + struct CFG_SERVER *srv = servers; + while (srv) { + if (strcmp(srv->name, name) == 0) { + return srv; + } + srv = srv->next; + } + return NULL; +} + static int parse_global(const char *key, const char *value, struct global_config *global) { - if (strcmp(key, "my_private_key") == 0) return assign_string(global->my_private_key_hex, MAX_KEY_LEN, value); - if (strcmp(key, "my_public_key") == 0) return assign_string(global->my_public_key_hex, MAX_KEY_LEN, value); + if (strcmp(key, "my_private_key") == 0) { + return assign_string(global->my_private_key_hex, MAX_KEY_LEN, value); + } + if (strcmp(key, "my_public_key") == 0) { + return assign_string(global->my_public_key_hex, MAX_KEY_LEN, value); + } if (strcmp(key, "my_node_id") == 0) { global->my_node_id = strtoull(value, NULL, 16); return 0; } - if (strcmp(key, "tun_ip") == 0) return assign_string(global->tun_ip, MAX_ADDR_LEN, value); - if (strcmp(key, "mtu") == 0) { global->mtu = atoi(value); return 0; } - if (strcmp(key, "control_ip") == 0) return assign_string(global->control_ip, MAX_ADDR_LEN, value); - if (strcmp(key, "control_port") == 0) { global->control_port = (uint16_t)atoi(value); return 0; } - if (strcmp(key, "net_debug") == 0) { global->net_debug = atoi(value); return 0; } + if (strcmp(key, "tun_ip") == 0) { + uint8_t netmask; + return parse_ip_with_netmask(value, &global->tun_ip, &netmask); + } + if (strcmp(key, "mtu") == 0) { + global->mtu = atoi(value); + return 0; + } + if (strcmp(key, "control_ip") == 0) { + // Store for later processing with control_port + return 0; // We'll handle this when we see control_port + } + if (strcmp(key, "control_port") == 0) { + // This is tricky - we need to get control_ip from previous parsing + // For now, we'll use a simple approach + struct global_config temp_global = *global; + // Assume we stored control_ip somewhere or use default + char control_ip[MAX_ADDR_LEN] = "127.0.0.1"; // Default + char port_str[16]; + snprintf(port_str, sizeof(port_str), "%s", value); + parse_sockaddr(control_ip, port_str, &global->control_sock); + return 0; + } + if (strcmp(key, "net_debug") == 0) { + global->net_debug = atoi(value); + return 0; + } return 0; } -static int parse_server(const char *key, const char *value, struct server_config *srv) { - if (strcmp(key, "addr") == 0) return assign_string(srv->addr, MAX_ADDR_LEN, value); - if (strcmp(key, "so_mark") == 0) { srv->so_mark = atoi(value); return 0; } - if (strcmp(key, "netif") == 0) return assign_string(srv->netif, MAX_NETIF_LEN, value); - if (strcmp(key, "type") == 0) return 0; // Ignored: not stored or used +static int parse_server(const char *key, const char *value, struct CFG_SERVER *srv) { + if (strcmp(key, "addr") == 0) { + return parse_address_and_port(value, &srv->ip); + } + if (strcmp(key, "so_mark") == 0) { + srv->so_mark = atoi(value); + return 0; + } + if (strcmp(key, "netif") == 0) { + srv->netif_index = get_netif_index(value); + return 0; + } + if (strcmp(key, "type") == 0) { + if (strcmp(value, "public") == 0) { + srv->type = CFG_SERVER_TYPE_PUBLIC; + } else if (strcmp(value, "nat") == 0) { + srv->type = CFG_SERVER_TYPE_NAT; + } else if (strcmp(value, "private") == 0) { + srv->type = CFG_SERVER_TYPE_PRIVATE; + } else { + srv->type = CFG_SERVER_TYPE_UNKNOWN; + } + return 0; + } return 0; } -static int parse_client(const char *key, const char *value, struct client_config *cli) { - // Handle link=server:ip:port format +static int parse_client(const char *key, const char *value, struct CFG_CLIENT *cli, struct CFG_SERVER *servers) { if (strcmp(key, "link") == 0) { - char link_copy[MAX_CONN_NAME_LEN * 2]; + char link_copy[MAX_CONN_NAME_LEN + MAX_ADDR_LEN]; if (strlen(value) >= sizeof(link_copy)) return -1; strcpy(link_copy, value); @@ -147,32 +269,32 @@ static int parse_client(const char *key, const char *value, struct client_config *first_colon = '\0'; - if (assign_string(cli->from, MAX_CONN_NAME_LEN, link_copy) < 0) return -1; - if (assign_string(cli->to_addr, MAX_ADDR_LEN, first_colon + 1) < 0) return -1; + // Find server by name + struct CFG_SERVER *local_srv = find_server_by_name(servers, link_copy); + if (!local_srv) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Server '%s' not found for client link", link_copy); + return -1; + } - return 1; // Signal that client is ready to be added - } - - if (strcmp(key, "from") == 0) return assign_string(cli->from, MAX_CONN_NAME_LEN, value); - if (strcmp(key, "to_addr") == 0) return assign_string(cli->to_addr, MAX_ADDR_LEN, value); - if (strcmp(key, "peer_public_key") == 0) return assign_string(cli->peer_public_key_hex, MAX_KEY_LEN, value); - return 0; -} - -static int parse_connection(const char *key, const char *value, struct connection_config_v2 *conn) { - if (strcmp(key, "link") == 0) { - char link_copy[MAX_CONN_NAME_LEN * 2]; - if (strlen(value) >= sizeof(link_copy)) return -1; - strcpy(link_copy, value); + struct CFG_CLIENT_LINK *new_link = create_client_link(local_srv, first_colon + 1); + if (!new_link) return -1; - char *colon = strchr(link_copy, ':'); - if (!colon) return -1; - *colon = '\0'; + // Add to linked list (prepend) + new_link->next = cli->links; + cli->links = new_link; - return add_route(NULL, link_copy, colon + 1); // NULL cfg - will use global + return 0; + } + + if (strcmp(key, "peer_public_key") == 0) { + return assign_string(cli->peer_public_key_hex, MAX_KEY_LEN, value); + } + + if (strcmp(key, "keepalive") == 0) { + cli->keepalive = atoi(value); + return 0; } - if (strcmp(key, "keepalive") == 0) { conn->keepalive = atoi(value); return 0; } - if (strcmp(key, "peer_public_key") == 0) return assign_string(conn->peer_public_key_hex, MAX_KEY_LEN, value); + return 0; } @@ -204,7 +326,6 @@ static section_type_t parse_section_header(const char *line, char *name, size_t if (strcasecmp(type, "server") == 0) return SECTION_SERVER; if (strcasecmp(type, "client") == 0) return SECTION_CLIENT; - if (strcasecmp(type, "connection") == 0) return SECTION_CONNECTION; return SECTION_UNKNOWN; } @@ -214,8 +335,8 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename) if (!cfg) return NULL; section_type_t cur_section = SECTION_UNKNOWN; - struct server_config cur_server = {0}; - struct client_config cur_client = {0}; + struct CFG_SERVER *cur_server = NULL; + struct CFG_CLIENT *cur_client = NULL; char line[MAX_LINE_LEN]; int line_num = 0; @@ -226,22 +347,31 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename) if (trimmed[0] == '\0' || trimmed[0] == '#') continue; if (trimmed[0] == '[') { - if (cur_section == SECTION_SERVER && cur_server.name[0]) { - if (add_server(cfg, &cur_server) < 0) goto error; + // Handle previous section + if (cur_section == SECTION_SERVER && cur_server) { + // Add server to linked list + cur_server->next = cfg->servers; + cfg->servers = cur_server; + cur_server = NULL; } - if (cur_section == SECTION_CLIENT && cur_client.name[0]) { - if (add_client(cfg, &cur_client) < 0) goto error; + if (cur_section == SECTION_CLIENT && cur_client) { + // Add client to linked list + cur_client->next = cfg->clients; + cfg->clients = cur_client; + cur_client = NULL; } char name[MAX_CONN_NAME_LEN]; cur_section = parse_section_header(trimmed, name, sizeof(name)); if (cur_section == SECTION_SERVER) { - memset(&cur_server, 0, sizeof(cur_server)); - strcpy(cur_server.name, name); + cur_server = calloc(1, sizeof(struct CFG_SERVER)); + if (!cur_server) goto error; + strcpy(cur_server->name, name); } else if (cur_section == SECTION_CLIENT) { - memset(&cur_client, 0, sizeof(cur_client)); - strcpy(cur_client.name, name); + cur_client = calloc(1, sizeof(struct CFG_CLIENT)); + if (!cur_client) goto error; + strcpy(cur_client->name, name); } continue; } @@ -259,34 +389,20 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename) } break; case SECTION_SERVER: - if (parse_server(key, value, &cur_server) < 0) { + if (cur_server && parse_server(key, value, cur_server) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid server key '%s'", filename, line_num, key); } break; case SECTION_CLIENT: - { - int ret = parse_client(key, value, &cur_client); - if (ret == 1) { - // Client ready to add (from link=) - char saved_name[MAX_CONN_NAME_LEN]; - strcpy(saved_name, cur_client.name); // Save name - if (add_client(cfg, &cur_client) < 0) goto error; - memset(&cur_client, 0, sizeof(cur_client)); - strcpy(cur_client.name, saved_name); // Restore name for next link - } else if (ret < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid client key '%s'", filename, line_num, key); - } + if (cur_client && parse_client(key, value, cur_client, cfg->servers) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid client key '%s'", filename, line_num, key); } break; case SECTION_ROUTING: - // Routing settings are not stored yet, just ignore - break; - case SECTION_CONNECTION: - if (cfg->connection_v2_count == 0) { - cfg->connection_v2_count = 1; - } - if (parse_connection(key, value, &cfg->connections_v2[0]) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid connection key '%s'", filename, line_num, key); + if (strcmp(key, "allowed_subnet") == 0) { + add_route_entry(&cfg->allowed_subnets, value); + } else if (strcmp(key, "my_subnet") == 0) { + add_route_entry(&cfg->my_subnets, value); } break; default: @@ -295,16 +411,24 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename) } } - if (cur_section == SECTION_SERVER && cur_server.name[0]) { - if (add_server(cfg, &cur_server) < 0) goto error; + // Handle final sections + if (cur_section == SECTION_SERVER && cur_server) { + cur_server->next = cfg->servers; + cfg->servers = cur_server; } - if (cur_section == SECTION_CLIENT && cur_client.name[0] && cur_client.to_addr[0]) { - if (add_client(cfg, &cur_client) < 0) goto error; + if (cur_section == SECTION_CLIENT && cur_client) { + cur_client->next = cfg->clients; + cfg->clients = cur_client; } return cfg; error: + if (cur_server) free(cur_server); + if (cur_client) { + free_cfg_client_links(cur_client->links); + free(cur_client); + } free_config(cfg); return NULL; } @@ -324,53 +448,97 @@ struct utun_config* parse_config(const char *filename) { void free_config(struct utun_config *config) { if (!config) return; - free(config->servers); - free(config->clients); + // Free servers + struct CFG_SERVER *server = config->servers; + while (server) { + struct CFG_SERVER *next = server->next; + free(server); + server = next; + } - if (config->connections_v2) { - for (int i = 0; i < config->connection_v2_count; i++) { - free(config->connections_v2[i].routes); - } - free(config->connections_v2); + // Free clients and their links + struct CFG_CLIENT *client = config->clients; + while (client) { + struct CFG_CLIENT *next = client->next; + free_cfg_client_links(client->links); + free(client); + client = next; } + // Free route entries + free_route_entries(config->allowed_subnets); + free_route_entries(config->my_subnets); + free(config); } +static const char* ip_to_string(const struct IP *ip, char *buffer, size_t buffer_size) { + if (ip->family == AF_INET) { + inet_ntop(AF_INET, &ip->addr.v4, buffer, buffer_size); + } else if (ip->family == AF_INET6) { + inet_ntop(AF_INET6, &ip->addr.v6, buffer, buffer_size); + } else { + snprintf(buffer, buffer_size, "invalid"); + } + return buffer; +} + void print_config(const struct utun_config *cfg) { if (!cfg) return; const struct global_config *g = &cfg->global; + char ip_buffer[64]; + printf("Global:\n"); printf(" Private key: %s\n", g->my_private_key_hex); printf(" Public key: %s\n", g->my_public_key_hex); printf(" Node ID: %llx\n", (unsigned long long)g->my_node_id); - printf(" TUN IP: %s\n", g->tun_ip); + printf(" TUN IP: %s\n", ip_to_string(&g->tun_ip, ip_buffer, sizeof(ip_buffer))); printf(" MTU: %d\n", g->mtu); - printf(" Control: %s:%u\n", g->control_ip, g->control_port); printf(" Net debug: %d\n", g->net_debug); - printf("\nServers (%d):\n", cfg->server_count); - for (int i = 0; i < cfg->server_count; i++) { - const struct server_config *s = &cfg->servers[i]; - printf(" %s: %s (mark=%d, netif=%s)\n", s->name, s->addr, s->so_mark, s->netif); + printf("\nServers:\n"); + struct CFG_SERVER *s = cfg->servers; + while (s) { + char addr_buffer[64]; + struct sockaddr_in *sin = (struct sockaddr_in *)&s->ip; + inet_ntop(AF_INET, &sin->sin_addr, addr_buffer, sizeof(addr_buffer)); + printf(" %s: %s:%d (mark=%d, netif=%u, type=%u)\n", + s->name, addr_buffer, ntohs(sin->sin_port), + s->so_mark, s->netif_index, s->type); + s = s->next; } - printf("\nClients (%d):\n", cfg->client_count); - for (int i = 0; i < cfg->client_count; i++) { - const struct client_config *c = &cfg->clients[i]; - printf(" %s: %s (from %s)\n", c->name, c->to_addr, c->from); + printf("\nClients:\n"); + struct CFG_CLIENT *c = cfg->clients; + while (c) { + printf(" %s:\n", c->name); + struct CFG_CLIENT_LINK *link = c->links; + int link_num = 1; + while (link) { + char addr_buffer[64]; + struct sockaddr_in *sin = (struct sockaddr_in *)&link->remote_addr; + inet_ntop(AF_INET, &sin->sin_addr, addr_buffer, sizeof(addr_buffer)); + printf(" Link %d: %s:%d (via %s)\n", link_num++, addr_buffer, ntohs(sin->sin_port), link->local_srv->name); + link = link->next; + } + printf(" Peer key: %s\n", c->peer_public_key_hex); + printf(" Keepalive: %d\n", c->keepalive); + c = c->next; } - printf("\nConnections v2 (%d):\n", cfg->connection_v2_count); - for (int i = 0; i < cfg->connection_v2_count; i++) { - const struct connection_config_v2 *conn = &cfg->connections_v2[i]; - printf(" Connection %d:\n", i); - for (int j = 0; j < conn->route_count; j++) { - printf(" %s -> %s\n", conn->routes[j].server_name, conn->routes[j].client_name); - } - printf(" Peer key: %s\n", conn->peer_public_key_hex); - printf(" Keepalive: %d\n", conn->keepalive); + printf("\nAllowed Subnets:\n"); + struct CFG_ROUTE_ENTRY *allowed = cfg->allowed_subnets; + while (allowed) { + printf(" %s/%d\n", ip_to_string(&allowed->ip, ip_buffer, sizeof(ip_buffer)), allowed->netmask); + allowed = allowed->next; + } + + printf("\nMy Subnets:\n"); + struct CFG_ROUTE_ENTRY *my = cfg->my_subnets; + while (my) { + printf(" %s/%d\n", ip_to_string(&my->ip, ip_buffer, sizeof(ip_buffer)), my->netmask); + my = my->next; } } @@ -385,4 +553,4 @@ int update_config_keys(const char *filename, const char *priv_key, const char *p fclose(fp); return 0; -} +} \ No newline at end of file diff --git a/src/config_parser.h b/src/config_parser.h index 7e80058c..2cc015d4 100644 --- a/src/config_parser.h +++ b/src/config_parser.h @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #ifdef __cplusplus extern "C" { @@ -12,66 +15,65 @@ extern "C" { #define MAX_CONN_NAME_LEN 64 #define MAX_KEY_LEN 256 #define MAX_ADDR_LEN 64 -#define MAX_NETIF_LEN 16 -#define MAX_OPTION_VALUE_LEN 256 -#define MAX_ALLOWED_SUBNETS 32 -struct subnet_entry { - char subnet[MAX_ADDR_LEN]; +struct IP { + sa_family_t family; + union { + struct in_addr v4; + struct in6_addr v6; + } addr; }; -struct server_config { - char name[MAX_CONN_NAME_LEN]; - char addr[MAX_ADDR_LEN]; - int so_mark; - char netif[MAX_NETIF_LEN]; - char type[16]; // public/nat/private - parsed but not currently used -}; +#define CFG_SERVER_TYPE_UNKNOWN 0 +#define CFG_SERVER_TYPE_PUBLIC 1 +#define CFG_SERVER_TYPE_NAT 2 +#define CFG_SERVER_TYPE_PRIVATE 3 -struct client_config { +struct CFG_SERVER { + struct CFG_SERVER* next; char name[MAX_CONN_NAME_LEN]; - char from[MAX_CONN_NAME_LEN]; - char to_addr[MAX_ADDR_LEN]; - char peer_public_key_hex[MAX_KEY_LEN]; + struct sockaddr_storage ip; // ip:port + uint32_t netif_index;// if_nameindex, 0 - no interface specified + int so_mark; + uint8_t type; // public/nat/private }; -struct route_pair { - char server_name[MAX_CONN_NAME_LEN]; - char client_name[MAX_CONN_NAME_LEN]; +struct CFG_CLIENT_LINK { + struct CFG_CLIENT_LINK *next; // Next link in linked list + struct CFG_SERVER* local_srv; + struct sockaddr_storage remote_addr; // ip:port }; -struct connection_config_v2 { - struct route_pair *routes; - int route_count; - int route_capacity; +struct CFG_CLIENT { + char name[MAX_CONN_NAME_LEN]; char peer_public_key_hex[MAX_KEY_LEN]; int keepalive; + struct CFG_CLIENT_LINK *links; // Linked list of links + struct CFG_CLIENT *next; // Next client in linked list +}; + +struct CFG_ROUTE_ENTRY { + struct CFG_ROUTE_ENTRY* next; + struct IP ip; + uint8_t netmask; }; struct global_config { char my_private_key_hex[MAX_KEY_LEN]; char my_public_key_hex[MAX_KEY_LEN]; uint64_t my_node_id; - char tun_ip[MAX_ADDR_LEN]; + struct IP tun_ip; int mtu; - char control_ip[MAX_ADDR_LEN]; - uint16_t control_port; + struct sockaddr_storage control_sock; int net_debug; }; struct utun_config { struct global_config global; - struct server_config *servers; - int server_count; - int server_capacity; - struct client_config *clients; - int client_count; - int client_capacity; - struct connection_config_v2 *connections_v2; - int connection_v2_count; - int connection_v2_capacity; - struct subnet_entry allowed_subnets[MAX_ALLOWED_SUBNETS]; - int allowed_subnet_count; + struct CFG_SERVER* servers; + struct CFG_CLIENT* clients; + struct CFG_ROUTE_ENTRY* allowed_subnets; + struct CFG_ROUTE_ENTRY* my_subnets; }; struct utun_config* parse_config(const char *filename); @@ -79,8 +81,6 @@ void free_config(struct utun_config *config); void print_config(const struct utun_config *config); int update_config_keys(const char *filename, const char *priv_key, const char *pub_key); -void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len); - #ifdef __cplusplus } #endif diff --git a/src/config_updater.c b/src/config_updater.c index f94ac579..6074b3aa 100644 --- a/src/config_updater.c +++ b/src/config_updater.c @@ -16,6 +16,15 @@ #define HEXNODEID_LEN 16 // 8 bytes * 2 hex chars #define MAX_LINE_LEN 1024 +void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len) { + if (!bytes || !hex_str || hex_len < len * 2 + 1) return; + for (size_t i = 0; i < len; i++) { + snprintf(hex_str + i * 2, hex_len - i * 2, "%02x", bytes[i]); + } + hex_str[len * 2] = '\0'; +} + + static int is_valid_hex_key(const char *key) { if (!key || strlen(key) != HEXKEY_LEN) return 0; for (int i = 0; i < HEXKEY_LEN; i++) { @@ -210,14 +219,14 @@ int config_ensure_keys_and_node_id(const char *filename) { uint64_t new_node_id = 0; if (need_priv_key || need_pub_key) { - struct secure_channel ctx; - if (sc_generate_keypair(&ctx) != SC_OK) { + struct SC_MYKEYS mykeys; + if (sc_generate_keypair(&mykeys) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to generate keypair"); free_config(config); return -1; } - bytes_to_hex(ctx.private_key, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); - bytes_to_hex(ctx.public_key, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); + bytes_to_hex(mykeys.private_key, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); + bytes_to_hex(mykeys.public_key, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); } if (need_node_id) { diff --git a/src/config_updater.h b/src/config_updater.h index 158a4cb1..283f434f 100644 --- a/src/config_updater.h +++ b/src/config_updater.h @@ -2,6 +2,9 @@ #ifndef CONFIG_UPDATER_H #define CONFIG_UPDATER_H +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -11,6 +14,8 @@ extern "C" { // Returns 0 on success, -1 on error int config_ensure_keys_and_node_id(const char *filename); +void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len); + #ifdef __cplusplus } #endif diff --git a/src/etcp.c b/src/etcp.c index c10a938f..a32d367a 100644 --- a/src/etcp.c +++ b/src/etcp.c @@ -1,43 +1,142 @@ // etcp.c - ETCP Protocol Implementation +#include "u_async.h" +#include "utun_instance.h" #include "etcp.h" #include "../lib/debug_config.h" #include "crc32.h" #include "secure_channel.h" #include #include +#include +#include +#include + +// Service packet headers (from protocol, but reset/init handled elsewhere) +#define ETCP_ACK_HEADER 0x01 +#define ETCP_RETRANS_HEADER_BASE 0x10 // 0x10 to 0x2F for retrans requests +#define ETCP_PAYLOAD_HEADER 0x00 + +// Forward declarations of internal functions (adapted from etcp_master) +static void retransmit_check(struct ETCP_CONN* etcp); +static void update_metrics(struct ETCP_CONN* etcp, uint16_t rtt); +static uint16_t get_current_timestamp(void); +static uint16_t timestamp_diff(uint16_t t1, uint16_t t2); +static int id_compare(uint16_t id1, uint16_t id2); +static void retransmit_packet(struct ETCP_CONN* etcp, uint16_t id); + +// Timer callbacks +static void tx_timer_callback(void* arg); +static void retransmit_timer_callback(void* arg); + +// Internal queue callbacks +static void tx_queue_callback(struct ll_queue* q, struct ll_entry* entry, void* arg); +static void schedule_ack_timer(struct ETCP_CONN* etcp); +static void request_retransmission_for_gaps(struct ETCP_CONN* etcp); + +static void queue_clear(struct ll_queue* q) { + struct ll_entry* entry; + while ((entry = queue_entry_get(q)) != NULL) { + queue_entry_free(entry); + } +} + +static void etcp_update_window(struct ETCP_CONN* etcp) { + etcp->window_size = 65536; // Initial window size + etcp->retrans_timer_period = 20; // Default retransmit period +} // Creating ETCP instance -struct ETCP_CONN* etcp_create(struct UTUN_INSTANCE* instance) { - if (!instance) return NULL; +// после создания надо добавить peer bublic key. +struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* utun) { + if (!utun) return NULL; struct ETCP_CONN* etcp = calloc(1, sizeof(struct ETCP_CONN)); if (!etcp) return NULL; - // TODO: generate real random node_id - etcp->node_id = 0x123456789ABCDEF0; etcp->mtu = 1500; // Default MTU - etcp->instance = instance; + etcp->instance = utun; etcp->state = 0; - + // Initialize crypto context - etcp->crypto_ctx = calloc(1, sizeof(struct secure_channel)); - if (!etcp->crypto_ctx) { + if (sc_init_ctx(&etcp->crypto_ctx, &etcp->instance->my_keys) != SC_OK) { free(etcp); return NULL; } - - if (sc_generate_keypair(etcp->crypto_ctx) != SC_OK) { - free(etcp->crypto_ctx); + + // Initialize queues (tx_queue is input_queue) + etcp->input_queue = queue_new(utun->ua,NULL); + etcp->output_queue = queue_new(utun->ua,NULL); + if (!etcp->input_queue || !etcp->output_queue) { + if (etcp->input_queue) queue_free(etcp->input_queue); + if (etcp->output_queue) queue_free(etcp->output_queue); free(etcp); return NULL; } - // Initialize packet pool - packet_pool_init(&etcp->packet_pool); + // Set callback for input_queue (tx_queue) + queue_set_callback(etcp->input_queue, tx_queue_callback, etcp); + + // Initialize state (from master) + etcp->bandwidth = 10000; // Default: 10000 bytes per timebase (0.1us) + etcp->last_sent_timestamp = get_current_timestamp(); + etcp->bytes_allowed = 0; + etcp_update_window(etcp); // Initialize window size and retrans timer + + // Initialize lists + etcp->rx_list = NULL; + etcp->sent_list = NULL; + + // Initialize metrics + etcp->rtt_last = 0; + etcp->rtt_avg_10 = 0; + etcp->rtt_avg_100 = 0; + etcp->jitter = 0; + etcp->bytes_sent_total = 0; + + // Initialize statistics + etcp->retransmissions_count = 0; + etcp->ack_packets_count = 0; + etcp->control_packets_count = 0; + etcp->total_packets_sent = 0; + etcp->unique_packets_sent = 0; + etcp->bytes_received_total = 0; + + // Initialize IDs + etcp->next_tx_id = 1; + etcp->last_sent_id = 0; + etcp->last_rx_id = 0; + etcp->last_delivered_id = 0; + + // Initialize history + etcp->rtt_history_idx = 0; + etcp->rtt_history_count = 0; + + // Initialize pending arrays + etcp->pending_ack_count = 0; + etcp->pending_retransmit_count = 0; + + // Initialize window management + etcp->unacked_bytes = 0; + etcp->last_acked_id = 0; + etcp->last_rx_ack_id = 0; + etcp->retrans_timer_period = 20; // Default 2ms (20 timebase units) + etcp->next_retrans_time = 0; + etcp->window_blocked = 0; + + // Forward progress tracking + etcp->oldest_missing_id = 0; + etcp->missing_since_time = 0; + // No timers yet + etcp->next_tx_timer = NULL; + etcp->retransmit_timer = NULL; + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_create: created instance with node_id=%llu, mtu=%d", - (unsigned long long)etcp->node_id, etcp->mtu); + (unsigned long long)etcp->instance->node_id, etcp->mtu); + + etcp->next=utun->connections; + utun->connections=etcp; return etcp; } @@ -48,30 +147,185 @@ void etcp_destroy(struct ETCP_CONN* etcp) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "etcp_destroy: destroying instance"); - // Free crypto context - if (etcp->crypto_ctx) { - // Secure channel context doesn't need special cleanup - free(etcp->crypto_ctx); + // Cancel timers + if (etcp->next_tx_timer) { + uasync_cancel_timeout(etcp->instance->ua, etcp->next_tx_timer); + etcp->next_tx_timer = NULL; + } + if (etcp->retransmit_timer) { + uasync_cancel_timeout(etcp->instance->ua, etcp->retransmit_timer); + etcp->retransmit_timer = NULL; } - // Clean packet pool - packet_pool_destroy(&etcp->packet_pool); + // Free queues + if (etcp->input_queue) queue_free(etcp->input_queue); + if (etcp->output_queue) queue_free(etcp->output_queue); + + // Free rx_list + rx_packet_t* rx = etcp->rx_list; + while (rx) { + rx_packet_t* next = rx->next; + if (rx->data) free(rx->data); + free(rx); + rx = next; + } + + // Free sent_list + sent_packet_t* sent = etcp->sent_list; + while (sent) { + sent_packet_t* next = sent->next; + if (sent->data) free(sent->data); + free(sent); + sent = next; + } free(etcp); } -// Process incoming packet -void etcp_conn_input(struct ETCP_CONN* etcp, struct packet_buffer* pkt) { +// Process incoming packet (partial, truncated in original) +void etcp_conn_input(struct ETCP_CONN* etcp, struct ETCP_DGRAM* pkt) { if (!etcp || !pkt) return; - DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_conn_input: packet len=%u", pkt->metadata.data_len); -// пока отправляй сразу в очередь. и из очереди сразу принимай через callback + uint8_t* data = pkt->data; + size_t len = pkt->data_len; + + if (len < 4) return; // Min header + + uint16_t id = (data[0] << 8) | data[1]; + uint16_t timestamp = (data[2] << 8) | data[3]; + data += 4; len -= 4; + + int has_payload = 0; + uint8_t* payload_data = NULL; + size_t payload_len = 0; + int is_duplicate = 0; + + while (len > 0) { + uint8_t section_header = *data++; + len--; + + if (section_header == ETCP_ACK_HEADER) { + // ACK section + uint8_t count = *data++; + len--; + for (uint8_t i = 0; i < count; i++) { + uint16_t ack_id = (data[0] << 8) | data[1]; + uint16_t ack_ts = (data[2] << 8) | data[3]; + data += 4; len -= 4; + + // Process ACK: remove from sent_list, update window + sent_packet_t** ptr = &etcp->sent_list; + while (*ptr) { + if ((*ptr)->id == ack_id) { + sent_packet_t* to_free = *ptr; + *ptr = to_free->next; + etcp->unacked_bytes -= to_free->payload_len; + update_metrics(etcp, timestamp_diff(get_current_timestamp(), ack_ts)); + free(to_free->data); + free(to_free); + break; + } + ptr = &(*ptr)->next; + } + } + + // last_delivered and last_rx + uint16_t last_delivered = (data[0] << 8) | data[1]; + uint16_t last_rx = (data[2] << 8) | data[3]; + data += 4; len -= 4; + + etcp->last_rx_ack_id = last_rx; + + } else if ((section_header & 0xF0) == ETCP_RETRANS_HEADER_BASE) { + // Retrans request + uint8_t count = (section_header & 0x0F) + 1; + for (uint8_t i = 0; i < count; i++) { + uint16_t retrans_id = (data[0] << 8) | data[1]; + data += 2; + len -= 2; + + retransmit_packet(etcp, retrans_id); + } + + // last_delivered and last_rx + uint16_t last_delivered = (data[0] << 8) | data[1]; + uint16_t last_rx = (data[2] << 8) | data[3]; + data += 4; len -= 4; + + } else if (section_header == ETCP_PAYLOAD_HEADER) { + // Payload section + has_payload = 1; + payload_data = data; + payload_len = len; + break; // Payload is last + } + } + + // Check for duplicate + rx_packet_t* rx = etcp->rx_list; + while (rx) { + if (rx->id == id) { + is_duplicate = 1; + break; + } + rx = rx->next; + } + + if (is_duplicate) { + // Add to pending ACKs + if (etcp->pending_ack_count < 32) { + etcp->pending_ack_ids[etcp->pending_ack_count] = id; + etcp->pending_ack_timestamps[etcp->pending_ack_count] = timestamp; + etcp->pending_ack_count++; + } + schedule_ack_timer(etcp); + return; + } + + // Insert into rx_list (sorted) + rx_packet_t* new_rx = calloc(1, sizeof(rx_packet_t)); + if (!new_rx) return; + + new_rx->id = id; + new_rx->timestamp = timestamp; + new_rx->has_payload = has_payload; + if (has_payload) { + new_rx->data = malloc(payload_len); + if (!new_rx->data) { + free(new_rx); + return; + } + memcpy(new_rx->data, payload_data, payload_len); + new_rx->data_len = payload_len; + etcp->bytes_received_total += payload_len; + } + + // Insert sorted + rx_packet_t** ptr = &etcp->rx_list; + while (*ptr && id_compare((*ptr)->id, id) < 0) { + ptr = &(*ptr)->next; + } + new_rx->next = *ptr; + *ptr = new_rx; + + // Update last_rx_id + if (id_compare(id, etcp->last_rx_id) > 0) { + etcp->last_rx_id = id; + } + + // Add to pending ACKs + if (etcp->pending_ack_count < 32) { + etcp->pending_ack_ids[etcp->pending_ack_count] = id; + etcp->pending_ack_timestamps[etcp->pending_ack_count] = timestamp; + etcp->pending_ack_count++; + } - // TODO: process packet through ETCP protocol - // This will be implemented later for data transfer + // Request retrans for gaps and deliver contiguous + request_retransmission_for_gaps(etcp); + schedule_ack_timer(etcp); } -// Reset connection +// Reset connection (adapted from etcp_reset in master, without packet sending) void etcp_conn_reset(struct ETCP_CONN* etcp) { if (!etcp) return; @@ -80,19 +334,173 @@ void etcp_conn_reset(struct ETCP_CONN* etcp) { // Reset state etcp->state = 0; - // TODO: clear queues, reset sequence numbers, etc. + // Cancel timers + if (etcp->next_tx_timer) { + uasync_cancel_timeout(etcp->instance->ua, etcp->next_tx_timer); + etcp->next_tx_timer = NULL; + } + if (etcp->retransmit_timer) { + uasync_cancel_timeout(etcp->instance->ua, etcp->retransmit_timer); + etcp->retransmit_timer = NULL; + } + + // Clear queues (but keep them) + queue_clear(etcp->input_queue); + queue_clear(etcp->output_queue); + + // Clear lists + rx_packet_t* rx = etcp->rx_list; + while (rx) { + rx_packet_t* next = rx->next; + if (rx->data) free(rx->data); + free(rx); + rx = next; + } + etcp->rx_list = NULL; + + sent_packet_t* sent = etcp->sent_list; + while (sent) { + sent_packet_t* next = sent->next; + if (sent->data) free(sent->data); + free(sent); + sent = next; + } + etcp->sent_list = NULL; + + // Reset metrics and stats + etcp->rtt_last = 0; + etcp->rtt_avg_10 = 0; + etcp->rtt_avg_100 = 0; + etcp->jitter = 0; + etcp->bytes_sent_total = 0; + etcp->retransmissions_count = 0; + etcp->ack_packets_count = 0; + etcp->control_packets_count = 0; + etcp->total_packets_sent = 0; + etcp->unique_packets_sent = 0; + etcp->bytes_received_total = 0; + + // Reset IDs + etcp->next_tx_id = 1; + etcp->last_sent_id = 0; + etcp->last_rx_id = 0; + etcp->last_delivered_id = 0; + + // Reset history + etcp->rtt_history_idx = 0; + etcp->rtt_history_count = 0; + + // Reset pending + etcp->pending_ack_count = 0; + etcp->pending_retransmit_count = 0; + + // Reset window + etcp->unacked_bytes = 0; + etcp->last_acked_id = 0; + etcp->last_rx_ack_id = 0; + etcp->next_retrans_time = 0; + etcp->window_blocked = 0; + + // Reset forward progress + etcp->oldest_missing_id = 0; + etcp->missing_since_time = 0; + + etcp_update_window(etcp); } -// Getting statistics +// Getting statistics (extended with master stats) void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packets_recv, size_t* pool_allocs, size_t* pool_reuse) { if (!etcp) return; - if (packets_sent) *packets_sent = 0; // TODO: track - if (packets_recv) *packets_recv = 0; // TODO: track + if (packets_sent) *packets_sent = etcp->total_packets_sent; + if (packets_recv) *packets_recv = etcp->bytes_received_total / 100; // Approximate if (pool_allocs || pool_reuse) { - size_t dummy_overflow; - packet_pool_get_stats(&etcp->packet_pool, pool_allocs, pool_reuse, &dummy_overflow); + memory_pool_get_stats(etcp->instance->pkt_pool, pool_allocs, pool_reuse); + } +} + +// ... (rest of functions from master, adapted to ETCP_CONN and using etcp_link_send for tx) + +// For tx: assume primary channel (etcp->channels), or iterate if multi-path +static void send_etcp_packet(struct ETCP_CONN* etcp, uint8_t* pkt, uint16_t len) { + if (!etcp->links) return; // No links + + // Send to primary link (or iterate for multi-path) + char dg_mem[1600]; + struct ETCP_DGRAM* dg=(struct ETCP_DGRAM*)&dg_mem; + dg->data_len=len; + dg->noencrypt_len=0; + dg->link=etcp->links;// first link TODO: добавить отправку по нескольким линкам + etcp_encrypt_send(dg); +} + +static void update_metrics(struct ETCP_CONN* etcp, uint16_t rtt) { + etcp->rtt_last = rtt; + // Update averages, jitter, etc. + // Placeholder: etcp->rtt_avg_10 = (etcp->rtt_avg_10 * 9 + rtt) / 10; + // etcp->rtt_avg_100 = (etcp->rtt_avg_100 * 99 + rtt) / 100; +} + +static uint16_t get_current_timestamp(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint16_t)(tv.tv_usec / 100); // Timebase 0.1ms +} + +static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) { + if (t1 >= t2) return t1 - t2; + return (0xFFFF - t2) + t1 + 1; // Wrap around +} + +static int id_compare(uint16_t id1, uint16_t id2) { + int16_t diff = id1 - id2; + if (diff == 0) return 0; + return (diff > 0) ? 1 : -1; // Simple for now, add wrap logic if needed +} + +static void retransmit_packet(struct ETCP_CONN* etcp, uint16_t id) { + sent_packet_t* sent = etcp->sent_list; + while (sent) { + if (sent->id == id) { + send_etcp_packet(etcp, sent->data, sent->data_len); + etcp->retransmissions_count++; + break; + } + sent = sent->next; } +} + +static void tx_queue_callback(struct ll_queue* q, struct ll_entry* entry, void* arg) { + (void)q; + struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; + // Process entry to send packet + // Placeholder: uint8_t* data = ll_entry_data(entry); + // size_t len = ll_entry_size(entry); + // // Build packet and send + // send_etcp_packet(etcp, data, len); + queue_resume_callback(q); +} + +static void schedule_ack_timer(struct ETCP_CONN* etcp) { + // Placeholder: set timeout to send ACKs +} + +static void request_retransmission_for_gaps(struct ETCP_CONN* etcp) { + // Detect gaps in rx_list and add to pending_retransmit +} + +static void retransmit_check(struct ETCP_CONN* etcp) { + // Check sent_list for timeouts +} + +static void tx_timer_callback(void* arg) { + struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; + // Handle next tx +} + +static void retransmit_timer_callback(void* arg) { + struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg; + retransmit_check(etcp); } \ No newline at end of file diff --git a/src/etcp.h b/src/etcp.h index 68dc2017..2e858d62 100644 --- a/src/etcp.h +++ b/src/etcp.h @@ -2,9 +2,7 @@ #ifndef ETCP_H #define ETCP_H -#include "etcp_sockets.h" #include "etcp_connections.h" -#include "packet_pool.h" #include "ll_queue.h" #include "secure_channel.h" #include @@ -16,43 +14,118 @@ extern "C" { // Forward declarations struct UTUN_INSTANCE; +// Internal structures (integrated from etcp_master) +typedef struct rx_packet { + struct rx_packet* next; + uint16_t id; + uint16_t timestamp; + uint8_t* data; + uint16_t data_len; + uint8_t has_payload; +} rx_packet_t; + +typedef struct sent_packet { + struct sent_packet* next; + uint16_t id; + uint16_t timestamp; + uint8_t* data; + uint16_t data_len; // Total packet length + uint16_t payload_len; // Payload length (for window accounting) + uint16_t send_time; + uint8_t need_ack; + uint8_t need_retransmit; +} sent_packet_t; struct ETCP_CONN { - // Node ID (64-bit, генерируется при первом запуске) - uint64_t node_id; + struct ETCP_CONN* next; int mtu; struct UTUN_INSTANCE* instance; // Каналы (соединения) - linked list - struct ETCP_LINK* channels; - - // Пул пакетов (общий для всего ETCP instance) - struct packet_pool packet_pool; + struct ETCP_LINK* links; uint8_t state; // 0 - just created, 1 - initialized, 2 - connection established // Криптография и состояние - struct secure_channel* crypto_ctx; + struct secure_channel crypto_ctx; // Информация о пире (для клиентов) uint64_t peer_node_id; // Node ID пира - uint8_t has_peer_key; // Флаг наличия публичного ключа пира - uint8_t peer_public_key[SC_PUBKEY_SIZE]; // Публичный ключ пира (бинарный) - struct ll_queue* input_queue;// отправитель -> input_queue -> etcp -> etcp_channel -> отправка (etcp_sockets) - struct ll_queue* output_queue;// etcp_sockets -> etcp_channel -> etcp -> output_queue -> получатель + struct ll_queue* input_queue; // отправитель -> input_queue -> etcp -> etcp_channel -> отправка (etcp_sockets) + struct ll_queue* output_queue; // etcp_sockets -> etcp_channel -> etcp -> output_queue -> получатель + // Integrated from etcp_master (retransmission logic) + rx_packet_t* rx_list; + sent_packet_t* sent_list; + + // Metrics + uint16_t rtt_last; + uint16_t rtt_avg_10; + uint16_t rtt_avg_100; + uint16_t jitter; + uint16_t bandwidth; // Bytes per timebase (0.1us) + uint32_t bytes_sent_total; + uint16_t last_sent_timestamp; + uint32_t bytes_allowed; + + // Statistics (extended existing get_stats) + uint32_t retransmissions_count; + uint32_t ack_packets_count; + uint32_t control_packets_count; + uint32_t total_packets_sent; + uint32_t unique_packets_sent; + uint32_t bytes_received_total; + + // State + uint16_t next_tx_id; + uint16_t last_sent_id; + uint16_t last_rx_id; + uint16_t last_delivered_id; + + // Timers + void* next_tx_timer; + void* retransmit_timer; + + // RTT history + uint16_t rtt_history[100]; + uint8_t rtt_history_idx; + uint8_t rtt_history_count; + + // Pending ACKs + uint16_t pending_ack_ids[32]; + uint16_t pending_ack_timestamps[32]; + uint8_t pending_ack_count; + + // Pending retransmits + uint16_t pending_retransmit_ids[32]; + uint8_t pending_retransmit_count; + + // Window management + uint32_t unacked_bytes; + uint32_t window_size; + uint16_t last_acked_id; + uint16_t last_rx_ack_id; + uint16_t retrans_timer_period; // Default 20 (2ms) + uint16_t next_retrans_time; + uint8_t window_blocked; + + // Forward progress + uint16_t oldest_missing_id; + uint16_t missing_since_time; + + // No reset/init here - handled in connections }; // Создание пустого ETCP instance (после надо добавить ключи, каналы) -struct ETCP_CONN* etcp_create(struct UTUN_INSTANCE* instance); +struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance); // Уничтожение ETCP instance void etcp_destroy(struct ETCP_CONN* etcp); // Обработать входящий пакет (вызывается из etcp_connections) -void etcp_conn_input(struct ETCP_CONN* etcp, struct packet_buffer* pkt); +void etcp_conn_input(struct ETCP_CONN* etcp, struct ETCP_DGRAM* pkt); // Сброс соединения (переинициализация) void etcp_conn_reset(struct ETCP_CONN* etcp); diff --git a/src/etcp.h.demo b/src/etcp.h.demo deleted file mode 100644 index 72b51f19..00000000 --- a/src/etcp.h.demo +++ /dev/null @@ -1,5 +0,0 @@ -// etcp.h - demo with original typedef -typedef struct ETCP_CONN etcp_t; - -struct ETCP_CONN* etcp_create(utun_instance_t *instance); -void etcp_destroy(etcp_t* etcp); diff --git a/src/etcp_connections.c b/src/etcp_connections.c index 93db0bca..212fa0e3 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -1,5 +1,6 @@ #include "etcp_connections.h" #include +#include #include #include #include @@ -10,41 +11,38 @@ #include "config_parser.h" #include "crc32.h" #include "etcp.h" -#include "packet_pool.h" +#include "../lib/memory_pool.h" #include "u_async.h" #include #include -// Конвертация hex строки в бинарный формат -static int hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) { - if (!hex_str || !binary || strlen(hex_str) != binary_len * 2) return -1; - - for (size_t i = 0; i < binary_len; i++) { - unsigned int byte; - if (sscanf(hex_str + i * 2, "%2x", &byte) != 1) return -1; - binary[i] = (uint8_t)byte; - } - return 0; -} -// Callback для приема пакетов через uasync -static void etcp_socket_read_callback(int fd, void* user_arg); +// CONNECTION MANAGEMENT (!!!это всё должно быть static!!!) +static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct ETCP_LINK* link); + -// Forward declaration -int etcp_socket_send(struct ETCP_SOCKET* sock, const uint8_t* data, size_t len, const struct sockaddr* to_addr); +// Отправка кодограмм протокола (!!!это всё должно быть static!!!) +static int etcp_link_send_init(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval); +static int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval); +static int etcp_link_send_reset(struct ETCP_LINK* link); + +static uint32_t sockaddr_hash(struct sockaddr_storage* addr) { + socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + return crc32_calc((void*)addr, addr_len); + } // Бинарный поиск линка по ip_port_hash -static int find_link_index(struct ETCP_CONNECTIONS* conns, uint32_t hash) { - if (!conns || conns->num_channels == 0) return -1; +static int find_link_index(struct ETCP_SOCKET* e_sock, uint32_t hash) { + if (!e_sock || e_sock->num_channels == 0) return -1; int left = 0; - int right = conns->num_channels - 1; + int right = e_sock->num_channels - 1; while (left <= right) { int mid = left + (right - left) / 2; - if (conns->links[mid]->ip_port_hash == hash) { + if (e_sock->links[mid]->ip_port_hash == hash) { return mid; - } else if (conns->links[mid]->ip_port_hash < hash) { + } else if (e_sock->links[mid]->ip_port_hash < hash) { left = mid + 1; } else { right = mid - 1; @@ -55,765 +53,504 @@ static int find_link_index(struct ETCP_CONNECTIONS* conns, uint32_t hash) { } // Реалокация массива линков с увеличением в 2 раза -static int realloc_links(struct ETCP_CONNECTIONS* conns) { - size_t new_max = conns->max_channels == 0 ? 8 : conns->max_channels * 2; - struct ETCP_LINK** new_links = realloc(conns->links, new_max * sizeof(struct ETCP_LINK*)); +static int realloc_links(struct ETCP_SOCKET* e_sock) { + size_t new_max = e_sock->max_channels == 0 ? 8 : e_sock->max_channels * 2; + struct ETCP_LINK** new_links = realloc(e_sock->links, new_max * sizeof(struct ETCP_LINK*)); if (!new_links) return -1; - conns->links = new_links; - conns->max_channels = new_max; + e_sock->links = new_links; + e_sock->max_channels = new_max; return 0; } // Вставка линка в отсортированный массив -static int insert_link(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) { - if (!conns || !link) return -1; +static int insert_link(struct ETCP_SOCKET* e_sock, struct ETCP_LINK* link) { + if (!e_sock || !link) return -1; - if (conns->num_channels >= conns->max_channels) { - if (realloc_links(conns) < 0) return -1; + if (e_sock->num_channels >= e_sock->max_channels) { + if (realloc_links(e_sock) < 0) return -1; } - int idx = find_link_index(conns, link->ip_port_hash); + int idx = find_link_index(e_sock, link->ip_port_hash); if (idx >= 0) return -1; idx = -(idx + 1); - if (idx < (int)conns->num_channels) { - memmove(&conns->links[idx + 1], &conns->links[idx], - (conns->num_channels - idx) * sizeof(struct ETCP_LINK*)); + if (idx < (int)e_sock->num_channels) { + memmove(&e_sock->links[idx + 1], &e_sock->links[idx], + (e_sock->num_channels - idx) * sizeof(struct ETCP_LINK*)); } - conns->links[idx] = link; - conns->num_channels++; + e_sock->links[idx] = link; + e_sock->num_channels++; return 0; } // Удаление линка из массива -static void remove_link(struct ETCP_CONNECTIONS* conns, uint32_t hash) { - if (!conns || conns->num_channels == 0) return; +static void remove_link(struct ETCP_SOCKET* e_sock, uint32_t hash) { + if (!e_sock || e_sock->num_channels == 0) return; - int idx = find_link_index(conns, hash); + int idx = find_link_index(e_sock, hash); if (idx < 0) return; - if (idx < (int)conns->num_channels - 1) { - memmove(&conns->links[idx], &conns->links[idx + 1], - (conns->num_channels - idx - 1) * sizeof(struct ETCP_LINK*)); + if (idx < (int)e_sock->num_channels - 1) { + memmove(&e_sock->links[idx], &e_sock->links[idx + 1], + (e_sock->num_channels - idx - 1) * sizeof(struct ETCP_LINK*)); } - conns->num_channels--; + e_sock->num_channels--; } -struct ETCP_CONNECTIONS* etcp_connections_init(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port) { - if (!etcp) return NULL; +// надо править, используй sockaddr_hash +static struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr) { + if (!e_sock || !addr) return NULL; - struct ETCP_CONNECTIONS* conns = calloc(1, sizeof(struct ETCP_CONNECTIONS)); - if (!conns) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connections"); + int idx = find_link_index(e_sock, sockaddr_hash(addr)); + if (idx < 0) return NULL; + + return e_sock->links[idx]; +} + + +// =============================== + +struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type) { + if (!instance || !ip) return NULL; + + struct ETCP_SOCKET* e_sock = calloc(1, sizeof(struct ETCP_SOCKET)); + if (!e_sock) { + DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection"); + return NULL; + } + + // Determine address family from the provided sockaddr_storage + int family = ip->ss_family; + if (family != AF_INET && family != AF_INET6) { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family); + free(e_sock); return NULL; } - conns->etcp = etcp; - conns->conns = conns; - conns->socket.etcp = etcp; - conns->socket.socket_id = (uint32_t)(uintptr_t)&conns->socket; - - conns->socket.fd = socket(AF_INET, SOCK_DGRAM, 0); - if (conns->socket.fd < 0) { + e_sock->fd = socket(family, SOCK_DGRAM, 0); + if (e_sock->fd < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to create socket: %s", strerror(errno)); - free(conns); + free(e_sock); return NULL; } - int flags = fcntl(conns->socket.fd, F_GETFL, 0); - fcntl(conns->socket.fd, F_SETFL, flags | O_NONBLOCK); + int flags = fcntl(e_sock->fd, F_GETFL, 0); + fcntl(e_sock->fd, F_SETFL, flags | O_NONBLOCK); - struct sockaddr_in* addr = (struct sockaddr_in*)&conns->socket.local_addr; - addr->sin_family = AF_INET; - addr->sin_port = htons(port); - conns->socket.local_addr_len = sizeof(struct sockaddr_in); + // Set socket mark if specified + if (so_mark > 0) { +#ifdef SO_MARK + if (setsockopt(e_sock->fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to set SO_MARK: %s", strerror(errno)); + } +#endif + } - if (bind_addr) { - inet_pton(AF_INET, bind_addr, &addr->sin_addr); - } else { - addr->sin_addr.s_addr = INADDR_ANY; + // Bind to interface if specified + if (netif_index > 0) { +#ifdef SO_BINDTODEVICE + char ifname[IF_NAMESIZE]; + if (if_indextoname(netif_index, ifname)) { + if (setsockopt(e_sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind to interface %s: %s", ifname, strerror(errno)); + } + } +#endif } - if (bind(conns->socket.fd, (struct sockaddr*)addr, conns->socket.local_addr_len) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind socket to %s:%u: %s", - bind_addr ? bind_addr : "ANY", port, strerror(errno)); - close(conns->socket.fd); - free(conns); + // Copy the address for binding + memcpy(&e_sock->local_addr, ip, sizeof(struct sockaddr_storage)); + + socklen_t addr_len = (e_sock->local_addr.ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + + // Bind socket + if (bind(e_sock->fd, (struct sockaddr*)&e_sock->local_addr, addr_len) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind socket: %s", strerror(errno)); + close(e_sock->fd); + free(e_sock); return NULL; } - if (getsockname(conns->socket.fd, (struct sockaddr*)addr, &conns->socket.local_addr_len) < 0) { + // Get actual bound address (in case port was 0) + if (getsockname(e_sock->fd, (struct sockaddr*)&e_sock->local_addr, &addr_len) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to get socket name: %s", strerror(errno)); - close(conns->socket.fd); - free(conns); + close(e_sock->fd); + free(e_sock); return NULL; } + + // Insert into instance's connections list + e_sock->next = instance->etcp_sockets; + instance->etcp_sockets = e_sock; - return conns; + return e_sock; } -void etcp_connections_destroy(struct ETCP_CONNECTIONS* conns) { - if (!conns) return; +void etcp_socket_remove(struct ETCP_SOCKET* conn) { + if (!conn) return; - for (size_t i = 0; i < conns->num_channels; i++) { - etcp_link_close(conns->links[i]); + if (conn->fd >= 0) { + close(conn->fd); } - if (conns->socket.fd >= 0) { - close(conns->socket.fd); + for (size_t i = 0; i < conn->num_channels; i++) { + etcp_link_close(conn->links[i]); } + free(conn->links); - free(conns->links); - free(conns); + free(conn); } -struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* socket, - struct ETCP_CONNECTIONS* conns, - const struct sockaddr* remote_addr, socklen_t addr_len) { - if (!socket || !remote_addr || addr_len == 0) return NULL; + +struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) { + if (!remote_addr) return NULL; struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK)); if (!link) return NULL; - link->socket = (struct ETCP_SOCKET*)socket; - link->etcp = etcp; - link->conns = conns; - memcpy(&link->remote_addr, remote_addr, addr_len); - link->remote_addr_len = addr_len; + link->conn = conn; + link->is_server = is_server; + memcpy(&link->remote_addr, remote_addr, sizeof(struct sockaddr_storage)); link->last_activity = time(NULL); - uint8_t* addr_bytes = (uint8_t*)remote_addr; - link->ip_port_hash = crc32_calc(addr_bytes, addr_len); + link->ip_port_hash = sockaddr_hash(remote_addr); + + insert_link(conn, link);// вставим в bind + struct ETCP_LINK* l=etcp->links;// и вставим в link + while (l->next) l=l->next; + l->next = link; return link; } void etcp_link_close(struct ETCP_LINK* link) { - if (!link) return; - free(link); -} - -int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETCP_CONNECTIONS* conns) { - if (!pkt || !socket || !conns) return -1; - - if (pkt->metadata.data_len < 1) return -1; - - uint8_t* data = pkt->data; - size_t data_len = pkt->metadata.data_len; - uint8_t cmd = data[0]; - - struct sockaddr* src_addr = packet_remote_addr(pkt); - socklen_t addr_len = sizeof(struct sockaddr_storage); - - // Обработка INIT пакета: сначала pubkey, потом derive, потом decrypt - sc_context_t* sc = conns->etcp->crypto_ctx; - uint8_t decrypted_buf[1500]; - bool was_decrypted = false; - - if (cmd == ETCP_INIT_REQUEST && data_len >= SC_PUBKEY_SIZE) { - if (!sc || !sc->initialized) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Crypto context not initialized"); - return -1; + if (!link || !link->etcp) return; + + // универсальное удаление из односвязного списка + struct ETCP_LINK **pp = &link->etcp->links; + while (*pp) { + if (*pp == link) { + *pp = link->next; + break; } - - // 1. Извлекаем pubkey из конца - uint8_t pubkey[SC_PUBKEY_SIZE]; - memcpy(pubkey, data + data_len - SC_PUBKEY_SIZE, SC_PUBKEY_SIZE); - data_len -= SC_PUBKEY_SIZE; - - // 2. Устанавливаем pubkey и вызываем derive - - // Обновляем cmd, так как data_len изменился - cmd = data[0]; + pp = &(*pp)->next; } - // Теперь можем дешифровать, если session_ready установлен - if (sc && sc->session_ready && data_len > SC_TAG_SIZE) { - size_t decrypted_len = sizeof(decrypted_buf); - - // Шифруется весь пакет (INIT_REQUEST без pubkey уже обрезан) - if (sc_decrypt(sc, data, data_len, decrypted_buf, &decrypted_len) == SC_OK) { - data = decrypted_buf; - data_len = decrypted_len; - cmd = data[0]; - was_decrypted = true; - conns->total_decrypted++; - } else { - conns->decrypt_errors++; - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Decryption failed after INIT"); - return -1; - } - } - - // Обработка INIT REQUEST - if (cmd == ETCP_INIT_REQUEST) { - if (pkt->metadata.data_len < 1 + 8 + SC_PUBKEY_SIZE + 2 + 2) { - return -1; - } - - struct ETCP_LINK* link = etcp_link_find_by_addr(conns, src_addr, addr_len); - if (link) { - if (link->initialized) { - etcp_conn_reset(link->etcp); - } - etcp_link_remove_from_connections(conns, link); - etcp_link_close(link); - } - - link = etcp_link_new(NULL, socket, conns, src_addr, addr_len); - if (!link) return -1; - - uint8_t* p = &data[1]; - link->etcp->peer_node_id = 0; - memcpy(&link->etcp->peer_node_id, p, 8); - p += 8; - - memcpy(link->etcp->peer_public_key, p, SC_PUBKEY_SIZE); - link->etcp->has_peer_key = 1; - p += SC_PUBKEY_SIZE; - - uint16_t peer_mtu = ntohs(*(uint16_t*)p); - p += 2; - uint16_t peer_keepalive = ntohs(*(uint16_t*)p); - - link->mtu = peer_mtu; - link->keepalive_interval = peer_keepalive; - - etcp_link_add_to_connections(conns, link); - - return etcp_link_send_init_response(link, 1500, 30); - } - - struct ETCP_LINK* link = etcp_link_find_by_addr(conns, src_addr, addr_len); - if (!link) { - struct ETCP_LINK* temp_link = etcp_link_new(NULL, socket, conns, src_addr, addr_len); - if (temp_link) { - etcp_link_send_reset(temp_link); - etcp_link_close(temp_link); - } - return -1; - } - - if (!link->initialized) { - switch (cmd) { - case ETCP_INIT_RESPONSE: - if (pkt->metadata.data_len < 1 + 8 + 2 + 2) return -1; - - link->etcp->peer_node_id = 0; - memcpy(&link->etcp->peer_node_id, &data[1], 8); - - link->mtu = ntohs(*(uint16_t*)&data[1 + 8]); - link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8 + 2]); - link->initialized = 1; - break; - - case ETCP_CHANNEL_INIT: - if (pkt->metadata.data_len < 1 + 8 + 2) return -1; - - link->etcp->peer_node_id = 0; - memcpy(&link->etcp->peer_node_id, &data[1], 8); - link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8]); - - return etcp_link_send_channel_response(link); - - case ETCP_CHANNEL_RESPONSE: - if (pkt->metadata.data_len < 1 + 8) return -1; - - link->etcp->peer_node_id = 0; - memcpy(&link->etcp->peer_node_id, &data[1], 8); - link->initialized = 1; - break; - - case ETCP_RESET: - etcp_link_remove_from_connections(conns, link); - etcp_link_close(link); - break; - - default: - etcp_link_send_reset(link); - return -1; - } - } else { - if (cmd >= 0x02 && cmd <= 0x06) { - etcp_link_send_reset(link); - return -1; - } - } - - link->last_activity = time(NULL); - - return 0; -} - -int etcp_link_init(struct ETCP_CONN* etcp, struct ETCP_LINK* link) { (void)etcp; (void)link; - return 0; -} + remove_link(link->conn, link->ip_port_hash); -int etcp_link_send(struct ETCP_CONN* etcp, struct ETCP_LINK* link, - const uint8_t* data, size_t len) { - if (!etcp || !link || !data || len == 0) return -1; - - link->last_activity = time(NULL); - - sc_context_t* sc = etcp->crypto_ctx; - int fd = link->socket->fd; - - if (sc && sc->session_ready && len < 1400) { - uint8_t encrypted_buf[1500]; - size_t encrypted_len = sizeof(encrypted_buf); - - if (sc_encrypt(sc, data, len, encrypted_buf, &encrypted_len) == SC_OK) { - ssize_t sent = sendto(fd, encrypted_buf, encrypted_len, MSG_DONTWAIT, - (struct sockaddr*)&link->remote_addr, - link->remote_addr_len); - - if (sent < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - link->conns->send_errors++; - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "sendto failed: %s", strerror(errno)); - } - return -1; - } - - link->conns->total_encrypted++; - return 0; - } else { - link->conns->encrypt_errors++; - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Encryption failed"); - return -1; - } - } - - ssize_t sent = sendto(fd, data, len, MSG_DONTWAIT, - (struct sockaddr*)&link->remote_addr, - link->remote_addr_len); - - return (sent >= 0) ? 0 : -1; + free(link); } -int etcp_link_send_init(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) { - if (!link || mtu <= 0 || mtu > 65535) return -1; - - uint8_t packet[1 + 8 + SC_PUBKEY_SIZE + 2 + 2]; - uint8_t* p = packet; - - *p++ = ETCP_INIT_REQUEST; - - uint64_t node_id = link->etcp->node_id; - memcpy(p, &node_id, 8); - p += 8; - - sc_context_t* sc = link->etcp->crypto_ctx; - if (!sc || !sc->initialized) return -1; - - memcpy(p, sc->public_key, SC_PUBKEY_SIZE); - p += SC_PUBKEY_SIZE; - - uint16_t mtu_be = htons(mtu); - memcpy(p, &mtu_be, 2); - p += 2; - - uint16_t keepalive_be = htons(keepalive_interval); - memcpy(p, &keepalive_be, 2); - p += 2; - - link->mtu = mtu; - link->keepalive_interval = keepalive_interval; - - return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), - (struct sockaddr*)&link->remote_addr); +int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { + + sc_context_t* sc = dgram->link->etcp->crypto_ctx; + int len=dgram->data_len-dgram->noencrypt_len; + if (len<=0 || len>1480) { dgram->link->send_errors++; return; } + uint8_t enc_buf[1600]; + size_t enc_buf_len; + sc_encrypt(sc, dgram->data, len, &enc_buf, &enc_buf_len); + if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; return; } + memcpy(enc_buf+enc_buf_len, dgram->data+enc_buf_len, dgram->noencrypt_len); + + struct sockaddr_storage* addr=dgram->link->remote_addr; + socklen_t addr_len = (to_addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + ssize_t sent = sendto(dgram->link->conn->fd, enc_buf, len, 0, addr, addr_len); + if (sent < 0) dgram->link->send_errors++; else dgram->link->total_encrypted += sent; + return (int)sent; } - +/* +// надо править int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) { - if (!link || mtu <= 0 || mtu > 65535) return -1; - - uint8_t packet[1 + 8 + 2 + 2]; + uint8_t packet[1 + 8 + 2 + 2] = {0}; uint8_t* p = packet; - *p++ = ETCP_INIT_RESPONSE; - uint64_t node_id = link->etcp->node_id; - memcpy(p, &node_id, 8); - p += 8; - - uint16_t mtu_be = htons(mtu); - memcpy(p, &mtu_be, 2); - p += 2; + uint64_t node_id = link->conns->etcp->utun_i->node_id; + memcpy(p, &node_id, 8); p += 8; - uint16_t keepalive_be = htons(keepalive_interval); - memcpy(p, &keepalive_be, 2); - p += 2; + *p++ = (mtu >> 8) & 0xFF; + *p++ = mtu & 0xFF; - link->mtu = mtu; - link->keepalive_interval = keepalive_interval; - link->initialized = 1; + *p++ = (keepalive_interval >> 8) & 0xFF; + *p++ = keepalive_interval & 0xFF; - return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), - (struct sockaddr*)&link->remote_addr); + return etcp_encrypt_send(link->conns, packet, sizeof(packet), (struct sockaddr*)&link->remote_addr, link->remote_addr_len); } +// надо править int etcp_link_send_channel_init(struct ETCP_LINK* link, uint16_t keepalive_interval) { - if (!link) return -1; - - uint8_t packet[1 + 8 + 2]; + uint8_t packet[1 + 8 + 2] = {0}; uint8_t* p = packet; - *p++ = ETCP_CHANNEL_INIT; - uint64_t node_id = link->etcp->node_id; - memcpy(p, &node_id, 8); - p += 8; - - uint16_t keepalive_be = htons(keepalive_interval); - memcpy(p, &keepalive_be, 2); - p += 2; - - link->keepalive_interval = keepalive_interval; - - return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), - (struct sockaddr*)&link->remote_addr); -} - -int etcp_link_send_channel_response(struct ETCP_LINK* link) { - if (!link) return -1; - - uint8_t packet[1 + 8]; - uint8_t* p = packet; - - *p++ = ETCP_CHANNEL_RESPONSE; + uint64_t node_id = link->conns->etcp->utun_i->node_id; + memcpy(p, &node_id, 8); p += 8; - uint64_t node_id = link->etcp->node_id; - memcpy(p, &node_id, 8); - p += 8; + *p++ = (keepalive_interval >> 8) & 0xFF; + *p++ = keepalive_interval & 0xFF; - link->initialized = 1; - - return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), - (struct sockaddr*)&link->remote_addr); + return etcp_encrypt_send(link->conns, packet, sizeof(packet), (struct sockaddr*)&link->remote_addr, link->remote_addr_len); } +// надо править int etcp_link_send_reset(struct ETCP_LINK* link) { - if (!link) return -1; - uint8_t packet[1] = {ETCP_RESET}; - return etcp_socket_send((struct ETCP_SOCKET*)link->socket, packet, sizeof(packet), - (struct sockaddr*)&link->remote_addr); + return etcp_connections_send(link->conns, packet, sizeof(packet), (struct sockaddr*)&link->remote_addr, link->remote_addr_len); } +*/ -struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_CONNECTIONS* conns, - const struct sockaddr* addr, socklen_t addr_len) { - if (!conns || !addr || addr_len == 0) return NULL; +static void etcp_connections_read_callback(int fd, void* arg) { + struct ETCP_SOCKET* e_sock = (struct ETCP_SOCKET*)arg; + if (!e_sock) return; - uint32_t hash = crc32_calc((const uint8_t*)addr, addr_len); - int idx = find_link_index(conns, hash); + socklen_t addr_len = sizeof(pkt->metadata.remote_addr); + struct sockaddr_storage addr; + uint8_t data[PACKET_DATA_SIZE]; + socklen_t addr_len=sizeof(addr); + memset(&addr, 0, sizeof(addr)); + ssize_t recv_len = recvfrom(fd, data, PACKET_DATA_SIZE, 0, (struct sockaddr*)&addr, &addr_len); - if (idx >= 0) { - return conns->links[idx]; + if (recv_len <= 0) { + return; } - return NULL; -} -int etcp_link_add_to_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) { - if (!conns || !link) return -1; - return insert_link(conns, link); -} + struct ETCP_DGRAM* pkt = memory_pool_alloc(&e_sock->instance->pkt_pool); + if (!pkt) return; + size_t pkt_len=0; + int errorcode=0; + + struct ETCP_LINK* link=etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, &addr); + if (link==NULL) {// пробуем расшифровать, возможно это init + struct secure_channel sc; + if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; goto ec_fr; } + sc_init_ctx(&sc, &e_sock->instance->my_keys); + if (sc_set_peer_public_key(&sc, data+recv_len-SC_PUBKEY_SIZE, 0)!=SC_OK) { errorcode=2; goto ec_fr; } + if (sc_decrypt(&sc, data, recv_len-SC_PUBKEY_SIZE, pkt->data, &pkt_len)) { errorcode=3; goto ec_fr; } + pkt->data_len=pkt_len; + pkt->noencrypt_len=0; + struct { + uint8_t main_id[2]; + uint8_t timestamp[2]; + uint8_t code; + uint8_t id[8]; + uint8_t mtu[2]; + uint8_t keepalive[2]; + uint8_t pubkey[SC_PUBKEY_SIZE]; + } *ack_hdr=(void*)&pkt->data[0]; + uint64_t peer_id; + memcpy(&peer_id, &pkt->data+1, 4); + if (ack_hdr->code!=0x02 && ack_hdr->code!=0x04) { errorcode=4; goto ec_fr; }// не init + + struct ETCP_CONN* conn=e_sock->instance->connections; + while (conn) {// ищем есть ли подключение к этому пиру + if (conn->peer_node_id==peer_id) break; + conn=conn->next; + } + if (conn==NULL) {// создаём новое + conn=etcp_connection_create(e_sock->instance); + memcpy(&conn->crypto_ctx, &sc, sizeof(sc));// добавляем ключ + conn->peer_node_id=peer_id; + } + else {// check keys + if (memcmp(&conn->crypto_ctx->peer_public_key, &sc.peer_public_key, SC_PUBKEY_SIZE)) { errorcode=5; goto ec_fr; }// коллизия - peer id совпал а ключи разные. + } + struct ETCP_LINK* link = etcp_link_new(etcp, e_sock, addr, 1); + if (ack_hdr->code==0x02) etcp_conn_reset(etcp); +// send reply - подключение создано + struct { + uint8_t main_id[2]; + uint8_t timestamp[2]; + uint8_t code; + uint8_t id[8]; + uint8_t mtu[2]; + } *ack_repl_hdr=(void*)&pkt->data[0]; + ack_repl_hdr->code=0x03; + ack_repl_hdr->main_id[0]=0; + ack_repl_hdr->main_id[1]=0; + memcpy(&ack_repl_hdr->id[0], &e_sock->instance->node_id, 8); + int mtu=e_sock->instance->config->global->mtu; + ack_repl_hdr->mtu[0]=mtu>>8; + ack_repl_hdr->mtu[1]=mtu; + pkt->data_len=sizeof(ack_repl_hdr); + pkt->noencrypt_len=0; + etcp_encrypt_send(pkt); + + packet_pool_free(&e_sock->instance->pkt_pool, pkt); + return; + } -void etcp_link_remove_from_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link) { - if (!conns || !link) return; - remove_link(conns, link->ip_port_hash); -} + if (sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, pkt->data, &pkt_len)) { errorcode=6; goto ec_fr; } + pkt->data_len=pkt_len; + pkt->noencrypt_len=0; + pkt->link=link; -// SOCKET FUNCTIONS (moved from etcp_sockets) -#include -#include -#include -#include + etcp_input(pkt, conns); + return; -struct ETCP_SOCKET* etcp_socket_create(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port) { - if (!etcp) return NULL; - - struct ETCP_SOCKET* sock = calloc(1, sizeof(struct ETCP_SOCKET)); - if (!sock) return NULL; - - sock->etcp = etcp; - sock->socket_id = (uint32_t)(uintptr_t)sock; - - sock->fd = socket(AF_INET, SOCK_DGRAM, 0); - if (sock->fd < 0) { - free(sock); - return NULL; - } - - int flags = fcntl(sock->fd, F_GETFL, 0); - fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK); - - struct sockaddr_in* addr = (struct sockaddr_in*)&sock->local_addr; - addr->sin_family = AF_INET; - addr->sin_port = htons(port); - sock->local_addr_len = sizeof(struct sockaddr_in); - - if (bind_addr) { - inet_pton(AF_INET, bind_addr, &addr->sin_addr); - } else { - addr->sin_addr.s_addr = INADDR_ANY; - } - - if (bind(sock->fd, (struct sockaddr*)addr, sock->local_addr_len) < 0) { - close(sock->fd); - free(sock); - return NULL; - } - - if (getsockname(sock->fd, (struct sockaddr*)addr, &sock->local_addr_len) < 0) { - close(sock->fd); - free(sock); - return NULL; - } - - return sock; +ec_fr: + e_sock->pkt_format_errors++; + e_sock->errorcode=errorcode; + packet_pool_free(&e_sock->instance->pkt_pool, pkt); + return; } -void etcp_socket_destroy(struct ETCP_SOCKET* sock) { - if (!sock) return; - - if (sock->fd >= 0) { - close(sock->fd); - } - - free(sock); -} +#define MIN(a,b) ((a) < (b) ? (a) : (b)) -int etcp_socket_send(struct ETCP_SOCKET* sock, const uint8_t* data, size_t len, const struct sockaddr* to_addr) { - if (!sock || sock->fd < 0 || !data || !to_addr) { - return -1; - } +int etcp_input(struct ETCP_DGRAM* pkt) { + if (!pkt || !e_sock) return -1; - socklen_t addr_len = (to_addr->sa_family == AF_INET) ? - sizeof(struct sockaddr_in) : - sizeof(struct sockaddr_in6); + uint8_t* data = pkt->data; + size_t len = pkt->metadata.data_len; - return sendto(sock->fd, data, len, 0, to_addr, addr_len); -} - -// Callback для приема пакетов через uasync -static void etcp_socket_read_callback(int fd, void* user_arg) { - struct ETCP_CONNECTIONS* conns = (struct ETCP_CONNECTIONS*)user_arg; - if (!conns || fd < 0) return; + if (len < 1) return -1; - struct packet_buffer* pkt = packet_pool_get(&conns->etcp->packet_pool); - if (!pkt) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to get packet from pool"); - return; - } + uint8_t header = data[0]; + data++; len--; - struct sockaddr_storage remote_addr; - socklen_t addr_len = sizeof(remote_addr); + struct ETCP_CONN* etcp = e_sock->etcp; - ssize_t nread = recvfrom(fd, pkt->data, sizeof(pkt->data), 0, - (struct sockaddr*)&remote_addr, &addr_len); - if (nread < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - conns->recv_errors++; - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "recvfrom failed: %s", strerror(errno)); + if (header != ETCP_INIT_REQUEST && header != ETCP_CHANNEL_INIT && etcp->has_peer_key) { + // Decrypt + sc_context_t* sc = etcp->crypto_ctx; + uint8_t decrypted[PACKET_DATA_SIZE]; + size_t decrypted_len; + if (sc_decrypt(sc, data, len, decrypted, &decrypted_len) != SC_OK) { + e_sock->decrypt_errors++; + return -1; } - packet_pool_put(&conns->etcp->packet_pool, pkt); - return; - } - - if (nread == 0) { - packet_pool_put(&conns->etcp->packet_pool, pkt); - return; + memcpy(data, decrypted, decrypted_len); + len = decrypted_len; + e_sock->total_decrypted += len; } - pkt->metadata.data_len = nread; - pkt->metadata.remote_addr = remote_addr; - pkt->metadata.s = &conns->socket; - - etcp_input(pkt, &conns->socket, conns); - - packet_pool_put(&conns->etcp->packet_pool, pkt); -} - -// Helper function to parse IP:port address -static int parse_ip_port(const char* addr_str, struct sockaddr_storage* addr, socklen_t* addr_len) { - if (!addr_str || !addr || !addr_len) return -1; - - char* colon = strchr(addr_str, ':'); - if (!colon) return -1; - - char ip_str[INET6_ADDRSTRLEN]; - size_t ip_len = colon - addr_str; - if (ip_len >= sizeof(ip_str)) return -1; + struct ETCP_LINK* link = etcp_link_find_by_addr(e_sock, (struct sockaddr*)&pkt->metadata.remote_addr, + sizeof(pkt->metadata.remote_addr)); - strncpy(ip_str, addr_str, ip_len); - ip_str[ip_len] = '\0'; - - char* port_str = colon + 1; - int port = atoi(port_str); - if (port <= 0 || port > 65535) return -1; - - struct sockaddr_in* sin = (struct sockaddr_in*)addr; - memset(sin, 0, sizeof(struct sockaddr_in)); - sin->sin_family = AF_INET; - sin->sin_port = htons(port); + if (!link) { + if (header == ETCP_INIT_REQUEST || header == ETCP_CHANNEL_INIT) { + // Create new link + link = etcp_link_new(etcp, e_sock, (struct sockaddr*)&pkt->metadata.remote_addr, + sizeof(pkt->metadata.remote_addr)); + if (!link) return -1; + } else { + // Send reset if not init + uint8_t reset_pkt[1] = {ETCP_RESET}; + etcp_connections_send(e_sock, reset_pkt, 1, (struct sockaddr*)&pkt->metadata.remote_addr, sizeof(pkt->metadata.remote_addr)); + return -1; + } + } - if (inet_pton(AF_INET, ip_str, &sin->sin_addr) != 1) { - return -1; + if (header == ETCP_INIT_REQUEST) { + // Parse init + if (len < 8 + 2 + 2 + SC_PUBKEY_SIZE) return -1; + uint64_t peer_node_id; + memcpy(&peer_node_id, data, 8); data += 8; len -= 8; + uint16_t peer_mtu = (data[0] << 8) | data[1]; data += 2; len -= 2; + uint16_t peer_keepalive = (data[0] << 8) | data[1]; data += 2; len -= 2; + uint8_t peer_pubkey[SC_PUBKEY_SIZE]; + memcpy(peer_pubkey, data, SC_PUBKEY_SIZE); + + etcp->peer_node_id = peer_node_id; + memcpy(etcp->peer_public_key, peer_pubkey, SC_PUBKEY_SIZE); + etcp->has_peer_key = 1; + sc_set_peer_public_key(etcp->crypto_ctx, peer_pubkey); + + link->mtu = MIN(etcp->mtu, peer_mtu); + link->keepalive_interval = peer_keepalive; + link->initialized = 1; + + // Send response + etcp_link_send_init_response(link, etcp->mtu, link->keepalive_interval); + + } else if (header == ETCP_INIT_RESPONSE) { + // Similar parsing without pubkey + } else if (header == ETCP_CHANNEL_RESPONSE) { + // Parse + } else if (header == ETCP_RESET) { + etcp_conn_reset(etcp); + } else { + // Forward to etcp_conn_input + pkt->metadata.channel = link; // Or etcp_channel if separate + etcp_conn_input(etcp, pkt); + return 0; } - *addr_len = sizeof(struct sockaddr_in); + packet_pool_put(&etcp->packet_pool, pkt); return 0; } -// Initialize connections from configuration int init_connections(struct UTUN_INSTANCE* instance) { - if (!instance || !instance->config) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid instance or config"); - return -1; - } + if (!instance || !instance->config) return -1; - struct utun_config* config = instance->config; - int total_servers = config->server_count; - - if (total_servers == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "No servers found in configuration"); - return -1; - } - - instance->connections = calloc(total_servers, sizeof(conn_handle_t*)); - if (!instance->connections) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connections array"); - return -1; - } + struct config* config = instance->config; + instance->connections = calloc(config->server_count, sizeof(struct ETCP_CONN)); + if (!instance->connections) return -1; instance->connection_count = 0; - for (int i = 0; i < total_servers; i++) { - struct server_config* server = &config->servers[i]; - - // Parse server bind address - struct sockaddr_storage bind_addr; - socklen_t bind_addr_len; - if (parse_ip_port(server->addr, &bind_addr, &bind_addr_len) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid server address '%s'", server->addr); - continue; - } - - // Get bind IP and port - struct sockaddr_in* sin = (struct sockaddr_in*)&bind_addr; - char bind_ip_str[INET_ADDRSTRLEN]; - if (!inet_ntop(AF_INET, &sin->sin_addr, bind_ip_str, sizeof(bind_ip_str))) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to convert bind address"); - continue; - } - uint16_t bind_port = ntohs(sin->sin_port); - - // Create ETCP instance - struct ETCP_CONN* etcp = etcp_create(instance); - if (!etcp) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP for server %s", server->name); - continue; - } - - // Create socket - struct ETCP_SOCKET* sock = etcp_socket_create(etcp, bind_ip_str, bind_port); - if (!sock) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create socket for %s", server->name); - etcp_destroy(etcp); - continue; - } - + struct CFG_SERVER* server = config->servers; + while (server) { + // Create connections manager (includes socket creation) - struct ETCP_CONNECTIONS* conns = etcp_connections_init(etcp, bind_ip_str, bind_port); - if (!conns) { + struct ETCP_CONN* conn = etcp_connection_add(instance, server->ip, server->netif_index, server->so_mark, server->type); + if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create connections for %s", server->name); etcp_destroy(etcp); continue; } - // Register socket with uasync - if (uasync_add_socket(instance->ua, conns->socket.fd, - etcp_socket_read_callback, NULL, NULL, conns) == NULL) { - DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to register socket with uasync for %s", server->name); - etcp_connections_destroy(conns); - etcp_destroy(etcp); - return -1; - } - - // Create connection handle - conn_handle_t* handle = calloc(1, sizeof(conn_handle_t)); - if (!handle) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection handle"); - etcp_connections_destroy(conns); - etcp_destroy(etcp); - continue; - } + printf("Initialized server %s on %s (links: %zu)\n", + server->name, server->addr, e_sock->num_channels); + server = server->next; + } - handle->etcp = etcp; - handle->conns = conns; + // Process connections that added to this server + for (int j = 0; j < config->client_count; j++) { + struct client_config* client = &config->clients[j]; - // Set first listen socket - if (i == 0) { - instance->first_listen_socket = &conns->socket; + // Check if this client is for current server + if (strcmp(client->from, server->name) != 0) { + continue; } + + struct ETCP_CONN* etcp_conn=etcp_connection_create(instance); + - // Process clients that connect to this server - for (int j = 0; j < config->client_count; j++) { - struct client_config* client = &config->clients[j]; - - // Check if this client is for current server - if (strcmp(client->from, server->name) != 0) { - continue; - } - - // Parse client address - struct sockaddr_storage client_addr; - socklen_t client_addr_len; - if (parse_ip_port(client->to_addr, &client_addr, &client_addr_len) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid client address '%s'", client->to_addr); - continue; + // Серверы получат pubkey через INIT пакет + sc_init_ctx(&etcp_conn->ctx, &instance->my_keys); + if (strlen(client->peer_public_key_hex) > 0) { + uint8_t peer_key_bin[SC_PUBKEY_SIZE]; + if (hex_to_binary(client->peer_public_key_hex, peer_key_bin, SC_PUBKEY_SIZE) == 0) { + memcpy(etcp_conn->peer_public_key, peer_key_bin, SC_PUBKEY_SIZE); + etcp_conn->has_peer_key = 1; + sc_set_peer_public_key(etcp_conn->crypto_ctx, peer_key_bin); } - + } + +// тут надо добавить линки + + struct client_link cl=client->links; + while (cl) { + conn= (надо найти) + // Create link for this client - struct ETCP_LINK* link = etcp_link_new(etcp, &conns->socket, conns, - (struct sockaddr*)&client_addr, - client_addr_len); + struct ETCP_LINK* link = etcp_link_new(etcp, conn, cl->remote_sockaddr, sizeof(struct sockaddr_storage)); if (!link) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create link for client %s", client->name); continue; } - - // Add link to connections - if (etcp_link_add_to_connections(conns, link) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to add link for client %s", client->name); - etcp_link_close(link); - continue; - } - - // Для клиентов, у которых есть peer_public_key в конфиге - сразу вызываем derive - // Серверы получат pubkey через INIT пакет - if (strlen(client->peer_public_key_hex) > 0) { - uint8_t peer_key_bin[SC_PUBKEY_SIZE]; - if (hex_to_binary(client->peer_public_key_hex, peer_key_bin, SC_PUBKEY_SIZE) == 0) { - memcpy(link->conns->etcp->peer_public_key, peer_key_bin, SC_PUBKEY_SIZE); - link->conns->etcp->has_peer_key = 1; - sc_set_peer_public_key(link->conns->etcp->crypto_ctx, peer_key_bin); - } - } - - printf(" Added client %s -> %s\n", client->name, client->to_addr); + cl=cl->next; } - instance->connections[instance->connection_count++] = handle; - printf("Initialized server %s on %s (links: %zu)\n", - server->name, server->addr, conns->num_channels); + printf(" Added client %s -> %s\n", client->name, client->to_addr); } - + + if (instance->connection_count == 0) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No connections initialized"); free(instance->connections); @@ -824,64 +561,3 @@ int init_connections(struct UTUN_INSTANCE* instance) { printf("Initialized %d connections\n", instance->connection_count); return 0; } - -void conn_destroy(conn_handle_t* handle) { - if (!handle) return; - - if (handle->conns) { - etcp_socket_destroy((struct ETCP_SOCKET*)&handle->conns->socket); - etcp_connections_destroy(handle->conns); - } - - if (handle->etcp) { - etcp_destroy(handle->etcp); - } - - free(handle); -} - -int conn_send(conn_handle_t* conn, const uint8_t* data, size_t len) { - if (!conn || !conn->etcp || !data || len == 0) { - return -1; - } - - struct ETCP_CONN* etcp = conn->etcp; - struct packet_buffer* pkt = packet_pool_get(&etcp->packet_pool); - if (!pkt) { - return -1; - } - - if (len > 1500) { - len = 1500; - } - - memcpy(packet_data(pkt), data, len); - pkt->metadata.data_len = len; - - etcp_conn_input(etcp, pkt); - return 0; -} - - - -size_t etcp_connections_get_channel_count(const struct ETCP_CONNECTIONS* conns) { - if (!conns) return 0; - return conns->num_channels; -} - - -void etcp_connections_get_crypto_stats(const struct ETCP_CONNECTIONS* conns, - size_t* encrypt_errors, - size_t* decrypt_errors, - size_t* send_errors, - size_t* recv_errors, - size_t* total_encrypted, - size_t* total_decrypted){ - if (!conns) return; - if (encrypt_errors) *encrypt_errors = conns->encrypt_errors; - if (decrypt_errors) *decrypt_errors = conns->decrypt_errors; - if (send_errors) *send_errors = conns->send_errors; - if (recv_errors) *recv_errors = conns->recv_errors; - if (total_encrypted) *total_encrypted = conns->total_encrypted; - if (total_decrypted) *total_decrypted = conns->total_decrypted; -} diff --git a/src/etcp_connections.h b/src/etcp_connections.h index 138c5f91..fb7a567b 100644 --- a/src/etcp_connections.h +++ b/src/etcp_connections.h @@ -1,14 +1,12 @@ #ifndef ETCP_CONNECTIONS_H #define ETCP_CONNECTIONS_H -#include "packet_buffer.h" #include "secure_channel.h" -#include "etcp_sockets.h" +#include "utun_instance.h" #include #include -// Forward declarations -struct UTUN_INSTANCE; +#define PACKET_DATA_SIZE 1536 // Типы кодограмм протокола #define ETCP_INIT_REQUEST 0x02 @@ -17,87 +15,71 @@ struct UTUN_INSTANCE; #define ETCP_CHANNEL_RESPONSE 0x05 #define ETCP_RESET 0x06 + +struct ETCP_DGRAM { + struct ETCP_LINK* link;// откуда получена или куда отправялем + uint16_t data_len; + uint16_t noencrypt_len;// число байт (с конца) которые не надо шифровать. для передачи pubkey + uint8_t data[0];// сами данные +}; + // список активных подключений которые обслуживает сокет. каждый сокет может обслуживать много подключений -struct ETCP_CONNECTIONS { - struct ETCP_CONNECTIONS* next; // Linked list для всех соединений +struct ETCP_SOCKET { + struct ETCP_SOCKET* next; // Linked list для всех соединений + struct UTUN_INSTANCE* instance; + int fd; // Файловый дескриптор UDP сокета + struct sockaddr_storage local_addr; // Локальный адрес - // сокет для отправки/приема - struct ETCP_SOCKET socket; // Сокет через который идет трафик - - // для входящих подключений - массив упорядоченный по ip_port_hash + // для входящих подключений (links) - массив упорядоченный по ip_port_hash size_t max_channels; // сколько выделено памяти size_t num_channels; // сколько активно struct ETCP_LINK** links;// массив указателей на линки, сортированный по ip_port_hash + int errorcode; + size_t pkt_format_errors; - // Дополнительные поля для управления соединениями - struct ETCP_CONN* etcp; // Родительский ETCP instance - struct ETCP_CONNECTIONS* conns;// Указатель на себя (для совместимости) - - // Статистика - size_t encrypt_errors; - size_t decrypt_errors; - size_t send_errors; - size_t recv_errors; - size_t total_encrypted; - size_t total_decrypted; }; // ETCP Link - одно динамическое соединение (один путь) struct ETCP_LINK { uint32_t ip_port_hash; // crc32 для быстрого поиска - struct ETCP_LINK* next; // Linked list подключений для ETCP_CONN + struct ETCP_LINK* next; // Linked list подключений для ETCP_CONN (каждое подключение это child для ETCP_CONN) + struct ETCP_CONN* etcp; // подключение (parent) - struct ETCP_SOCKET* socket; // Сокет через который идет трафик - struct ETCP_CONN* etcp; // Родительский ETCP instance - struct ETCP_CONNECTIONS* conns; // Родительский connections (для статистики) + struct ETCP_SOCKET* conn; // сокет через который работаем // Путь соединения struct sockaddr_storage remote_addr; // Удалённый адрес - socklen_t remote_addr_len; // Параметры соединения uint16_t mtu; // MTU соединения uint16_t keepalive_interval; // Keepalive интервал - uint8_t initialized; // Флаг инициализации + uint8_t is_server; // инициирует подключение клиент + uint8_t initialized; // Флаг инициализации uint64_t last_activity; // Время последней активности -}; -// CONNECTIONS FUNCTIONS -struct ETCP_CONNECTIONS* etcp_connections_init(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port); -void etcp_connections_destroy(struct ETCP_CONNECTIONS* conns); -struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* socket, - struct ETCP_CONNECTIONS* conns, - const struct sockaddr* remote_addr, socklen_t addr_len); -void etcp_link_close(struct ETCP_LINK* link); -int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETCP_CONNECTIONS* conns); -int etcp_link_send(struct ETCP_CONN* etcp, struct ETCP_LINK* link, const uint8_t* data, size_t len); - -// CONNECTION MANAGEMENT -struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_CONNECTIONS* conns, const struct sockaddr* addr, socklen_t addr_len); -int etcp_link_add_to_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link); -void etcp_link_remove_from_connections(struct ETCP_CONNECTIONS* conns, struct ETCP_LINK* link); + size_t encrypt_errors; + size_t decrypt_errors; + size_t send_errors; + size_t recv_errors; + size_t total_encrypted; + size_t total_decrypted; +}; // INITIALIZATION (создаёт listen-сокеты и подключения из конфига) int init_connections(struct UTUN_INSTANCE* instance); -// Отправка кодограмм протокола -int etcp_link_send_init(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval); -int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval); -int etcp_link_send_channel_init(struct ETCP_LINK* link, uint16_t keepalive_interval); -int etcp_link_send_channel_response(struct ETCP_LINK* link); -int etcp_link_send_reset(struct ETCP_LINK* link); +// SOCKET FUNCTIONS +// добавляет новый версер (сокет для приёма и отправки кодограмм. обслуживает много подключений) +struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type); +// удаляет сокет и освобождает ресурсы (грохает все его подключения и сокет) +void etcp_socket_remove(struct ETCP_SOCKET* conn); -// Utility functions -size_t etcp_connections_get_channel_count(const struct ETCP_CONNECTIONS* conns); - -// Получение статистики шифрования -void etcp_connections_get_crypto_stats(const struct ETCP_CONNECTIONS* conns, - size_t* encrypt_errors, - size_t* decrypt_errors, - size_t* send_errors, - size_t* recv_errors, - size_t* total_encrypted, - size_t* total_decrypted); +// connection functions +// создает новый канал связи для etcp подключения (ETCP_CONN) +struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server); +void etcp_link_close(struct ETCP_LINK* link); +//int etcp_input_cbk(struct packet_buffer* pkt, struct ETCP_SOCKET* conn);// получает расшифрованный пакет +int etcp_encrypt_send(struct ETCP_DGRAM* dgram);// зашифровывает и отправляет пакет #endif // ETCP_CONNECTIONS_H diff --git a/src/etcp_protocol.txt b/src/etcp_protocol.txt index d66d7e23..8a86e9d3 100755 --- a/src/etcp_protocol.txt +++ b/src/etcp_protocol.txt @@ -25,23 +25,15 @@ Кодограммы с этими секциями обрабатываются в etcp_connections (в этих кодограммах всегда только одна секция): - г) Init запрос - заголовок 0x02: - [0x02] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low] [my publick key (32 байта, не шифруется)] - - Инициирует первый connection и + etcp instance + г) Init запрос - заголовок 0x02 (со сбросом etcp сессии) или 0x04 (бес сброса): + [0x02/0x04] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low] [my publick key (32 байта, не шифруется)] + - Инициирует новый connection для tcp instance. если tcp instance нет (первое подключение) - создаёт. Между нодами только одно подключение, но можно добавлять каналы. - Публичный ключ отправляется в конце пакета без шифрования, чтобы получатель мог установить его и расшифровать остальную часть пакета д) Init подтверждение - заголовок 0x03: - [0x03] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low] + [0x03] [my_node_id 64bit] [my mtu high] [my mty low] - Подтверждение инициализации - г) Channel init запрос: - [0x04] [my_node_id 64bit] [keepalive high] [keepalive low] - - Инициирует новый connection в существующем etcp instance - - д) Channel init подтверждение - заголовок 0x05: - [0x05] [my_node_id 64bit] [my publick key (32 байта, не шифруется)] - - Подтверждение иниуиализации дополнительного канала - е) Reset запрос: [0x06] - отправляется в ответ отправителю, если соединение не инициализировано и получен пакет не init (0x02, 0x03) diff --git a/src/etcp_sockets.h b/src/etcp_sockets.h deleted file mode 100644 index c49b6234..00000000 --- a/src/etcp_sockets.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef ETCP_SOCKET_H -#define ETCP_SOCKET_H - -#include "packet_buffer.h" -#include -#include -#include -#include - -// Forward declarations -struct ETCP_CONN; - -// ETCP Socket - интегрированный UDP сокет с ETCP функциональностью -struct ETCP_SOCKET { - int fd; // Файловый дескриптор UDP сокета - struct sockaddr_storage local_addr; // Локальный адрес - socklen_t local_addr_len; // Длина локального адреса - - struct ETCP_CONN* etcp; // Родительский ETCP instance - uint32_t socket_id; // Уникальный ID сокета - - // Callback для получения данных - void (*recv_callback)(struct ETCP_SOCKET* sock, struct packet_buffer* pkt, void* user_data); - void* recv_user_data; // User data для callback -}; - -typedef void (*etcp_socket_recv_cb)(struct ETCP_SOCKET* sock, - struct packet_buffer* pkt, - void* user_data); - -#endif // ETCP_SOCKET_H diff --git a/src/memory_pool.c b/src/memory_pool.c deleted file mode 100644 index 8289ecbb..00000000 --- a/src/memory_pool.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "memory_pool.h" -#include -#include - -// Инициализировать пул памяти -void memory_pool_init(struct memory_pool* pool, size_t object_size) { - pool->object_size = object_size; - pool->free_count = 0; - pool->allocations = 0; - pool->reuse_count = 0; - memset(pool->free_list, 0, sizeof(pool->free_list)); -} - -// Выделить объект из пула или из malloc -void* memory_pool_alloc(struct memory_pool* pool) { - pool->allocations++; - - // Если есть свободные объекты в пуле, использовать их - if (pool->free_count > 0) { - pool->free_count--; - pool->reuse_count++; - void* obj = pool->free_list[pool->free_count]; - pool->free_list[pool->free_count] = NULL; - return obj; - } - - // Иначе выделить через malloc - return malloc(pool->object_size); -} - -// Освободить объект в пул или в free -void memory_pool_free(struct memory_pool* pool, void* obj) { - if (!obj) return; - - // Если пул не заполнен, сохранить объект для повторного использования - if (pool->free_count < MEMORY_POOL_SIZE) { - pool->free_list[pool->free_count] = obj; - pool->free_count++; - return; - } - - // Иначе освободить через free - free(obj); -} - -// Получить статистику пула -void memory_pool_get_stats(struct memory_pool* pool, size_t* allocations, size_t* reuse_count) { - if (allocations) *allocations = pool->allocations; - if (reuse_count) *reuse_count = pool->reuse_count; -} - -// Очистить пул памяти -void memory_pool_destroy(struct memory_pool* pool) { - // Освободить все объекты в пуле - for (int i = 0; i < pool->free_count; i++) { - if (pool->free_list[i]) { - free(pool->free_list[i]); - pool->free_list[i] = NULL; - } - } - pool->free_count = 0; -} \ No newline at end of file diff --git a/src/memory_pool.h b/src/memory_pool.h deleted file mode 100644 index b379ccb1..00000000 --- a/src/memory_pool.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MEMORY_POOL_H -#define MEMORY_POOL_H - -#include // для size_t - -// Размер пула для объектов одинакового размера -#define MEMORY_POOL_SIZE 64 - -// Структура пула памяти для оптимизации аллокаций -struct memory_pool { - void* free_list[MEMORY_POOL_SIZE]; // Список свободных блоков - int free_count; // Количество свободных блоков - size_t object_size; // Размер объектов в пуле - size_t allocations; // Статистика: всего аллокаций - size_t reuse_count; // Статистика: повторное использование -}; - -// Тип пула памяти -typedef struct memory_pool memory_pool_t; - -// Инициализировать пул памяти -void memory_pool_init(struct memory_pool* pool, size_t object_size); - -// Выделить объект из пула или из malloc -void* memory_pool_alloc(struct memory_pool* pool); - -// Освободить объект в пул или в free -void memory_pool_free(struct memory_pool* pool, void* obj); - -// Получить статистику пула -void memory_pool_get_stats(struct memory_pool* pool, size_t* allocations, size_t* reuse_count); - -// Очистить пул памяти -void memory_pool_destroy(struct memory_pool* pool); - -#endif // MEMORY_POOL_H \ No newline at end of file diff --git a/src/packet_buffer.h b/src/packet_buffer.h deleted file mode 100644 index 09550103..00000000 --- a/src/packet_buffer.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef PACKET_BUFFER_H -#define PACKET_BUFFER_H - -#include -#include -#include -#include - - -// Стадии обработки пакета -typedef enum { - PACKET_STAGE_RX_SOCKET, // Получен из сокета (зашифрован) - PACKET_STAGE_RX_DECRYPTED, // Расшифрован (plain-text) - PACKET_STAGE_RX_ETCP, // Обработан ETCP (собран фрагмент) - PACKET_STAGE_RX_APP, // Передан в приложение - PACKET_STAGE_TX_APP, // Из приложения на отправку - PACKET_STAGE_TX_ETCP, // Обработан ETCP (фрагментирован) - PACKET_STAGE_TX_ENCRYPTED // Зашифрован, готов к отправке -} packet_stage_t; - -// Флаги пакета -#define PACKET_FLAG_ENCRYPTED (1 << 0) -#define PACKET_FLAG_FRAGMENTED (1 << 1) -#define PACKET_FLAG_RETRANSMIT (1 << 2) -#define PACKET_FLAG_CONTROL (1 << 3) // Служебный пакет (RST, INIT) - -// Размеры -#define PACKET_METADATA_SIZE 64 -#define PACKET_DATA_SIZE 1536 -#define PACKET_TOTAL_SIZE 1600 -#define PACKET_POOL_SIZE 64 - -// Основная структура пакета -struct packet_buffer { - - // Метаданные (64 байта) - struct { - struct ETCP_SOCKET* s; // Сокет через который получен/ планируется отправить - struct etcp_channel* channel; // Канал ETCP (NULL до поиска) - struct sockaddr_storage remote_addr;// Адрес удаленного endpoint - uint64_t timestamp_us; // Время создания пакета - uint16_t data_len; // Длина данных в буфере - uint8_t stage; // Стадия обработки пакета - } metadata; - struct packet_buffer* next_free; // Для пула - используется только когда пакет свободен - - uint8_t data[0]; // Данные (variable size) - -}; - -// Инлайн функции для удобного доступа - -// Доступ к данным -static inline uint8_t* packet_data(struct packet_buffer* pkt) { - return pkt->data; -} - -static inline struct sockaddr* packet_remote_addr(struct packet_buffer* pkt) { - return (struct sockaddr*)&pkt->metadata.remote_addr; -} - -static inline uint16_t packet_remote_port(const struct packet_buffer* pkt) { - if (pkt->metadata.remote_addr.ss_family == AF_INET) { - return ((struct sockaddr_in*)&pkt->metadata.remote_addr)->sin_port; - } - return 0; -} - -// Инициализация -static inline void packet_init(struct packet_buffer* pkt) { - memset(&pkt->metadata, 0, sizeof(pkt->metadata)); - pkt->metadata.timestamp_us = 0; // TODO: get current time - pkt->metadata.stage = PACKET_STAGE_RX_SOCKET; -} - -#endif // PACKET_BUFFER_H \ No newline at end of file diff --git a/src/packet_pool.c b/src/packet_pool.c deleted file mode 100644 index bd1be347..00000000 --- a/src/packet_pool.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "packet_pool.h" -#include "packet_buffer.h" -#include -#include -#include - -void packet_pool_init(struct packet_pool* pool) { - pool->free_count = 0; - pool->allocations = 0; - pool->reuse_count = 0; - pool->overflow_count = 0; - memset(pool->free_list, 0, sizeof(pool->free_list)); - - // Предварительно аллоцируем пакеты - for (int i = 0; i < PACKET_POOL_SIZE / 2; i++) { - struct packet_buffer* pkt = calloc(1, PACKET_TOTAL_SIZE); - if (pkt) { - pool->free_list[pool->free_count++] = pkt; - } - } -} - -struct packet_buffer* packet_pool_get(struct packet_pool* pool) { - pool->allocations++; - - // Если есть свободные пакеты в пуле, использовать их - if (pool->free_count > 0) { - pool->reuse_count++; - pool->free_count--; - struct packet_buffer* pkt = pool->free_list[pool->free_count]; - pool->free_list[pool->free_count] = NULL; - - // Инициализировать метаданные - packet_init(pkt); - pkt->next_free = NULL; - - return pkt; - } - - // Иначе выделить через malloc - pool->overflow_count++; - struct packet_buffer* pkt = calloc(1, PACKET_TOTAL_SIZE); - if (pkt) { - packet_init(pkt); - } - - return pkt; -} - -void packet_pool_put(struct packet_pool* pool, struct packet_buffer* pkt) { - if (!pkt) return; - - // Если пул не заполнен, сохранить пакет для повторного использования - if (pool->free_count < PACKET_POOL_SIZE) { - pool->free_list[pool->free_count] = pkt; - pool->free_count++; - return; - } - - // Иначе освободить через free (переполнение) - free(pkt); -} - -void packet_pool_get_stats(const struct packet_pool* pool, - size_t* allocations, - size_t* reuse_count, - size_t* overflow_count) { - if (allocations) *allocations = pool->allocations; - if (reuse_count) *reuse_count = pool->reuse_count; - if (overflow_count) *overflow_count = pool->overflow_count; -} - -void packet_pool_destroy(struct packet_pool* pool) { - // Освободить все пакеты в пуле - for (int i = 0; i < pool->free_count; i++) { - if (pool->free_list[i]) { - free(pool->free_list[i]); - pool->free_list[i] = NULL; - } - } - pool->free_count = 0; - pool->allocations = 0; - pool->reuse_count = 0; - pool->overflow_count = 0; -} \ No newline at end of file diff --git a/src/packet_pool.h b/src/packet_pool.h deleted file mode 100644 index c08dc99a..00000000 --- a/src/packet_pool.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef PACKET_POOL_H -#define PACKET_POOL_H - -#include "packet_buffer.h" - -// Размер пула пакетов -#define PACKET_POOL_SIZE 64 - -struct packet_pool { - struct packet_buffer* free_list[PACKET_POOL_SIZE]; // Список свободных пакетов - int free_count; // Количество свободных пакетов - size_t allocations; // Всего аллокаций - size_t reuse_count; // Повторное использование - size_t overflow_count; // Переполнения пула -}; - -// Инициализация пула -void packet_pool_init(struct packet_pool* pool); - -// Получить пакет из пула -struct packet_buffer* packet_pool_get(struct packet_pool* pool); - -// Вернуть пакет в пул -void packet_pool_put(struct packet_pool* pool, struct packet_buffer* pkt); - -// Получить статистику -void packet_pool_get_stats(const struct packet_pool* pool, - size_t* allocations, - size_t* reuse_count, - size_t* overflow_count); - -// Очистить пул и освободить всю память -void packet_pool_destroy(struct packet_pool* pool); - -#endif // PACKET_POOL_H \ No newline at end of file diff --git a/src/secure_channel.c b/src/secure_channel.c index ac0fed27..3719b2f8 100644 --- a/src/secure_channel.c +++ b/src/secure_channel.c @@ -68,7 +68,7 @@ static int sc_validate_key(const uint8_t *public_key) return uECC_valid_public_key(public_key, curve); } -sc_status_t sc_generate_keypair(sc_context_t *ctx) +sc_status_t sc_generate_keypair(struct SC_MYKEYS *ctx) { if (!ctx) { return SC_ERR_INVALID_ARG; @@ -81,23 +81,25 @@ sc_status_t sc_generate_keypair(sc_context_t *ctx) /* Set custom RNG function */ uECC_set_rng(sc_rng); - if (!uECC_make_key(ctx->public_key, ctx->private_key, curve)) { + if (!uECC_make_key(ctx->pk->public_key, ctx->pk->private_key, curve)) { return SC_ERR_CRYPTO; } - - ctx->initialized = 1; - ctx->peer_key_set = 0; - ctx->session_ready = 0; - ctx->tx_counter = 0; - ctx->rx_counter = 0; - return SC_OK; } -sc_status_t sc_init_local_keys(sc_context_t *ctx, - const uint8_t *public_key, - const uint8_t *private_key) -{ +// Конвертация hex строки в бинарный формат +static int hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) { + if (!hex_str || !binary || strlen(hex_str) != binary_len * 2) return -1; + + for (size_t i = 0; i < binary_len; i++) { + unsigned int byte; + if (sscanf(hex_str + i * 2, "%2x", &byte) != 1) return -1; + binary[i] = (uint8_t)byte; + } + return 0; +} + +sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, const char *private_key) { if (!ctx || !public_key || !private_key) { return SC_ERR_INVALID_ARG; } @@ -111,9 +113,14 @@ sc_status_t sc_init_local_keys(sc_context_t *ctx, return SC_ERR_INVALID_ARG; } - memcpy(ctx->public_key, public_key, SC_PUBKEY_SIZE); - memcpy(ctx->private_key, private_key, SC_PRIVKEY_SIZE); + if (hex_to_binary(public_key, mykeys->public_key, SC_PUBKEY_SIZE)) return SC_ERR_INVALID_ARG; + if (hex_to_binary(private_key, mykeys->private_key, SC_PRIVKEY_SIZE)) return SC_ERR_INVALID_ARG; + return SC_OK; +} + +sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys) { + ctx->pk=mykeys; ctx->initialized = 1; ctx->peer_key_set = 0; ctx->session_ready = 0; @@ -123,10 +130,14 @@ sc_status_t sc_init_local_keys(sc_context_t *ctx, return SC_OK; } -sc_status_t sc_set_peer_public_key(sc_context_t *ctx, - const uint8_t *peer_public_key) -{ +sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key_h, int mode) { uint8_t shared_secret[SC_SHARED_SECRET_SIZE]; + uint8_t peer_public_key[SC_PUBKEY_SIZE]; + + if (mode) { + if (hex_to_binary(peer_public_key_h, peer_public_key, SC_PUBKEY_SIZE)) return SC_ERR_INVALID_ARG; + } + else memcpy(peer_public_key, peer_public_key_h, SC_PUBKEY_SIZE); if (!ctx || !peer_public_key) { return SC_ERR_INVALID_ARG; diff --git a/src/secure_channel.h b/src/secure_channel.h index d20f6563..b4b4a6a9 100644 --- a/src/secure_channel.h +++ b/src/secure_channel.h @@ -27,12 +27,15 @@ typedef int sc_status_t; typedef struct secure_channel sc_context_t; -// Контекст защищенного канала -struct secure_channel { +struct SC_MYKEYS { /* Локальные ключи */ uint8_t private_key[SC_PRIVKEY_SIZE]; uint8_t public_key[SC_PUBKEY_SIZE]; + }; +// Контекст защищенного канала +struct secure_channel { + struct SC_MYKEYS* pk; /* Ключи пира (после key exchange) */ uint8_t peer_public_key[SC_PUBKEY_SIZE]; uint8_t session_key[SC_SESSION_KEY_SIZE]; /* Derived session key */ @@ -49,22 +52,13 @@ struct secure_channel { }; // Функции инициализации -sc_status_t sc_generate_keypair(sc_context_t *ctx); -sc_status_t sc_init_local_keys(sc_context_t *ctx, - const uint8_t *public_key, - const uint8_t *private_key); -sc_status_t sc_set_peer_public_key(sc_context_t *ctx, - const uint8_t *peer_public_key); +sc_status_t sc_init_ctx(sc_context_t *ctx, struct SC_MYKEYS *mykeys); +sc_status_t sc_generate_keypair(struct SC_MYKEYS *keys); +sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, const char *private_key); +sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const char *peer_public_key, int mode);// mode: 0-bin 1-hex key format // Криптографические операции -sc_status_t sc_encrypt(sc_context_t *ctx, - const uint8_t *plaintext, size_t plaintext_len, - uint8_t *ciphertext, size_t *ciphertext_len); - -sc_status_t sc_decrypt(sc_context_t *ctx, - const uint8_t *ciphertext, size_t ciphertext_len, - uint8_t *plaintext, size_t *plaintext_len); - -sc_status_t sc_derive_shared_key(sc_context_t *ctx); +sc_status_t sc_encrypt(sc_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len); +sc_status_t sc_decrypt(sc_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t *plaintext_len); #endif // SECURE_CHANNEL_H diff --git a/src/tun_if.c b/src/tun_if.c index 66c98051..3ac995a2 100644 --- a/src/tun_if.c +++ b/src/tun_if.c @@ -249,3 +249,82 @@ static uint32_t tun_get_dest_ip(const uint8_t *packet, size_t len) { memcpy(&dest_ip, packet + 16, 4); return dest_ip; } + +// Extract destination IPv4 address from packet +static uint32_t get_dest_ip(const uint8_t *packet, size_t len) { + if (len < 20) return 0; // Minimum IPv4 header size + // Check IP version (first nibble) + uint8_t version = (packet[0] >> 4) & 0x0F; + if (version != 4) return 0; + // Destination IP is at offset 16 + uint32_t dest_ip; + memcpy(&dest_ip, packet + 16, 4); + return dest_ip; +} + +/* +// Callback for TUN device read events +static void tun_read_callback(int fd, void* user_arg) { + struct UTUN_INSTANCE *instance = (struct UTUN_INSTANCE*)user_arg; + uint8_t buffer[MAX_PACKET_SIZE]; + + // Read from TUN device + ssize_t nread = tun_read(fd, buffer, sizeof(buffer)); + if (nread < 0) { + if (errno == EINTR) return; + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN: %s", strerror(errno)); + return; + } + + if (nread > 0) { + // Route packet based on destination IP + uint32_t dest_ip = get_dest_ip(buffer, nread); + struct route_entry route; + + if (routing_table_lookup(instance->routing_table, dest_ip, &route)) { + // Found route, send to next hop connection + if (route.next_hop) { + if (conn_send(route.next_hop, buffer, nread) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to send packet via route"); + } + } else { + // Local route - no forwarding needed + DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Local packet, no forwarding"); + } + } else { + // No route found, drop packet + char ip_str[16]; + ip_to_string(dest_ip, ip_str); + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "No route for destination IP %s", ip_str); + } + } +} + +// Register sockets with uasync +int utun_instance_register_sockets(struct UTUN_INSTANCE *instance) { + if (!instance || !instance->ua || instance->tun.fd < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Invalid instance or TUN fd"); + return -1; + } + + // Register TUN file descriptor + if (uasync_add_socket(instance->ua, instance->tun.fd, + tun_read_callback, NULL, NULL, instance) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket"); + return -1; + } + + DEBUG_INFO(DEBUG_CATEGORY_TUN, "Registered TUN socket (fd=%d)", instance->tun.fd); + return 0; +} + +// Unregister sockets +void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance) { + if (!instance || !instance->ua) return; + + if (instance->tun.fd >= 0) { + uasync_remove_socket(instance->ua, instance->tun.fd); + DEBUG_INFO(DEBUG_CATEGORY_TUN, "Unregistered TUN socket"); + } +} +*/ diff --git a/src/tun_if.h b/src/tun_if.h index c86c74f3..95f00ffe 100644 --- a/src/tun_if.h +++ b/src/tun_if.h @@ -10,6 +10,8 @@ extern "C" { #endif +#define MAX_PACKET_SIZE 1500 + // TUN interface configuration struct tun_config { char ifname[16]; // Interface name (e.g., "tun12") diff --git a/src/utun.c b/src/utun.c index b1b27863..ea23b2bc 100644 --- a/src/utun.c +++ b/src/utun.c @@ -36,7 +36,6 @@ utun instances: можно stop() - он ывзывает закрытие вс // Global wakeup pipe write fd for signal handler static int g_wakeup_pipe_write_fd = -1; -#define MAX_PACKET_SIZE 2048 #define DEFAULT_CONFIG "utun.conf" #define DEFAULT_PIDFILE "/var/run/utun.pid" @@ -231,13 +230,13 @@ static FILE* open_logfile(const char *logfile) { // Main function static volatile sig_atomic_t g_running = 1; -static struct UTUN_INSTANCE *g_instance = NULL; +struct UASYNC* main_ua = NULL; static void signal_handler(int sig) { (void)sig; g_running = 0; - if (g_instance && g_instance->ua) { - uasync_wakeup(g_instance->ua); + if (main_ua) { + uasync_wakeup(main_ua); } } @@ -249,9 +248,17 @@ int main(int argc, char *argv[]) { print_usage(argv[0]); return 0; } - + + // Create uasync instance + struct UASYNC* ua = uasync_create(); + main_ua=ua; + if (!ua) { + DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create uasync instance"); + return 1; + } + // Create and initialize instance - struct UTUN_INSTANCE *instance = utun_instance_create(args.config_file, args.log_file); + struct UTUN_INSTANCE *instance = utun_instance_create(ua, args.config_file, args.log_file); if (!instance) { fprintf(stderr, "Failed to create UTUN instance\n"); return 1; @@ -280,7 +287,6 @@ int main(int argc, char *argv[]) { signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); - g_instance = instance; // Daemonize if not in foreground if (!args.foreground) { @@ -296,16 +302,12 @@ int main(int argc, char *argv[]) { utun_instance_destroy(instance); return 1; } - - // Main event loop - FILE *log_fp = open_logfile(args.log_file); - fprintf(log_fp ? log_fp : stderr, "Starting main loop...\n"); - - while (g_running) { utun_instance_run(instance); if (instance->running == 0) break; - } - + + while (instance->running) uasync_poll(ua, 100); + // Cleanup - fprintf(log_fp ? log_fp : stderr, "Shutting down...\n"); + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Shutdown"); + utun_instance_unregister_sockets(instance); utun_instance_destroy(instance); remove_pidfile(args.pid_file); diff --git a/src/utun_fixes.c b/src/utun_fixes.c deleted file mode 100644 index cf8d3b56..00000000 --- a/src/utun_fixes.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "utun_instance.h" -#include "routing.h" -#include "etcp_connections.h" -#include "config_parser.h" -#include "../lib/u_async.h" - -conn_handle_t* route_get_next_hop(routing_table_t* rt, uint32_t dest_ip) { - route_entry_t route = {0}; - if (!rt || !routing_table_lookup(rt, dest_ip, &route)) return NULL; - return (conn_handle_t*)route.next_hop; -} - -static int add_default_route(struct UTUN_INSTANCE* *instance) { - if (!instance || !instance->routing_table || instance->connection_count == 0) return -1; - - route_entry_t default_route = {0}; - default_route.network = 0; // 0.0.0.0 - default_route.prefix_length = 0; - default_route.next_hop_ip = 0; - default_route.next_hop = (struct ETCP_CONNECTIONS*)instance->connections[0]->conns; - default_route.type = ROUTE_TYPE_STATIC; - default_route.flags = ROUTE_FLAG_ACTIVE; - default_route.created_time = 0; - - return routing_table_insert((routing_table_t*)instance->routing_table, &default_route) ? 0 : -1; -} - -void conn_destroy(conn_handle_t* conn); -int conn_send(conn_handle_t* conn, const uint8_t* data, size_t len); -uint32_t get_dest_ip(const uint8_t *packet, size_t len); -int parse_subnet(const char* subnet_str, uint32_t* network, uint8_t* prefix_len); - -conn_handle_t* route_find_connection(struct UTUN_INSTANCE** instance, uint32_t dest_ip) { - if (!instance || !instance->routing_table) return NULL; - - route_entry_t route = {0}; - if (!routing_table_lookup((routing_table_t*)instance->routing_table, dest_ip, &route)) { - return NULL; - } - - struct ETCP_CONNECTIONS* conns = route.next_hop; - if (!conns) return NULL; - - // Find matching connection handle - for (int i = 0; i < instance->connection_count; i++) { - if (instance->connections[i] && instance->connections[i]->conns == conns) { - return instance->connections[i]; - } - } - - return NULL; -} diff --git a/src/utun_instance.c b/src/utun_instance.c index f6ab03b4..f9b4ff12 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -14,24 +14,22 @@ #include #include -#define MAX_PACKET_SIZE 2048 - // Forward declarations static void tun_read_callback(int fd, void* user_arg); static uint32_t get_dest_ip(const uint8_t *packet, size_t len); -static void utun_instance_set(struct UTUN_INSTANCE *instance); // Global instance for signal handlers static struct UTUN_INSTANCE *g_instance = NULL; // Create and initialize root instance -struct UTUN_INSTANCE* utun_instance_create(const char *config_file, const char *log_file) { +struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config_file, const char *log_file) { struct UTUN_INSTANCE *instance = calloc(1, sizeof(struct UTUN_INSTANCE)); if (!instance) return NULL; // Initialize basic fields instance->running = 0; instance->log_fp = NULL; + instance->ua = ua; // Ensure keys and node_id exist in config if (config_ensure_keys_and_node_id(config_file) < 0) { @@ -55,22 +53,54 @@ struct UTUN_INSTANCE* utun_instance_create(const char *config_file, const char * DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to open log file %s: %s", log_file, strerror(errno)); } } + // Set node_id from config + instance->node_id = instance->config->global.my_node_id; - // Create uasync instance - instance->ua = uasync_create(); - if (!instance->ua) { - DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to create uasync instance"); - utun_instance_destroy(instance); - return NULL; + // Set my keys + sc_init_local_keys(&instance->my_keys, instance->config->global.my_public_key_hex, instance->config->global.my_private_key_hex); + + instance->pkt_pool=memory_pool_init(PACKET_DATA_SIZE+100); +/* + // Initialize TUN device + if (tun_create(&instance->tun) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device"); + return -1; } - // uasync has built-in wakeup mechanism, no need for manual pipe + // Configure TUN device + if (tun_set_ip(instance->tun.ifname, instance->config->global.tun_ip) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP"); + tun_close(&instance->tun); + return -1; + } - // Set node_id from config - instance->node_id = instance->config->global.my_node_id; + if (instance->config->global.mtu > 0) { + if (tun_set_mtu(instance->tun.ifname, instance->config->global.mtu) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU"); + tun_close(&instance->tun); + return -1; + } + } - // Set global instance - utun_instance_set(instance); + if (tun_set_up(instance->tun.ifname) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface"); + tun_close(&instance->tun); + return -1; + } + + // Create routing table + instance->routing_table = routing_table_create(); + if (!instance->routing_table) { + DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to create routing table"); + return -1; + } +*/ + // Initialize connections from configuration + if (init_connections(instance) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize connections"); + // Cleanup will be handled by utun_instance_destroy + return NULL; + } return instance; } @@ -93,12 +123,7 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) { // Cleanup connections if (instance->connections) { - for (int i = 0; i < instance->connection_count; i++) { - if (instance->connections[i]) { - conn_destroy(instance->connections[i]); - } - } - free(instance->connections); +// etcp_socket_remove(...) } // Cleanup TUN @@ -126,154 +151,15 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) { free(instance); } -// Initialize all components -int utun_instance_init(struct UTUN_INSTANCE *instance) { - if (!instance || !instance->config) return -1; - - // Initialize TUN device - if (tun_create(&instance->tun) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device"); - return -1; - } - - // Configure TUN device - if (tun_set_ip(instance->tun.ifname, instance->config->global.tun_ip) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP"); - tun_close(&instance->tun); - return -1; - } - - if (instance->config->global.mtu > 0) { - if (tun_set_mtu(instance->tun.ifname, instance->config->global.mtu) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU"); - tun_close(&instance->tun); - return -1; - } - } - - if (tun_set_up(instance->tun.ifname) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface"); - tun_close(&instance->tun); - return -1; - } - - // Create routing table - instance->routing_table = routing_table_create(); - if (!instance->routing_table) { - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "Failed to create routing table"); - return -1; - } - - // Initialize connections from configuration - if (init_connections(instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize connections"); - // Cleanup will be handled by utun_instance_destroy - return -1; - } - - return 0; -} - -// Start main event loop (single iteration) -void utun_instance_run(struct UTUN_INSTANCE *instance) { - if (!instance || !instance->ua) return; - - // Single iteration - returns after processing events or timeout - uasync_poll(instance->ua, 1000); // 100ms timeout -} - // Stop instance void utun_instance_stop(struct UTUN_INSTANCE *instance) { if (!instance) return; instance->running = 0; - // Wakeup main loop using built-in uasync wakeup if (instance->ua) { + memory_pool_destroy(instance->pkt_pool); uasync_wakeup(instance->ua); } -} - -// Global instance access -struct UTUN_INSTANCE* utun_instance_get(void) { - return g_instance; -} - -void utun_instance_set(struct UTUN_INSTANCE *instance) { - g_instance = instance; -} -// Extract destination IPv4 address from packet -static uint32_t get_dest_ip(const uint8_t *packet, size_t len) { - if (len < 20) return 0; // Minimum IPv4 header size - // Check IP version (first nibble) - uint8_t version = (packet[0] >> 4) & 0x0F; - if (version != 4) return 0; - // Destination IP is at offset 16 - uint32_t dest_ip; - memcpy(&dest_ip, packet + 16, 4); - return dest_ip; -} - -// Callback for TUN device read events -static void tun_read_callback(int fd, void* user_arg) { - struct UTUN_INSTANCE *instance = (struct UTUN_INSTANCE*)user_arg; - uint8_t buffer[MAX_PACKET_SIZE]; - - // Read from TUN device - ssize_t nread = tun_read(fd, buffer, sizeof(buffer)); - if (nread < 0) { - if (errno == EINTR) return; - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN: %s", strerror(errno)); - return; - } - - if (nread > 0) { - // Route packet based on destination IP - uint32_t dest_ip = get_dest_ip(buffer, nread); - struct route_entry route; - - if (routing_table_lookup(instance->routing_table, dest_ip, &route)) { - // Found route, send to next hop connection - if (route.next_hop) { - if (conn_send(route.next_hop, buffer, nread) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to send packet via route"); - } - } else { - // Local route - no forwarding needed - DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Local packet, no forwarding"); - } - } else { - // No route found, drop packet - char ip_str[16]; - ip_to_string(dest_ip, ip_str); - DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "No route for destination IP %s", ip_str); - } - } -} -// Register sockets with uasync -int utun_instance_register_sockets(struct UTUN_INSTANCE *instance) { - if (!instance || !instance->ua || instance->tun.fd < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Invalid instance or TUN fd"); - return -1; - } - - // Register TUN file descriptor - if (uasync_add_socket(instance->ua, instance->tun.fd, - tun_read_callback, NULL, NULL, instance) < 0) { - DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket"); - return -1; - } - - DEBUG_INFO(DEBUG_CATEGORY_TUN, "Registered TUN socket (fd=%d)", instance->tun.fd); - return 0; -} -// Unregister sockets -void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance) { - if (!instance || !instance->ua) return; - - if (instance->tun.fd >= 0) { - uasync_remove_socket(instance->ua, instance->tun.fd); - DEBUG_INFO(DEBUG_CATEGORY_TUN, "Unregistered TUN socket"); - } } diff --git a/src/utun_instance.h b/src/utun_instance.h index dca02f6f..6310fabc 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -4,14 +4,15 @@ #include #include #include +#include "../lib/memory_pool.h" +#include "secure_channel.h" #include "tun_if.h" // Forward declarations struct utun_config; struct uasync_s; struct routing_table; -struct ETCP_CONNECTIONS; -typedef struct ETCP_CONNECTIONS conn_handle_t; +struct ETCP_CONN; struct ETCP_SOCKET; // uTun instance configuration @@ -21,34 +22,33 @@ struct UTUN_INSTANCE { // TUN interface struct tun_config tun; - char tun_name[64]; - char tun_ip[64]; - char tun_ip_mask[64]; void *tun_socket_id; // Socket ID from uasync_add_socket // Identification uint64_t node_id; - + + struct SC_MYKEYS my_keys; + // Main async context - struct uasync_s *ua; + struct UASYNC* ua; // State int running; FILE *log_fp; - + + struct memory_pool* pkt_pool; // Routing struct routing_table *routing_table; // Connections - conn_handle_t **connections; - int connection_count; + struct ETCP_CONN* connections;// linked-list - // First listen socket - struct ETCP_SOCKET* first_listen_socket; + // Active sockets + struct ETCP_SOCKET* etcp_sockets;// linked-list }; // Functions -struct UTUN_INSTANCE* utun_instance_create(const char* config_file, const char* log_file); +struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char* config_file, const char* log_file); void utun_instance_destroy(struct UTUN_INSTANCE* instance); int utun_instance_init(struct UTUN_INSTANCE *instance); void utun_instance_run(struct UTUN_INSTANCE *instance); diff --git a/test_invalid_keys.conf b/test_invalid_keys.conf new file mode 100644 index 00000000..3178a701 --- /dev/null +++ b/test_invalid_keys.conf @@ -0,0 +1,19 @@ +[global] +my_private_key=8d893d54930fc1b428e17c3ef01f0eb7578fba00bc43f3b5260b30aace064c81 + +my_public_key=193ba8d4829818e2571789432ec065963ee364b1c524ba04902130e9a0961ab7 + +my_node_id=3e62f4ffc02efa41 + +tun_ip=10.0.0.1/24 +mtu=1500 +control_ip=127.0.0.1 +control_port=12345 +net_debug=0 + +[routing] +allowed_subnet=10.0.0.0/24 + +[server:test] +addr=192.168.0.10:1234 +netif=et \ No newline at end of file diff --git a/test_no_keys.conf b/test_no_keys.conf new file mode 100644 index 00000000..f80738fb --- /dev/null +++ b/test_no_keys.conf @@ -0,0 +1,16 @@ +[global] +tun_ip=10.0.0.1/24 +mtu=1500 +control_ip=127.0.0.1 +control_port=12345 +net_debug=0 + +my_node_id=338e13218f721d15 +my_private_key=ccb9f2ae2f348f7f8fc8618c58395c242107a802a1de5f674e81ecd03bfc7a0d +my_public_key=d12a4aa8d289b15264c47c867812620abab80890164b22e0f69918d696d91ccd +[routing] +allowed_subnet=10.0.0.0/24 + +[server:test] +addr=192.168.0.10:1234 +netif=eth0 diff --git a/tests/test_etcp_crypto b/tests/test_etcp_crypto new file mode 100755 index 0000000000000000000000000000000000000000..b35126691945df9dfbc1eaf288e177f039b2c251 GIT binary patch literal 360432 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⋙a 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

g|JQFh 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 literal 0 HcmV?d00001 diff --git a/tests/test_etcp_crypto.c b/tests/test_etcp_crypto.c new file mode 100644 index 00000000..40ac2063 --- /dev/null +++ b/tests/test_etcp_crypto.c @@ -0,0 +1,213 @@ +// test_etcp_crypto.c - Test ETCP encryption/decryption with secure channel +#include "etcp.h" +#include "config_parser.h" +#include "secure_channel.h" +#include "etcp_connections.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// Test configuration +#define TEST_PORT 32345 +#define CLIENT_PORT 32346 +#define TEST_DATA "Hello, encrypted world!" +#define TEST_DATA_LEN 23 + +// Helper: create UDP socket bound to port +static int create_udp_socket(int port) { + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) return -1; + + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + + if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + close(fd); + return -1; + } + + return fd; +} + +// Helper: generate test keys +static void generate_test_keys(uint8_t* server_priv, uint8_t* server_pub, + uint8_t* client_priv, uint8_t* client_pub) { + // Use fixed test keys for reproducibility + const char* server_priv_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + const char* server_pub_hex = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"; + const char* client_priv_hex = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"; + const char* client_pub_hex = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"; + + for (int i = 0; i < 32; i++) { + sscanf(server_priv_hex + i*2, "%2hhx", &server_priv[i]); + sscanf(server_pub_hex + i*2, "%2hhx", &server_pub[i]); + sscanf(client_priv_hex + i*2, "%2hhx", &client_priv[i]); + sscanf(client_pub_hex + i*2, "%2hhx", &client_pub[i]); + } +} + +// Helper: hex to binary +static int hex_to_bin(const char* hex, uint8_t* bin, size_t len) { + if (strlen(hex) != len * 2) return -1; + for (size_t i = 0; i < len; i++) { + if (sscanf(hex + i*2, "%2hhx", &bin[i]) != 1) return -1; + } + return 0; +} + +int main(void) { + printf("=== ETCP Crypto Test ===\n"); + + // Generate test keys + uint8_t server_priv[32], server_pub[32]; + uint8_t client_priv[32], client_pub[32]; + generate_test_keys(server_priv, server_pub, client_priv, client_pub); + + // Create UDP sockets + int server_fd = create_udp_socket(TEST_PORT); + int client_fd = create_udp_socket(CLIENT_PORT); + if (server_fd < 0 || client_fd < 0) { + printf("ERROR: Failed to create sockets\n"); + return 1; + } + + // Create ETCP instances + struct ETCP_CONN* server_etcp = calloc(1, sizeof(struct ETCP_CONN)); + struct ETCP_CONN* client_etcp = calloc(1, sizeof(struct ETCP_CONN)); + if (!server_etcp || !client_etcp) { + printf("ERROR: Failed to allocate ETCP instances\n"); + return 1; + } + + // Initialize secure channels + server_etcp->crypto_ctx = calloc(1, sizeof(sc_context_t)); + client_etcp->crypto_ctx = calloc(1, sizeof(sc_context_t)); + if (!server_etcp->crypto_ctx || !client_etcp->crypto_ctx) { + printf("ERROR: Failed to allocate crypto contexts\n"); + return 1; + } + + // Set keys + memcpy(server_etcp->crypto_ctx->private_key, server_priv, 32); + memcpy(server_etcp->crypto_ctx->public_key, server_pub, 32); + server_etcp->crypto_ctx->initialized = 1; + + memcpy(client_etcp->crypto_ctx->private_key, client_priv, 32); + memcpy(client_etcp->crypto_ctx->public_key, client_pub, 32); + client_etcp->crypto_ctx->initialized = 1; + + // Client sets server's public key as peer + memcpy(client_etcp->peer_public_key, server_pub, 32); + client_etcp->has_peer_key = 1; + sc_set_peer_public_key(client_etcp->crypto_ctx, server_pub); + + // Server will get client's public key from INIT packet + + // Create connections managers + struct ETCP_CONNECTIONS* server_conns = etcp_connections_init(server_etcp, "127.0.0.1", 0); + struct ETCP_CONNECTIONS* client_conns = etcp_connections_init(client_etcp, "127.0.0.1", 0); + if (!server_conns || !client_conns) { + printf("ERROR: Failed to create connections\n"); + return 1; + } + + // Create client link (client initiates connection) + struct sockaddr_in server_addr; + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + server_addr.sin_port = htons(TEST_PORT); + + struct ETCP_LINK* client_link = etcp_link_new(client_etcp, &client_conns->socket, client_conns, + (struct sockaddr*)&server_addr, sizeof(server_addr)); + if (!client_link) { + printf("ERROR: Failed to create client link\n"); + return 1; + } + + // Send INIT from client to server + printf("Sending INIT from client...\n"); + if (etcp_link_send_init(client_link, 1500, 30) < 0) { + printf("ERROR: Failed to send INIT\n"); + return 1; + } + + // Server should receive INIT and create link + usleep(100000); // 100ms + + struct sockaddr_in from_addr; + socklen_t from_len = sizeof(from_addr); + uint8_t buffer[2048]; + ssize_t received = recvfrom(server_fd, buffer, sizeof(buffer), MSG_DONTWAIT, + (struct sockaddr*)&from_addr, &from_len); + + if (received > 0) { + printf("Server received %zd bytes\n", received); + + // Process packet on server + struct packet_buffer pkt; + memcpy(pkt.data, buffer, received); + pkt.metadata.data_len = received; + pkt.metadata.remote_addr = *(struct sockaddr_storage*)&from_addr; + pkt.metadata.s = &server_conns->socket; + + if (etcp_input(&pkt, &server_conns->socket, server_conns) == 0) { + printf("Server processed INIT successfully\n"); + + // Check that server got client's public key + if (server_etcp->has_peer_key) { + printf("Server received client's public key\n"); + } + } + } + + // Test encrypted data transfer + printf("\nTesting encrypted data transfer...\n"); + + const char* test_data = TEST_DATA; + if (etcp_link_send(client_etcp, client_link, (const uint8_t*)test_data, TEST_DATA_LEN) == 0) { + printf("Client sent encrypted data\n"); + } + + usleep(100000); + + received = recvfrom(server_fd, buffer, sizeof(buffer), MSG_DONTWAIT, + (struct sockaddr*)&from_addr, &from_len); + if (received > 0) { + printf("Server received %zd encrypted bytes\n", received); + // In real scenario, etcp_input would decrypt and process + } + + // Print statistics + printf("\n=== Statistics ===\n"); + size_t enc_err, dec_err, send_err, total_enc, total_dec; + etcp_connections_get_crypto_stats(server_conns, &enc_err, &dec_err, &send_err, NULL, &total_enc, &total_dec); + printf("Server: encrypted=%zu, decrypted=%zu, errors=%zu/%zu/%zu\n", + total_enc, total_dec, enc_err, dec_err, send_err); + + etcp_connections_get_crypto_stats(client_conns, &enc_err, &dec_err, &send_err, NULL, &total_enc, &total_dec); + printf("Client: encrypted=%zu, decrypted=%zu, errors=%zu/%zu/%zu\n", + total_enc, total_dec, enc_err, dec_err, send_err); + + // Cleanup + close(server_fd); + close(client_fd); + free(server_etcp->crypto_ctx); + free(client_etcp->crypto_ctx); + free(server_etcp); + free(client_etcp); + + printf("\n=== Test completed ===\n"); + return 0; +} diff --git a/tests/test_etcp_crypto_fix b/tests/test_etcp_crypto_fix new file mode 100755 index 0000000000000000000000000000000000000000..aca281902d12431f29ef3f657b65b8606c630b5b GIT binary patch literal 360616 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 +#include +#include +#include +#include +#include +#include +#include + +// Test configuration +#define TEST_PORT 42345 +#define CLIENT_PORT 42346 +#define TEST_DATA "Hello, encrypted world!" +#define TEST_DATA_LEN 23 + +// Helper: create UDP socket bound to port +static int create_udp_socket(int port) { + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) return -1; + + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + + if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + close(fd); + return -1; + } + + return fd; +} + +// Helper: generate test keys +static void generate_test_keys(uint8_t* server_priv, uint8_t* server_pub, + uint8_t* client_priv, uint8_t* client_pub) { + // Use fixed test keys for reproducibility + const char* server_priv_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + const char* server_pub_hex = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"; + const char* client_priv_hex = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"; + const char* client_pub_hex = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"; + + for (int i = 0; i < 32; i++) { + sscanf(server_priv_hex + i*2, "%2hhx", &server_priv[i]); + sscanf(server_pub_hex + i*2, "%2hhx", &server_pub[i]); + sscanf(client_priv_hex + i*2, "%2hhx", &client_priv[i]); + sscanf(client_pub_hex + i*2, "%2hhx", &client_pub[i]); + } +} + +// Helper: hex to binary +static int hex_to_bin(const char* hex, uint8_t* bin, size_t len) { + if (strlen(hex) != len * 2) return -1; + for (size_t i = 0; i < len; i++) { + if (sscanf(hex + i*2, "%2hhx", &bin[i]) != 1) return -1; + } + return 0; +} + +int main(void) { + printf("=== ETCP Crypto Test ===\n"); + + // Generate test keys + uint8_t server_priv[32], server_pub[32]; + uint8_t client_priv[32], client_pub[32]; + generate_test_keys(server_priv, server_pub, client_priv, client_pub); + + // Create UDP sockets + int server_fd = create_udp_socket(TEST_PORT); + int client_fd = create_udp_socket(CLIENT_PORT); + if (server_fd < 0 || client_fd < 0) { + printf("ERROR: Failed to create sockets\n"); + return 1; + } + + // Create ETCP instances + struct ETCP_CONN* server_etcp = calloc(1, sizeof(struct ETCP_CONN)); + struct ETCP_CONN* client_etcp = calloc(1, sizeof(struct ETCP_CONN)); + if (!server_etcp || !client_etcp) { + printf("ERROR: Failed to allocate ETCP instances\n"); + return 1; + } + + // Initialize secure channels + server_etcp->crypto_ctx = calloc(1, sizeof(sc_context_t)); + client_etcp->crypto_ctx = calloc(1, sizeof(sc_context_t)); + if (!server_etcp->crypto_ctx || !client_etcp->crypto_ctx) { + printf("ERROR: Failed to allocate crypto contexts\n"); + return 1; + } + + // Set keys + memcpy(server_etcp->crypto_ctx->private_key, server_priv, 32); + memcpy(server_etcp->crypto_ctx->public_key, server_pub, 32); + server_etcp->crypto_ctx->initialized = 1; + + memcpy(client_etcp->crypto_ctx->private_key, client_priv, 32); + memcpy(client_etcp->crypto_ctx->public_key, client_pub, 32); + client_etcp->crypto_ctx->initialized = 1; + + // Client sets server's public key as peer + memcpy(client_etcp->peer_public_key, server_pub, 32); + client_etcp->has_peer_key = 1; + sc_set_peer_public_key(client_etcp->crypto_ctx, server_pub); + + // Server will get client's public key from INIT packet + + // Create connections managers + struct ETCP_CONNECTIONS* server_conns = etcp_connections_init(server_etcp, "127.0.0.1", 0); + struct ETCP_CONNECTIONS* client_conns = etcp_connections_init(client_etcp, "127.0.0.1", 0); + if (!server_conns || !client_conns) { + printf("ERROR: Failed to create connections\n"); + return 1; + } + + // Create client link (client initiates connection) + struct sockaddr_in server_addr; + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + server_addr.sin_port = htons(TEST_PORT); + + struct ETCP_LINK* client_link = etcp_link_new(client_etcp, &client_conns->socket, client_conns, + (struct sockaddr*)&server_addr, sizeof(server_addr)); + if (!client_link) { + printf("ERROR: Failed to create client link\n"); + return 1; + } + + // Send INIT from client to server + printf("Sending INIT from client...\n"); + if (etcp_link_send_init(client_link, 1500, 30) < 0) { + printf("ERROR: Failed to send INIT\n"); + return 1; + } + + // Server should receive INIT and create link + usleep(100000); // 100ms + + struct sockaddr_in from_addr; + socklen_t from_len = sizeof(from_addr); + uint8_t buffer[2048]; + ssize_t received = recvfrom(server_fd, buffer, sizeof(buffer), MSG_DONTWAIT, + (struct sockaddr*)&from_addr, &from_len); + + if (received > 0) { + printf("Server received %zd bytes\n", received); + + // Process packet on server - use packet pool + struct packet_buffer* pkt = packet_pool_get(&server_etcp->packet_pool); + if (pkt) { + memcpy(packet_data(pkt), buffer, received); + pkt->metadata.data_len = received; + pkt->metadata.remote_addr = *(struct sockaddr_storage*)&from_addr; + pkt->metadata.s = &server_conns->socket; + + if (etcp_input(pkt, &server_conns->socket, server_conns) == 0) { + printf("Server processed INIT successfully\n"); + + // Check that server got client's public key + if (server_etcp->has_peer_key) { + printf("Server received client's public key\n"); + } + } + + packet_pool_put(&server_etcp->packet_pool, pkt); + } + } + + // Test encrypted data transfer + printf("\nTesting encrypted data transfer...\n"); + + const char* test_data = TEST_DATA; + if (etcp_link_send(client_etcp, client_link, (const uint8_t*)test_data, TEST_DATA_LEN) == 0) { + printf("Client sent encrypted data\n"); + } + + usleep(100000); + + received = recvfrom(server_fd, buffer, sizeof(buffer), MSG_DONTWAIT, + (struct sockaddr*)&from_addr, &from_len); + if (received > 0) { + printf("Server received %zd encrypted bytes\n", received); + // In real scenario, etcp_input would decrypt and process + } + + // Print statistics + printf("\n=== Statistics ===\n"); + size_t enc_err, dec_err, send_err, total_enc, total_dec; + etcp_connections_get_crypto_stats(server_conns, &enc_err, &dec_err, &send_err, NULL, &total_enc, &total_dec); + printf("Server: encrypted=%zu, decrypted=%zu, errors=%zu/%zu/%zu\n", + total_enc, total_dec, enc_err, dec_err, send_err); + + etcp_connections_get_crypto_stats(client_conns, &enc_err, &dec_err, &send_err, NULL, &total_enc, &total_dec); + printf("Client: encrypted=%zu, decrypted=%zu, errors=%zu/%zu/%zu\n", + total_enc, total_dec, enc_err, dec_err, send_err); + + // Cleanup + close(server_fd); + close(client_fd); + free(server_etcp->crypto_ctx); + free(client_etcp->crypto_ctx); + free(server_etcp); + free(client_etcp); + + printf("\n=== Test completed ===\n"); + return 0; +} diff --git a/utun_test_backup.conf b/utun_test_backup.conf new file mode 100755 index 00000000..6e89ab42 --- /dev/null +++ b/utun_test_backup.conf @@ -0,0 +1,42 @@ +[global] +my_private_key=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +my_public_key=abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 +my_node_id=babababa1123 # 64bit ID +option=value1,value2 +tun_ip=10.0.0.1 +mtu=1500 # MTU for all connections (0 = use default 1500) +control_ip=127.0.0.1 +control_port=12345 +net_debug=0 + +[routing] +allowed_subnet=10.0.0.0/24 +allowed_subnet=10.22.0.0/16 +allowed_subnet=10.23.0.0/16 +my_subnet=10.23.5.0/24 +my_subnet=10.23.6.0/24 + +# мои адреса и каналы +[server: wired1_fast] +addr=192.168.0.10:1234 +so_mark=100 +netif=eth0 +type=nat # public / nat / private + +[server: wireless_bkp] +addr=192.168.0.10:1234 +so_mark=100 +netif=eth0 +type=public # public / nat / private + +[client: client_test1] + +# линки +link=wired1_fast:192.168.0.20:1234 +link=wired1_fast:1.2.3.4:1234 +link=wireless_bkp:192.168.0.20:1234 +link=wireless_bkp:1.2.3.4:1234 + +#keepalive после ресета etcp передаём серверу +keepalive=1 +peer_public_key=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef