Filter both directions of the main TUN and remove obsolete firewall guide

This commit is contained in:
evgeny committed 2026-10-21 19:49:32 +02:00
1 parent cf6c3c99e8
commit 5de0eb5115
3 files changed
+42 -51

No files matched your search

-28
View File
@@ -1,28 +0,0 @@
# Firewall rule engine
## 1. Назначение
Фильтр пакетов по IP/порту для входящего/исходящего трафика. Правила загружаются из конфига, сортируются по IP и порту, затем проверка идёт бинарным поиском. Используется для разрешения/запрета прохождения пакетов через туннель.
## 2. Как пользоваться
```c
struct firewall_ctx fw;
fw_init(&fw);
fw_load_rules(&fw, &global_cfg);
if (fw_check(&fw, ip_host, port)) { /* пакет разрешён */ }
fw_free(&fw);
```
Правила задаются в конфиге в секции `[firewall]`:
- `rule = ip port` — разрешить IP:port (port=0 — любой порт)
- `bypass_all = 1` — пропускать всё независимо от правил
Сортировка — по IP, затем по порту. При проверке: бинарный поиск по IP, затем линейный скан соседних записей с тем же IP для сверки порта. Правило с `port=0` означает любой порт для этого IP.
## 3. API
| Функция/Структура | Описание |
|---|---|
| `struct firewall_ctx` | Набор правил (`rules`), их количество (`count`), флаг `bypass_all` |
| `fw_init(ctx)` | Обнуление контекста |
| `fw_load_rules(ctx, cfg)` | Копирование правил из конфига, сортировка qsort, установка bypass_all |
| `fw_check(ctx, ip, port)` | Возвращает 1 если пакет разрешён (bypass_all=1 или IP+port есть в правилах), 0 — запрещён |
| `fw_free(ctx)` | Освобождение памяти, обнуление полей |
+38 -21
View File
@@ -56,31 +56,31 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_pkt: invalid arguments: instance=%p entry=%p entry->len=%zu",
(void*)instance, (void*)entry, entry ? entry->len : 0);
if (entry) {
queue_entry_free(entry);
queue_dgram_free(entry);
queue_entry_free(entry);
}
return;
}
if (!instance->rt) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_pkt: no route table");
queue_entry_free(entry);
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
if (!instance->tun) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_pkt: no TUN interface");
queue_entry_free(entry);
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
// Check packet data (skip cmd byte)
if (!entry->dgram || entry->len < 2) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: packet too small: len=%zu, expected >=2", entry->len);
queue_entry_free(entry);
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
@@ -92,18 +92,17 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
if (ip_len > TUN_MAX_PACKET_SIZE) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: packet too large: len=%zu max=%d, dropping",
ip_len, TUN_MAX_PACKET_SIZE);
queue_entry_free(entry);
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
// Extract destination IP
uint32_t dst_ip = extract_dst_ip(ip_data, ip_len);
if (dst_ip == 0) {
// DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: failed to extract dst IP: len=%zu first_byte=0x%02x, dropping",
// ip_len, ip_data ? ip_data[0] : 0);
queue_entry_free(entry);
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: invalid IPv4 destination, len=%zu first_byte=0x%02x", ip_len, ip_data[0]);
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
@@ -112,15 +111,17 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
// Multicast: 224.0.0.0 - 239.255.255.255
if (first_octet >= 224 && first_octet <= 239) {
queue_entry_free(entry);
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: multicast destination dropped");
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
// Broadcast: only 255.255.255.255 (limited broadcast)
if (dst_ip == 0xFFFFFFFF) {
queue_entry_free(entry);
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: broadcast destination dropped");
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
@@ -133,8 +134,8 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
if (!route) {
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: no route to %s, dropping", ip_to_str(&addr, AF_INET).str);
instance->dropped_packets++;
queue_entry_free(entry);
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
@@ -156,6 +157,17 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
return;
}
// Вход в основной TUN: правило назначения такое же, как при выходе из TUN.
int allowed = fw_check_packet(&instance->fw, ip_data, ip_len);
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Firewall: to TUN=%s src_node=%016llx result=%d",
instance->tun->ifname, (unsigned long long)src_node_id, allowed);
if (allowed <= 0) {
instance->dropped_packets++;
queue_dgram_free(entry);
queue_entry_free(entry);
return;
}
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_TRAFFIC)) {
char* packet_str = dump_ip_packet_to_buffer(ip_data, ip_len);
DEBUG_DEBUG(DEBUG_CATEGORY_TRAFFIC, "DUMP: %s", packet_str);
@@ -171,8 +183,6 @@ void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry, uint64_t
ip_to_str(&addr, AF_INET).str, put_err);
instance->dropped_packets++;
instance->routed_packets--;
queue_entry_free(entry);
queue_dgram_free(entry);
return;
}
}
@@ -184,8 +194,8 @@ static void routing_pkt_from_etcp_cb(struct ETCP_CONN* conn, struct ll_entry* pk
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "invalid arguments: conn=%p pkt=%p",
(void*)conn, (void*)pkt);
if (pkt) {
queue_entry_free(pkt);
queue_dgram_free(pkt);
queue_entry_free(pkt);
}
return;
}
@@ -194,16 +204,16 @@ static void routing_pkt_from_etcp_cb(struct ETCP_CONN* conn, struct ll_entry* pk
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "connection has no instance: conn=%p pkt_len=%zu",
(void*)conn, pkt->len);
queue_entry_free(pkt);
queue_dgram_free(pkt);
queue_entry_free(pkt);
return;
}
// Реальный отправитель — из [svc_id][src_node_id][dst_node_id][ip] (роутер встраивает src/dst)
if (pkt->len < ROUTER_SVC_HDR_SIZE + 1) {
if (!pkt->dgram || pkt->len < ROUTER_SVC_HDR_SIZE + 1) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing: short packet len=%u", pkt->len);
queue_entry_free(pkt);
queue_dgram_free(pkt);
queue_entry_free(pkt);
return;
}
uint64_t src_node_id;
@@ -227,10 +237,17 @@ static void routing_pkt_from_tun_cb(struct ll_queue* q, void* arg) {
struct ll_entry* pkt = queue_data_get(instance->tun->output_queue);
if (!pkt) return;
// Route packet (unified function handles everything)
// Source is the local node (TUN interface)
uint64_t src_node_id = instance->node_id;
route_pkt(instance, pkt, src_node_id);
// Выход из основного TUN проверяется до маршрутизации/отправки в ETCP.
int allowed = -1;
if (pkt->dgram && pkt->len > 1) allowed = fw_check_packet(&instance->fw, pkt->dgram + 1, pkt->len - 1);
else DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Firewall: malformed TUN entry, len=%u", pkt->len);
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Firewall: from TUN=%s result=%d", instance->tun->ifname, allowed);
if (allowed > 0) route_pkt(instance, pkt, instance->node_id);
else {
instance->dropped_packets++;
queue_dgram_free(pkt);
queue_entry_free(pkt);
}
// Resume callback for next packet
queue_resume_callback(instance->tun->output_queue);
+4 -2
View File
@@ -47,8 +47,10 @@ allow_all=0
#key=04c1cae041a8e6bfba5245f6669c73f0793d7f9929300a2ba2e123ca55260d6e474480056720d94f7f0836a4a472763a74aacbc487cc7a1b2b0e066b519400fe
[firewall]
#ограничиваем подключения к собственным ресурсам. по умолчанию всё запрещено. разрешаем доступ директивами:
# Firewall rules: allow=all, allow=IP or allow=IP:port
# Основной TUN: входящие и исходящие пакеты проверяются одинаково по IP/порту назначения.
# По умолчанию всё запрещено; ответы требуют своих разрешений. NAT/proxy TUN используют отдельные интерфейсы.
# allow=IP — все протоколы IP; allow=IP:port — TCP/UDP; :0 — весь IP. Подсети CIDR не поддерживаются.
# Фрагменты IPv4 требуют allow=IP или allow=all; разрешения одного порта недостаточно.
allow=all
#allow=192.168.1.100
#allow=10.0.0.50:443