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
5.0 KiB
106 lines
5.0 KiB
/* Локальные 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); |
|
|
|
// Найти соединение по 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
|
|
|