Как восстановить поток TCP из нескольких IP-пакетов?

Я работаю над VPN-сервером на основе TUN, целью которого является анализ пакетов, которые он получает, прежде чем пересылать их в пункт назначения. В настоящее время я получаю IP-пакеты от интерфейса TUN и просто отправляю их в пункт назначения без изменений.

Я понимаю, что анализ содержимого UDP-пакетов будет таким же простым, как удаление заголовков IP и UDP. Однако для анализа содержимого TCP-трафика мне нужно будет восстановить сообщение с нескольких IP-адресов пакетированный. Существует ли простой способ сделать это без повторной реализации TCP? Существуют ли легкодоступные библиотеки C / C++, предназначенные для этой задачи? Я бы предпочел системные библиотеки Linux и/или библиотеки с открытым исходным кодом, не вирусные / не-copyleft.

одна вещь, которую я уже рассмотрел, - это создание копии каждого IP-пакета и изменение IP-адреса назначения копии на localhost, чтобы другая часть моего сервера могла получать эти TCP-запросы и ответы, полностью восстановленные и без заголовки. Однако я не смог бы связать IP-адреса назначения с контентом трафика, что является тем, что я хочу.

2 ответов


вероятно, функциональность, которая вам нужна, всегда будет тесно связана с рассечением пакетов. Хорошие протокольные диссекторы действительно необходимы для извлечения необходимой информации. Поэтому я предлагаю использовать лучший инструмент с открытым исходным кодом -wireshark.org

он обеспечивает функциональность "Follow TCP stream":

enter image description here

Я не похоже, что вы можете легко извлечь часть логики Wireshark dissection, но, по крайней мере, есть хороший пример пакет-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 использование:

/* 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;
    }

фактическая логика хорошо документирована и доступна здесь:

/*
 * 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. Можно извлечь эту библиотеку и использовать ее самостоятельно. Пожалуйста, будьте осторожны с лицензией.


может быть, вы могли бы быть заинтересованы в libipq - библиотека очереди пакетов iptables userspace.

#include <linux/netfilter.h>
#include <libipq.h>

Netfilter обеспечивает механизм для передачи пакетов из стека для очереди в userspace, а затем получения этих пакетов обратно в ядро с вердиктом, указывающим, что делать с пакетами (например, Принять или отбросить). Эти пакеты также могут быть изменены в userspace до для повторного ввода обратно в ядро. Для каждого поддержанного протокола модуль ядра, называемый обработчиком очереди, может регистрироваться в Netfilter для проанализировать механизмы передачи пакетов от разработки.

стандартный обработчик очереди для IPv4 ip_queue. Это предусмотрено как экспериментальный модуль с 2.4 ядрами и использует сокет Netlink для kernel / userspace communication.

Как только ip_queue загружен, IP-пакеты могут быть выбраны с iptables и очередь для обработки пространства пользователей через очередь цель

вот краткий пример того, как разложить пакет tcp/ip:

ipq_packet_msg_t *m = ipq_get_packet(buf);

struct iphdr *ip = (struct iphdr*) m->payload;

struct tcphdr *tcp = (struct tcphdr*) (m->payload + (4 * ip->ihl));

int port = htons(tcp->dest);        

status = ipq_set_verdict(h, m->packet_id,
                          NF_ACCEPT, 0, NULL);
if (status < 0)
        die(h);

быстрая интро

Если это не то, что вы ищете, вы могли бы попробовать использовать библиотека wireshark EPAN.