LIBTCPIP 技术探秘(tun2sys-socket)

LIBTCPIP 技术探秘

一、项目概述与用途

LIBTCPIP 是一个基于 LwIP TCP/IP C netstack 2.13-RC2 实现的 TCP/IP loopback 子网络栈。

核心用途: 该项目的主要目的是创建一个用户态的 TCP/IP 网络栈,用于实现透明代理或 NAT 转换功能。它可以拦截和处理 IP 数据包,建立本地 TCP 连接来代理原始的 TCP 连接。

二、技术原理

2.1 核心设计

LIBTCPIP 采用双层网络栈架构

  1. LwIP 层:使用轻量级 TCP/IP 协议栈处理数据包
  2. 本地 Socket 层:使用真实的 TCP Socket 与目标服务通信

项目配置为 NO_SYS 模式运行,仅支持 TCP 协议,禁用了 UDP、ICMP、ARP、DHCP 等其他协议。

2.2 工作原理

Loopback 模式: 当 IP 数据包进入系统时,LwIP 会处理这些数据包。对于 TCP 连接,系统会在本地环回地址(localhost)上创建真实的 TCP Socket 连接来代理流量。

三、核心结构

3.1 主要 API 接口

项目提供三个核心 C API:

  1. libtcpip_loopback:初始化 loopback 网络栈,配置 IP、网关、掩码和输出回调函数

  2. libtcpip_input:将 IP 数据包输入到网络栈进行处理

  3. libtcpip_link:查询 NAT 映射信息,获取源/目标 IP 和端口

3.2 核心数据结构

netstack_tcp_socket:这是连接管理的核心结构,包含:

  • LwIP 的 tcp_pcb 指针
  • Boost.Asio 的真实 TCP Socket
  • 本地和远程 IP/端口信息
  • 发送缓冲区队列(分为 LwIP 层和 Socket 层)
  • NAT 端口映射标识符

3.3 管理映射表

使用两个哈希表管理 Socket 连接:

  • p2ss_:PCB 指针到 Socket 的映射
  • n2ss_:NAT 端口到 Socket 的映射

四、实现细节

4.1 初始化流程

初始化时会:

  1. 验证 IP、网关、掩码参数的有效性
  2. 设置输出回调函数和网络参数
  3. 初始化 LwIP 协议栈
  4. 配置网络接口的 IP 地址和输出函数
  5. 创建监听所有端口的 TCP PCB
  6. 启动独立线程运行 Boost.Asio 事件循环

4.2 TCP 连接建立流程

当收到 TCP 连接请求时:

  1. 接受连接 :LwIP 的 netstack_tcp_doaccept 被调用

  2. 创建 Socket 对象 :分配 netstack_tcp_socket 结构,记录连接的四元组信息

  3. 建立映射:将 PCB 与 Socket 对象关联

  4. 打开本地连接:在 localhost 上创建真实的 TCP Socket

  5. 连接目标:异步连接到目标端点(localhost)

  6. 注册回调:设置接收、发送、错误和轮询回调函数

4.3 数据转发机制

LwIP → Socket 方向:

  • LwIP 接收到数据时,通过 netstack_tcp_dorecv 处理
  • 数据被转发到真实的 Socket 通过 netstack_tunnel_send

Socket → LwIP 方向:

  • 从 Socket 读取数据通过 netstack_tunnel_dorecv
  • 使用 netstack_tcp_send 将数据写入 LwIP 的 TCP PCB

4.4 发送队列管理

系统维护两层发送队列:

  1. LWIP 层队列:当 LwIP 的发送缓冲区满时,数据会排队等待

  2. Socket 层队列:在真实 Socket 连接建立之前,数据会被缓存

当发送缓冲区有空间或连接建立时,队列中的数据会被逐一发送

4.5 NAT 端口映射

系统使用本地绑定端口作为 NAT 标识符,建立本地端口与原始连接的映射关系

通过 link 函数可以查询 NAT 映射,获取原始的源和目标地址信息

五、工作流程图

目标服务 本地 TCP Socket LwIP 协议栈 LIBTCPIP API 应用程序 目标服务 本地 TCP Socket LwIP 协议栈 LIBTCPIP API 应用程序 loop [数据转发] libtcpip_loopback(初始化) 初始化协议栈 libtcpip_input(IP 包) 处理数据包 TCP 连接请求 创建本地 Socket 连接 localhost 从 LwIP 接收数据 转发到目标 接收响应数据 回传到 LwIP output 回调 返回 IP 包

六、性能优化

  1. 零拷贝优化 :使用 TCP_WRITE_FLAG_COPY 标志让 LwIP 处理数据复制

  2. 高优先级线程:事件循环线程设置为最高优先级(Windows 上为 THREAD_PRIORITY_TIME_CRITICAL,Linux 上为 SCHED_FIFO)

  3. TCP Fast Open:尝试启用 TCP Fast Open 优化

  4. 禁用校验和验证:禁用所有协议的校验和检查以提高性能

  5. 配置大的 TCP 窗口:TCP 窗口大小设置为 32KB

Notes

应用场景:

  • 透明代理:拦截 TCP 流量并转发到代理服务器
  • VPN/隧道:实现用户态的网络隧道
  • 流量分析:在用户态分析和修改 TCP 流量
  • 网络模拟:模拟不同的网络条件进行测试

技术特点:

  • 纯用户态实现,无需内核模块
  • 基于成熟的 LwIP 协议栈
  • 使用 Boost.Asio 实现异步 I/O
  • 支持 Windows 和 Linux 平台
  • 提供 C API 接口,易于集成

局限性:

  • 仅支持 TCP 协议
  • 需要配合其他组件(如 TUN/TAP)实现完整的网络代理功能
  • 所有流量都通过 localhost 转发,适合本地代理场景

Citations

File: README.md (L1-2)

markdown 复制代码
# libtcpip
TCP/IP loopback sub-netstack based on LwIP TCP/IP C netstack 2.13-RC2.

File: lwip/my/lwipopts.h (L36-60)

text 复制代码
#define NO_SYS 1
#define LWIP_TIMERS 1

#define IP_DEFAULT_TTL 64
#define LWIP_ARP 0
#define ARP_QUEUEING 0
#define IP_FORWARD 0
#define LWIP_ICMP 0
#define LWIP_RAW 0
#define LWIP_DHCP 0
#define LWIP_AUTOIP 0
#define LWIP_SNMP 0
#define LWIP_IGMP 0
#define LWIP_DNS 0
#define LWIP_UDP 0
#define LWIP_UDPLITE 0
#define LWIP_TCP 1
#define LWIP_CALLBACK_API 1
#define LWIP_NETIF_API 0
#define LWIP_NETIF_LOOPBACK 0
#define LWIP_HAVE_LOOPIF 1
#define LWIP_HAVE_SLIPIF 0
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#define PPP_SUPPORT 0

File: lwip/my/lwipopts.h (L65-70)

text 复制代码
// disable checksum checks
#define CHECKSUM_CHECK_IP 0
#define CHECKSUM_CHECK_UDP 0
#define CHECKSUM_CHECK_TCP 0
#define CHECKSUM_CHECK_ICMP 0
#define CHECKSUM_CHECK_ICMP6 0

File: lwip/my/lwipopts.h (L85-86)

text 复制代码
#define TCP_WND 32 * 1024
#define TCP_SND_BUF (TCP_WND)

File: netstack.cpp (L13-42)

cpp 复制代码
    struct netstack_tcp_socket {
        typedef struct {
            std::shared_ptr<char>                       p;
            int                                         sz;
        } buffer_chunk;

        typedef struct {
            buffer_chunk                                buf;
            std::function<void(struct tcp_pcb*)>        cb;
        } send_context;
        typedef std::shared_ptr<send_context>           send_context_ptr;

        typedef enum {
            ENETSTACK_TCP_SENT_LWIP,
            ENETSTACK_TCP_SENT_SOCK,
            ENETSTACK_TCP_SENT_MAX
        } ENETSTACK_TCP_SENT_BUFS;

        std::list<send_context_ptr>                     sents[ENETSTACK_TCP_SENT_MAX];
        std::shared_ptr<boost::asio::ip::tcp::socket>   socket;
        bool                                            open;
        int                                             pnat;

        struct tcp_pcb*                                 pcb;
        ip_addr_t                                       local_ip;
        u16_t                                           local_port;
        ip_addr_t                                       remote_ip;
        u16_t                                           remote_port;
        u8_t                                            buf[1400];
    };

File: netstack.cpp (L54-56)

cpp 复制代码
    static Ptr2Socket                                   p2ss_;
    static Nat2Socket                                   n2ss_;
    static NetstackMutex                                lockobj_;

File: netstack.cpp (L146-189)

cpp 复制代码
    inline static err_t netstack_tcp_send(struct tcp_pcb* pcb, void* data, u16_t len, const std::function<void(struct tcp_pcb*)>& callback) noexcept {
        if (!pcb) {
            return ERR_ARG;
        }

        std::shared_ptr<netstack_tcp_socket> socket_ = netstack_tcp_getsocket(pcb->callback_arg);
        if (!socket_) {
            return ERR_ABRT;
        }

        if (!data || !len) {
            return ERR_ARG;
        }

        static auto tcp_enqueue_ =
            [](netstack_tcp_socket* socket_, struct tcp_pcb* pcb, void* data, u16_t len, const std::function<void(struct tcp_pcb*)>& callback) noexcept {
            std::shared_ptr<char> chunk_ = std::shared_ptr<char>((char*)malloc(len), free);
            memcpy(chunk_.get(), data, len);

            netstack_tcp_socket::send_context_ptr context_ =
                std::make_shared<netstack_tcp_socket::send_context>();
            context_->buf.p = std::move(chunk_);
            context_->buf.sz = len;
            context_->cb = callback;
            socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP].push_back(std::move(context_));
            return ERR_OK;
        };
        if (!socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP].empty()) {
            return tcp_enqueue_(socket_.get(), pcb, data, len, callback);
        }

        err_t err = tcp_write(pcb, data, len, TCP_WRITE_FLAG_COPY);
        if (err == ERR_OK) {
            tcp_output(pcb);
            if (callback) {
                callback(pcb);
            }
            return err;
        }
        else if (err == ERR_MEM) {
            return tcp_enqueue_(socket_.get(), pcb, data, len, callback);
        }
        return err;
    }

File: netstack.cpp (L278-298)

cpp 复制代码
    inline static err_t netstack_tcp_dorecv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) noexcept {
        LWIP_UNUSED_ARG(arg);

        if (p) {
            std::shared_ptr<netstack_tcp_socket> socket = netstack_tcp_getsocket(pcb->callback_arg);
            if (!socket) {
                tcp_abort(pcb);
                return ERR_ABRT;
            }

            for (struct pbuf* q = p; p; p = p->next) {
                tcp_recved(pcb, q->len);
                netstack_tunnel_send(socket, p->payload, p->len, true);
            }
            netstack_pbuf_free(p);
        }
        else if (err == ERR_OK) {
            return netstack_tcp_closesocket(pcb);
        }
        return ERR_OK;
    }

File: netstack.cpp (L300-335)

cpp 复制代码
    inline static err_t netstack_tcp_dosent(void* arg, struct tcp_pcb* pcb, u16_t len) noexcept {
        LWIP_UNUSED_ARG(arg);

        std::shared_ptr<netstack_tcp_socket> socket_ = netstack_tcp_getsocket(pcb->callback_arg);
        if (socket_) {
            std::list<netstack_tcp_socket::send_context_ptr>& sents = socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_LWIP];
            while (!sents.empty()) { // tcp_sndbuf
                err_t err_;
                do {
                    netstack_tcp_socket::send_context_ptr context_ = sents.front();
                    err_ = tcp_write(pcb,
                        context_->buf.p.get(),
                        context_->buf.sz, TCP_WRITE_FLAG_COPY);
                    if (err_ == ERR_OK) {
                        tcp_output(pcb);
                        if (context_->cb) {
                            context_->cb(pcb);
                        }
                        sents.pop_front();
                    }
                } while (0);
                if (err_) {
                    if (err_ == ERR_MEM) {
                        break;
                    }
                    netstack_tcp_closesocket(socket_);
                    return ERR_ABRT;
                }
            }
            return ERR_OK;
        }
        else {
            tcp_abort(pcb);
            return ERR_ABRT;
        }
    }

File: netstack.cpp (L364-366)

cpp 复制代码
    inline static err_t netstack_tcp_doaccept(void* arg, struct tcp_pcb* pcb, err_t err) noexcept {
        LWIP_UNUSED_ARG(arg);
        LWIP_UNUSED_ARG(err);

File: netstack.cpp (L368-376)

cpp 复制代码
        std::shared_ptr<netstack_tcp_socket> socket_ = std::make_shared<netstack_tcp_socket>();
        socket_->pcb = pcb;
        socket_->pnat = 0;
        socket_->open = false;
        socket_->socket = std::make_shared<boost::asio::ip::tcp::socket>(context_);
        socket_->local_ip = pcb->remote_ip;
        socket_->local_port = pcb->remote_port;
        socket_->remote_ip = pcb->local_ip;
        socket_->remote_port = pcb->local_port;

File: netstack.cpp (L378-385)

cpp 复制代码
        void* callback_arg = netstack_tcp_linksocket(pcb, socket_);
        if (callback_arg) {
            netstack_tcp_arg(pcb, callback_arg);
        }
        else {
            netstack_tcp_closesocket(socket_);
            return ERR_ABRT;
        }

File: netstack.cpp (L389-389)

cpp 复制代码
            netstack_tcp_event(pcb, netstack_tcp_dorecv, netstack_tcp_dosent, netstack_tcp_doerrf, netstack_tcp_dopoll);

File: netstack.cpp (L398-437)

cpp 复制代码
    inline static bool netstack_tunnel_send(const std::shared_ptr<netstack_tcp_socket>& socket_, void* data, int len, bool unsafe_) noexcept {
        if (!socket_ || !data || len < 1) {
            return false;
        }

        std::shared_ptr<boost::asio::ip::tcp::socket>& socket = socket_->socket;
        if (!socket || !socket->is_open()) {
            return false;
        }

        if (!socket_->open) {
            std::shared_ptr<char> chunk_ = std::shared_ptr<char>((char*)malloc(len), free);
            memcpy(chunk_.get(), data, len);

            netstack_tcp_socket::send_context_ptr context_ =
                std::make_shared<netstack_tcp_socket::send_context>();
            context_->buf.p = std::move(chunk_);
            context_->buf.sz = len;

            socket_->sents[netstack_tcp_socket::ENETSTACK_TCP_SENT_SOCK].push_back(std::move(context_));
            return true;
        }

        std::shared_ptr<char> chunk_;
        if (unsafe_) {
            chunk_ = std::shared_ptr<char>((char*)malloc(len), free);
            memcpy(chunk_.get(), data, len);
        }
        else {
            chunk_ = *(std::shared_ptr<char>*)data;
        }

        std::shared_ptr<netstack_tcp_socket> socket__ = socket_;
        boost::asio::async_write(*socket, boost::asio::buffer(chunk_.get(), len), [socket__, chunk_](const boost::system::error_code& ec, size_t sz) noexcept {
            if (ec) {
                netstack_tcp_closesocket(socket__);
            }
        });
        return true;
    }

File: netstack.cpp (L439-462)

cpp 复制代码
    inline static bool netstack_tunnel_dorecv(const std::shared_ptr<netstack_tcp_socket>& socket_) noexcept {
        if (!socket_) {
            return false;
        }

        std::shared_ptr<boost::asio::ip::tcp::socket>& socket = socket_->socket;
        if (!socket || !socket->is_open()) {
            return false;
        }

        std::shared_ptr<netstack_tcp_socket> socket__ = socket_;
        socket->async_read_some(boost::asio::buffer(socket_->buf, sizeof(socket_->buf)), [socket__](const boost::system::error_code& ec, size_t sz) {
            int by = std::max<int>(-1, ec ? -1 : (int)sz);
            if (by < 1) {
                netstack_tcp_closesocket(socket__);
            }
            else {
                netstack_tcp_send(socket__->pcb, socket__->buf, by, [socket__](struct tcp_pcb*) {
                    netstack_tunnel_dorecv(socket__);
                });
            }
        });
        return true;
    }

File: netstack.cpp (L478-509)

cpp 复制代码
    inline static bool netstack_socket_connect(const std::shared_ptr<netstack_tcp_socket>& socket_, const boost::asio::ip::tcp::endpoint& remoteEP_) noexcept {
        if (!socket_) {
            return false;
        }
        
        std::shared_ptr<boost::asio::ip::tcp::socket> socket = socket_->socket;
        if (!socket) {
            return false;
        }

        socket->async_connect(remoteEP_, [socket_](const boost::system::error_code& ec) noexcept {
            if (ec) {
                netstack_tcp_closesocket(socket_);
                return;
            }

            if (socket_->open) {
                netstack_tcp_closesocket(socket_);
                return;
            }
            else {
                socket_->open = true;
            }

            bool ok = netstack_tunnel_dorecv(socket_) && nestack_tunnel_post_all_unsent(socket_);
            if (!ok) {
                netstack_tcp_closesocket(socket_);
                return;
            }
        });
        return true;
    }

File: netstack.cpp (L511-552)

cpp 复制代码
    inline static bool netstack_tunnel_open(const std::shared_ptr<netstack_tcp_socket>& socket_, boost::asio::ip::tcp::endpoint& remoteEP_) noexcept {
        std::shared_ptr<boost::asio::ip::tcp::socket>& socket = socket_->socket;
        if (!socket || socket->is_open()) {
            return false;
        }

        if (IP_IS_V4_VAL(socket_->remote_ip)) {
            remoteEP_ = boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::loopback(), netstack::Localhost);
        }
        else {
            return false;
        }

        boost::system::error_code ec;
        try {
            socket->open(remoteEP_.protocol(), ec);
            if (ec) {
                return false;
            }

            socket->set_option(boost::asio::detail::socket_option::boolean<IPPROTO_TCP, TCP_FASTOPEN>(true), ec);
            socket->bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::loopback(), 0), ec);
            if (ec) {
                return false;
            }

            boost::asio::ip::tcp::endpoint localEP = socket->local_endpoint(ec);
            if (ec) {
                return false;
            }
            
            socket_->pnat = netstack_tcp_linksocket(localEP.port(), socket_);
            if (!socket_->pnat) {
                return false;
            }

            return true;
        }
        catch (std::exception&) {
            return false;
        }
    }

File: netstack.cpp (L571-579)

cpp 复制代码
        struct tcp_pcb* pcb = tcp_new();

        tcp_bind(pcb, IP_ADDR_ANY, 0);
        pcb = tcp_listen(pcb);
        tcp_arg(pcb, NULL);
        tcp_accept(pcb, netstack_tcp_doaccept);

        pcb_ = pcb;
        return pcb_ != NULL;

File: netstack.cpp (L628-628)

cpp 复制代码
        lwip_init();

File: netstack.cpp (L634-637)

cpp 复制代码
        ip4_addr_t ips[] = { netstack::IP, netstack::MASK, netstack::IP };
        netif_set_ipaddr(netif, ips + 0);
        netif_set_netmask(netif, ips + 1);
        netif_set_gw(netif, ips + 2);

File: netstack.cpp (L645-657)

cpp 复制代码
        std::thread([]() noexcept {
#ifdef _WIN32
            SetThreadPriority(GetCurrentProcess(), THREAD_PRIORITY_TIME_CRITICAL);
#else
            /* ps -eo state,uid,pid,ppid,rtprio,time,comm */
            struct sched_param param_;
            param_.sched_priority = sched_get_priority_max(SCHED_FIFO); // SCHED_RR
            pthread_setschedparam(pthread_self(), SCHED_FIFO, &param_);
#endif
            boost::system::error_code ec_;
            boost::asio::io_context::work work_(context_);
            context_.run(ec_);
        }).detach();

File: netstack.cpp (L692-719)

cpp 复制代码
    bool netstack::link(int nat, uint32_t& srcAddr, int& srcPort, uint32_t& dstAddr, int& dstPort) noexcept {
        dstAddr = 0;
        dstPort = 0;
        srcAddr = 0;
        srcPort = 0;

        std::shared_ptr<netstack_tcp_socket> socket = netstack_tcp_getsocket(nat);
        if (!socket) {
            return false;
        }

        if (IP_IS_V4_VAL(socket->remote_ip)) {
            dstAddr = ip_addr_get_ip4_u32(&socket->remote_ip);
            dstPort = socket->remote_port;
        }
        else {
            return false;
        }

        if (IP_IS_V4_VAL(socket->local_ip)) {
            srcAddr = ip_addr_get_ip4_u32(&socket->local_ip);
            srcPort = socket->local_port;
            return true;
        }
        else {
            return false;
        }
    }

File: libtcpip.h (L25-26)

text 复制代码
LIBTCPIP_API
bool libtcpip_input(void* packet, int size) noexcept;

File: libtcpip.h (L28-29)

text 复制代码
LIBTCPIP_API
bool libtcpip_link(int nat, uint32_t& srcAddr, int& srcPort, uint32_t& dstAddr, int& dstPort) noexcept;

File: libtcpip.h (L31-32)

text 复制代码
LIBTCPIP_API
bool libtcpip_loopback(int localhost, uint32_t ip, uint32_t gw, uint32_t mask, LIBTCPIP_IPV4_OUTPUT outputfn) noexcept;

File: libtcpip.cpp (L6-16)

cpp 复制代码
    if (ip == INADDR_ANY || ip == INADDR_NONE) {
        return false;
    }

    if (gw == INADDR_ANY || gw == INADDR_NONE) {
        return false;
    }

    if (mask == INADDR_ANY || !outputfn) {
        return false;
    }

File: libtcpip.cpp (L18-22)

cpp 复制代码
    lwip::netstack::output = outputfn;
    lwip::netstack::IP = ip;
    lwip::netstack::GW = gw;
    lwip::netstack::MASK = mask;
    lwip::netstack::Localhost = localhost;
相关推荐
yyy(十一月限定版)18 小时前
c++(3)类和对象(中)
java·开发语言·c++
落羽凉笙18 小时前
Python基础(4)| 玩转循环结构:for、while与嵌套循环全解析(附源码)
android·开发语言·python
ytttr87318 小时前
MATLAB的流体动力学与热传导模拟仿真实现
开发语言·matlab
山上三树18 小时前
详细介绍 C 语言中的 #define 宏定义
c语言·开发语言·算法
zbtlink18 小时前
2.5G路由器是啥?和家用的有哪些差异?
网络·智能路由器
测试游记18 小时前
基于 FastGPT 的 LangChain.js + RAG 系统实现
开发语言·前端·javascript·langchain·ecmascript
DYS_房东的猫18 小时前
写出第一个程序
c++
以太浮标18 小时前
华为eNSP模拟器综合实验之- HRP(华为冗余协议)双机热备
运维·网络·华为·信息与通信
小罗和阿泽18 小时前
java 【多线程基础 三】
java·开发语言