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  = 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 }

时间: 2024-10-09 01:29:28

TCP协议学习记录 (三) Ping程序 RR选项 记录路由hop的相关文章

TCP/IP之TCP协议首部、三次握手、四次挥手、FSM

TCP包头 <--------------------------------32 位------------------------------> 0 8 16 24 32 |----------------|----------------|----------------|----------------| ----- | Source port | Destination port | | |-----------------------------------------------

TCP协议中的三次握手和四次挥手(图解)【转】

建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. [更新于2017.01.04 ]该部分内容配图有误,请大家见谅,正确的配图如下,错误配图也不删了,大家可以比较下,对比理解效果更好.这么久才来更新,抱歉!! 错误配图如下: 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源.Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了. 那如何断开连接呢?

tcp/ip协议学习 第三章 IP协议

派猴子来的救兵 关于IP的RFC文档在此! IP的头文件还是先贴一下, 总是记不住. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-

TCP协议学习笔记(一)首部以及TCP的三次握手连接四次挥手断开

TCP协议是一种面向连接的.可靠的流协议. 流即不间断的数据结构.这样能够保证接收到数据顺序与发送相同.但是犹如数据间没有间隔,因此在TCP通信中,发送端应用可以在自己所要发送的消息中设置一个标示长度或间隔的字段信息. 由于TCP为应用提供可靠传输,所以需要对数据传输时数据破坏.丢包.重复以及乱序问题有充分的控制能力.同时TCP协议作为面向连接的协议,只有确认对端存在才会发送数据. TCP通过检验和.序列号.确认应答.重发控制.连接管理.窗口控制等实现可靠传输. 当传输层采用TCP协议进行通信时

tcp协议报文和三次握手与四次挥手

tcp协议: tcp是面向连接.可靠的进程到进程之间的协议.tcp提供全双工服务:即:数据可在同一时间双向传输. tcp报文段首部格式: 各字段含义: 源端口号:16位字段,为发送端进程对应的端口号 目标端口:16位字段,为接收端进程对应的端口号,接收方接收到数据包之后根据这个字段确定将数据发送给对应程序来处理 序号:32位字段,当tcp从进程中接收到数据之后,就会把他存储在发送缓存中.并对每一个字节进行编号,形成的序列号.特点如下: 会生成一个随机数作为第一个字节的编号,成为序列号(ISN),

TCP 协议学习小结

TCP 传输控制协议(Transmission Control Protocal): (1)TCP协议概括介绍: TCP协议是传输层的通信协议,有同学或许不理解了,IP是网络层的传输协议,这个传输层和网络层有什么区别呢?依我之见,网络层是用来寻找网络中的主机的,通过IP地址是可以锁定唯一主机的.我们通常的通信,是一个进程和另一个进程之间的通信,而进程是依附于主机的.故在一个进程到另一个进程的通信流程可简化为:进程A——主机A——主机B——进程B.而传输层协议就是实现主机A——主机B之间的通信的.

python TCP协议详解 三次握手四次挥手和11种状态

11种状态解析 LISTEN  --------------------  等待从任何远端TCP 和端口的连接请求. SYN_SENT  ---------------  发送完一个连接请求后等待一个匹配的连接请求. SYN_RECEIVED  --------  发送连接请求并且接收到匹配的连接请求以后等待连接请求确认. ESTABLISHED  -----------  表示一个打开的连接,接收到的数据可以被投递给用户.连接的数据传输阶段的正常状态. FIN_WAIT_1  --------

深入理解TCP协议及其源代码——三次握手

Wireshark分析报文 对TCP三次握手过程进行抓包分析,并通过Wireshark的Analyze分析出tcp握手过程,通过截图体现传输内容. 1.捕获大量的由本地主机到远程服务器的TCP分组: 2.浏览追踪信息 在显示筛选规则编辑框中输入“tcp”,可以看到在本地主机和服务器之间传输的一系列tcp和HTTP消息,你应该能看到包含SYN Segment的三次握手.通过Analyze的Follow TCP Stream分析出传输内容.写出其中某TCP数据包的源IP地址,目的IP地址,源端口,目

TCP协议学习总结(下)

在前两边TCP学习总结中,也大概地学习了TCP的整个流程,但许多细节中的细节并没有详细学习,例如超时重传问题,每次瓶颈回归慢启动效率问题以及最大窗口限制问题等.本学习篇章最要针对这些细节中的细节进行学习.TCP的复杂很多时候就是细节太多了,需要考虑许多的场景并利用许多复杂的算法和启动异步线程定时处理这些问题,对于每一个连接,TCP管理4个不同的定时器,分别是: 1).重传定时器使用于当希望收到另一端的确认: 2).坚持定(persist)时器使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口