Thread: ping program

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Jan 2003
    Posts
    88

    ping program

    hello.

    doing some raw sockets programming and having some fun...this stuff has some real potential!

    but,
    im having a strange bug in my ping program....
    Code:
    /*
     *    pinger.c 
     *    This is a ping imitation program 
     *    It will send an ICMP ECHO packet to the server of 
     *    your choice and listen for an ICMP REPLY packet
     *    Have fun!
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <linux/ip.h>
    #include <linux/icmp.h>
    #include <string.h>
    #include <unistd.h>
    
    
    char dst_addr[15];
    char src_addr[15];
    
    unsigned short in_cksum(unsigned short *, int);
    void parse_argvs(char**, char*, char* );
    void usage();
    char* getip();
    
    int main(int argc, char* argv[])
    {
        struct iphdr* ip;
        struct iphdr* ip_reply;
        struct icmphdr* icmp;
        struct sockaddr_in connection;
        char* packet;
        char* buffer;
        int sockfd;
        int optval;
        int addrlen;
        
        if (getuid() != 0)
        {
    	fprintf(stderr, "%s: root privelidges needed\n", *(argv + 0));
    	exit(EXIT_FAILURE);
        }
    
        parse_argvs(argv, dst_addr, src_addr);
        printf("Source address: %s\n", src_addr);
        printf("Destination address: %s\n", dst_addr);
        
        /*
         * allocate all necessary memory
        */
        ip = malloc(sizeof(struct iphdr));
        ip_reply = malloc(sizeof(struct iphdr));
        icmp = malloc(sizeof(struct icmphdr));
        packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        /****************************************************************/
        
        ip = (struct iphdr*) packet;
        icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));
        
        /*  
         *	here the ip packet is set up except checksum
         */
        ip->ihl			= 5;
        ip->version			= 4;
        ip->tos			= 0;
        ip->tot_len			= sizeof(struct iphdr) + sizeof(struct icmphdr);
        ip->id			= htons(random());
        ip->ttl			= 255;
        ip->protocol		= IPPROTO_ICMP;
        ip->saddr			= inet_addr(src_addr);
        ip->daddr			= inet_addr(dst_addr);
    
        
        if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
        {
    	perror("socket");
    	exit(EXIT_FAILURE);
        }
        
        /* 
         *	IP_HDRINCL must be set on the socket so that
         *	the kernel does not attempt to automatically add
         *	a default ip header to the packet
         */
        
        setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
        
        /*
         *	here the icmp packet is created
         *	also the ip checksum is generated
         */
        icmp->type			= ICMP_ECHO;
        icmp->code			= 0;
        icmp->un.echo.id		= 0;
        icmp->un.echo.sequence	= 0;
        icmp->checksum 		= 0;
        icmp-> checksum		= in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
        
        ip->check			= in_cksum((unsigned short *)ip, sizeof(struct iphdr));
        
        connection.sin_family = AF_INET;
        connection.sin_addr.s_addr = inet_addr(dst_addr);
        
        /*
         *	now the packet is sent
         */
        
        sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
        printf("Sent %d byte packet to %s\n", sizeof(packet), dst_addr);
        
        /*
         *	now we listen for responses
         */
        addrlen = sizeof(connection);
        if (recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen) == -1)
        {
    	perror("recv");
        }
        else
        {
    	printf("Received %d byte reply from %s:\n", sizeof(buffer), dst_addr);
            ip_reply = (struct iphdr*) buffer;
    	printf("ID: %d\n", ntohs(ip_reply->id));
    	printf("TTL: %d\n", ip_reply->ttl);
        }
        close(sockfd);
        return 0;
    }
    
    void parse_argvs(char** argv, char* dst, char* src)
    {
        int i;
        if(!(*(argv + 1))) 
        {
    	/* there are no options on the command line */
    	usage();
    	exit(EXIT_FAILURE);	
        }
        if (*(argv + 1) && (!(*(argv + 2)))) 
        {
    	/* 
    	 *   only one argument provided
    	 *   assume it is the destination server
    	 *   source address is local host
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	strncpy(src, getip(), 15);
    	return;
        }
        else if ((*(argv + 1) && (*(argv + 2))))
        {
    	/* 
    	 *    both the destination and source address are defined
    	 *    for now only implemented is a source address and 
    	 *    destination address
    	 */
    	strncpy(dst, *(argv + 1), 15);
    	i = 2;
    	while(*(argv + i + 1))
    	{
    	    if (strncmp(*(argv + i), "-s", 2) == 0)
    	    {
    		strncpy(src, *(argv + i + 1), 15);
    		break;
    	    }
    	    i++;
    	}
    
        }
    }
    
    void usage()
    {
        fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");
        fprintf(stderr, "Destination must be provided\n");
        fprintf(stderr, "Source is optional\n\n");
    }
    
    char* getip()
    {
        char buffer[256];
        struct hostent* h;
        
        gethostname(buffer, 256);
        h = gethostbyname(buffer);
        
        return inet_ntoa(*(struct in_addr *)h->h_addr);
        
    }
    /*
     * in_cksum --
     * Checksum routine for Internet Protocol
     * family headers (C Version)
     */
    unsigned short in_cksum(unsigned short *addr, int len)
    {
        register int sum = 0;
        u_short answer = 0;
        register u_short *w = addr;
        register int nleft = len;
        /*
         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
         * sequential 16 bit words to it, and at the end, fold back all the
         * carry bits from the top 16 bits into the lower 16 bits.
         */
        while (nleft > 1)
        {
    	  sum += *w++;
    	  nleft -= 2;
        }
        /* mop up an odd byte, if necessary */
        if (nleft == 1)
        {
    	  *(u_char *) (&answer) = *(u_char *) w;
    	  sum += answer;
        }
        /* add back carry outs from top 16 bits to low 16 bits */
        sum = (sum >> 16) + (sum & 0xffff);		/* add hi 16 to low 16 */
        sum += (sum >> 16);				/* add carry */
        answer = ~sum;				/* truncate to 16 bits */
        return (answer);
    }

    the code is pretty simple...it should make sense...


    say 192.168.0.5 is a machine on my network and 192.168.0.7 is my machine:

    if i do:
    ./pinger 192.168.0.5 -s 192.168.0.7
    it works! its great i even confirmed the ICMP REPLY packet with a sniffer (ethereal) and the ttl and the ID match....very sexy
    but if i do
    ./pinger 192.168.0.5
    (note that getip() does return 192.168.0.7) no reply is received....looking closer i found that the one with out source specified on the command line ends up sending only an ip packet with the fragment flags turned on! what the hell is that all about?

    thx for help
    Last edited by lithium; 07-08-2003 at 01:34 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Using variables in system()
    By Afro in forum C Programming
    Replies: 8
    Last Post: 07-03-2007, 12:27 PM
  2. ping client
    By cpp_is_fun in forum C Programming
    Replies: 4
    Last Post: 11-29-2006, 12:44 PM
  3. BOOKKEEPING PROGRAM, need help!
    By yabud in forum C Programming
    Replies: 3
    Last Post: 11-16-2006, 11:17 PM
  4. My program, anyhelp
    By @licomb in forum C Programming
    Replies: 14
    Last Post: 08-14-2001, 10:04 PM