Я пытаюсь вычислить значение контрольной суммы TCP (которое, очевидно, совпадает с контрольной суммой IP4), но получаю неправильные результаты. Я думаю, что проблема возникает из-за заполнения в конце или из поля заголовка TCP, но я не могу найти какие-либо подробности (из RFC) о том, как они должны быть рассчитаны.
Для построения псевдоголовка ( wiki ) Я использую следующий код для объединения данных (field('xyz').bin()
возвращает двоичную строку поля xyz
.):
public String genChecksum()
{
String pseudoHeader = "";
// From IPv4 - Pseudo Header
pseudoHeader += peekField("source").bin();
pseudoHeader += peekField("destination").bin();
pseudoHeader += "00000000"; // reserved block
pseudoHeader += peekField("protocol").bin();
/* TCP Length field:
* headerSize() = (TCP.dataOffset * 32) to get TCP header length
* dataSize() = (IP4.totalLength * 8) - ((IP4.internetHeaderLength * 32) + (TCP.dataOffset * 32))
*/
pseudoHeader += Types.hexToBin(Types.numToHex((int) Math.ceil((headerSize() + dataSize()) / 8)));
// From TCP Header
pseudoHeader += field("srcPort").bin();
pseudoHeader += field("dstPort").bin();
pseudoHeader += field("seqNum").bin();
pseudoHeader += field("ackNum").bin();
pseudoHeader += field("dataOffset").bin();
pseudoHeader += field("reserved").bin();
pseudoHeader += field("flagNS").bin();
pseudoHeader += field("flagCWR").bin();
pseudoHeader += field("flagECE").bin();
pseudoHeader += field("flagURG").bin();
pseudoHeader += field("flagACK").bin();
pseudoHeader += field("flagPSH").bin();
pseudoHeader += field("flagRST").bin();
pseudoHeader += field("flagSYN").bin();
pseudoHeader += field("flagFIN").bin();
pseudoHeader += field("windowSize").bin();
pseudoHeader += "0000000000000000"; // checksum zeroed out
pseudoHeader += field("urgPointer").bin();
pseudoHeader += field("optional").bin();
pseudoHeader += field("data").bin();
// Pad to 16 bit boundary as stated in RFC
for (int i = 0; i < (pseudoHeader.length() % 16); i++)
{
pseudoHeader += "0";
}
System.out.println("pseudoHeader: " + Types.binToHex(pseudoHeader));
return Types.binToHex(pseudoHeader);
}
Я вполне уверен, что значения при сближении (field()
и peekField()
верны, я проверил их с помощью wireshark и контрольная сумма IP4 верна. Фактический метод контрольной суммы включен ниже, но я есть тест, чтобы проверить это тоже правильно:
public static String CRC16(String hex)
{
byte[] buf = Types.hexToBytes(hex);
int length = buf.length;
int i = 0;
long sum = 0;
long data;
while (length > 1)
{
data = (((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0xFF));
sum += data;
if ((sum & 0xFFFF0000) > 0)
{
sum = sum & 0xFFFF;
sum += 1;
}
i += 2;
length -= 2;
}
if (length > 0)
{
sum += (buf[i] << 8 & 0xFF00);
if ((sum & 0xFFFF0000) > 0)
{
sum = sum & 0xFFFF;
sum += 1;
}
}
sum = ~sum;
sum = sum & 0xFFFF;
System.out.println("CRCV: " + String.format("%X", sum));
return String.format("%X", sum);
}
public static void assertTestChecksum()
{
byte[] buf = {(byte) 0xe3, 0x4f, 0x23, (byte) 0x96, 0x44, 0x27, (byte) 0x99, (byte) 0xf3};
if (!CRC16(Types.bytesToHex(buf)).equals("1AFF"))
{
Utils.exit("Checksum.java", "assertTestChecksum() failed.");
}
}
Я делаю что-то явно не так?