Linux下的ping程序源代码

futurezone 2010-02-17

Linux下用C++写了ping的源代码,期间遇到段错误,百思不得其解。用了几条printf测试输出,终于找到了根源所在, 原来是memcpy(packet, icmp , icmplen);的时候icmplen的值不对,照成了内存访问越界。
#include<iostream>
#include<string.h>
#include<errno.h>
#include<signal.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdio.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<netdb.h>
#include<netinet/in_systm.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#include<sys/types.h>

#define ICMPHEAD 8
#define MAXICMPLEN 200
//typedef unsigned int socklen_t;

using namespace std;

 


class RawSock
{
    public:
    int sock;
    int error;
    RawSock(int protocol =0);
    virtual ~RawSock();
    int send(const void* msg, int msglen, struct sockaddr* addr, unsigned int len);
    int send(const void* msg, int msglen, char *addr);
    int receive(void *buf, int buflen, sockaddr *from, socklen_t *len);
    int Error() { return error; }
};

class ICMP : public RawSock
{
    public:
    struct icmp *packet;
    int max_len;
    int length;

    uint16_t checksum(uint16_t *addr, int len);
    ICMP();
    ICMP(int len);
    ~ICMP();
    int send_icmp(char *to, void *buf, int len);
    int recv_icmp(sockaddr *from);
    void setCode(int c) { packet->icmp_code =c; }
    void setId(int i) { packet->icmp_id =i; }
    void setSeq(int s) { packet->icmp_seq = s; }
    void setType(int t) { packet->icmp_type = t; }
};

RawSock:: RawSock(int protocol )
{
    sock = socket(AF_INET, SOCK_RAW, protocol);
    setuid(getuid());
    if( sock == -1 ) error = 1;
    else error = 0;
}


RawSock:: ~RawSock()
{
    close(sock);
}

int RawSock:: send(const void* msg, int msglen, struct sockaddr* to, unsigned int len)
{
    if (error )
    return -1;
    int length = sendto(sock, msg, msglen, 0, (const struct sockaddr *)to, len);
    if( length == -1)
    {
    error = 2;
    return -1;
    }
    return length;
}


int RawSock:: send(const void* msg, int msglen, char *hostname)
{
    sockaddr_in sin;
    if(error)
    return -1;

    if(hostname)
    {
    hostent *hostnm = gethostbyname(hostname);
    if( hostnm == (struct hostent *)0)
    {
        return -1;
    }
    sin.sin_addr = *((struct in_addr *)hostnm->h_addr);
    }
    else
    return -1;
    sin.sin_family = AF_INET;
    return send(msg, msglen, (sockaddr *)&sin, sizeof(sin));
}


int RawSock::receive(void *buf, int buflen, sockaddr* from, socklen_t *len)
{
    if(error) return -1;
    while(1)
    {
    int length =recvfrom(sock, buf, buflen, 0, from, len);
    if(length == -1)
        if( error == EINTR ) continue;
        else {
        error = 3;
        return -1;
        }
    return length;
    }
}

 

/********************
* ICMP 瀹炵幇
*
*
* ********************/

ICMP::ICMP() : RawSock(IPPROTO_ICMP)
{
    max_len = MAXICMPLEN;
    packet = (struct icmp *)new char [max_len];
   
    packet->icmp_code = 0;
    packet->icmp_id = 0;
    packet->icmp_seq = 0;
    packet->icmp_type = ICMP_ECHO;

}


ICMP::ICMP(int len) : RawSock(IPPROTO_ICMP)
{
    max_len = len;
    packet = (struct icmp *) new char [max_len];
    packet->icmp_code = 0;

    packet->icmp_id = 0;
    packet->icmp_seq = 0;
    packet->icmp_type = ICMP_ECHO;

}

ICMP::~ICMP()
{
    delete [] (char *)packet;
}

uint16_t ICMP::checksum(uint16_t *addr, int len)
{
    int nleft = len;
    int sum =0;
    unsigned short *w = addr;
    unsigned short 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);
}


int ICMP:: send_icmp(char *host, void *buf, int len)
{
    memcpy(packet->icmp_data, buf, len);
    packet->icmp_cksum =0;
    packet->icmp_cksum = checksum((uint16_t *)packet, ICMPHEAD + 6);
    int err = send(packet, MAXICMPLEN, host);
    return err;

}


int ICMP:: recv_icmp(sockaddr *from)
{
    char buf[MAXICMPLEN + 100];
    int hlen1, icmplen;
    struct ip *ip;
    struct icmp *icmp;

    if( Error() )
    {
    printf("Error() = %d\n", Error());
    return -1;
    }
   
   socklen_t addrlen = 0;
    int len = receive(buf, MAXICMPLEN+100, from , &addrlen);

    if ( len == -1)
    {
    cout<<"Receive Failed\n";
    return -1;
    }

    ip = (struct ip *)buf;
    hlen1 = ip->ip_hl << 2;

    icmp = (struct icmp *) (buf + hlen1);

    if( (icmplen = len -hlen1) < 8)
    {
    cout<<"Receive Fail\n";
    return -1;
    }

    memcpy(packet, icmp , icmplen);
   // printf("11111\n");
    return 0;
}


main(int argc, char *argv[])
{
    ICMP icmp;
    struct sockaddr from;
    char *host;
    int count;

    if(argc < 2)
    {
    printf("can shu you wu\n");
    exit(1);
    }
    if(argc == 2)
    {
    host = argv[1];
    count = 5;
    }
    if( argc == 3)
    {
    host = argv[1];
    count = 3;
    }

    for( int i=0; i<=count; i++)
    {
    icmp.setId(getpid());
    icmp.setSeq(i);
    char *test_data = "abcde";
    icmp.send_icmp(host, test_data, strlen(test_data));
    printf("count = %d\n", count);
    }

    int num = 1;
    while(1)
    {
    if(icmp.recv_icmp(&from) < 0)
        continue;
    if(icmp.packet->icmp_type == ICMP_ECHOREPLY)
    {
           if( icmp.packet->icmp_id == getpid())
        {
        printf("%d bypes form %s: seq=%u, data=%s\n",
            icmp.length, host, icmp.packet->icmp_seq, icmp.packet->icmp_data);
        num++;
        if(num > count)
            break;
        }

    }
    }
}

相关推荐