/* Клиент TCP-прокси: принимает IPv4 с отдельного TUN через lwIP либо TCP от SOCKS/HTTP listener. * Передаёт потоки через UTUN-router на via_node_id; proxy_flow обеспечивает окно и backpressure. * create/destroy и callbacks — в uasync. Владеет созданными TUN/lwIP/listener/потоками, * заимствует inst/ua/mappings до destroy. Без пары непустых tun_name/tun_ip работает только SOCKS/HTTP. * Владелец сам записывает результат create в inst->tcp_proxy_client и обнуляет поле после destroy. * Клиент принимает TCP-ответы только от via_node_id в TOPO_GROUP_UTUN; UDP/ICMP требуют TUN. */ #ifndef TCP_PROXY_CLIENT_H #define TCP_PROXY_CLIENT_H #ifdef __cplusplus extern "C" { #endif #include #include "proxy_protocol.h" #include #include "../lib/socket_compat.h" #include "../lib/ll_queue.h" struct UASYNC; struct UTUN_INSTANCE; struct ETCP_CONN; struct tun_if; struct ll_queue; struct ll_entry; struct memory_pool; struct tcp_proxy_client_mapping_config; struct tcp_proxy_server; struct lwip_tcp_ctx; struct socks_proxy_conn; struct listen_ctx; struct tcp_pcb; struct tcp_proxy_client_conn { struct tcp_proxy_client_conn* next; // следующий lwIP-поток клиента struct tcp_proxy_client* proxy; // заимствованный владелец struct tcp_pcb* pcb; // принадлежит lwIP; NULL после detach/err callback struct proxy_flow flow; // окно и retry CONNECTED/WINDOW/FIN uint32_t stream_id; // общий генератор с SOCKS/HTTP-потоками struct ll_queue* to_lwip; // DATA от exit → lwIP (управление потоком) uint8_t fin_local; // локальная сторона отправила FIN (lwIP) uint8_t fin_remote; // exit отправил FIN (назначение закрылось) uint8_t fin_deferred; // FIN от exit пришёл, но отложен до дренажа to_lwip uint8_t rem_closed; // exit отправил CLOSE uint8_t error; // ошибка, немедленная очистка uint8_t close_sent; // отправили CLOSE/ERROR в exit uint8_t close_pending; // CLOSE/ERROR не принят router, повтор в poll/free пока pc жив struct ll_queue* tx_queue; // буфер lwIP→ETCP при backpressure (аналог server read_queue) struct queue_waiter_handle tx_waiter; // waiter на send_q (etcp_router_on_send_ready) void* tx_retry_timer; // safety-net 500 мс, повтор DATA с force=1 (окно proxy сохраняется) uint32_t bytes_to_exit; // байт принято router для exit (из lwIP/TUN) uint32_t bytes_from_exit; // байт получено от exit (в lwIP/TUN) uint32_t bp_count; // счётчик backpressure (send fail) uint8_t dest_ip[4]; // IPv4 назначения в сетевом порядке uint16_t dest_port; // порт назначения в сетевом порядке }; struct tcp_proxy_client { struct UTUN_INSTANCE* inst; // заимствован; NULL допустим для автономного TUN smoke test struct UASYNC* ua; // заимствованный event loop struct tun_if* tun; // собственный TUN или NULL для SOCKS/HTTP без TUN struct tcp_proxy_client_conn* conns; // список собственных lwIP-потоков int conn_count; // число lwIP-потоков, без SOCKS/HTTP struct memory_pool* entry_pool; // собственный пул ll_entry для очередей lwIP-потоков uint32_t next_stream_id; // общий счётчик TUN/SOCKS/HTTP, init=1, перед выдачей инкрементируется uint64_t via_node_id; // настроенный exit для всех потоков struct lwip_tcp_ctx* lwip; // собственный TCP-стек или NULL без TUN struct tcp_proxy_client_mapping_config* mappings; // указатель на конфиг int mapping_count; // число записей mappings, порты конфига в host byte order // SOCKS proxy int socks_enabled; // запрошен SOCKS5; не гарантирует успешный listener struct socks_proxy_conn* socks_conns; // собственные SOCKS5-клиенты int socks_conn_count; // число SOCKS5-клиентов struct listen_ctx* socks_listen; // собственный listener или NULL при отключении/ошибке // HTTP forward proxy и CONNECT int http_proxy_enabled; // запрошен HTTP; не гарантирует успешный listener struct socks_proxy_conn* http_conns; // собственные HTTP-клиенты int http_conn_count; // число HTTP-клиентов struct listen_ctx* http_listen; // собственный listener или NULL при отключении/ошибке }; // Создать клиент; ua обязателен. Непустые tun_name И tun_ip включают TUN/lwIP (mtu<=0 → 1500). // test_mode передаётся tun_init_nat: ненулевой использует тестовый TUN; mappings заимствуются до destroy. // SOCKS/HTTP создаются при enabled и непустом IPv4:port; via_node_id — общий exit. // Результат: собственный p или NULL при критической ошибке/отсутствии режима. // Ошибки listener/router bind/UDP/ICMP не делают create атомарным: проверять listener и диагностику отдельно. struct tcp_proxy_client* tcp_proxy_client_create(struct UTUN_INSTANCE* inst, struct UASYNC* ua, const char* tun_name, const char* tun_ip, int mtu, int test_mode, struct tcp_proxy_client_mapping_config* mappings, int mapping_count, uint64_t via_node_id, int socks_enabled, const char* socks_addr, int http_proxy_enabled, const char* http_proxy_addr); // Остановить listeners, освободить потоки/TUN/lwIP и снять router binding; NULL допустим. // UDP/ICMP сохраняются, пока включён сервер того же inst. Не обнуляет inst->tcp_proxy_client. void tcp_proxy_client_destroy(struct tcp_proxy_client* p); // Router callback: conn->instance задаёт владельца, entry содержит метаданные router и передаёт владение. // Освобождает entry/dgram при любом исходе; CLOSE_ALL = пустой payload router, а не TCP-подкоманда. void tcp_proxy_client_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry); #ifdef __cplusplus } #endif #endif // TCP_PROXY_CLIENT_H