7

私は、受信したパケットを宛先に転送する前に分析することを目標とする TUN ベースの VPN サーバーに取り組んでいます。現在、私は TUN インターフェースから IP パケットを受信し、単純に変更せずに宛先に送信しています。

UDP パケットの内容を分析することは、IP および UDP ヘッダーを削除するのと同じくらい簡単であることを理解しています。ただし、TCP トラフィックの内容を分析するには、複数の IP パケットからメッセージを再構築する必要があります。TCP を再実装せずにこれを行う簡単な方法はありますか? このタスク用の簡単にアクセスできる C/C++ ライブラリはありますか? 私は、Linux システム ライブラリおよび/またはオープンソースの非バイラル/非コピーレフト ライブラリを好みます。

すでに検討したことの 1 つは、各 IP パケットのコピーを作成し、コピーの宛先 IP を localhost に変更することです。これにより、サーバーの別の部分がこれらの TCP 要求と応答を完全に再構築され、ヘッダーなしで受信できるようになります。ただし、目的のトラフィック コンテンツに宛先 IP を関連付けることはできません。

4

2 に答える 2

6

必要な機能は、常にパケットの分析と密接に結びついている可能性があります。必要な情報を抽出するには、優れたプロトコル ディセクタが本当に必要です。だから私の提案は、利用可能な最高のオープンソースツールを使用することです-wireshark.org

「TCP ストリームに従う」機能を提供します。

ここに画像の説明を入力

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 使用法に注意してください。

/* 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 ライブラリを使用することです。このライブラリを抽出して、単独で使用することができます。ライセンスに注意してください。

于 2013-09-15T00:58:49.407 に答える