From 53d41d5c620902f101fbaada8b0634ce6693be33 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 1 Jul 2026 18:53:23 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20use-after-free=20in=20route=20table=20?= =?UTF-8?q?=E2=80=94=20add=20route=5Fdelete=20before=20u=5Ffree=20in=20rou?= =?UTF-8?q?te=5Fbgp=5Fupdate=5Fmy=5Fnodeinfo=20and=20route=5Fbgp=5Fprocess?= =?UTF-8?q?=5Fnodeinfo,=20relax=20routes=5Foverlap=20to=20allow=20hierarch?= =?UTF-8?q?ical=20routes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: when bgp->local_node was reallocated (changed=1), old route entries remained with stale v_node_info pointing to freed memory. The freed memory got reused by a BGP peer's NODEINFO_Q, causing route_lookup to return wrong node_id (b3b2b1b0afaeadac instead of local), which then failed at etcp_route_send with 'no BGP route' and dropped packets to 10.23.2.1. Changes: - route_node.c: route_delete(old) before u_free + route_insert(new) after alloc - utun_instance.c: remove duplicate route_insert (now atomic inside function) - route_bgp.c: route_delete before freeing old peer NODEINFO_Q - route_lib.c: routes_overlap now rejects only exact prefix+network duplicates - tests/Makefile.am: add route_lib.o to test_route6_lib --- AGENTS.md | 2 +- readme.md | 27 +++++++++++++++++++++++++++ src/route_bgp.c | 1 + src/route_lib.c | 5 +---- src/route_node.c | 10 +++++++++- src/utun_instance.c | 3 +-- tests/Makefile.am | 1 + 7 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 readme.md diff --git a/AGENTS.md b/AGENTS.md index 9b25af0e..db8aa02d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -490,7 +490,7 @@ void lottie_animation_destroy(Lottie_Animation *anim); - **Commit Messages:** Use imperative mood, concise (50-72 chars) - **Language:** Mix of English (technical) and Russian (business logic) - **Tags:** Version tags follow vX.Y.Z format -- "cp" or "кп" in prompt = do commit and push (всех изменений на текущий момент, не откатывая) +- "cp" or "кп" in prompt = do commit and push (всех изменений на текущий момент, не откатывая). Запрещено откатывать "лишние" изменения сделаные вне сессии (если сильно надо - сделать бэкап). если нет дополнительных указаний - комить всё что изменилось как есть. ## Quick Start for New Features 1. Add new source file to `src/Makefile.am` under `utun_SOURCES` diff --git a/readme.md b/readme.md new file mode 100644 index 00000000..40abc118 --- /dev/null +++ b/readme.md @@ -0,0 +1,27 @@ +UTUN + +Идея: объединить узлы в единую локальную сеть. +Чтобы узлы сами находили оптимальные линки между собой, пробивали NAT где это можно, где нельзя - выбирали посредника с хорошей связью; чтобы подсто было добавлять новые узлы и адреса узлов сразу виделись во всей сети. + +Потенциальные варианты использования: + - локальная сеть. хочу объединить офис, сотрудников (включая их работчие подсети), телефоны, офисы, сервер доступа итд в одно адресное пространство. + - чат с файлообменником. узлы сети - это мемберы группы и одновременно сети. + - CDN. узлы - потребители контента - это мемберы сети, которые распространяют трафик. + +То есть задача utun - обеспечить связность группы узлов и адаптацию работы всей сети к подключению-отключении отдельных узлов. + +Механизмы: +1. Пробитие nat. +2. автообновление списка узлов и их адресов для подключения +3. шифрование трафика и маскировка handshake. + handshake просиходит без сигнатур по которым можно опреедлить тип сервиса, весь трафик выглядлит как случайный набор байт случайного размера +4. многоканальные подключения, агрегирование каналов, исключение мёртвых каналов + подключиться к узлу можно через несколько линков. UTUN будет объединять пропускную способность каналов, наблюдая за состоянием каналов, не допуская перегрузки и обеспечивая быстрые переповторы через другие каналы при потерях или большой задержке. +5. динамическая маршрутизация. Узлы могут назначать себе IP адреса и при подключении к сети анонсировать свои адреса/подсети. + это максимально упрощает добавление нового узла в сеть. +6. автоматический роутинг между узлами: узлы маршрутизируют трафик между собой. + используя статические подключения, прописанные в конфиге. +7. прямые подключения и поиск лучших подключений + узлы могут подключаться друг к другу напрямую, либо если оба узла за строгим NAT - выбирать оптимального посредника. + Узлы определяют свой тип подключения и NAT. Например у ростелеком - EIM NAT который можно использовать и для входящих подклюений. + Можно использовать IPv6. diff --git a/src/route_bgp.c b/src/route_bgp.c index f02d2be1..5e2beaaf 100644 --- a/src/route_bgp.c +++ b/src/route_bgp.c @@ -790,6 +790,7 @@ int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from, co if (need_alloc) { if (nodeinfo1) { + if (bgp->instance->rt) route_delete(bgp->instance->rt, nodeinfo1); queue_remove_data(bgp->nodes, &nodeinfo1->ll); queue_free(paths); queue_entry_free(&nodeinfo1->ll); diff --git a/src/route_lib.c b/src/route_lib.c index 92bd718c..941442dc 100644 --- a/src/route_lib.c +++ b/src/route_lib.c @@ -21,10 +21,7 @@ static uint32_t prefix_to_mask(uint8_t prefix) { } static bool routes_overlap(uint32_t net1, uint8_t pre1, uint32_t net2, uint8_t pre2) { - uint32_t mask1 = prefix_to_mask(pre1); - uint32_t mask2 = prefix_to_mask(pre2); - if ((net1 & mask2) == net2 && pre1 >= pre2) return true; - if ((net2 & mask1) == net1 && pre2 >= pre1) return true; + if (pre1 == pre2 && net1 == net2) return true; return false; } diff --git a/src/route_node.c b/src/route_node.c index 2640bdd6..274d891a 100644 --- a/src/route_node.c +++ b/src/route_node.c @@ -10,6 +10,7 @@ #include "config_parser.h" #include "route_node.h" #include "route_bgp.h" +#include "route_lib.h" #include "etcp_debug.h" static const uint8_t* node_dyn_start(const struct NODEINFO* info) { @@ -486,7 +487,10 @@ int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BG } if (changed) { - if (bgp->local_node) u_free(bgp->local_node); + if (bgp->local_node) { + if (instance->rt) route_delete(instance->rt, bgp->local_node); + u_free(bgp->local_node); + } bgp->local_node = u_calloc(1, sizeof(struct NODEINFO_Q) + dyn); if (!bgp->local_node) return -1; bgp->local_node->node.node_id = instance->node_id; @@ -608,6 +612,10 @@ int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BG DEBUG_INFO(DEBUG_CATEGORY_BGP, "my_nodeinfo updated: v4s=%d v4a=%d v6s=%d v6a=%d v4sub=%d v6sub=%d ver=%d", sock_count, addr_count, sock6_count, addr6_count, vc, vc6, bgp->local_node->node.ver); + if (instance->rt) { + if (!route_insert(instance->rt, bgp->local_node)) + DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_bgp_update_my_nodeinfo: failed to re-insert local routes after update"); + } } else { bgp->local_node->last_ver = bgp->local_node->node.ver; } diff --git a/src/utun_instance.c b/src/utun_instance.c index 114b267b..46fc89a6 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -126,8 +126,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u } else { DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized"); if (instance->rt && instance->bgp->local_node) { - route_bgp_update_my_nodeinfo(instance,instance->bgp); - if (route_insert(instance->rt,instance->bgp->local_node)) DEBUG_INFO(DEBUG_CATEGORY_ROUTING,"Added local routes"); else DEBUG_WARN(DEBUG_CATEGORY_ROUTING,"Failed to add local routes"); + route_bgp_update_my_nodeinfo(instance, instance->bgp); } } diff --git a/tests/Makefile.am b/tests/Makefile.am index 79df5c07..37df79eb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -209,6 +209,7 @@ test_radix_LDADD = $(COMMON_LIBS) test_route6_lib_SOURCES = test_route6_lib.c test_route6_lib_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib test_route6_lib_LDADD = $(top_builddir)/src/utun-route6_lib.o \ + $(top_builddir)/src/utun-route_lib.o \ $(top_builddir)/src/utun-route_node.o \ $(top_builddir)/src/utun-etcp_debug.o \ $(COMMON_LIBS)