透析ICMP协议(四): 应用篇ping(RAW Socket) …
2008-02-22 12:38:04来源:互联网 阅读 ()
void init_ping_packet(ICMPHeader* icmp_hdr, int packet_size, int seq_no)
{
// Set up the packet's fields
icmp_hdr->type = ICMP_ECHO_REQUEST;
icmp_hdr->code = 0;
icmp_hdr->checksum = 0;
icmp_hdr->id = (USHORT)GetCurrentProcessId();
icmp_hdr->seq = seq_no;
icmp_hdr->timestamp = GetTickCount();
// "You're dead meat now, packet!"
const unsigned long int deadmeat = 0xDEADBEEF;
char* datapart = (char*)icmp_hdr sizeof(ICMPHeader);
int bytes_left = packet_size - sizeof(ICMPHeader);
while (bytes_left > 0) {
memcpy(datapart, &deadmeat, min(int(sizeof(deadmeat)),
bytes_left));
bytes_left -= sizeof(deadmeat);
datapart = sizeof(deadmeat);
}
// Calculate a checksum on the result
icmp_hdr->checksum = ip_checksum((USHORT*)icmp_hdr, packet_size);
}
// 发送生成的ICMP包
// 返回值 <0 表失败
int send_ping(SOCKET sd, const sockaddr_in& dest, ICMPHeader* send_buf,
int packet_size)
{
// Send the ping packet in send_buf as-is
cout << "Sending " << packet_size << " bytes to " <<
inet_ntoa(dest.sin_addr) << "..." << flush;
int bwrote = sendto(sd, (char*)send_buf, packet_size, 0,
(sockaddr*)&dest, sizeof(dest));
if (bwrote == SOCKET_ERROR) {
cerr << "send failed: " << WSAGetLastError() << endl;
return -1;
}
else if (bwrote < packet_size) {
cout << "sent " << bwrote << " bytes..." << flush;
}
return 0;
}
// 接受ICMP包
// 返回值 <0 表失败
int recv_ping(SOCKET sd, sockaddr_in& source, IPHeader* recv_buf,
int packet_size)
{
// Wait for the ping reply
int fromlen = sizeof(source);
int bread = recvfrom(sd, (char*)recv_buf,
packet_size sizeof(IPHeader), 0,
(sockaddr*)&source, &fromlen);
if (bread == SOCKET_ERROR) {
cerr << "read failed: ";
if (WSAGetLastError() == WSAEMSGSIZE) {
cerr << "buffer too small" << endl;
}
else {
cerr << "error #" << WSAGetLastError() << endl;
}
return -1;
}
return 0;
}
// 对收到的ICMP解码
// 返回值 -2表忽略, -1 表失败, 0 成功
int decode_reply(IPHeader* reply, int bytes, sockaddr_in* from)
{
// 跳过IP包头, 找到ICMP的包头
unsigned short header_len = reply->h_len * 4;
ICMPHeader* icmphdr = (ICMPHeader*)((char*)reply header_len);
// 包的长度合法, header_len ICMP_MIN为最小ICMP包的长度
if (bytes < header_len ICMP_MIN) {
cerr << "too few bytes from " << inet_ntoa(from->sin_addr) <<
endl;
return -1;
}
// 下面的包类型详细参见我的第一部分 "透析ICMP协议(一): 协议原理"
else if (icmphdr->type != ICMP_ECHO_REPLY) { //非正常回复
if (icmphdr->type != ICMP_TTL_EXPIRE) { //ttl减为零
if (icmphdr->type == ICMP_DEST_UNREACH) { //主机不可达
cerr << "Destination unreachable" << endl;
}
else { //非法的ICMP包类型
cerr << "Unknown ICMP packet type " << int(icmphdr->type) <<
" received" << endl;
}
return -1;
}
}
else if (icmphdr->id != (USHORT)GetCurrentProcessId()) {
//不是本进程发的包, 可能是同机的其它ping进程发的
return -2;
}
// 指出包传递了多远
// [bugfree]我认为作者这里有问题, 因为有些系统的ttl初值为128如winXP,
// 有些为256如我的DNS服务器211.97.168.129, 作者假设为256有点武断,
// 可以一起探讨这个问题, 回email:zhangliangsd@hotmail.com
int nHops = int(256 - reply->ttl);
if (nHops == 192) {
// TTL came back 64, so ping was probably to a host on the
// LAN -- call it a single hop.
nHops = 1;
}
else if (nHops == 128) {
// Probably localhost
nHops = 0;
}
// 所有工作结束,打印信息
cout << endl << bytes << " bytes from " <<
inet_ntoa(from->sin_addr) << ", icmp_seq " <<
icmphdr->seq << ", ";
if (icmphdr->type == ICMP_TTL_EXPIRE) {
cout << "TTL expired." << endl;
}
else {
cout << nHops << " hop" << (nHops == 1 ? "" : "s");
cout << ", time: " << (GetTickCount() - icmphdr->timestamp) <<
" ms." << endl;
}
return 0;
}
总结和建议:
-----------
bugfree建议其中的这些方面需要改进:
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash
