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
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
|
|
|