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 00000000..b3512669 Binary files /dev/null and b/tests/test_etcp_crypto differ 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 00000000..aca28190 Binary files /dev/null and b/tests/test_etcp_crypto_fix differ diff --git a/tests/test_etcp_crypto_fix.c b/tests/test_etcp_crypto_fix.c new file mode 100644 index 00000000..a548c035 --- /dev/null +++ b/tests/test_etcp_crypto_fix.c @@ -0,0 +1,219 @@ +// 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 "packet_buffer.h" +#include "packet_pool.h" +#include +#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