首页 > 代码库 > TCP协议学习记录 (三) Ping程序 RR选项 记录路由hop

TCP协议学习记录 (三) Ping程序 RR选项 记录路由hop

一开始想直接在上个程序改,自己构造IP包头,但后来发现不行,微软不让干了,所有后来选用libcap库来收发包

代码写的很乱..

  1 #pragma pack(4)
  2 
  3 #define  ECHO_REQUEST       8
  4 #define  DATASIZE           65500
  5 #define  PACKETSIZE         65535
  6 #define  IPCOUNT            9
  7 #define  MACSIZE            6
  8 #define  OPTION_RR          7
  9 
 10 struct ethhdr
 11 {
 12     char  mac_dst[MACSIZE];
 13     char  mac_src[MACSIZE];
 14     
 15     unsigned short eth_protocol;
 16 
 17     char  eth_data[DATASIZE];
 18 };
 19 
 20 struct iphdr
 21 {
 22     unsigned char  ip_hdr_len : 4; //包头长度
 23     unsigned char  ip_version : 4; //版本
 24     unsigned char  ip_tos;
 25 
 26     unsigned short ip_length;  //总长度
 27     unsigned short ip_identify;//标识
 28     unsigned short ip_offset;//片偏移
 29     unsigned char  ip_ttl;
 30     unsigned char  ip_protocol;
 31     unsigned short ip_cksum;
 32 
 33     struct in_addr ip_src; //源地址
 34     struct in_addr ip_dst; //目的地址
 35     
 36     unsigned char  ip_code;
 37     unsigned char  ip_len;
 38     unsigned char  ip_ptr;
 39     
 40     struct in_addr ip_router[IPCOUNT];
 41 
 42     char  ip_data[DATASIZE];
 43 };
 44 
 45 struct icmphdr
 46 {
 47     unsigned char  icmp_type; //8位类型
 48     unsigned char  icmp_code; //8位代码
 49     unsigned short icmp_cksum; //16位的校验和
 50 
 51     unsigned short icmp_identify;
 52     unsigned short icmp_seq;
 53     
 54     LONGLONG       icmp_timestamp;
 55     char           icmp_data[DATASIZE];
 56 };
 57 
 58 bool ping_rr(char * target,int payload,int count)
 59 {
 60     WSADATA wsaData;
 61     WSAStartup(MAKEWORD(2, 2), &wsaData);
 62 
 63     if(payload > DATASIZE)
 64     {
 65         printf("发送的字节数有错误,有效范围从 0 到 %d",DATASIZE);
 66         return false;
 67     }
 68 
 69     payload = payload - sizeof(LONGLONG); 
 70 
 71     struct hostent* phostent  = gethostbyname(target);  
 72     if (!phostent)  
 73     {  
 74         printf("解析IP失败!\n");
 75         return false;
 76     }
 77 
 78     struct in_addr addrSrv = {0};
 79     addrSrv.S_un.S_addr    = *(u_long *)phostent->h_addr_list[0];
 80 
 81     printf("正在 Ping %s [%s] 具有 %d 字节的数据: \n",target,inet_ntoa(addrSrv),payload + sizeof(LONGLONG));
 82 
 83     icmphdr ihdr        = {0};
 84     iphdr   ip_hdr      = {0};
 85     ethhdr  eth_hdr     = {0};
 86 
 87     char mac_src[] = "\x68\xf7\x28\x7f\xc2\x71"; //本机MAC地址
 88     char mac_dst[] = "\x84\xd9\x31\xb9\x21\x98"; //目的MAC地址
 89     
 90     memcpy((void *)eth_hdr.mac_src,(void *)mac_src,sizeof(mac_src) -1);
 91     memcpy((void *)eth_hdr.mac_dst,(void *)mac_dst,sizeof(mac_dst) -1);
 92 
 93     eth_hdr.eth_protocol  = htons(2048); //0x0800 //链路层IP数据报
 94     
 95     ip_hdr.ip_hdr_len      = 0xf; //包头设置为最大长度
 96     ip_hdr.ip_version      = 4;
 97     ip_hdr.ip_identify     = (unsigned short)GetCurrentProcessId();
 98     ip_hdr.ip_offset       = 0;
 99     ip_hdr.ip_ttl          = 0x40;//默认设置为64
100     ip_hdr.ip_protocol     = IPPROTO_ICMP;
101     ip_hdr.ip_src.s_addr   = inet_addr("172.30.1.145"); //本机IP
102     ip_hdr.ip_dst.s_addr   = *(u_long *)phostent->h_addr_list[0];
103     ip_hdr.ip_code         = OPTION_RR;    //RR选项为7
104     ip_hdr.ip_len          = 0x27;          //39字节 最多能存9个IP地址
105     ip_hdr.ip_ptr          = 4;
106     ip_hdr.ip_cksum        = 0;
107     
108     memset((void *)ip_hdr.ip_router,0,sizeof(struct in_addr) * IPCOUNT);
109 
110     memset((void *)ihdr.icmp_data,0,DATASIZE);
111     memset((void *)ip_hdr.ip_data,0,DATASIZE);
112 
113     packet_pad(ihdr.icmp_data,payload); //填充数据
114     
115     ihdr.icmp_type       = ECHO_REQUEST;
116     ihdr.icmp_identify = (unsigned short)GetCurrentProcessId();
117     
118     int hdr_len           = payload + sizeof(icmphdr) - DATASIZE;
119     int datalen           = hdr_len + (ip_hdr.ip_hdr_len << 2);
120     int sendlen           = datalen + sizeof(ethhdr) - DATASIZE;
121     ip_hdr.ip_length      = htons(datalen);
122     
123     char recv[PACKETSIZE]   = {0};
124 
125     unsigned long interval  = 0;
126     unsigned long avgdelay  = 0;
127     unsigned long maxdelay  = 0;
128     unsigned long mindelay  = ~0;
129 
130     unsigned int  sendcnt   = count;
131     unsigned int  losscnt   = 0;
132 
133     char strErrorbuf[PCAP_ERRBUF_SIZE] = {0};
134 
135     std::string strNickName = "\\Device\\NPF_{D8AECAAE-F28C-4161-BA6B-BCA1B807F2E5}"; //本机网卡
136 
137     pcap_t* pcap_handle  = NULL;    
138     if ((pcap_handle = pcap_open_live(strNickName.c_str(),65536,1,1000,strErrorbuf))==NULL)
139     {    
140         return false;
141     }
142 
143     if( pcap_datalink(pcap_handle) != DLT_EN10MB )
144     {
145         return false;
146     }
147 
148     unsigned int netip,netmask;
149     if (pcap_lookupnet(strNickName.c_str(),&netip,&netmask,strErrorbuf) < 0)
150     {
151         return false;
152     }
153 
154     std::string strFilter = "icmp"; //协议过滤  只抓icmp的包
155     struct bpf_program nFcode;
156     if ( pcap_compile(pcap_handle, &nFcode,strFilter.c_str(), 1, netmask) < 0 )
157     {
158         return false;
159     }
160 
161     if ( pcap_setfilter(pcap_handle, &nFcode) < 0 )
162     {
163         return false;
164     }
165 
166     int next = 0;
167 
168     struct pcap_pkthdr *  header    = NULL;
169     const unsigned char*  pkt_data  =http://www.mamicode.com/ NULL;
170 
171     for(int seq = 0; seq < count; ++seq)
172     {
173         memset((void *)ip_hdr.ip_router,0,sizeof(struct in_addr) * IPCOUNT);
174         
175         ihdr.icmp_seq        = seq;
176         ihdr.icmp_cksum      = 0;
177         ihdr.icmp_timestamp  = GetSysTickCount64(); //发送时间
178         ihdr.icmp_cksum      = checksum(hdr_len,(unsigned short *)&ihdr);
179 
180         memcpy((void *)ip_hdr.ip_data,(void *)&ihdr,hdr_len);
181 
182         ip_hdr.ip_cksum      = 0;
183         ip_hdr.ip_ptr        = 4;
184         ip_hdr.ip_cksum      = checksum(datalen,(unsigned short *)&ip_hdr);
185 
186         memcpy((void *)eth_hdr.eth_data,(void *)&ip_hdr,datalen);
187         
188         if(pcap_sendpacket(pcap_handle,(unsigned char *)&eth_hdr,sendlen) != 0) //发送数据包
189         {
190             --sendcnt;
191             continue;
192         }
193 
194         while(next = pcap_next_ex(pcap_handle, &header, &pkt_data))
195         {
196             iphdr* piphdr = (iphdr *) (pkt_data + sizeof(ethhdr) - DATASIZE);
197         
198             if(checksum(piphdr->ip_hdr_len << 2,(unsigned short *)piphdr) != 0)
199             {
200                 printf("invalid ip packet!\n");
201                 continue;
202             }
203 
204             icmphdr* pichdr = (icmphdr *)(pkt_data + sendlen - hdr_len);
205             if(checksum(hdr_len,(unsigned short *)pichdr) != 0)
206             {
207                 printf("invalid icmp packet!\n");
208                 continue;
209             }
210 
211             if(piphdr->ip_ptr == 4)
212             {
213                 continue;
214             }
215 
216             memcpy((void *)piphdr->ip_router,(void *)((char *)piphdr->ip_router -1),sizeof(struct in_addr) * IPCOUNT);//内存对齐问题 
217 
218             interval = GetSysTickCount64() - pichdr->icmp_timestamp;
219             avgdelay+= interval;
220 
221             maxdelay = interval > maxdelay ? interval : maxdelay;
222             mindelay = interval > mindelay ? mindelay : interval;
223 
224             int record = (piphdr->ip_ptr-4) >> 2;
225 
226             printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%u\n",inet_ntoa(addrSrv),payload + sizeof(LONGLONG),interval,piphdr->ip_ttl);
227             
228             printf("    路由: %s -->\n",inet_ntoa(piphdr->ip_router[0]));
229             for(int i = 1; i < record;i++)
230             {
231                 printf("           %s -->\n",inet_ntoa(piphdr->ip_router[i]));
232             }
233             
234             break;
235         }
236 
237         if(next == -2)
238         {
239             losscnt++;
240         }
241 
242     }
243 
244     printf("\n");
245     printf("%s 的 Ping 统计信息: \n",inet_ntoa(addrSrv));
246     printf("    数据包: 已发送 = %d, 已接收 = %d, 丢失 = %d (%.2f%% 丢失),\n",sendcnt,sendcnt-losscnt,losscnt,(losscnt * 100) / (double)sendcnt);
247     printf("往返行程的估计时间(以毫秒为单位):\n");
248     printf("    最短 = %dms, 最长 = %dms, 平均 = %dms\n",mindelay,maxdelay,avgdelay / sendcnt);
249     printf("\n");
250 
251     return true;
252 }

 技术分享

TCP协议学习记录 (三) Ping程序 RR选项 记录路由hop