add framed read for raw fd (2-byte len prefix), TCP_NODELAY, fix test half-close ordering

This commit is contained in:
Evgeny committed 2026-05-12 19:43:44 +03:00
1 parent d0af315ff6
commit d3b6057f82
7 files changed
+65 -570

No files matched your search

+55 -36
View File
@@ -24,6 +24,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif
@@ -124,14 +125,18 @@ static err_t tcp_output_cb(void *arg, struct pbuf *p, uint32_t src_ip, uint32_t
(void)src_ip; (void)dst_ip;
uint16_t len = p->tot_len;
if (len > 2000) return LERR_BUF;
uint8_t buf[2000];
pbuf_copy_partial(p, buf, len, 0);
DEBUG_ERROR(DEBUG_CATEGORY_TRAFFIC, "TCP OUT %u.%u.%u.%u→%u.%u.%u.%u len=%u fd=%d",
uint8_t buf[2002];
if (proxy->tun) {
pbuf_copy_partial(p, buf, len, 0);
tun_platform_write(proxy->tun, buf, len);
} else if (proxy->ip_fd >= 0) {
buf[0] = (len >> 8) & 0xFF; buf[1] = len & 0xFF;
pbuf_copy_partial(p, buf + 2, len, 0);
ssize_t n = write(proxy->ip_fd, buf, 2 + len); (void)n;
}
DEBUG_ERROR(DEBUG_CATEGORY_TRAFFIC, "TCP OUT %u.%u.%u.%u→%u.%u.%u.%u len=%u",
(uint8_t)(src_ip), (uint8_t)(src_ip>>8), (uint8_t)(src_ip>>16), (uint8_t)(src_ip>>24),
(uint8_t)(dst_ip), (uint8_t)(dst_ip>>8), (uint8_t)(dst_ip>>16), (uint8_t)(dst_ip>>24),
len, proxy->ip_fd);
if (proxy->tun) tun_platform_write(proxy->tun, buf, len);
else if (proxy->ip_fd >= 0) { ssize_t n = write(proxy->ip_fd, buf, len); (void)n; }
(uint8_t)(dst_ip), (uint8_t)(dst_ip>>8), (uint8_t)(dst_ip>>16), (uint8_t)(dst_ip>>24), len);
return LERR_OK;
}
@@ -233,8 +238,8 @@ static err_t proxy_accept_cb(void *arg, struct tcp_pcb *newpcb, err_t err) {
}
pc->next = p->conns; p->conns = pc; p->conn_count++;
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "TCP proxy: new passive conn to %d.%d.%d.%d:%d (client port %d)",
pc->dest_ip[0], pc->dest_ip[1], pc->dest_ip[2], pc->dest_ip[3], ntohs(pc->dest_port), ntohs(newpcb->remote_port));
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "TCP proxy: new passive conn to %d.%d.%d.%d:%d",
pc->dest_ip[0], pc->dest_ip[1], pc->dest_ip[2], pc->dest_ip[3], ntohs(pc->dest_port));
return LERR_OK;
}
@@ -268,7 +273,6 @@ static err_t proxy_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t
pbuf_free(p);
} else if (pc->transport && !pc->half_closed) {
uint16_t len = p->tot_len;
DEBUG_ERROR(DEBUG_CATEGORY_TRAFFIC, "RECV passive pc=%p len=%u transport=%p connected=%d", (void*)pc, len, (void*)pc->transport, ((struct sock_transport*)pc->transport)->connected);
uint8_t *data = u_malloc(len);
if (data) {
pbuf_copy_partial(p, data, len, 0);
@@ -333,32 +337,45 @@ static err_t proxy_connected_cb(void *arg, struct tcp_pcb *pcb, err_t err) {
// ====================================================================
static void tcp_proxy_raw_read(int fd, void* arg) {
(void)fd; struct tcp_proxy* p = (struct tcp_proxy*)arg;
uint8_t buf[2000]; ssize_t n = read(p->ip_fd, buf, sizeof(buf));
if (n <= 0) return;
ssize_t n;
size_t offset = 0;
while (offset < (size_t)n) {
size_t remaining = (size_t)n - offset;
if (remaining < 20) break;
uint8_t *pkt = buf + offset;
if (tcp_proxy_handle_non_tcp(p, pkt, remaining)) { offset += remaining; continue; }
if (p->raw_need == 0) {
/* Ждём 2-байтный заголовок длины */
n = read(p->ip_fd, p->raw_buf + p->raw_pos, 2 - p->raw_pos);
if (n <= 0) { if (n < 0 && errno == EAGAIN) return; p->raw_pos = 0; return; }
p->raw_pos += n;
if (p->raw_pos < 2) return;
p->raw_need = ((uint16_t)p->raw_buf[0] << 8) | p->raw_buf[1];
if (p->raw_need == 0 || p->raw_need > 2000) { p->raw_pos = 0; return; }
p->raw_pos = 0;
}
/* Ждём p->raw_need байт данных */
n = read(p->ip_fd, p->raw_buf + 2 + p->raw_pos, p->raw_need - p->raw_pos);
if (n <= 0) { if (n < 0 && errno == EAGAIN) return; p->raw_pos = p->raw_need = 0; return; }
p->raw_pos += n;
if (p->raw_pos < p->raw_need) return;
/* Пакет получен полностью */
uint8_t* pkt = p->raw_buf + 2;
size_t remaining = p->raw_need;
p->raw_pos = 0; p->raw_need = 0;
if (!tcp_proxy_handle_non_tcp(p, pkt, remaining)) {
uint8_t proto = pkt[9];
if (proto != IPPROTO_TCP) { offset += remaining; continue; }
uint16_t ip_hdr_len = (pkt[0] & 0x0F) * 4;
uint16_t ip_total = ((uint16_t)pkt[2] << 8) | pkt[3];
if (ip_hdr_len < 20 || ip_total < ip_hdr_len || (size_t)ip_total > remaining) break;
uint32_t src_ip, dst_ip;
memcpy(&src_ip, pkt + 12, 4); memcpy(&dst_ip, pkt + 16, 4);
DEBUG_ERROR(DEBUG_CATEGORY_TRAFFIC, "TCP IN %u.%u.%u.%u→%u.%u.%u.%u proto=%u iplen=%u",
(uint8_t)(src_ip), (uint8_t)(src_ip>>8), (uint8_t)(src_ip>>16), (uint8_t)(src_ip>>24),
(uint8_t)(dst_ip), (uint8_t)(dst_ip>>8), (uint8_t)(dst_ip>>16), (uint8_t)(dst_ip>>24),
proto, ip_total);
uint16_t tcp_len = ip_total - ip_hdr_len;
struct pbuf *pb = pbuf_alloc(PBUF_RAW, tcp_len);
if (!pb) break;
pbuf_take(pb, pkt + ip_hdr_len, tcp_len);
lwip_tcp_input(p->lwip, pb, src_ip, dst_ip);
offset += ip_total;
if (proto == IPPROTO_TCP) {
uint16_t ip_hdr_len = (pkt[0] & 0x0F) * 4;
uint16_t ip_total = ((uint16_t)pkt[2] << 8) | pkt[3];
if (ip_hdr_len >= 20 && ip_total >= ip_hdr_len && (size_t)ip_total <= remaining) {
uint32_t src_ip, dst_ip;
memcpy(&src_ip, pkt + 12, 4); memcpy(&dst_ip, pkt + 16, 4);
uint16_t tcp_len = ip_total - ip_hdr_len;
DEBUG_ERROR(DEBUG_CATEGORY_TRAFFIC, "TCP IN %u.%u.%u.%u→%u.%u.%u.%u iplen=%u",
(uint8_t)(src_ip), (uint8_t)(src_ip>>8), (uint8_t)(src_ip>>16), (uint8_t)(src_ip>>24),
(uint8_t)(dst_ip), (uint8_t)(dst_ip>>8), (uint8_t)(dst_ip>>16), (uint8_t)(dst_ip>>24), ip_total);
struct pbuf *pb = pbuf_alloc(PBUF_RAW, tcp_len);
if (pb) { pbuf_take(pb, pkt + ip_hdr_len, tcp_len); lwip_tcp_input(p->lwip, pb, src_ip, dst_ip); }
}
}
}
}
@@ -399,6 +416,7 @@ static struct sock_transport* sock_transport_create(struct proxy_conn* pc, struc
st->sock = socket(AF_INET, SOCK_STREAM, 0);
if(st->sock == SOCKET_INVALID) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socket() failed: %s", strerror(errno)); u_free(st); return NULL; }
socket_set_nonblocking(st->sock);
{ int one = 1; setsockopt(st->sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); }
st->read_id = uasync_add_socket_t(ua, st->sock, sock_transport_read_callback, sock_transport_write_callback, sock_transport_error_callback, st);
if(!st->read_id) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "uasync_add_socket_t failed"); socket_close_wrapper(st->sock); u_free(st); return NULL; }
return st;
@@ -408,7 +426,7 @@ static void sock_transport_connect(struct sock_transport* st) {
struct proxy_conn* pc = st->conn;
struct sockaddr_in addr; memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; memcpy(&addr.sin_addr.s_addr, pc->dest_ip, 4); addr.sin_port = pc->dest_port;
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "TCP proxy: connecting to %d.%d.%d.%d:%d", pc->dest_ip[0], pc->dest_ip[1], pc->dest_ip[2], pc->dest_ip[3], ntohs(pc->dest_port));
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "TCP proxy: connecting to %d.%d.%d.%d:%d", pc->dest_ip[0], pc->dest_ip[1], pc->dest_ip[2], pc->dest_ip[3], ntohs(pc->dest_port));
st->connect_called = 1;
int ret = connect(st->sock, (struct sockaddr*)&addr, sizeof(addr));
if(ret < 0 && errno != EINPROGRESS) { DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "connect() failed: %s", strerror(errno)); sock_transport_close(&st->base); return; }
@@ -829,7 +847,8 @@ int tcp_proxy_active_send_done(struct tcp_proxy* p, struct proxy_conn* pc) {
(void)p;
if (!pc || !pc->active || !pc->pcb) return 1;
if (pc->closing) return 1;
if (queue_entry_count(pc->transport_to_uip) > 0) return 0;
int q = queue_entry_count(pc->transport_to_uip);
if (q > 0) return 0;
if (pc->pcb->unsent || pc->pcb->unacked) return 0;
return 1;
}
+4
View File
@@ -82,6 +82,10 @@ struct tcp_proxy {
struct lwip_tcp_ctx* lwip; // lwIP TCP stack context
uint32_t tun_ip_addr; // TUN IP (network byte order) for reply packets
int ip_fd_mode; // 1=raw fd input, 0=TUN input
// Framed read: для raw-fd mode, где поток байт не сохраняет границы пакетов
uint8_t raw_buf[2002]; // 2-byte len + max IP packet (MTU=1500 + 2B prefix)
size_t raw_pos; // сколько байт уже получено в текущем кадре
uint16_t raw_need; // сколько ещё байт ждать (0=ждём 2-байтный заголовок)
};
// ========== API ==========