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

时间:2022-09-19 20:36:03

一开始想直接在上个程序改,自己构造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