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

代码写的很乱..

 #pragma pack(4)

 #define  ECHO_REQUEST       8
#define DATASIZE 65500
#define PACKETSIZE 65535
#define IPCOUNT 9
#define MACSIZE 6
#define OPTION_RR 7 struct ethhdr
{
char mac_dst[MACSIZE];
char mac_src[MACSIZE]; unsigned short eth_protocol;
char eth_data[DATASIZE];
}; struct iphdr
{
unsigned char ip_hdr_len : ; //包头长度
unsigned char ip_version : ; //版本
unsigned char ip_tos; unsigned short ip_length; //总长度
unsigned short ip_identify;//标识
unsigned short ip_offset;//片偏移
unsigned char ip_ttl;
unsigned char ip_protocol;
unsigned short ip_cksum; struct in_addr ip_src; //源地址
struct in_addr ip_dst; //目的地址 unsigned char ip_code;
unsigned char ip_len;
unsigned char ip_ptr; struct in_addr ip_router[IPCOUNT]; char ip_data[DATASIZE];
}; struct icmphdr
{
unsigned char icmp_type; //8位类型
unsigned char icmp_code; //8位代码
unsigned short icmp_cksum; //16位的校验和 unsigned short icmp_identify;
unsigned short icmp_seq; LONGLONG icmp_timestamp;
char icmp_data[DATASIZE];
}; bool ping_rr(char * target,int payload,int count)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(, ), &wsaData); if(payload > DATASIZE)
{
printf("发送的字节数有错误,有效范围从 0 到 %d",DATASIZE);
return false;
} payload = payload - sizeof(LONGLONG); struct hostent* phostent = gethostbyname(target);
if (!phostent)
{
printf("解析IP失败!\n");
return false;
} struct in_addr addrSrv = {};
addrSrv.S_un.S_addr = *(u_long *)phostent->h_addr_list[]; printf("正在 Ping %s [%s] 具有 %d 字节的数据: \n",target,inet_ntoa(addrSrv),payload + sizeof(LONGLONG)); icmphdr ihdr = {};
iphdr ip_hdr = {};
ethhdr eth_hdr = {}; unsigned char mac_src[] = "\x68\xf7\x28\x7f\xc2\x71"; //本机MAC地址
unsigned char mac_dst[] = "\x84\xd9\x31\xb9\x21\x98"; //目的MAC地址 memcpy((void *)eth_hdr.mac_src,(void *)mac_src,sizeof(mac_src) -);
memcpy((void *)eth_hdr.mac_dst,(void *)mac_dst,sizeof(mac_dst) -); eth_hdr.eth_protocol = htons(); //0x0800 //链路层IP数据报 ip_hdr.ip_hdr_len = 0xf; //包头设置为最大长度
ip_hdr.ip_version = ;
ip_hdr.ip_identify = (unsigned short)GetCurrentProcessId();
ip_hdr.ip_offset = ;
ip_hdr.ip_ttl = 0x40;//默认设置为64
ip_hdr.ip_protocol = IPPROTO_ICMP;
ip_hdr.ip_src.s_addr = inet_addr("172.30.1.145"); //本机IP
ip_hdr.ip_dst.s_addr = *(u_long *)phostent->h_addr_list[];
ip_hdr.ip_code = OPTION_RR; //RR选项为7
ip_hdr.ip_len = 0x27; //39字节 最多能存9个IP地址
ip_hdr.ip_ptr = ;
ip_hdr.ip_cksum = ; memset((void *)ip_hdr.ip_router,,sizeof(struct in_addr) * IPCOUNT); memset((void *)ihdr.icmp_data,,DATASIZE);
memset((void *)ip_hdr.ip_data,,DATASIZE); packet_pad(ihdr.icmp_data,payload); //填充数据 ihdr.icmp_type = ECHO_REQUEST;
ihdr.icmp_identify = (unsigned short)GetCurrentProcessId(); int hdr_len = payload + sizeof(icmphdr) - DATASIZE;
int datalen = hdr_len + (ip_hdr.ip_hdr_len << );
int sendlen = datalen + sizeof(ethhdr) - DATASIZE;
ip_hdr.ip_length = htons(datalen); char recv[PACKETSIZE] = {}; unsigned long interval = ;
unsigned long avgdelay = ;
unsigned long maxdelay = ;
unsigned long mindelay = ~; unsigned int sendcnt = count;
unsigned int losscnt = ; char strErrorbuf[PCAP_ERRBUF_SIZE] = {}; std::string strNickName = "\\Device\\NPF_{D8AECAAE-F28C-4161-BA6B-BCA1B807F2E5}"; //本机网卡 pcap_t* pcap_handle = NULL;
if ((pcap_handle = pcap_open_live(strNickName.c_str(),,,,strErrorbuf))==NULL)
{
return false;
} if( pcap_datalink(pcap_handle) != DLT_EN10MB )
{
return false;
} unsigned int netip,netmask;
if (pcap_lookupnet(strNickName.c_str(),&netip,&netmask,strErrorbuf) < )
{
return false;
} std::string strFilter = "icmp"; //协议过滤 只抓icmp的包
struct bpf_program nFcode;
if ( pcap_compile(pcap_handle, &nFcode,strFilter.c_str(), , netmask) < )
{
return false;
} if ( pcap_setfilter(pcap_handle, &nFcode) < )
{
return false;
} int next = ; struct pcap_pkthdr * header = NULL;
const unsigned char* pkt_data = NULL; for(int seq = ; seq < count; ++seq)
{
memset((void *)ip_hdr.ip_router,,sizeof(struct in_addr) * IPCOUNT); ihdr.icmp_seq = seq;
ihdr.icmp_cksum = ;
ihdr.icmp_timestamp = GetSysTickCount64(); //发送时间
ihdr.icmp_cksum = checksum(hdr_len,(unsigned short *)&ihdr); memcpy((void *)ip_hdr.ip_data,(void *)&ihdr,hdr_len); ip_hdr.ip_cksum = ;
ip_hdr.ip_ptr = ;
ip_hdr.ip_cksum = checksum(datalen,(unsigned short *)&ip_hdr); memcpy((void *)eth_hdr.eth_data,(void *)&ip_hdr,datalen); if(pcap_sendpacket(pcap_handle,(unsigned char *)&eth_hdr,sendlen) != ) //发送数据包
{
--sendcnt;
continue;
} while(next = pcap_next_ex(pcap_handle, &header, &pkt_data))
{
iphdr* piphdr = (iphdr *) (pkt_data + sizeof(ethhdr) - DATASIZE); if(checksum(piphdr->ip_hdr_len << ,(unsigned short *)piphdr) != )
{
printf("invalid ip packet!\n");
continue;
} icmphdr* pichdr = (icmphdr *)(pkt_data + sendlen - hdr_len);
if(checksum(hdr_len,(unsigned short *)pichdr) != )
{
printf("invalid icmp packet!\n");
continue;
} if(piphdr->ip_ptr == )
{
continue;
} memcpy((void *)piphdr->ip_router,(void *)((char *)piphdr->ip_router -),sizeof(struct in_addr) * IPCOUNT);//内存对齐问题 interval = GetSysTickCount64() - pichdr->icmp_timestamp;
avgdelay+= interval; maxdelay = interval > maxdelay ? interval : maxdelay;
mindelay = interval > mindelay ? mindelay : interval; int record = (piphdr->ip_ptr-) >> ; printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%u\n",inet_ntoa(addrSrv),payload + sizeof(LONGLONG),interval,piphdr->ip_ttl); printf(" 路由: %s -->\n",inet_ntoa(piphdr->ip_router[]));
for(int i = ; i < record;i++)
{
printf(" %s -->\n",inet_ntoa(piphdr->ip_router[i]));
} break;
} if(next == -)
{
losscnt++;
} } printf("\n");
printf("%s 的 Ping 统计信息: \n",inet_ntoa(addrSrv));
printf(" 数据包: 已发送 = %d, 已接收 = %d, 丢失 = %d (%.2f%% 丢失),\n",sendcnt,sendcnt-losscnt,losscnt,(losscnt * ) / (double)sendcnt);
printf("往返行程的估计时间(以毫秒为单位):\n");
printf(" 最短 = %dms, 最长 = %dms, 平均 = %dms\n",mindelay,maxdelay,avgdelay / sendcnt);
printf("\n"); return true;
}

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

  1. TCP/IP协议学习之实例ping命令学习笔记

    TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...

  2. [网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序]

    [网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序] 为何学习socket套接字一定要先学习互联网协议: 1.首先:要想开发一款自己的C/S架构软件,就必须掌握socket ...

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

    建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. [更新于2017.01.04 ]该部分内容配图有误,请大家见谅,正确的配图如下,错误配图也不删 ...

  4. TCP协议学习记录 (二) Ping程序

    简单的实现了一个ping程序,没有做icmp差错报文的检查. 支持自定义字节数,支持发包个数 #pragma pack(4) #define ECHO_REQUEST 8 #define DATASI ...

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

    TCP协议是一种面向连接的.可靠的流协议. 流即不间断的数据结构.这样能够保证接收到数据顺序与发送相同.但是犹如数据间没有间隔,因此在TCP通信中,发送端应用可以在自己所要发送的消息中设置一个标示长度 ...

  6. TCP协议学习总结(上)

    在计算机领域,数据的本质无非0和1,创造0和1的固然伟大,但真正百花齐放的还是基于0和1之上的各种层次之间的组合(数据结构)所带给我们人类各种各样的可能性.例如TCP协议,我们的生活无不无时无刻的站在 ...

  7. 计算机网络:这是一份全面 & 详细 的TCP协议学习指南

    原文链接:blog.csdn.net 用这个媒体播放器组件,实时互动时也可共同观看本地视频juejin.im 前言 计算机网络基础 该是程序猿需掌握的知识,但往往会被忽略 今天,我将详细讲解计算机网络 ...

  8. TCP协议学习总结(中)

    很多人都说TCP协议是一个十分复杂的协议,在学习当中,我对协议每一个问题都分解学习后,每一个分解我都能体会和理解它的要点,并不难理解.但我把这些拆分的细节合并后,确认感觉这样一个协议相对“臃肿”但又好 ...

  9. TCP协议学习笔记

    TCP协议数据格式 TCP协议在互联网ISO协议的传输层. 在互联网传输过程中,互联网包在数据链路层,是传输数据的最基础的包.一个互联网的包包含IP包,即互联网包 = 互联网信息包头(至少20字节)+ ...

随机推荐

  1. clientTop、offsetTop和scrollTop的区分

    页可见区域宽: document.body.clientWidth; 网页可见区域高: document.body.clientHeight; 网页可见区域宽: document.body.offse ...

  2. leetcode174. Dungeon Game

    // learn from https://discuss.leetcode.com/topic/6912/c-dp-solution ''' class Solution { public: int ...

  3. According to TLD or attribute directive in tag file, attribute test does not accept any expressions

    HTTP Status 500 - /WEB-INF/views/emp/list.jsp (line: 30, column: 4) According to TLD or attribute di ...

  4. Web后台技术趋势

    今天使用Google Trend比较了一下服务器端的程序开发语言技术ASP/ASP.NET Core, PHP, Node.Js的变化趋势,发现一下特点. ASP.NET最近几年一直再下降. ASP和 ...

  5. 你注意了么?int与Integer的区别

    上次做项目时遇到了一个小问题. 我把javabean中的custid属性定义为int类型,当然与数据库中相应类型是一致的,而且在hibernate文件中配置时专门设置了not-null="f ...

  6. 利用npoi导出Excel

    npoi库是当下最流行的处理Excel.Word.PPT等Office文件格式 npoi的下载地址:http://npoi.codeplex.com/ npoi的官方学习地址: http://www. ...

  7. C#图片上传服务器缩放存储功能

    项目需求上需要用户上传头像.本来是用第三方的插件的.但是很多都是收费的. 不过,我需要花这钱么?是不?所以网络上搜集了些资料.. 果然.这个世界 大神是很多很多的. 用了个免费插件. <scri ...

  8. prolog 阶段总结

    http://blog.csdn.net/mwsong/article/details/1766382   到现在为止,我们已经对Prolog有了一个基本的了解,现在有必要对我们所学过的知识做一个系统 ...

  9. android超快模拟器Ggenymotion的安装和配置

    原文地址:http://xiaochu.blog.51cto.com/1048262/1639613 Genymotion是一款运行速度快,且易于使用的android模拟器,非常适合与android程 ...

  10. strstr函数

    原型:char * strstr( char *haystack,  char *needle ) 用法:#include <string.h> 功能:在haystack中寻找needle ...