パケット解析のエラー

私はパケットを解析しようとしています。すべてのIPヘッダーが正常になるまで(私はすべての値を正しく取得できます)。 udpヘッダーの場合(プロトコルが17の場合にチェックされます)、値は間違っています(すべての4つのフィールド)。 私はこれをやろうとしている:

struct udp_header{
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t chksum;
};
 struct udp_header* udp= (struct udp_header*)(packet + 14 + ip_hdr->ip_hl*4); 

パケットは、パケットの先頭を指すポインタです。 14はイーサネットヘッダー用です。チェックされると、ヘッダー長さipが正しい値を出力します。しかし、この操作を実行した後、私はすべてのフィールドを間違って取得しています。データタイプとしてuint8_tを試してみたとき(私は間違っていることを知っています!)、destintionポートは何とか正しく出力されています。

0
どのようにパケットを送っていますか?
追加された 著者 Richard J. Ross III,
変数 packet はどのように宣言されていますか?また、16ビット値と32ビット値はすべてネットワークバイトオーダであることに注意してください。
追加された 著者 Some programmer dude,
@JoachimPileborg:u_char *
追加された 著者 user1192671,

3 答え

あなたはエンディアンに慣れています。 IPパケットはすべてのフィールドをネットワークバイトオーダー(別名ビックエンディアン)で持ち、ホストシステムはおそらくリトルエンディアンを実行します。 1つのアプローチについては、 ntohs()と友人を参照してください。

適切な方法は、ネットワークデータからそのまま構造をコピーせず、各フィールドを手動で抽出し、必要に応じてバイトスワップすることです。これはまた、パディングとアライメントの問題を回避するために、パケットがシリアル化されたのとまったく同じ方法で struct がコンピュータのメモリにマップされるという保証はありません。

たとえば、次のようにします。

udp_header.sport = ntohs(*(unsigned short*) (packet + 14 + 4 * ip_hdr->ip_hl));

結果のアドレスが unsigned short へのポインタに有効にキャストされることができると仮定しているため、これも少しiffyです。 x86上では動作しますが、叙事詩ではありません。

さらに、私の意見では、ポインタの使用を中止し、代わりに、関数と呼ばれる関数を書くことです。バイト単位で値を抽出して返す unsigned short read_u16(void * packet、size_t offset)それから、

udp_header.sport = read_u16(packet, 14 + 4 * ip_hdr->ip_hl);
3
追加された
私にそれをビート:)
追加された 著者 Richard J. Ross III,
@ user1192671あなたは今のように行いますが、後で使用してください。 udp-> sport = ntohs(udp-> sport); など、他のフィールドでも同じ操作を行います。
追加された 著者 Some programmer dude,
だから何が変わるだろうか?エンディアンに応じて構造定義を変更する必要がありますか?
追加された 著者 user1192671,

私はいつもこの構造体をIPヘッダーに使用します:

struct sniff_ip {
    u_char  ip_vhl;                 /* version << 4 | header length >> 2 */
    u_char  ip_tos;                 /* type of service */
    u_short ip_len;                 /* total length */
    u_short ip_id;                  /* identification */
    u_short ip_off;                 /* fragment offset field */
    #define IP_RF 0x8000            /* reserved fragment flag */
    #define IP_DF 0x4000            /* dont fragment flag */
    #define IP_MF 0x2000            /* more fragments flag */
    #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
    u_char  ip_ttl;                 /* time to live */
    u_char  ip_p;                   /* protocol */
    u_short ip_sum;                 /* checksum */
    struct  in_addr ip_src,ip_dst;  /* source and dest address */
};
#define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip)                (((ip)->ip_vhl) >> 4)

UDP構造体ポインタを取得するには:

udp = (struct sniff_udp*)(packet + SIZE_ETHERNET + (IP_HL(ip)*4));
2
追加された

もう1つの答えとして、データのエンディアンを扱わなければなりません。

あなたが対処する必要があるもう一つのことは、バイト配列です。スピードのために、Cの中で以下のように構造体を定義するとき:

struct udp_header{
uint16_t sport;
uint16_t dport;
uint16_t len;
uint16_t chksum;
};

The C compiler may leave padding bytes between these fields so that member accesses can be done with faster single-instruction memory access assembly instructions. You can check if your c compiler is doing this by printf("struct size is: %u\n", sizeof(struct udp_header));

GCCを使用していると仮定すると、構造体定義の前に #pragma pack(1)を追加することでパディングバイトを無効にする必要があります。速度のためにパディングを再び有効にするには、 #pragma pack()を使用する必要があります。

0
追加された