Browse Source

Backup before fixing test_routing_mesh segfault

nodeinfo-routing-update
Evgeny 2 months ago
parent
commit
a5818d9cc4
  1. 29
      AGENTS.md
  2. 1080
      c_util
  3. 13
      doc/etcp_protocol.txt
  4. 55
      src/etcp_connections.c
  5. 7
      src/etcp_connections.h
  6. 2
      src/utun.c
  7. BIN
      tests/bench_uasync_timeouts
  8. 2
      utun_start.sh
  9. 2
      utun_stop.sh
  10. 2
      utun_stop1.sh
  11. BIN
      wintun.dll

29
AGENTS.md

@ -255,6 +255,7 @@ Crypto: Fixed CCM nonce size to 13 bytes, all crypto tests passing
- прежде чем вносить правки хорошо разберись как должно работать, просмотри все нужные функции полностью, нужно целостное понимание. - прежде чем вносить правки хорошо разберись как должно работать, просмотри все нужные функции полностью, нужно целостное понимание.
- при написании кода мысленно анализируй логику работы, думай как сделать проще и удобнее. Проверяй дубликаты и что уже есть, продумай логику до тех пор пока не будет полного понимания - при написании кода мысленно анализируй логику работы, думай как сделать проще и удобнее. Проверяй дубликаты и что уже есть, продумай логику до тех пор пока не будет полного понимания
- во всех блоках обработки ошибок/нештатных ситуаций должны быть сообщения DEBUG_ERROR/DEBUG_WARN - во всех блоках обработки ошибок/нештатных ситуаций должны быть сообщения DEBUG_ERROR/DEBUG_WARN
- тесты: запускаё все сразу (make check) - ошибок быть не должно. если что не такт смотри логи - каждый тест пишет лог.
Действия при поиске бага: Действия при поиске бага:
1. создать комит или бэкап всего что меняешь 1. создать комит или бэкап всего что меняешь
@ -290,30 +291,8 @@ Crypto: Fixed CCM nonce size to 13 bytes, all crypto tests passing
/doc/etcp_protocol.txt - основной протокол (похож на TCP+QUIC, поддеиживает шифрования, load balancing multi-link, работу а неустойчивых каналах, утилизацию полосы и недопущение перегрузки каналов связи) /doc/etcp_protocol.txt - основной протокол (похож на TCP+QUIC, поддеиживает шифрования, load balancing multi-link, работу а неустойчивых каналах, утилизацию полосы и недопущение перегрузки каналов связи)
- реализация в /src/etcp*.c/h - реализация в /src/etcp*.c/h
## Навигация по коду: c_util запуск utun от root (для tun) - /home/vnc1/proj/utun3/utun_start.sh
стоп utun: sudo /home/vnc1/proj/utun3/utun_stop1.sh
Скрипт для навигации по C-коду проекта. логи - utun.log
**Команды:**
```bash
# Оглавление проекта - все функции/структуры/enum с номерами строк
./c_util toc
# Показать сигнатуры с комментариями (по именам)
./c_util description <name1> [name2 ...]
# Показать полный код с номерами строк и checksum
./c_util show <name1> [name2 ...]
# Редактировать код с проверкой checksum
./c_util edit <file> <start_line> <checksum1> [checksum2 ...] <<'EOF'
<новый код>
EOF
```
**edit:** заменяет блок строк начиная с `start_line`. Проверяет контрольные суммы всех заменяемых строк (hex, 2 символа). При несовпадении - ошибка без изменений. Новый код автоматически форматируется с правильными отступами (табы/пробелы определяются из файла).
*Last updated: 2026-02-13 - c_util fully functional with toc/description/show/edit commands* *Last updated: 2026-02-13 - c_util fully functional with toc/description/show/edit commands*

1080
c_util

File diff suppressed because it is too large Load Diff

13
doc/etcp_protocol.txt

@ -10,15 +10,14 @@
1. берем пакет из списка неподтвержденных пакетов ожидающих отправку 1. берем пакет из списка неподтвержденных пакетов ожидающих отправку
2. если есть место в rwin (объём inflight данных) то берем очередной пакет из ETCP input_queue и его отправляем 2. если есть место в rwin (объём inflight данных) то берем очередной пакет из ETCP input_queue и его отправляем
если пакет найден: если пакет найден:
1. вызываем функцию формирования опциональных секций (ACK, RETRANS, channel timestamp) - они записываются в начало 1. вызываем функцию формирования опциональных секций (ACK, channel timestamp) - они записываются в начало
2. в конец добавляем секцию 0x00 с данными пакета 2. в конец добавляем секцию 0x00 с данными пакета
при отправке пакета помечаем в inflight списке с какого интерфейса он отправлен при отправке пакета помечаем в inflight списке с какого интерфейса он отправлен
Функция прикрепления опциональных секций: Функция прикрепления опциональных секций:
- запрашивает выбор канала передачи. - запрашивает выбор канала передачи.
- добавляет накопившиеся ACK и RETRANS - добавляет накопившиеся ACK
При приёме пакета (от etcp_connections): При приёме пакета (от etcp_connections):
- последовательно сканируем секции и отдаём их на обработку нужным обработчикам: - последовательно сканируем секции и отдаём их на обработку нужным обработчикам:
- retrans: помечаем секции как нужна ретрансмиссия. также ставим флаг в конце запустить etcp если он в wait timeout, т.е. wait_timeout!=NULL
- ack: помечаем в inflight пакеты как подтверждённые и проставляем время подтверждения. также и ставим флаг в конце запустить etcp если он в wait timeout, т.е. wait_timeout!=NULL - ack: помечаем в inflight пакеты как подтверждённые и проставляем время подтверждения. также и ставим флаг в конце запустить etcp если он в wait timeout, т.е. wait_timeout!=NULL
- timestamp: обновляем last RTT, пересчитываем RTT10,RTT100 (плавающим окном за последние 10/100 пакетов), и jitter=max(last 10)-min(last 10 packets) - timestamp: обновляем last RTT, пересчитываем RTT10,RTT100 (плавающим окном за последние 10/100 пакетов), и jitter=max(last 10)-min(last 10 packets)
- [0x00] payload: добавляем пакет в нужное место сборочного linked-list (сверяем по ID если дубликат - игнорируем). - [0x00] payload: добавляем пакет в нужное место сборочного linked-list (сверяем по ID если дубликат - игнорируем).
@ -55,8 +54,10 @@ bandwidth по каждому линку адаптивно подстраива
**** Формат кодограмм для etcp.c/h **** **** Формат кодограмм для etcp.c/h ****
Каждая кодограмма состоит из обязательного заголовка и опциональных секций: Каждая кодограмма состоит из обязательного заголовка и опциональных секций:
1. Обязательный заголовок всего пакета (2 байта) добавляется при передаче, есть во всех пакетах: 1. Обязательный заголовок всего пакета (2 байта) добавляется при передаче, есть во всех пакетах:
[Timestamp high][Timestamp low] [Timestamp high][Timestamp low][flags]
- Timestamp: время отправки в единицах 0.1 мс (циклическое). при переповторах время обновляется - Timestamp: время отправки в единицах 0.1 мс (циклическое). при переповторах время обновляется
- flags: bit0 = up/down (recv_keepalive)
шифруется строго ВСЁ включая ВСЕ заголовки (кроме INIT+publickey). timestamp вставляется ВСЕГДА ВО ВСЕ КОДОГРАММЫ шифруется строго ВСЁ включая ВСЕ заголовки (кроме INIT+publickey). timestamp вставляется ВСЕГДА ВО ВСЕ КОДОГРАММЫ
2. Опциональные секции (одна или несколько) добавляются в etcp.c: 2. Опциональные секции (одна или несколько) добавляются в etcp.c:
а) Подтверждения (ACK) - заголовок 0x01: а) Подтверждения (ACK) - заголовок 0x01:
@ -64,10 +65,6 @@ bandwidth по каждому линку адаптивно подстраива
- count: количество пар ID+timestamp (1-32) - count: количество пар ID+timestamp (1-32)
- last_delivered_id: последний ID, доставленный получателю - last_delivered_id: последний ID, доставленный получателю
- last_rx_id: последний полученный ID (для синхронизации прогресса) - last_rx_id: последний полученный ID (для синхронизации прогресса)
б) Запросы ретрансмиссии (RETRANS) - заголовок 0x10-0x2F:
[0x10+(count-1)][(id_hi,id_lo)×count][last_delivered_hi,lo][last_rx_hi,lo]
- count: (заголовок & 0x0F) + 1 (1-32)
- last_delivered_id, last_rx_id: для синхронизации состояния
в) channel timestamp (добавляется после выбора канала передачи): в) channel timestamp (добавляется после выбора канала передачи):
[0x0F] [RET_Timestamp high][RET_Timestamp low] [RECV_Timestamp high][RECV_Timestamp low] [0x0F] [RET_Timestamp high][RET_Timestamp low] [RECV_Timestamp high][RECV_Timestamp low]
- RET_Timestamp: это timestamp последнего принятого пакета по этому каналу ETCP_LINK плюс разница времени между принятием этого пакета и текущим временем. т.е. приёмная сторона по этому timestamp (и зная своё время) может просчитать время в пути туда + обратно - RET_Timestamp: это timestamp последнего принятого пакета по этому каналу ETCP_LINK плюс разница времени между принятием этого пакета и текущим временем. т.е. приёмная сторона по этому timestamp (и зная своё время) может просчитать время в пути туда + обратно

55
src/etcp_connections.c

@ -163,17 +163,19 @@ static void keepalive_timer_cb(void* arg) {
uint64_t elapsed = now - link->last_recv_local_time; uint64_t elapsed = now - link->last_recv_local_time;
if (elapsed > timeout_units) { if (elapsed > timeout_units) {
if (link->link_status != 0) { if (link->recv_keepalive != 0) {
link->link_status = 0; // down link->recv_keepalive = 0; // down
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) status changed to DOWN - " link->link_status = 0;
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) recv status changed to DOWN - "
"no packets received for %llu ms (timeout=%u ms)", "no packets received for %llu ms (timeout=%u ms)",
link->etcp->log_name, link, link->local_link_id, link->etcp->log_name, link, link->local_link_id,
(unsigned long long)(elapsed / 10), link->keepalive_timeout); (unsigned long long)(elapsed / 10), link->keepalive_timeout);
} }
} else { } else {
if (link->link_status != 1) { if (link->recv_keepalive != 1) {
link->link_status = 1; // up link->recv_keepalive = 1; // up
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) status changed to UP", // loadbalancer_link_ready(link);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) recv status changed to UP",
link->etcp->log_name, link, link->local_link_id); link->etcp->log_name, link, link->local_link_id);
} }
} }
@ -580,8 +582,12 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
if (!dgram || !dgram->link) return -1; if (!dgram || !dgram->link) return -1;
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Send rk=%d lk=%d up=%d",
dgram->link->etcp->log_name, dgram->link->recv_keepalive, dgram->link->remote_keepalive, dgram->link->link_status);
// Mark that packet was sent (for keepalive logic) // Mark that packet was sent (for keepalive logic)
dgram->link->pkt_sent_since_keepalive = 1; dgram->link->pkt_sent_since_keepalive = 1;
dgram->flag_up=dgram->link->recv_keepalive;
int errcode=0; int errcode=0;
sc_context_t* sc = &dgram->link->etcp->crypto_ctx; sc_context_t* sc = &dgram->link->etcp->crypto_ctx;
@ -594,7 +600,7 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
// DUMP: Show packet before encryption // DUMP: Show packet before encryption
if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO)) log_dump("ECTP_ENCRYPT_SEND", dgram->data, dgram->data_len); if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO)) log_dump("ECTP_ENCRYPT_SEND", dgram->data, dgram->data_len);
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Encrypt start"); // DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Encrypt start");
sc_encrypt(sc, (uint8_t*)&dgram->timestamp/*не править это, тут верно!*/, sizeof(uint16_t) + len, enc_buf, &enc_buf_len); sc_encrypt(sc, (uint8_t*)&dgram->timestamp/*не править это, тут верно!*/, 3 + len, enc_buf, &enc_buf_len);
// DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Encrypt end"); // DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Encrypt end");
if (enc_buf_len == 0) { if (enc_buf_len == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_encrypt_send: encryption failed for node %llu", (unsigned long long)dgram->link->etcp->instance->node_id); DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_encrypt_send: encryption failed for node %llu", (unsigned long long)dgram->link->etcp->instance->node_id);
@ -647,6 +653,7 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// 4 - не init пакет (неверный код) // 4 - не init пакет (неверный код)
// 5 - коллизия peer ID и ключей // 5 - коллизия peer ID и ключей
// 6 - не удалось расшифровать обычный пакет // 6 - не удалось расшифровать обычный пакет
// 7 - слишком короткий пакет
// 13 - переполнение при парсинге пакета // 13 - переполнение при парсинге пакета
// 46 - расшифрованный пакет слишком маленький (< 3 байта) // 46 - расшифрованный пакет слишком маленький (< 3 байта)
// 55 - не удалось создать подключение // 55 - не удалось создать подключение
@ -682,6 +689,10 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// Try normal decryption first if we have an established link with session keys // Try normal decryption first if we have an established link with session keys
// This is the common case for data packets and responses // This is the common case for data packets and responses
if (link) {
link->recv_keepalive = 1; // Link is up after successful initialization
}
if (link!=NULL && link->etcp!=NULL && link->etcp->crypto_ctx.session_ready) { if (link!=NULL && link->etcp!=NULL && link->etcp->crypto_ctx.session_ready) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Decrypt start (normal)"); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Decrypt start (normal)");
if (!sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, (uint8_t*)&pkt->timestamp, &pkt_len)) { if (!sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, (uint8_t*)&pkt->timestamp, &pkt_len)) {
@ -718,7 +729,13 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
} }
// INIT decryption succeeded - process as new incoming connection // INIT decryption succeeded - process as new incoming connection
pkt->data_len=pkt_len-2; if (pkt_len<3) {
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: too short packet");
errorcode=7;
goto ec_fr;
}
pkt->data_len=pkt_len-3;
pkt->noencrypt_len=0; pkt->noencrypt_len=0;
struct { struct {
uint8_t code; uint8_t code;
@ -796,6 +813,8 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
pkt->data_len=sizeof(*ack_repl_hdr); pkt->data_len=sizeof(*ack_repl_hdr);
pkt->noencrypt_len=0; pkt->noencrypt_len=0;
pkt->link=link; pkt->link=link;
link->recv_keepalive = 1;
DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Sending INIT RESPONSE, link=%p, local_link_id=%d, remote_link_id=%d", link, link->local_link_id, link->remote_link_id); DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Sending INIT RESPONSE, link=%p, local_link_id=%d, remote_link_id=%d", link, link->local_link_id, link->remote_link_id);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP DEBUG] Send INIT RESPONSE"); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[ETCP DEBUG] Send INIT RESPONSE");
etcp_encrypt_send(pkt); etcp_encrypt_send(pkt);
@ -803,7 +822,6 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
memory_pool_free(e_sock->instance->pkt_pool, pkt); memory_pool_free(e_sock->instance->pkt_pool, pkt);
link->initialized = 1;// получен init request (server), считаем линк уже готовым к работе link->initialized = 1;// получен init request (server), считаем линк уже готовым к работе
link->link_status = 1; // Link is up after successful initialization
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) initialized and marked as UP (server)", DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) initialized and marked as UP (server)",
link->etcp->log_name, link, link->local_link_id); link->etcp->log_name, link, link->local_link_id);
@ -828,17 +846,22 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
process_decrypted: process_decrypted:
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Decrypt end"); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Decrypt end");
if (pkt_len<3) { errorcode=46; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: decrypted packet too small, size=%zu", pkt_len); goto ec_fr; } if (pkt_len<3) { errorcode=46; DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback: decrypted packet too small, size=%zu", pkt_len); goto ec_fr; }
pkt->data_len=pkt_len-2; pkt->data_len=pkt_len-3;
pkt->noencrypt_len=0; pkt->noencrypt_len=0;
pkt->link=link; pkt->link=link;
link->remote_keepalive=pkt->flag_up;
if ( link->remote_keepalive && !link->link_status && link->initialized) loadbalancer_link_ready(link);// up выставляем только если и remote=up и local=up
link->link_status=link->remote_keepalive;
link->last_recv_local_time=get_current_time_units(); link->last_recv_local_time=get_current_time_units();
link->last_recv_timestamp=pkt->timestamp; link->last_recv_timestamp=pkt->timestamp;
link->last_recv_updated=1; link->last_recv_updated=1;
// Mark link as up when receiving packets // Mark link as up when receiving packets
if (link->link_status != 1) { if (link->recv_keepalive != 1) {
link->link_status = 1; link->recv_keepalive = 1;
// loadbalancer_link_ready(link);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) status changed to UP - packet received", DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) status changed to UP - packet received",
link->etcp->log_name, link, link->local_link_id); link->etcp->log_name, link, link->local_link_id);
} }
@ -913,11 +936,13 @@ process_decrypted:
// Mark link as initialized // Mark link as initialized
// DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Setting link->initialized=1, link=%p, is_server=%d", link, link->is_server); // DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Setting link->initialized=1, link=%p, is_server=%d", link, link->is_server);
link->initialized = 1;// получен init response (client) link->initialized = 1;// получен init response (client)
link->link_status = 1; // Link is up after successful initialization // link->link_status = 1; // Link is up after successful initialization
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) initialized and marked as UP (client)", loadbalancer_link_ready(link);
link->etcp->log_name, link, link->local_link_id); DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) initialized and marked as UP (client): rk=%d lk=%d up=%d",
link->etcp->log_name, link, link->local_link_id, link->recv_keepalive, link->remote_keepalive, link->link_status);
// Start keepalive timer // Start keepalive timer
etcp_link_send_keepalive(link);
if (!link->keepalive_timer && link->keepalive_interval > 0) { if (!link->keepalive_timer && link->keepalive_interval > 0) {
link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua, link->keepalive_timer = uasync_set_timeout(link->etcp->instance->ua,
link->keepalive_interval * 10, link->keepalive_interval * 10,

7
src/etcp_connections.h

@ -17,13 +17,16 @@
#define ETCP_CHANNEL_RESPONSE 0x05 #define ETCP_CHANNEL_RESPONSE 0x05
#pragma pack(push, 1)
struct ETCP_DGRAM {// пакет (незашифрованный) struct ETCP_DGRAM {// пакет (незашифрованный)
struct ETCP_LINK* link;// откуда получена или куда отправялем struct ETCP_LINK* link;// откуда получена или куда отправялем
uint16_t data_len;// общий размер пакета не включая timestamp uint16_t data_len;// общий размер пакета не включая timestamp
uint16_t noencrypt_len;// число байт (с конца) которые не надо шифровать. для передачи pubkey uint16_t noencrypt_len;// число байт (с конца) которые не надо шифровать. для передачи pubkey
uint16_t timestamp;// timestamp отправляющего узла при отправке пакета uint16_t timestamp;// timestamp отправляющего узла при отправке пакета
uint8_t flag_up:1;// bit0 = up/down (recv_keepalive)
uint8_t data[0];// данные пакета (без timestamp) uint8_t data[0];// данные пакета (без timestamp)
}; };
#pragma pack(pop)
// список активных подключений которые обслуживает сокет. каждый сокет может обслуживать много подключений // список активных подключений которые обслуживает сокет. каждый сокет может обслуживать много подключений
struct ETCP_SOCKET { struct ETCP_SOCKET {
@ -60,7 +63,9 @@ struct ETCP_LINK {
uint8_t initialized; // Флаг инициализации (1=подтверждено или получен request) uint8_t initialized; // Флаг инициализации (1=подтверждено или получен request)
uint8_t local_link_id; // id моего линка uint8_t local_link_id; // id моего линка
uint8_t remote_link_id; // id этого линка на peer (устанавливается в момент initialized) uint8_t remote_link_id; // id этого линка на peer (устанавливается в момент initialized)
uint8_t link_status; // 1 - up, 0 - down uint8_t recv_keepalive; // 1 - up, 0 - down (принимаются ли пакеты)
uint8_t remote_keepalive; // 1 - up, 0 - down (удаленная сторона сообщает - принимаются ли у нее пакеты)
uint8_t link_status; // 1 - up, 0 - down (итоговый статус - если есть проблемы на любой стороне - линк down)
// Состояние установки соединения (только для клиентов) // Состояние установки соединения (только для клиентов)
void* init_timer; // Таймер для повторов INIT (NULL=не подключается) void* init_timer; // Таймер для повторов INIT (NULL=не подключается)

2
src/utun.c

@ -264,7 +264,7 @@ int main(int argc, char *argv[]) {
debug_config_init(); debug_config_init();
debug_set_level(DEBUG_LEVEL_TRACE); debug_set_level(DEBUG_LEVEL_TRACE);
debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_UASYNC); // Enable all except uasync debug_set_categories(DEBUG_CATEGORY_ALL & ~DEBUG_CATEGORY_UASYNC & ~DEBUG_CATEGORY_TIMERS); // Enable all except uasync
debug_enable_function_name(1); debug_enable_function_name(1);
if (args.debug_config) { if (args.debug_config) {

BIN
tests/bench_uasync_timeouts

Binary file not shown.

2
utun_start.sh

@ -0,0 +1,2 @@
#!/bin/sh
sudo ./utun >utun.log 2>utun_err.log

2
utun_stop.sh

@ -0,0 +1,2 @@
#!/bin/sh
killall -9 utun

2
utun_stop1.sh

@ -0,0 +1,2 @@
#!/bin/sh
sudo ./utun_stop.sh

BIN
wintun.dll

Binary file not shown.
Loading…
Cancel
Save