您的位置:首页 > 其它

icmp实现ping

2016-01-26 23:02 387 查看
以前弄到的一段代码, 一个用原始套接字raw socket实现icmp协议ping工具

myping.c

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/time.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/ip_icmp.h>

#define ICMP_PACKET_SIZE 16
#define TIME_OUT_SECONDS 2

unsigned short cal_chksum(unsigned short *buf, int len)
{
unsigned int sum = 0;
unsigned short ret;

while(len > 1) {
sum += *buf;
buf++;
len -= 2;
}
if(1 == len) {
sum += (*(unsigned char *)buf);
}

sum = (sum >> 16) + (sum & 0xFFFF);
sum = (sum >> 16) + (sum & 0xFFFF);        //sum = (sum >> 16) + sum;

ret = ~sum;

return    ret;
}

int    pack_icmp(char *buf, int seq)
{
struct    icmp *icmp_packet = (struct icmp *)buf;

icmp_packet->icmp_type = ICMP_ECHO;
icmp_packet->icmp_code = 0;
icmp_packet->icmp_id = getpid();
icmp_packet->icmp_seq = seq;
icmp_packet->icmp_cksum = 0;    //must clean it before cal_chksum or you will get bad chksum(can't error when ping your own ipaddress )

struct timeval tv;
gettimeofday(&tv, NULL);

memcpy(buf + 8, &tv, sizeof(tv));

icmp_packet->icmp_cksum = cal_chksum((unsigned short *)icmp_packet,ICMP_PACKET_SIZE);

}

int parse_ip_icmp_info(void *buf, struct sockaddr_in answer)
{
unsigned short chk_sum;
unsigned char ttl;
unsigned short seq;
struct timeval tv_send, tv_now;
unsigned int mini_sec;

struct ip *ip_packet = (struct ip *)buf;
struct icmp *icmp_packet = (struct icmp *)(buf + (ip_packet->ip_hl << 2));

if(icmp_packet->icmp_id != getpid()) {
return -1;
}
if(icmp_packet->icmp_type != ICMP_ECHOREPLY) {
return -1;
}

ttl = ip_packet->ip_ttl;
seq = icmp_packet->icmp_seq;
chk_sum = icmp_packet->icmp_cksum;
icmp_packet->icmp_cksum = 0;

if(chk_sum != cal_chksum((unsigned short *)icmp_packet,ICMP_PACKET_SIZE)) {
return -1;
}

gettimeofday(&tv_now, NULL);
memcpy(&tv_send, ((char *)icmp_packet + 8), sizeof(tv_send));

mini_sec = (tv_now.tv_sec - tv_send.tv_sec) * 1000000 +
(tv_now.tv_usec - tv_send.tv_usec);

printf("%d bytes data from: %s icmp_seq = %d, ttl = %d, times = %.3fms\n",
(ip_packet->ip_hl << 2) + 16,
inet_ntoa(answer.sin_addr),
seq,
ttl,
mini_sec/1000.0);
return    0;
}

int main(int argc, char *argv[])
{
if(argc != 2) {
printf("Usage: %s ipaddr/hostname\n", argv[0]);
exit( 0 );
}

struct hostent * host = gethostbyname(argv[1]);
if(host == NULL) {
printf("ping: unknow host %s \n", argv[1]);
exit(2);
}

struct sockaddr_in dest;
dest.sin_family = AF_INET;
memcpy( &dest.sin_addr, host->h_addr, sizeof(int));

int sock_raw_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(sock_raw_fd == -1) {
perror("socket");
exit(1);
}

char buf[ICMP_PACKET_SIZE];

int seq = 0;

char recv_buf[50];
struct sockaddr_in answer;
int answer_len = sizeof(answer);
while(1) {
seq ++;
pack_icmp(buf, seq);
sendto(sock_raw_fd, buf, ICMP_PACKET_SIZE, 0, (struct sockaddr *)&dest, sizeof(dest));

while(1) {
fd_set readset;
FD_ZERO(&readset);
FD_SET(sock_raw_fd, &readset);

struct timeval tv;
tv.tv_sec = TIME_OUT_SECONDS;
tv.tv_usec = 0;

int ret = select(sock_raw_fd+1, &readset, NULL, NULL, &tv);
if(ret == -1) {
perror("select");
exit(3);
} else if(ret == 0) {
printf("time out.\n");
break;
} else {
int resolve = 0;
int ret = recvfrom(sock_raw_fd, recv_buf, 36, 0, (struct sockaddr *)&answer, &answer_len);

if(ret > 0)
resolve = parse_ip_icmp_info(recv_buf, answer);
if(resolve == 0)
break;
}
}
sleep(1);
}

return 0;
}


编译链接执行. 输出如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: