Вставка контрольной суммы заголовка IPv4 в фиктивный заголовок IP - PullRequest
1 голос
/ 01 декабря 2010

Я пытаюсь создать пакет с учетом только содержимого полезной нагрузки. Поэтому мне придется создавать фиктивные заголовки IPv4 и UDP. У меня возникли проблемы с вставкой значения контрольной суммы IPv4 в фиктивный заголовок IP. Значение контрольной суммы рассчитывается с использованием алгоритма, используемого Wireshark. Я лишь немного изменил код, чтобы вставить контрольную сумму в заголовок IP.

Мой код выглядит следующим образом (с использованием Microsoft Visual Studio .NET 2003):

/********************** main.c ***********************/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <string.h>
#include <tchar.h>
#include <strsafe.h>
#include "in_cksum.h"

#define SIZE_IP_HDR 20

unsigned char ip_header[] = {0x45, 0x00, 0x05, 0x30, 0x00, 0x00, 0x40, 0x00, 0x20, 0x11, 0x00, 0x00, 0x21, 0x4f, 0x02, 0x7b, 0xcc, 0x5c, 0x46, 0x00};

int main(int argc, char **argv)
{
    ip_cal_checksum(ip_header, SIZE_IP_HDR);
    ip_header[12] = 0x2d;
    ip_cal_checksum(ip_header, SIZE_IP_HDR);
    return 0;
}


/********************** in_cksum.h ***********************/
#ifndef IN_CKSUM_H
#define IN_CKSUM_H

typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;

typedef struct
{
    const uint8_t *ptr;
    int len;
} vec_t;

int in_cksum(const vec_t *vec, int veclen);
uint16_t calculate_cksum(const vec_t *vec, int veclen);
void ip_cal_checksum(const uint8_t *ptr, int len);

#endif /* IN_CKSUM_H */


/********************** in_cksum.c ***********************/
#include "in_cksum.h"

#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}

int in_cksum(const vec_t *vec, int veclen)
{
    register const uint16_t *w;
    register int sum = 0;
    register int mlen = 0;
    int byte_swapped = 0;

    union {
        uint8_t c[2];
        uint16_t s;
    } s_util;
    union {
        uint16_t s[2];
        uint32_t l;
    } l_util;

    for (; veclen != 0; vec++, veclen--) {
        if (vec->len == 0)
            continue;
        w = (const uint16_t *)vec->ptr;
        if (mlen == -1) {
            /*
             * The first byte of this chunk is the continuation
             * of a word spanning between this chunk and the
             * last chunk.
             *
             * s_util.c[0] is already saved when scanning previous
             * chunk.
             */
            s_util.c[1] = *(const uint8_t *)w;
            sum += s_util.s;
            w = (const uint16_t *)((const uint8_t *)w + 1);
            mlen = vec->len - 1;
        } else
            mlen = vec->len;
        /*
         * Force to even boundary.
         */
        if ((1 & (unsigned long) w) && (mlen > 0)) {
            REDUCE;
            sum <<= 8;
            s_util.c[0] = *(const uint8_t *)w;
            w = (const uint16_t *)((const uint8_t *)w + 1);
            mlen--;
            byte_swapped = 1;
        }
        /*
         * Unroll the loop to make overhead from
         * branches &c small.
         */
        while ((mlen -= 32) >= 0) {
            sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
            sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
            sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
            sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
            w += 16;
        }
        mlen += 32;
        while ((mlen -= 8) >= 0) {
            sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
            w += 4;
        }
        mlen += 8;
        if (mlen == 0 && byte_swapped == 0)
            continue;
        REDUCE;
        while ((mlen -= 2) >= 0) {
            sum += *w++;
        }
        if (byte_swapped) {
            REDUCE;
            sum <<= 8;
            byte_swapped = 0;
            if (mlen == -1) {
                s_util.c[1] = *(const uint8_t *)w;
                sum += s_util.s;
                mlen = 0;
            } else
                mlen = -1;
        } else if (mlen == -1)
            s_util.c[0] = *(const uint8_t *)w;
    }
    if (mlen == -1) {
        /* The last mbuf has odd # of bytes. Follow the
           standard (the odd byte may be shifted left by 8 bits
           or not as determined by endian-ness of the machine) */
        s_util.c[1] = 0;
        sum += s_util.s;
    }
    REDUCE;
    return (~sum & 0xffff);
}

uint16_t calculate_cksum(const vec_t *vec, int veclen)
{
    register const uint16_t *w;
    register int sum = 0;
    register int mlen = 0;
    int byte_swapped = 0;

    union {
        uint8_t c[2];
        uint16_t s;
    } s_util;
    union {
        uint16_t s[2];
        uint32_t l;
    } l_util;

    for (; veclen != 0; vec++, veclen--) {
        if (vec->len == 0)
            continue;
        w = (const uint16_t *)vec->ptr;
        if (mlen == -1) {
            /*
             * The first byte of this chunk is the continuation
             * of a word spanning between this chunk and the
             * last chunk.
             *
             * s_util.c[0] is already saved when scanning previous
             * chunk.
             */
            s_util.c[1] = *(const uint8_t *)w;
            sum += s_util.s;
            w = (const uint16_t *)((const uint8_t *)w + 1);
            mlen = vec->len - 1;
        } else
            mlen = vec->len;
        /*
         * Force to even boundary.
         */
        if ((1 & (unsigned long) w) && (mlen > 0)) {
            REDUCE;
            sum <<= 8;
            s_util.c[0] = *(const uint8_t *)w;
            w = (const uint16_t *)((const uint8_t *)w + 1);
            mlen--;
            byte_swapped = 1;
        }
        /*
         * Unroll the loop to make overhead from
         * branches &c small.
         */
        while ((mlen -= 32) >= 0) {
            sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
            sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
            sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
            sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
            w += 16;
        }
        mlen += 32;
        while ((mlen -= 8) >= 0) {
            sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
            w += 4;
        }
        mlen += 8;
        if (mlen == 0 && byte_swapped == 0)
            continue;
        REDUCE;
        while ((mlen -= 2) >= 0) {
            sum += *w++;
        }
        if (byte_swapped) {
            REDUCE;
            sum <<= 8;
            byte_swapped = 0;
            if (mlen == -1) {
                s_util.c[1] = *(const uint8_t *)w;
                sum += s_util.s;
                mlen = 0;
            } else
                mlen = -1;
        } else if (mlen == -1)
            s_util.c[0] = *(const uint8_t *)w;
    }
    if (mlen == -1) {
        /* The last mbuf has odd # of bytes. Follow the
           standard (the odd byte may be shifted left by 8 bits
           or not as determined by endian-ness of the machine) */
        s_util.c[1] = 0;
        sum += s_util.s;
    }
    REDUCE;
    return (~sum & 0xffff);
}

void ip_cal_checksum(const uint8_t *ptr, int len)
{
    vec_t cksum_vec[1];
    uint16_t ip_checksum = 0;

    cksum_vec[0].ptr = ptr;
    cksum_vec[0].len = len;
    ip_checksum = calculate_cksum(&cksum_vec[0], 1);
    printf("%x\n", ip_checksum);
    memcpy((void *)&ptr[10], &ip_checksum, 2);  // copy checksum value to IP header
}

Код выше является упрощенной версией. В реальном коде я создал пакет с заголовками и содержимым и записал их в файл pcap. Используя Wireshark, я затем проверяю правильность контрольной суммы IP-адреса, то есть того же значения, которое вычисляется самим Wireshark. Моя проблема в том, что без строки memcpy в ip_cal_checksum () я получаю правильные значения контрольной суммы для всех созданных пакетов. Однако в строке memcpy верна только первая контрольная сумма, а большинство, если не все остальные значения контрольной суммы, неверны.

Например, используя код выше, первое вычисленное значение контрольной суммы равно 0x971f независимо от наличия строки memcpy. Однако второе вычисленное значение контрольной суммы составляет 0x9713 БЕЗ строки memcpy и 0xfff3 С memcpy.

Почему значение контрольной суммы изменяется в зависимости от наличия строки memcpy и как я могу решить эту проблему?

Спасибо.

С уважением, Rayne

1 Ответ

2 голосов
/ 01 декабря 2010

Строка memcpy изменяет заголовок (путем установки в нем контрольной суммы), и этот измененный заголовок является входом для второй контрольной суммы.

Вы должны установить поле контрольной суммы на 0 до вычисления контрольной суммы, чтобы получить правильный результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...