c++ - 如何从多个 IP 数据包重建 TCP 流?

标签 c++ sockets networking tcp vpn

我在一个基于 TUN 的 VPN 服务器上工作,它的目标是在将它们转发到目的地之前分析它收到的数据包。目前我正在从 TUN 接口(interface)接收 IP 数据包,并简单地将它们原封不动地发送到目的地。

我知道分析 UDP 数据包的内容就像剥离 IP 和 UDP header 一样简单。但是,要分析 TCP 流量的内容,我需要从多个 IP 数据包中重建消息。有没有一种简单的方法可以在不重新实现 TCP 的情况下做到这一点?是否有用于此任务的易于访问的 C/C++ 库?我更喜欢 Linux 系统库和/或开源、非病毒/非 copyleft 库。

我已经考虑过的一件事是制作每个 IP 数据包的拷贝,并将拷贝的目标 IP 更改为本地主机,以便我的服务器的不同部分可以接收这些 TCP 请求和响应,这些请求和响应完全重构且没有 header 。但是,我无法将目标 IP 与流量内容相关联,这是我想要的。

最佳答案

您需要的功能很可能总是与数据包解析紧密结合。确实需要好的协议(protocol)解析器来提取所需的信息。所以我的建议是使用可用的最佳开源工具 - wireshark.org

它提供“跟随 TCP 流”功能:

enter image description here

我看起来不像您可以轻松提取 Wireshark 剖析逻辑的一部分,但至少有一个很好的例子 packet-tcp :

typedef struct _tcp_flow_t {
    guint32 base_seq;   /* base seq number (used by relative sequence numbers)
                 * or 0 if not yet known.
                 */
    tcp_unacked_t *segments;
    guint32 fin;        /* frame number of the final FIN */
    guint32 lastack;    /* last seen ack */
    nstime_t lastacktime;   /* Time of the last ack packet */
    guint32 lastnondupack;  /* frame number of last seen non dupack */
    guint32 dupacknum;  /* dupack number */
    guint32 nextseq;    /* highest seen nextseq */
    guint32 maxseqtobeacked;/* highest seen continuous seq number (without hole in the stream) from the fwd party,
                 * this is the maximum seq number that can be acked by the rev party in normal case.
                 * If the rev party sends an ACK beyond this seq number it indicates TCP_A_ACK_LOST_PACKET contition */
    guint32 nextseqframe;   /* frame number for segment with highest
                 * sequence number
                 */

基本上,有单独的对话提取逻辑,请注意find_conversation usage :

/* Attach process info to a flow */
/* XXX - We depend on the TCP dissector finding the conversation first */
void
add_tcp_process_info(guint32 frame_num, address *local_addr, address *remote_addr, guint16 local_port, guint16 remote_port, guint32 uid, guint32 pid, gchar *username, gchar *command) {
    conversation_t *conv;
    struct tcp_analysis *tcpd;
    tcp_flow_t *flow = NULL;

    conv = find_conversation(frame_num, local_addr, remote_addr, PT_TCP, local_port, remote_port, 0);
    if (!conv) {
        return;
    }

实际逻辑有据可查且可用 here :

/*
 * Given two address/port pairs for a packet, search for a conversation
 * containing packets between those address/port pairs.  Returns NULL if
 * not found.
 *
 * We try to find the most exact match that we can, and then proceed to
 * try wildcard matches on the "addr_b" and/or "port_b" argument if a more
 * exact match failed.
 * ...
 */
conversation_t *
find_conversation(const guint32 frame_num, const address *addr_a, const address *addr_b, const port_type ptype,
    const guint32 port_a, const guint32 port_b, const guint options)
{
   conversation_t *conversation;

   /*
    * First try an exact match, if we have two addresses and ports.
    */
   if (!(options & (NO_ADDR_B|NO_PORT_B))) {

所以我实际上是建议使用 EPAN library .可以提取这个库并独立使用它。请小心使用许可证。

关于c++ - 如何从多个 IP 数据包重建 TCP 流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18727135/

相关文章:

c++ - 我修改了 gtest/gmock,所以模拟非虚函数真的很容易

c++ - 'prior value shall be accessed only to determine the value to be stored' 是什么意思?

c++ - 为什么具有固定底层 char 类型的枚举的值解析为 fct(int) 而不是 fct(char)?

c++ - qtcreator 没有使用指定的编译器

Java:如何在池中维护 SSLSocket session 以防止对每条消息进行新的握手

java - Java中字节/整数数组的实际数据大小是多少

xml - XML over Sockets 是好的还是坏的做法?

c# - 通过 ping 或 socket 检查代理有什么区别?

azure - 无法连接到 Azure 文件共享驱动器,使用映射驱动器无法连接,我也添加了端口 445

networking - Arduino 射频传感器网络