歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux下用RAW socket發送syn包

源碼編譯方法:gcc -o syn syn.c

結果:在CentOS 6上成功運行,用tcpdump抓包分析,發送的對端有syn,ack包返回,一切正常。

過程:寫代碼時忘記了對tcph->protocol賦值,計算出得checksum老不對,數據包是成功發出去了,但是對端沒syn,ack包回,查了幾個小時,郁悶死我~~~

疑問:ip->check為0是內核會計算ip頭的checksum,但是計算出得結果和我用ip_fast_csum得到的結果不一致,這是為何?標記一下,有結論再附上。

  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <string.h>   
  4. #include <getopt.h>   
  5.   
  6. #include <netinet/ip.h>   
  7. #include <netinet/tcp.h>   
  8.   
  9. /* 數據包最大長度,無負載 */  
  10. #define MAX_PKG_SIZE 80 /* ip header = 20 ~ 40, tcp header = 20 ~ 40; max = 80 */   
  11. /* 計算TCP校驗和的最大使用長度 www.linuxidc.com*/  
  12. #define MAX_PSD_SIZE 52 /* psd header = 12, tcp header = 20 ~ 40; max = 52 */   
  13. /* 數據包構造參數 */  
  14. struct st_args{  
  15.     struct sockaddr_in saddr; /* 源地址 */  
  16.     struct sockaddr_in daddr; /* 目的地址 */  
  17. };  
  18.   
  19. /* 用於計算TCP校驗和的偽頭部 */  
  20. struct psdhdr{  
  21.     uint32_t saddr; /* ip頭部源地址 */  
  22.     uint32_t daddr; /* ip頭部目的地址 */  
  23.     uint8_t mbz; /* 補全字段,需為0 */  
  24.     uint8_t protocol; /* ip頭部協議 */  
  25.     uint16_t tcpl; /* tcp長度,包括頭部和數據部分 */  
  26. };  
  27.   
  28.   
  29. /* 
  30.  * 采用匯編計算ip頭部校驗和 
  31.  * @param[in]: iph, ip頭指針;  
  32.  * @param[in]: ihl, ip頭長度(4的倍數) 
  33.  * 
  34.  * @return 16位校驗和 
  35.  * */  
  36. static inline uint16_t ip_fast_csum(const void *iph, unsigned int ihl)  
  37. {  
  38.     unsigned int sum;  
  39.   
  40.     asm("  movl (%1), %0\n"  
  41.         "  subl $4, %2\n"  
  42.         "  jbe 2f\n"  
  43.         "  addl 4(%1), %0\n"  
  44.         "  adcl 8(%1), %0\n"  
  45.         "  adcl 12(%1), %0\n"  
  46.         "1: adcl 16(%1), %0\n"  
  47.         "  lea 4(%1), %1\n"  
  48.         "  decl %2\n"  
  49.         "  jne  1b\n"  
  50.         "  adcl $0, %0\n"  
  51.         "  movl %0, %2\n"  
  52.         "  shrl $16, %0\n"  
  53.         "  addw %w2, %w0\n"  
  54.         "  adcl $0, %0\n"  
  55.         "  notl %0\n"  
  56.         "2:"  
  57.     /* Since the input registers which are loaded with iph and ihl 
  58.        are modified, we must also specify them as outputs, or gcc 
  59.        will assume they contain their original values. */  
  60.         : "=r" (sum), "=r" (iph), "=r" (ihl)  
  61.         : "1" (iph), "2" (ihl)  
  62.         : "memory");  
  63.     return (uint16_t)sum;  
  64. }  
  65.   
  66. /* 
  67.  * 計算校驗和 
  68.  * @param[in]: buffer, 待計算數據指針 
  69.  * @param[in]: size, 數據長度 
  70.  * 
  71.  * @return 校驗和 
  72.  * */  
  73. uint16_t csum(uint16_t *buffer, int size)  
  74. {  
  75.     unsigned long cksum = 0;  
  76.   
  77.     while(size>1)  
  78.     {  
  79.         cksum += *buffer++;  
  80.         size -= sizeof(uint16_t);  
  81.     }  
  82.   
  83.     if(size)  
  84.     {  
  85.         cksum += *(unsigned char*)buffer;  
  86.     }  
  87.   
  88.     cksum = (cksum>>16) + (cksum&0xffff);  
  89.     cksum += (cksum>>16);   
  90.       
  91.     return (uint16_t)(~cksum);  
  92. }  
  93. /* 
  94.  * 調試用的函數,用於輸出數據 
  95.  * */  
  96. void data_dump(uint8_t *pdata, int len)  
  97. {  
  98.     int i = 0;  
  99.     printf("len = %d\n", len);  
  100.     for(i = 0;  i < len; ++i)  
  101.     {  
  102.         printf("%02X ", *(pdata + i));  
  103.         if((i + 1) % 4 == 0)  
  104.             printf("\n");  
  105.     }  
  106. }  
  107.   
  108. /* 
  109.  * 數據包發送函數,www.linuxidc.com只構造了ip頭+tcp頭大小的長度; 
  110.  * ip頭和tcp都無選項部分,tcp無負載數據 
  111.  * @param[in]: parg, 構造數據包是采用的一些參數 
  112.  *  
  113.  * @return -1, 發送失敗;0, 發送成功 
  114.  * */  
  115. int send_pkg(struct st_args* parg)  
  116. {  
  117.     uint8_t datagram[MAX_PKG_SIZE] = {0};  
  118.     uint8_t psdheader[MAX_PSD_SIZE] = {0};  
  119.       
  120.     struct iphdr *iph = (struct iphdr*)datagram;  
  121.     struct tcphdr *tcph = (struct tcphdr*)(datagram + sizeof(struct iphdr));  
  122.     struct tcp_options *tcpopt = (struct tcp_options*)(datagram + sizeof(struct iphdr)  
  123.                                  + sizeof(struct tcphdr));  
  124.     struct psdhdr *psdh = (struct psdhdr*)psdheader;  
  125.     struct tcphdr *tcph_psd = (struct tcphdr*)(psdheader + sizeof(struct psdhdr));  
  126.       
  127.     int sockfd = -1, ret = 0;  
  128.     int optval = 1;  
  129.     const int *poptval = &optval;  
  130.       
  131.     sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);  
  132.     if(sockfd < 0)  
  133.     {  
  134.         perror("create socket failed!\n");  
  135.         goto err_out;  
  136.     }  
  137.       
  138.     iph->ihl = 5; /* header length, 5 * 4 = 20 Bytes */  
  139.     iph->version = 4;   /* version, ipv4 */  
  140.     iph->tos = 0; /* type of service, gernarel */  
  141.     iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); /* total length, iph + tcph = 32 Bytes */  
  142.     iph->id = htons(54321); /* identifcation */  
  143.     iph->frag_off = htons(0x02 << 13); /* fragment offset field */  
  144.     iph->ttl = 64; /* time to live */  
  145.     iph->protocol = 6; /* protocol, tcp */  
  146.     iph->check = 0; /* checksum */  
  147.     iph->saddr = parg->saddr.sin_addr.s_addr; /* source address */  
  148.     iph->daddr = parg->daddr.sin_addr.s_addr; /* dest address */  
  149.       
  150.     tcph->source = parg->saddr.sin_port; /* source port */  
  151.     tcph->dest = parg->daddr.sin_port; /* dest port */  
  152.     tcph->seq = random(); /* current sended packet sequence number */  
  153.     tcph->ack_seq = 0; /* expect received next packet sequence number */  
  154.     tcph->doff = sizeof(struct tcphdr) / 4; /* data position in the packet */  
  155.     tcph->syn = 1; /* syn packet */  
  156.     tcph->window = htons(65535); /* size of tcp window, FreeBSD uses this value */  
  157.     tcph->check = 0; /* checksum */  
  158.     tcph->urg_ptr = 0; /* urgent data position */  
  159.       
  160.     psdh->saddr = iph->saddr;  
  161.     psdh->daddr = iph->daddr;  
  162.     psdh->mbz = 0;  
  163.     psdh->protocol = iph->protocol;  
  164.     psdh->tcpl = htons(sizeof(struct tcphdr));  
  165.     //data_dump(psdheader, sizeof(struct psdhdr));   
  166.   
  167.     memcpy(tcph_psd, tcph, sizeof(struct tcphdr));  
  168.       
  169.     tcph->check = csum((uint16_t*)psdheader, sizeof(struct psdhdr) + sizeof(struct tcphdr));  
  170.     /* iph->check == 0時, 內核會自動計算校驗和 */  
  171.     //iph->check = ip_fast_csum(datagram, iph->ihl);   
  172.   
  173.     if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, poptval, sizeof(optval)) < 0)  
  174.     {  
  175.         perror("setsockopt failed!");  
  176.         goto err_out;  
  177.     }  
  178.       
  179.     ret = sendto(sockfd, datagram, iph->tot_len, 0,   
  180.             (struct sockaddr*)&(parg->daddr), sizeof(parg->daddr));  
  181.     if(ret < 0)  
  182.     {  
  183.         perror("sendto socket failed!");  
  184.         goto err_out;  
  185.     }  
  186.   
  187.     //data_dump(datagram, 40);   
  188.     close(sockfd);  
  189.     return 0;  
  190.       
  191. err_out:  
  192.     if(sockfd != -1)  
  193.         close(sockfd);  
  194.     return -1;  
  195. }  
  196.   
  197. int main(int argc, char **argv)  
  198. {  
  199.     struct st_args args;  
  200.       
  201. #define MAX_IP_SIZE 16   
  202.     uint8_t sip[MAX_IP_SIZE] = "192.168.1.107";  
  203.     uint8_t dip[MAX_IP_SIZE] = "192.168.1.1";  
  204.     uint16_t sport = 55555;  
  205.     uint16_t dport = 80;  
  206.     int8_t arg = 0;  
  207.   
  208.     struct option lopts[] = {  
  209.         {"saddr", required_argument, 0, 's'},  
  210.         {"sport", required_argument, 0, 'p'},  
  211.         {"daddr", required_argument, 0, 'd'},  
  212.         {"dport", required_argument, 0, 'f'}  
  213.     };  
  214.     while((arg = getopt_long(argc, argv, "s:p:d:f:", lopts, NULL)) != -1)  
  215.     {  
  216.         switch(arg)  
  217.         {  
  218.         case 's':  
  219.             memcpy(sip, optarg, MAX_IP_SIZE);  
  220.             break;  
  221.         case 'p':  
  222.             sport = atoi(optarg);  
  223.             break;  
  224.         case 'd':  
  225.             memcpy(dip, optarg, MAX_IP_SIZE);  
  226.             break;  
  227.         case 'f':  
  228.             dport = atoi(optarg);  
  229.             break;  
  230.         default:  
  231.             break;  
  232.         }  
  233.     }  
  234.       
  235.     memset(&args, 0, sizeof(struct st_args));  
  236.     inet_pton(AF_INET, sip, (void*)&args.saddr.sin_addr);  
  237.     args.saddr.sin_port = htons(sport);  
  238.   
  239.     inet_pton(AF_INET, dip, (void*)&args.daddr.sin_addr);  
  240.     args.daddr.sin_port = htons(dport);  
  241.   
  242.     send_pkg(&args);  
  243.     return 0;  
  244. }  
Copyright © Linux教程網 All Rights Reserved