You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

106 lines
4.8 KiB

// socks_proxy.h — SOCKS5 / HTTP CONNECT proxy (client side)
#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;
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)
};
// HTTP-состояния совпадают по значениям с SOCKS-состояниями (общая state-машина
// в on_read_cb), поэтому явно привязаны к SOCKS_STATE_* — иначе возникает коллизия
// SOCKS_STATE_CONNECTING(2) == HTTP_STATE_RELAY(2) и RELAY-данные дропаются.
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;
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 is_http;
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
uint8_t* dns_pending; // HTTP proxy: накопленный запрос (headers+body) до DNS
uint16_t dns_pending_len;
};
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 получает значение сокета (для последующего close).
void socks_proxy_close_listen(struct UASYNC* ua, struct listen_ctx* ctx, socket_t* sock_out);
// Найти соединение по stream_id
struct socks_proxy_conn* socks_proxy_find_conn(struct socks_proxy_conn* head, uint32_t stream_id);
// Обработать входящее ETCP сообщение (DATA/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