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

Jom*_*asi 7 c++ sockets vpn networking tcp

我正在开发一个基于TUN的VPN服务器,其目的是在将数据包转发到目的地之前分析它收到的数据包.目前,我从TUN接口接收IP数据包,只是将它们发送到目的地未经修改.

我知道分析UDP数据包的内容就像剥离IP和UDP头一样简单.但是,为了分析TCP流量的内容,我需要从多个IP数据包重建消息.有没有重新实现TCP的简单方法呢?是否有任何易于访问的C/C++库用于此任务?我更喜欢Linux系统库和/或开源,非病毒/非copyleft库.

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

Ren*_*nov 6

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

它提供"Follow TCP stream"功能:

在此输入图像描述

我看起来你不能轻易提取部分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
                 */
Run Code Online (Sandbox Code Playgroud)

基本上,有单独的会话提取逻辑,请注意find_conversation 用法:

/* 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;
    }
Run Code Online (Sandbox Code Playgroud)

实际逻辑已有详细记录,可在此处获得:

/*
 * 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))) {
Run Code Online (Sandbox Code Playgroud)

所以我实际建议的是使用EPAN库.可以提取此库并单独使用它.请注意许可证.