109 lines
5.2 KiB
C
109 lines
5.2 KiB
C
/* Локальные SOCKS5 CONNECT и HTTP proxy/CONNECT: DNS, handshake и передача TCP через удалённый exit.
|
|
* tcp_proxy_client владеет listener и списками соединений; их callbacks выполняются в uasync.
|
|
* init_listen заимствует указатели на списки/счётчики до close_listen; закрытие listener не освобождает клиентов. */
|
|
#ifndef SOCKS_PROXY_H
|
|
#define SOCKS_PROXY_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
#include <stdint.h>
|
|
#include "proxy_protocol.h"
|
|
#include "../lib/socket_compat.h"
|
|
#include "../lib/ll_queue.h"
|
|
|
|
struct UASYNC;
|
|
struct UTUN_INSTANCE;
|
|
struct ll_entry;
|
|
struct ll_queue;
|
|
struct tcp_conn;
|
|
struct adns_query;
|
|
struct socks_http_state;
|
|
|
|
enum {
|
|
SOCKS_STATE_GREETING = 0, // ждём SOCKS5 greeting (ver + methods)
|
|
SOCKS_STATE_REQUEST, // ждём SOCKS5 CONNECT request (== HTTP_STATE_REQUEST)
|
|
SOCKS_STATE_CONNECTING, // DNS в процессе (== HTTP_STATE_CONNECTING)
|
|
SOCKS_STATE_RELAY // релей данных (== HTTP_STATE_RELAY)
|
|
};
|
|
|
|
// DNS/connect и сырой туннель используют общие состояния; HTTP framing хранится отдельно в http.
|
|
enum {
|
|
HTTP_STATE_REQUEST = SOCKS_STATE_REQUEST, // ждём заголовки очередного HTTP-запроса
|
|
HTTP_STATE_CONNECTING = SOCKS_STATE_CONNECTING, // DNS в процессе
|
|
HTTP_STATE_RELAY = SOCKS_STATE_RELAY // релей данных
|
|
};
|
|
|
|
struct socks_proxy_conn {
|
|
struct socks_proxy_conn* next;
|
|
struct socks_proxy_conn** head; // указатель на голову списка (для удаления)
|
|
int* count; // указатель на счётчик списка
|
|
struct tcp_conn* tc;
|
|
struct UASYNC* ua;
|
|
struct UTUN_INSTANCE* inst;
|
|
uint64_t via_node_id;
|
|
struct proxy_flow flow;
|
|
uint32_t stream_id;
|
|
uint32_t* next_stream_id; // HTTP: новый поток для следующей транзакции
|
|
struct socks_http_state* http;
|
|
uint8_t dest_ip[4];
|
|
uint16_t dest_port;
|
|
uint8_t fin_remote;
|
|
uint8_t rem_closed;
|
|
uint8_t close_sent;
|
|
uint8_t close_pending;
|
|
uint8_t state;
|
|
uint8_t freed;
|
|
uint8_t close_queued;
|
|
void* free_soon_id; // handle отложенного освобождения (uasync_call_soon)
|
|
uint8_t buf[16384];
|
|
uint16_t buf_len;
|
|
uint8_t* tx_buf; // буфер при backpressure (retry в tx_waiter_cb)
|
|
uint16_t tx_len;
|
|
uint32_t bytes_to_client; // байт записано клиенту (curl) через write_queue
|
|
uint32_t bytes_from_exit; // байт получено от exit node через ETCP DATA
|
|
struct queue_waiter_handle tx_waiter;
|
|
void* tx_retry_timer; // safety-net таймер backpressure (force=1)
|
|
uint8_t fin_deferred; // FIN отложен до сброса tx_buf
|
|
struct adns_query* dns_q; // активный DNS-запрос (NULL когда нет)
|
|
uint8_t dns_kind; // DNSK_SOCKS / DNSK_HTTP_CONNECT / DNSK_HTTP_PROXY
|
|
};
|
|
|
|
struct listen_ctx;
|
|
|
|
// Создать слушающий сокет для SOCKS/HTTP proxy. addr_str = "IP:PORT".
|
|
// listen_ctx должен быть освобождён через socks_proxy_close_listen.
|
|
// Возвращает listen_ctx при успехе, NULL при ошибке.
|
|
struct listen_ctx* socks_proxy_init_listen(struct UASYNC* ua, const char* addr_str,
|
|
struct socks_proxy_conn** conns, int* count, uint32_t* next_stream_id,
|
|
struct UTUN_INSTANCE* inst, uint64_t via_node_id, int is_http);
|
|
|
|
// Закрыть слушающий сокет и освободить listen_ctx.
|
|
// Если sock_out задан, в него записывается SOCKET_INVALID: сокет уже закрыт.
|
|
void socks_proxy_close_listen(struct UASYNC* ua, struct listen_ctx* ctx, socket_t* sock_out);
|
|
// Фактический порт активного listener (IP:0 выбирает ОС); 0 при ошибке.
|
|
uint16_t socks_proxy_get_port(const struct listen_ctx* ctx);
|
|
|
|
// Найти соединение по stream_id
|
|
struct socks_proxy_conn* socks_proxy_find_conn(struct socks_proxy_conn* head, uint32_t stream_id);
|
|
|
|
// Обработать ответ exit: CONNECTED/DATA/WINDOW_UPDATE/CLOSE/ERROR/FIN.
|
|
// Возвращает 1 если обработано, 0 если stream_id не найден
|
|
int socks_proxy_handle_etcp(struct socks_proxy_conn** head, int* count,
|
|
uint32_t stream_id, uint8_t subcmd,
|
|
const uint8_t* data, size_t data_len);
|
|
|
|
// Освободить одно соединение (удаляет из списка)
|
|
void socks_proxy_conn_free(struct socks_proxy_conn* c);
|
|
|
|
// Освободить все соединения в списке
|
|
void socks_proxy_conn_free_all(struct socks_proxy_conn** head, int* count);
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif // SOCKS_PROXY_H
|