Linux下使用原始套接字实现ping 功能
//获得某个网卡的IP地址
char* GetIpAddress(const char* interfaceName)
{
register int fd, intrface;
struct ifreq buf[MAXINTERFACES]; //#define MAXINTERFACES 12
struct ifconf ifc;
if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0)
{
ifc.ifc_len = sizeof buf;
ifc.ifc_buf = (caddr_t) buf;
if (!ioctl (fd, SIOCGIFCONF, (char *) &ifc))
{
intrface = ifc.ifc_len / sizeof (struct ifreq);
while (intrface-- > 0)
{
if (0 != strcmp(buf[intrface].ifr_name, interfaceName))
continue;
//get the ip address of this net device
if (!(ioctl (fd, SIOCGIFADDR, (char *) &buf[intrface])))
{
::close(fd);
return (inet_ntoa(((struct sockaddr_in*)(&buf[intrface].ifr_addr))->sin_addr));
}
else
{
char str[256];
sprintf (str, "cpm: ioctl device %s", buf[intrface].ifr_name);
perror (str);
}
}
}
::close(fd);
}
return "";
}
bool IsValidIpAddress(const char* ipAddress)
{
struct sockaddr_in sin;
sin.sin_family = AF_INET;
memset(&sin, 0, sizeof(sin));
if (inet_pton(AF_INET, ipAddress, &sin.sin_addr) <= 0)
{
return false;
}
else
{
char strConvertedIP[MAX_IP_LENGTH]; //#define MAX_IP_LENGTH 30
if (NULL != inet_ntop(AF_INET, &sin.sin_addr, strConvertedIP, MAX_IP_LENGTH) )
{
if(0 != strcmp(strConvertedIP, "0.0.0.0"))
{
return true;
}
}
return false;
}
}
bool send_echo_req(int sock_fd,struct sockaddr_in *dstaddr)
{
char buf[100];
size_t len = sizeof(struct icmp);
struct icmp *icmp;
socklen_t dstlen = sizeof(struct sockaddr_in);
bzero(buf, sizeof(buf));
icmp = (struct icmp *)buf;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_id = getpid();
icmp->icmp_seq = 1;
icmp->icmp_cksum = in_cksum((uint16_t *) icmp, sizeof(struct icmp));
if (sendto(sockfd, buf, len, 0, (struct sockaddr*)dstaddr, dstlen) == -1)
{
err_sys("sendto");
return false;
}
return true;
}
bool recv_echo_reply(int sock_fd)
{
char buf[100];
ssize_t n;
struct ip *ip;
struct icmp *icmp;
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(sockfd+1, &rfds, NULL, NULL, &tv);
if (retval == -1)
{
perror("select()");
return false;
}
else if (retval)
{
/* FD_ISSET(0, &rfds) will be true. */
if ((n = read(sockfd, buf, sizeof(buf))) == -1)
{
err_sys("read");
return false;
}
ip = (struct ip *)buf;
if (ip->ip_p != IPPROTO_ICMP) {
fprintf(stderr, "protocol error.\r\n");
return false;
}
icmp = (struct icmp *)(buf + sizeof(struct ip));
if (icmp->icmp_type == ICMP_ECHOREPLY) {
if (icmp->icmp_id != getpid()) {
fprintf(stderr, "not this process.\r\n");
return false;
} else {
//printf("destination host is alive.\r\n");
return true;
}
}
}
//printf("ping timeout.\n");
return false;
}
uint16_t in_cksum(uint16_t* addr, int len)
{
int nleft = len;
uint32_t sum = 0;
uint16_t *w = addr;
uint16_t answer = 0;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w ;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
bool Ping (char* dest)
{
int sockfd;
struct sockaddr_in dstaddr;
bool ret;
char* ipAddr;
ipAddr = GetIPAddress(m_wirelessNetworkDevice);
if(!IsValidIPAddress(ipAddr.toUtf8().constData()))
return false;
if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) //ICMP协议,原始套接字类型
{
err_sys("socket");
return false;
}
bzero(&dstaddr, sizeof(dstaddr));
dstaddr.sin_family = AF_INET;
dstaddr.sin_port = htons(0);
//printf("dest is %s\n",dest);
if (inet_pton(AF_INET, dest, &dstaddr.sin_addr) <= 0)
{
err_sys("inet_pton");
::close(sockfd);
return false;
}
ret = send_echo_req(sockfd, &dstaddr);
if (!ret)
{
::close(sockfd);
return false;
}
ret = recv_echo_reply(sockfd);
if (ret)
{
::close(sockfd);
return true;
}
else
{
::close(sockfd);
return false;
}
}
以上是Linux下的代码。