add framed read for raw fd (2-byte len prefix), TCP_NODELAY, fix test half-close ordering
This commit is contained in:
1 parent
d0af315ff6
commit
d3b6057f82
7 files changed
+65
-570
No files matched your search
+55
-36
@@ -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;
|
||||
}
|
||||
@@ -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 ==========
|
||||
|
||||
Reference in new issue
Block a user