Filter both directions of the main TUN and remove obsolete firewall guide
This commit is contained in:
1 parent
cf6c3c99e8
commit
5de0eb5115
3 files changed
+42
-51
No files matched your search
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user