linux下ping程序实现

ping.h

#ifndef __PING_H_
#define __PING_H_

#include <stdio.h>
#include <stdlib.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/time.h>


#define MAX_BUFF_SIZE   (1024)
#define MAX_PACKET_SIZE (1024)
#define DEF_PACKET_SIZE (32)
#define DEBUG           (0)

int CodePingReq(const struct icmphdr hdr, int datasize, unsigned char *output);
int DecodeIPHeader(unsigned char* buff, int size, struct iphdr &hdr);
int DecodePingResp(unsigned char* buff, int size);
unsigned short GetCheckSum(unsigned short *data, int size);
long getCurrentTimeUs();
void SendPingMsg(int sockfd,struct sockaddr_in DstAddr,int datasize, int times);

#endif

main.cpp

#include "ping.h"


void PrintHexStr(unsigned char* buff, int size)
{
    for(int i=0;i<size;i++)
    {
        printf("%02X ", buff[i]);
    }
    printf("\n");
}

unsigned short GetCheckSum(unsigned short *data, int size)
{
    unsigned long checksum = 0;
    while(size > 1)
    {
        checksum += *data++;
        size -= sizeof(unsigned short);
    }

    if(size > 0)
    {
        checksum += *(unsigned char*)data;
    }

    // 高16位与低16位相加
    checksum = (checksum >> 16) + (checksum & 0xffff);
    checksum += (checksum >> 16);
    
    return (unsigned short)(~checksum);

}

long getCurrentTimeUs()
{
    long timems = 0;
    struct timeval tv = { 0 };
    if(0 != gettimeofday(&tv, NULL))
    {
        printf("gettimeofday() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
    }

    timems = tv.tv_sec*1000000 + tv.tv_usec;
    return timems;
}

int CodePingReq(const struct icmphdr hdr, int datasize ,unsigned char *output)
{
    int nOffset = 0;
    unsigned char *pos = output;
    
    memcpy(pos + nOffset, &(hdr.type), sizeof(hdr.type));
    nOffset += sizeof(hdr.type);

    memcpy(pos + nOffset, &(hdr.code), sizeof(hdr.code));
    nOffset += sizeof(hdr.code);

    int nCheckSumPos = nOffset;
    memcpy(pos + nOffset, &(hdr.checksum), sizeof(hdr.checksum));
    nOffset += sizeof(hdr.checksum);

    memcpy(pos + nOffset, &(hdr.un.echo.id), sizeof(hdr.un.echo.id));
    nOffset += sizeof(hdr.un.echo.id);

    unsigned short seq =hdr.un.echo.sequence;
    memcpy(pos + nOffset, &seq, sizeof(seq));
    nOffset += sizeof(seq);

    unsigned long lTimeStamp = getCurrentTimeUs();
    memcpy(pos + nOffset, &lTimeStamp, sizeof(lTimeStamp));
    nOffset += sizeof(lTimeStamp);
    
    char *pDataPart = (char*)malloc(datasize);
    memset(pDataPart, 'E', datasize);
    memcpy(pos + nOffset, pDataPart, datasize);
    nOffset += datasize;
    
    // 更新校验和
    unsigned short checksum = GetCheckSum((unsigned short*)pos, nOffset);

    memcpy(pos + nCheckSumPos, &checksum, sizeof(checksum));
    
#if DEBUG
    printf("Code Ping Message:\n");
    printf("type:%d,code:%d,checksum:%d,id:%d,sequence:%d,timestamp:%ld\n",
        hdr.type,
        hdr.code,
        checksum,
        hdr.un.echo.id,
        seq),
        lTimeStamp);
#endif
/*
struct icmphdr {
  __u8      type;
  __u8      code;
  __sum16   checksum;
  union {
    struct {
        __be16  id;
        __be16  sequence;
    } echo;
    __be32  gateway;
    struct {
        __be16  __unused;
        __be16  mtu;
    } frag;
    __u8    reserved[4];
  } un;
};
*/
    printf("Code Ping Header ==>type:%d,code:%d,checksum:%d,id:%d,sequence:%d,timestamp:%ld\n",
        hdr.type,
        hdr.code,
        checksum,
        hdr.un.echo.id,
        seq,
        lTimeStamp);

    return nOffset;
}

int DecodePingResp(unsigned char* buff, int size, struct icmphdr &hdr, unsigned long &lRecvTime)
{
    int nOffset = 0;
    if(size < sizeof(struct icmphdr))
    {
        printf("Ping resp message too short!\n");
        return 0;
    }

    memcpy(&hdr.type, buff + nOffset, sizeof(hdr.type));
    nOffset += sizeof(hdr.type);

    memcpy(&hdr.code, buff + nOffset, sizeof(hdr.code));
    nOffset += sizeof(hdr.code);

    memcpy(&hdr.checksum, buff + nOffset, sizeof(hdr.checksum));
    nOffset += sizeof(hdr.checksum);
    
    memcpy(&hdr.un.echo.id, buff + nOffset, sizeof(hdr.un.echo.id));
    nOffset += sizeof(hdr.un.echo.id);

    memcpy(&hdr.un.echo.sequence, buff + nOffset, sizeof(hdr.un.echo.sequence));
    //hdr.un.echo.sequence = ntohs(hdr.un.echo.sequence);
    nOffset += sizeof(hdr.un.echo.sequence);

    memcpy(&lRecvTime, buff + nOffset, sizeof(lRecvTime));
    nOffset += sizeof(lRecvTime);

#if DEBUG
    printf("Decode Ping Message:\n");
    printf("type:%d, code:%d, checksum:%d, id:%d, seq:%d, recvtime:%ld\n",
        hdr.type,
        hdr.code,
        hdr.checksum,
        hdr.un.echo.id,
        hdr.un.echo.sequence,
        lRecvTime);

    for(int i=0;i<size-nOffset;i++)
    {
        printf("%02X ", buff[i]);
    }
    printf("\n");
#endif

    return size;
}

int DecodeIPHeader(unsigned char* buff, int size, struct iphdr &hdr)
{
    int nOffset = 0;
    
    unsigned char version = 0;
    memcpy(&version, buff + nOffset, sizeof(version));
    nOffset += sizeof(version);

    hdr.ihl = (version >> 4)& 0xf;
    hdr.version = (version) & 0xf;

    memcpy(&hdr.tos, buff + nOffset, sizeof(hdr.tos));
    nOffset += sizeof(hdr.tos);

    memcpy(&hdr.tot_len, buff + nOffset, sizeof(hdr.tot_len));
    nOffset += sizeof(hdr.tot_len);
    hdr.tot_len = ntohs(hdr.tot_len);

    memcpy(&hdr.id, buff + nOffset, sizeof(hdr.id));
    nOffset += sizeof(hdr.id);
    //hdr.id = ntohs(hdr.id);

    memcpy(&hdr.frag_off, buff + nOffset, sizeof(hdr.frag_off));
    nOffset += sizeof(hdr.frag_off);
    hdr.frag_off = ntohs(hdr.frag_off);

    memcpy(&hdr.ttl, buff + nOffset, sizeof(hdr.ttl));
    nOffset += sizeof(hdr.ttl);

    memcpy(&hdr.protocol, buff + nOffset, sizeof(hdr.protocol));
    nOffset += sizeof(hdr.protocol);

    memcpy(&hdr.check, buff + nOffset, sizeof(hdr.check));
    nOffset += sizeof(hdr.check);
    hdr.check = ntohs(hdr.check);

    memcpy(&hdr.saddr, buff + nOffset, sizeof(hdr.saddr));
    nOffset += sizeof(hdr.saddr);

    memcpy(&hdr.daddr, buff + nOffset, sizeof(hdr.daddr));
    nOffset += sizeof(hdr.daddr);
    
    return nOffset;
}

void SendPingMsg(int sockfd, struct sockaddr_in DstAddr, int datasize, int times)
{
    unsigned char szSendBuffer[MAX_BUFF_SIZE] = { 0 };
    unsigned char szRecvBuffer[MAX_BUFF_SIZE] = { 0 };
    
    struct icmphdr hdr = { 0 };
    hdr.type = ICMP_ECHO;
    hdr.code = 0;
    hdr.checksum = 0;
    hdr.un.echo.id = (unsigned short)getpid();
    hdr.un.echo.sequence = 0;
    
    long statics = 0;
    long seqno = 0;
    for(int i=0;i<times;i++)
    {
        hdr.un.echo.sequence = seqno++;
        hdr.checksum = 0;
        
        int nDataSize = CodePingReq(hdr, datasize, szSendBuffer);
        int nSend = sendto(sockfd, szSendBuffer, nDataSize, 0, (struct sockaddr*)&DstAddr, sizeof(DstAddr));
        if(nSend < 0)
        {
            printf("sendto() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
            break;
        }
    
        struct sockaddr_in fromAddr = { 0 };
        socklen_t addrlen = sizeof(fromAddr);
        int nRecv = recvfrom(sockfd, szRecvBuffer, MAX_BUFF_SIZE, 0, (struct sockaddr*)&fromAddr, &addrlen);
        if(nRecv < 0)
        {
            printf("recvfrom() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
            break;
        }
        unsigned long lRecvTime = getCurrentTimeUs();

        char szFromIp[64] = { 0 };
        if(inet_ntop(AF_INET, &fromAddr.sin_addr, szFromIp, sizeof(szFromIp)) < 0)
        {
            printf("inet_ntop() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        }

        printf("recv %d bytes from %s.\n", nRecv, szFromIp);
        
        struct iphdr ip_hdr = { 0 };
        struct icmphdr icmp_hdr = { 0 };
        unsigned long lSendTime = 0;
        
        int nIPOffset = DecodeIPHeader(szRecvBuffer, nRecv, ip_hdr);
        char szSrcIp[64] = { 0 }, szDstIp[64] = { 0 };
        if(inet_ntop(AF_INET, &ip_hdr.saddr, szSrcIp, sizeof(szSrcIp)) < 0)
        {
            printf("inet_ntop() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        }

        if(inet_ntop(AF_INET, &ip_hdr.daddr, szDstIp, sizeof(szDstIp)) < 0)
        {
            printf("inet_ntop() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        }        
        printf("Decode IP Header (%d bytes) <== ihl:%x, version:%x, tos:%x, tot_len:%x, id:%x, frag_off:%x, ttl:%x, protocol:%x, check:%x, saddr:%x(%s), daddr:%x(%s)\n",
            nIPOffset,
            ip_hdr.ihl,
            ip_hdr.version,
            ip_hdr.tos,
            ip_hdr.tot_len,
                ip_hdr.id,
            ip_hdr.frag_off,
            ip_hdr.ttl,
            ip_hdr.protocol,
            ip_hdr.check,
            ip_hdr.saddr,
            szSrcIp,
            ip_hdr.daddr,
            szDstIp);
        
        int nICMPOffset = DecodePingResp(szRecvBuffer + nIPOffset, nRecv - nIPOffset, icmp_hdr, lSendTime);
        printf("Decode Ping Header (%d bytes) <== type:%d, code:%d, checksum:%d, id:%d, seq:%d, sendtime:%.3fms\n",
            nICMPOffset,
            icmp_hdr.type,
            icmp_hdr.code,
            icmp_hdr.checksum,
            icmp_hdr.un.echo.id,
            icmp_hdr.un.echo.sequence,
            (lRecvTime - lSendTime)*0.1/1000
        );

        memset(szSendBuffer,0,sizeof(szSendBuffer));
        memset(szRecvBuffer,0,sizeof(szRecvBuffer));
        sleep(1);
    }
}


int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("Usage:%s <ADDR>\n", argv[0]);
        return 0;
    }
    char* destination = argv[1];
    int nDataSize = 48;
    int nTimes = 4;

    struct protoent *protocol = getprotobyname("icmp");
    int sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto);
    if(sockfd < 0)
    {
        printf("socket failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        return -1;
    }

    if(nDataSize > MAX_PACKET_SIZE)
    {
        nDataSize = DEF_PACKET_SIZE;
        printf("data size too large, set to def packet size(%d).", DEF_PACKET_SIZE);
    }

    struct hostent *hDestHost = gethostbyname2(destination, AF_INET);
    unsigned long lDstAddr = 0;

    if(hDestHost == NULL)
    {
        printf("hostent is null\n");
        if(inet_pton(AF_INET, destination, &lDstAddr) < 0)
        {
            printf("inet_pton failed\n");
            lDstAddr = 0;
        }
    }

    if(hDestHost == NULL && lDstAddr == INADDR_NONE)
    {
        printf("Unable to resovle %s\n", destination);
        close(sockfd);
        return -1;
    }

    char destAddrIp[64] = { 0 };
    int destAddrType = 0;

    if(hDestHost)
    {
        destAddrType = hDestHost->h_addrtype;
        if(inet_ntop(AF_INET, (struct in_addr*)*hDestHost->h_addr_list, destAddrIp, sizeof(destAddrIp)) < 0)
        {
            printf("inet_ntop() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        }
    }
    else
    {
        destAddrType = AF_INET;
        struct in_addr addr = { 0 };
        addr.s_addr = lDstAddr;
        if(inet_ntop(AF_INET, &addr, destAddrIp, sizeof(destAddrIp)) < 0)
        {
            printf("inet_ntop() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
            close(sockfd);
            return -1;
        }          
    }
    
    struct sockaddr_in dstaddr = { 0 };
    dstaddr.sin_family = destAddrType;
    if(inet_pton(AF_INET, destAddrIp, &dstaddr.sin_addr) < 0)
    {
        printf("inet_pton() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        close(sockfd);
        return -1;
    }

    // 设置超时
    struct timeval tv = {1000, 0};

    // 接收超时
    if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0)
    {
        printf("setsockopt() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        close(sockfd);
        return -1;
    }

    // 发送超时
    if(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
    {
        printf("setsockopt() failed, errno=%d, errmsg=%s\n", errno, strerror(errno));
        close(sockfd);
        return -1;
    }
   
    printf("Pinging %s ...\n", destAddrIp);

    SendPingMsg(sockfd, dstaddr, nDataSize, nTimes);

    close(sockfd);
    printf("main quit\n");
    return 0;
}


        

Makefile

CC=g++
SRC:=main.cpp
OBJS :=main.o
TARGET=ping
CFLAGS=-Werror

all:
	${CC} -c ${SRC}
	${CC} -o ${TARGET} ${OBJS}
clean:
	rm -f ${OBJS} ${TARGET}

输出

root@ubuntu:~/code/imcp# ./ping 10.107.11.1
Pinging 10.107.11.1 ...
Code Ping Header ==>type:8,code:0,checksum:36444,id:9945,sequence:0,timestamp:1614393999141661
recv 84 bytes from 10.107.11.1.
Decode IP Header (20 bytes) <== ihl:4, version:5, tos:0, tot_len:54, id:c6f, frag_off:0, ttl:40, protocol:1, check:d9ba, saddr:10b6b0a(10.107.11.1), daddr:c126b0a(10.107.18.12)
Decode Ping Header (64 bytes) <== type:0, code:0, checksum:36452, id:9945, seq:0, sendtime:0.023ms
Code Ping Header ==>type:8,code:0,checksum:18549,id:9945,sequence:1,timestamp:1614394000142580
recv 84 bytes from 10.107.11.1.
Decode IP Header (20 bytes) <== ihl:4, version:5, tos:0, tot_len:54, id:d6f, frag_off:0, ttl:40, protocol:1, check:d9b9, saddr:10b6b0a(10.107.11.1), daddr:c126b0a(10.107.18.12)
Decode Ping Header (64 bytes) <== type:0, code:0, checksum:18557, id:9945, seq:1, sendtime:0.039ms
Code Ping Header ==>type:8,code:0,checksum:1051,id:9945,sequence:2,timestamp:1614394001143102
recv 84 bytes from 10.107.11.1.
Decode IP Header (20 bytes) <== ihl:4, version:5, tos:0, tot_len:54, id:e6f, frag_off:0, ttl:40, protocol:1, check:d9b8, saddr:10b6b0a(10.107.11.1), daddr:c126b0a(10.107.18.12)
Decode Ping Header (64 bytes) <== type:0, code:0, checksum:1059, id:9945, seq:2, sendtime:0.042ms
Code Ping Header ==>type:8,code:0,checksum:49076,id:9945,sequence:3,timestamp:1614394002143636
recv 84 bytes from 10.107.11.1.
Decode IP Header (20 bytes) <== ihl:4, version:5, tos:0, tot_len:54, id:f6f, frag_off:0, ttl:40, protocol:1, check:d9b7, saddr:10b6b0a(10.107.11.1), daddr:c126b0a(10.107.18.12)
Decode Ping Header (64 bytes) <== type:0, code:0, checksum:49084, id:9945, seq:3, sendtime:0.044ms
main quit

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值