一开始想直接在上个程序改,自己构造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. Mongodb集群搭建过程及常见错误

    Replica Sets MongoDB 支持在多个机器中通过异步复制达到故障转移和实现冗余.多机器中同一时刻只 有一台是用于写操作.正是由于这个情况,为 MongoDB 提供了数据一致性的保障.担当 ...

  2. Hibernate配置文档详解

    Hibernate配置文档有框架总部署文档hibernate.cfg.xml 和映射类的配置文档 ***.hbm.xml hibernate.cfg.xml(文件位置直接放在src源文件夹即可) (在 ...

  3. 《算法导论》 调用RANDOM(0,1),实现RANDOM(a,b)的过程

    描述RANDOM(a,b)的过程的一种实现,它只调用RANDOM(0,1).作为a和b的函数,你的程序的期望运行时间是多少?(RANDOM(0,1)以等概率输出0或者1,RANDOM(a,b)以等概率 ...

  4. Web API WinForm使用HttpClient呼叫Web API

    前言 之前几篇文章已经介绍了 Web 与 Web API 的使用方式,接下来将介绍如何在 Windows Form 呼叫 Web API 的方法,要在 WinForm 中使用 Web API 的话,除 ...

  5. Bootstrap文件上传插件File Input的使用

    基于Metronic的Bootstrap开发框架经验总结(5)--Bootstrap文件上传插件File Input的使用 Bootstrap文件上传插件File Input是一个不错的文件上传控件, ...

  6. java 获取当月第一天和最后一天 获取前一个月第一天和最后一天

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");                    //获取前月的第一 ...

  7. shell中的语法(1)

    反引号 命令替换.将命令的输出放在命令行的任意位置. eg. [root@gam ~]# echo The Data is `date` The Data is Fri Nov 18 10:13:56 ...

  8. 初学python之urllib

    urllib.request urlopen()urllib.urlopen(url, data, proxies) :创建一个表示远程url的类文件对象,然后像本地文件一样操作这个类文件对象来获取远 ...

  9. vi常用命令

    哎,看书上vi命令那么多,真是记不住.记几个常用的备忘吧. 在一般模式下(不可编辑),比如用vi命令打开或创建一个文件,常用的命令如下: 按键 作用 h或← 光标左移动一个字符 j或↓ 光标下移动一个 ...

  10. Visual Studio 2015 工具箱丢失

    网上主要的解答分为两种:1. 未打开设计界面 2. 重置 实际上,还有一个原因是,没有启动完整版的VS. 安装完后,会有两个VS的程序,一个是Blend For Visual Studio 2015, ...