Вычислить контрольную сумму Интернета (он же IP, он же RFC791) в С#

Интересно, что я могу найти реализации Internet Checksum почти на всех языках, кроме C#. У кого-нибудь есть реализация, которой можно поделиться?

Помните, что интернет-протокол указывает следующее:

«Поле контрольной суммы представляет собой 16-битное дополнение до единицы суммы всех 16-битных слов в заголовке. Для целей вычисления контрольной суммы значение поля контрольной суммы равно нулю».

Дополнительные пояснения можно найти у Dr. Математика.

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

Пожалуйста, включите ваши тесты! (Редактировать: Действительный комментарий относительно тестирования чужого кода, но я выхожу из протокола, у меня нет собственных тестовых векторов, и я предпочел бы его модульное тестирование, а не запуск в производство, чтобы увидеть, соответствует ли он тому, что используется в настоящее время! ;-)

Изменить: вот несколько модульных тестов, которые я придумал. Они тестируют метод расширения, который перебирает всю коллекцию байтов. Пожалуйста, прокомментируйте, если вы обнаружите ошибки в тестах.

[TestMethod()]
public void InternetChecksum_SimplestValidValue_ShouldMatch()
{
    IEnumerable<byte> value = new byte[1]; // should work for any-length array of zeros
    ushort expected = 0xFFFF;

    ushort actual = value.InternetChecksum();

    Assert.AreEqual(expected, actual);
}

[TestMethod()]
public void InternetChecksum_ValidSingleByteExtreme_ShouldMatch()
{
    IEnumerable<byte> value = new byte[]{0xFF};
    ushort expected = 0xFF;

    ushort actual = value.InternetChecksum();

    Assert.AreEqual(expected, actual);
}

[TestMethod()]
public void InternetChecksum_ValidMultiByteExtrema_ShouldMatch()
{
    IEnumerable<byte> value = new byte[] { 0x00, 0xFF };
    ushort expected = 0xFF00;

    ushort actual = value.InternetChecksum();

    Assert.AreEqual(expected, actual);
}

person Pat    schedule 02.02.2010    source источник
comment
Принадлежит plzsendtehcodez.com. :-P (Извините, не удержался, увидев, что пожалуйста, включите ссылку на ваши тесты; я ожидаю, что вы напишете свои собственные тесты для проверки чужих реализаций.)   -  person Chris Jester-Young    schedule 03.02.2010
comment
Не пробовал, но похоже на NBit (zer7.com/software/nbit и далее NuGet) могут иметь методы для этой контрольной суммы, среди прочего.   -  person Pat    schedule 23.11.2013


Ответы (2)


Я знал, что это где-то хранится... http://cyb3rspy.wordpress.com/2008/03/27/ip-header-checksum-function-in-c/

person Jesper Palm    schedule 02.02.2010
comment
Спасибо, Джеспер, но эта реализация не прошла тест InternetChecksum_ValidSingleByteExtreme_ShouldMatch (фактическое значение = 65535). Я адаптировал вашу реализацию к вызову моего метода, добавив к нему префикс int start = 0; заголовок var = значение.ToArray(); int length = заголовок.Длина - 1; Примечание. Длина должна быть меньше, чем header.Length, потому что ваш цикл обращается к заголовку [i+1] (было выдано исключение). - person Pat; 03.02.2010

Что ж, я откопал реализацию из старой кодовой базы, и она проходит те тесты, которые я указал в вопросе, так что вот она (как метод расширения):

public static ushort InternetChecksum(this IEnumerable<byte> value)
{
    byte[] buffer = value.ToArray();
    int length = buffer.Length;
    int i = 0;
    UInt32 sum = 0;
    UInt32 data = 0;
    while (length > 1)
    {
        data = 0;
        data = (UInt32)(
        ((UInt32)(buffer[i]) << 8)
        |
        ((UInt32)(buffer[i + 1]) & 0xFF)
        );

        sum += data;
        if ((sum & 0xFFFF0000) > 0)
        {
            sum = sum & 0xFFFF;
            sum += 1;
        }

        i += 2;
        length -= 2;
    }

    if (length > 0)
    {
        sum += (UInt32)(buffer[i] << 8);
        //sum += (UInt32)(buffer[i]);
        if ((sum & 0xFFFF0000) > 0)
        {
            sum = sum & 0xFFFF;
            sum += 1;
        }
    }
    sum = ~sum;
    sum = sum & 0xFFFF;
    return (UInt16)sum;
}
person Pat    schedule 04.02.2010