TCP协议学习记录 Ping程序 RR选项 记录路由hop
Posted gtxvs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; 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 unsigned char mac_src[] = "\\x68\\xf7\\x28\\x7f\\xc2\\x71"; //本机MAC地址 88 unsigned 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 = 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 *)ð_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的主要内容,如果未能解决你的问题,请参考以下文章