vikramlinux Ответов: 3

Контрольная сумма TCP по IPv6


Привет Ребята,
Я пытаюсь выяснить контрольную сумму TCP по IPV6. Пожалуйста, смотрите ниже треску

Что я уже пробовал:

char src_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xa1, 0xe4, 0x22, 0x2c, 0x0c, 0x9b, 0x57, 0x22
};

char dest_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x18, 0xd7, 0xc9, 0x57, 0x52, 0xd7, 0x0f, 0xcd
};

_inline unsigned short TOWORD(unsigned int a)
{
    return (unsigned short)( ((a>>8)&0x00FFL) + ((a<<8)&0xFF00L) );
}


int _tmain(int argc, _TCHAR* argv[])
{
	unsigned int sum=0;

	for(int i = 0; i < 8; i++)
	{
		sum += *((unsigned short*)(src_addr+i));
	}

	for(int i = 0; i < 8; i++)
	{
		sum += *(((unsigned short*)dest_addr+i));
	}
	
	unsigned short type = 0x06; // TCP protocol
	sum += TOWORD(type);

	unsigned int tcplen = 0x1c; // 28 bytes length

	sum += ((tcplen <<8) & 0xFFFF) + (tcplen >> 8);

	sum = (sum>>16)+(sum&0xffff);
	sum += (sum>>16);

	sum = (~sum & 0xFFFF);
	unsigned short sum1 =  sum;

	printf("Checksum = %x\n", sum1);
	return 0;
}


дает выход 3а96.

Однако WireShak показывает контрольную сумму 0x3c3b.

Не могли бы вы мне помочь?

3 Ответов

Рейтинг:
25

Jochen Arndt

Это очевидно неправильно и прекрасный пример того, почему кастинг может быть небезопасным:

for(int i = 0; i < 8; i++)
{
    sum += *((unsigned short*)(src_addr+i));
}

Вы находитесь кастинг char указатель на unsigned short*. Хотя это может быть использовано, вы забыли, по крайней мере, что тогда вам нужно увеличить указатель на два.

Я не знаю о порядке байтов в этом случае, поэтому возможным решением может быть одно из них:
for(int i = 0; i < 16; i += 2)
{
    sum += src_addr[i] + (src_addr[i+1] << 8U);
    // Or this (EDIT: I guess this is it)
    sum += (src_addr[i] << 8U) + src_addr[i+1];
}

[РЕДАКТИРОВАТЬ]
Могут быть и другие ошибки и/или неправильная реализация. Контрольная сумма IPv6 TCP генерируется на заголовке TCP, псевдо-заголовке и данных.
Ваш код вычисляет контрольную сумму для псевдо-заголовка. Я не знаю, какая контрольная сумма сообщается WireShark, но ожидаю, что она будет полной.
[/РЕДАКТИРОВАТЬ]


Рейтинг:
2

vikramlinux

Отсутствовал заголовок TCP + данные. Спасибо, Йохен.


Member 13641570

Поделитесь кодом, который работал на вас?

Рейтинг:
0

vikramlinux

Попробовал ниже код в соответствии с приведенным выше предложением.

char src_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xa1, 0xe4, 0x22, 0x2c, 0x0c, 0x9b, 0x57, 0x22
};

char dest_addr[] = {
  0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x18, 0xd7, 0xc9, 0x57, 0x52, 0xd7, 0x0f, 0xcd
};


_inline unsigned short TOWORD(unsigned int a)
{
    return (unsigned short)( ((a>>8)&0x00FFL) + ((a<<8)&0xFF00L) );
}


int _tmain(int argc, _TCHAR* argv[])
{
	unsigned int sum=0;

	for(int i = 0; i < 16; i += 2)
	{
		sum += src_addr[i] + (src_addr[i+1] << 8U);
	}

	for(int i = 0; i < 16; i += 2)
	{
		sum += dest_addr[i] + (dest_addr[i+1] << 8U);
	}

	
	unsigned short type = 0x06; // TCP protocol
	sum += TOWORD(type);

	unsigned int tcplen = 0x1c; // 28 bytes length
	sum += ((tcplen <<8) & 0xFFFF) + (tcplen >> 8);

	sum = (sum>>16)+(sum&0xffff);
	sum += (sum>>16);

	sum = (~sum & 0xFFFF);
	unsigned short sum1 =  sum;

	printf("Checksum = %x\n", sum1);
	return 0;
}


результаты в контрольную сумму 3e9c