Click here to Skip to main content
15,891,762 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm required to write a packet sniffer in the C programming language and Identify the Packet as IP, ARP, or Broadcast and count how many packets of each. I'm able to get IP packets identified and counted, but don't seem to be seeing any ARP or Broadcasts correctly or count them.

I also get this warning when I compile my code:
/netdump.c: In function 'raw_print':
./netdump.c:284: warning: cast to pointer from integer of different size
./netdump.c:285: warning: comparison between pointer and integer

Any help is appreciated!!! I'm more concerned with why I'm not getting any ARP or Broadcast packets being identified and counted.

Thanks Again,
JW

C
#define RETSIGTYPE void
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <pcap.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifndef setsignal_h
#define setsignal_h

RETSIGTYPE (*setsignal(int, RETSIGTYPE (*)(int)))(int);
#endif

/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN	6
#define SIZE_ETHERNET 	14
#define SIZE_IPHDR		20

/* Ethernet header */
struct sniff_ethernet {
	u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
	u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
	u_short ether_type; 				/* IP? ARP? etc */
};

/* ARP packet */
struct sniff_arp {
	u_short arp_hwtype;
	u_short arp_proto;
	u_char arp_addrlen;
	u_char arp_protolen;
	u_short arp_operation;
	u_char arp_src[6];
	u_char arp_src_proto_addr[4];
	u_char arp_dst[6];
	u_char arp_dst_proto_addr[4];
};

/* IP header */
struct sniff_ip {
	u_char ip_vhl;				/* version << 4 | header length >> 2 */
	u_char ip_tos;				/* type of service */
	u_short ip_len;				/* total length */
	u_short ip_id;				/* identification */
	u_short ip_off;				/* fragment offset field */
	#define IP_RF 0x8000		/* reserved fragment flag */
	#define IP_DF 0x4000		/* dont fragment flag */
	#define IP_MF 0x2000		/* more fragments flag */
	#define IP_OFFMASK 0x1fff	/* mask for fragmenting bits */
	u_char ip_ttl;				/* time to live */
	u_char ip_p;				/* protocol */
	u_short ip_sum;				/* checksum */
	u_char ip_src[4];			/* source port */
	u_char ip_dst[4];			/* destination port */
	//	struct in_addr ip_src,ip_dst; /* source and dest address */
};

int nPackets = 1;
int nARP = 0;
int nIP = 0;
int nBroadcast = 0;


char cpre580f98[] = "netdump";

void raw_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p);

int packettype;

char *program_name;

/* Externs */
extern void bpf_dump(struct bpf_program *, int);

extern char *copy_argv(char **);

/* Forwards */
 void program_ending(int);

/* Length of saved portion of packet. */
int snaplen = 1500;;

static pcap_t *pd;

extern int optind;
extern int opterr;
extern char *optarg;
int pflag = 0, aflag = 0;

int
main(int argc, char **argv)
{
        int cnt, op, i, done = 0;
        bpf_u_int32 localnet, netmask;
        char *cp, *cmdbuf, *device;
        struct bpf_program fcode;
         void (*oldhandler)(int);
        u_char *pcap_userdata;
        char ebuf[PCAP_ERRBUF_SIZE];

        cnt = -1;
        device = NULL;

        if ((cp = strrchr(argv[0], '/')) != NULL)
                program_name = cp + 1;
        else
                program_name = argv[0];

        opterr = 0;
        while ((i = getopt(argc, argv, "pa")) != -1)
        {
                switch (i)
                {
                case 'p':
                        pflag = 1;
                break;
                case 'a':
                        aflag = 1;
                break;
                case '?':
                default:
                        done = 1;
                break;
                }
                if (done) break;
        }
        if (argc > (optind)) cmdbuf = copy_argv(&argv[optind]);
                else cmdbuf = "";

        if (device == NULL) {
                device = pcap_lookupdev(ebuf);
                if (device == NULL)
                        error("%s", ebuf);
        }
        pd = pcap_open_live(device, snaplen,  1, 1000, ebuf);
        if (pd == NULL)
                error("%s", ebuf);
        i = pcap_snapshot(pd);
        if (snaplen < i) {
                warning("snaplen raised from %d to %d", snaplen, i);
                snaplen = i;
        }
        if (pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
                localnet = 0;
                netmask = 0;
                warning("%s", ebuf);
        }
        /*
         * Let user own process after socket has been opened.
         */
        setuid(getuid());

        if (pcap_compile(pd, &fcode, cmdbuf, 1, netmask) < 0)
                error("%s", pcap_geterr(pd));

        (void)setsignal(SIGTERM, program_ending);
        (void)setsignal(SIGINT, program_ending);
        /* Cooperate with nohup(1) */
        if ((oldhandler = setsignal(SIGHUP, program_ending)) != SIG_DFL)
                (void)setsignal(SIGHUP, oldhandler);

        if (pcap_setfilter(pd, &fcode) < 0)
                error("%s", pcap_geterr(pd));
        pcap_userdata = 0;
        (void)fprintf(stderr, "%s: listening on %s\n", program_name, device);
        if (pcap_loop(pd, cnt, raw_print, pcap_userdata) < 0) {
                (void)fprintf(stderr, "%s: pcap_loop: %s\n",
                    program_name, pcap_geterr(pd));
                exit(1);
        }
        pcap_close(pd);
        exit(0);
}

/* routine is executed on exit */
void program_ending(int signo)
{
        struct pcap_stat stat;

        if (pd != NULL && pcap_file(pd) == NULL) {
                (void)fflush(stdout);
                putc('\n', stderr);
                if (pcap_stats(pd, &stat) < 0)
                        (void)fprintf(stderr, "pcap_stats: %s\n",
                            pcap_geterr(pd));
                else {
					printf("Statistics:\n_________________________________________________\n");
					printf("Packet Counts:\n");
					printf("ARP......%d\n",nARP); 
					printf("IP.......%d\n",nIP);
					printf("BRDCST...%d\n\n",nBroadcast); 
					printf("\n\n");
					(void)fprintf(stderr, "%d packets received by filter\n",stat.ps_recv);
					(void)fprintf(stderr, "%d packets dropped by kernel\n",stat.ps_drop);
				}
			}
        exit(0);
}

/* Like default_print() but data need not be aligned */
void
default_print_unaligned(register const u_char *cp, register u_int length)
{
        register u_int i, s;
        register int nshorts;

        nshorts = (u_int) length / sizeof(u_short);
        i = 0;
        while (--nshorts >= 0) {
                if ((i++ % 8) == 0)
                        (void)printf("\n\t\t\t");
                s = *cp++;
                (void)printf(" %02x%02x", s, *cp++);
        }
        if (length & 1) {
                if ((i % 8) == 0)
                        (void)printf("\n\t\t\t");
                (void)printf(" %02x", *cp);
        }
}

/*
 * By default, print the packet out in hex.
 */
void
default_print(register const u_char *bp, register u_int length)
{
        register const u_short *sp;
        register u_int i;
        register int nshorts;

        if ((long)bp & 1) {
                default_print_unaligned(bp, length);
                return;
        }
        sp = (u_short *)bp;
        nshorts = (u_int) length / sizeof(u_short);
        i = 0;
        while (--nshorts >= 0) {
                if ((i++ % 8) == 0)
                        (void)printf("\n\t");
                (void)printf(" %04x", ntohs(*sp++));
        }
        if (length & 1) {
                if ((i % 8) == 0)
                        (void)printf("\n\t");
                (void)printf(" %02x", *(u_char *)sp);
        }
}

/*
insert your code in this routine

*/

void raw_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
{
	
	
	/* declare pointers to packet headers */
	const struct sniff_ethernet *ethernet;  /* The ethernet header */
	const struct sniff_arp *arp;			/* The arp packet */
	const struct sniff_ip *ip;				/* The IP header */
	char *payload;							/* Packet payload */
	char data[1480];
	int shoPayload = 0;	
	
	ethernet = (struct sniff_ethernet*)(p);
	
	//decode ethernet packet header
	u_short type;
	int i=0, bcst=1;
	u_char test;
	//short bcast = "ff";
	printf("Ethernet Header\n---------------------------\n");
	printf("Src: %02x:%02x:%02x:%02x:%02x:%02x\n", ethernet->ether_shost[0],ethernet->ether_shost[1],ethernet->ether_shost[2],ethernet->ether_shost[3],ethernet->ether_shost[4],ethernet->ether_shost[5]);
	printf("Dst: %02x:%02x:%02x:%02x:%02x:%02x\n", ethernet->ether_dhost[0],ethernet->ether_dhost[1],ethernet->ether_dhost[2],ethernet->ether_dhost[3],ethernet->ether_dhost[4],ethernet->ether_dhost[5]);
	
	
	 while (i < 6) {
		printf("%x:",(u_char *)ethernet->ether_dhost[i]);
		if 	("ff" != ethernet->ether_dhost[i]) {
			printf("%x:",ethernet->ether_dhost[i]);
			bcst = 0;
			//bcst ++;
			//nBroadcast++;
			//printf("Broadcast\n");
		}
		i++;
	}
	if (bcst == 1) {
		nBroadcast++;
		printf("Broadcast\n");
	}
		
	type = ntohs(ethernet->ether_type);
	printf("\nType: 0x%x \n", type);
	
	switch (type) {
		case 0x806:
			//decode ARP packet header
			arp = (struct sniff_arp*)(p + SIZE_ETHERNET);
			printf("Payload = ARP\n");
			printf("\n\tARP Decode\n\t-------------------\n");
 			printf("\tHW type: %04x\n", arp->arp_hwtype);
			printf("\tProto type: %04x\n", arp->arp_proto);
			printf("\tHW Addr Len: %02x\n", arp->arp_addrlen);
			printf("\tProto Len: %02x\n", arp->arp_protolen);
			printf("\tSrc: %02x:%02x:%02x:%02x:%02x:%02x\n", arp->arp_src[0],arp->arp_src[1],arp->arp_src[2],arp->arp_src[3],arp->arp_src[4],arp->arp_src[5]);
			printf("\tDst: %02x:%02x:%02x:%02x:%02x:%02x\n", arp->arp_dst[0],arp->arp_dst[1],arp->arp_dst[2],arp->arp_dst[3],arp->arp_dst[4],arp->arp_dst[5]);
			//printf("\tSrc IP: %d.%d.%d.%d\n", arp->arp_src_proto_addr[0],arp->arp_src_proto_addr[1],arp->arp_src_proto_addr[2],arp->arp_src_proto_addr[3]);
			//printf("\tDst IP: %d.%d.%d.%d\n", arp->arp_dst_proto_addr[0],arp->arp_dst_proto_addr[1],arp->arp_dst_proto_addr[2],arp->arp_dst_proto_addr[3]);
 			nARP++;
			break;
		case 0x800:
			//decode IP packet header
			ip = (struct sniff_ip*)(p + SIZE_ETHERNET);
			printf("Payload = IP\n");
			printf("\n\tIP Header\n\t-------------------\n");
			printf("\tSrc: %d.%d.%d.%d\n", ip->ip_src[0],ip->ip_src[1],ip->ip_src[2],ip->ip_src[3]);
			printf("\tDst: %d.%d.%d.%d\n", ip->ip_dst[0],ip->ip_dst[1],ip->ip_dst[2],ip->ip_dst[3]);
			printf("\tIP Version: %x\n", (ip->ip_vhl) >> 4);
			//printf("\tHeader Len: %x\n",(ip->ip_vhl) & 0x0F);
			//printf("\tTOS: %x\n", ip->ip_tos);
			printf("\tLength: %d\n", ntohs(ip->ip_len));
			//printf("\tPacket ID: %d\n", ntohs(ip->ip_id));
			//printf("\tOffset: %d\n", ntohs(ip->ip_off) & 0x1fff);
			//printf("\tTTL: %d\n", ip->ip_ttl);
			//printf("\tChecksum: %d\n", ntohs(ip->ip_sum));
			nIP++;
			break;
			}
        u_int length = h->len;
        u_int caplen = h->caplen;
		default_print(p, caplen);
        putchar('\n');
} 
Posted
Updated 22-Sep-12 12:48pm
v2
Comments
pasztorpisti 22-Sep-12 18:58pm    
The warning comes because of this:
printf("%x:",(u_char *)ethernet->ether_dhost[i]);
if ("ff" != ethernet->ether_dhost[i]) {
In the first line you cast an u_char to a pointer before printing, this is needless and because of this your print might print bad results if you are compiling on a big endian system or if later you add more printable lparameters to the format string and your pointer is 64 bits (on 64 bit system).
The second line: In C you never compare strings like that, there is a zero terminated string stored somwhere for you by the compiler in a global memory area, and you compare the address of that const string with an integer value. That probably always evaluated to false so your if block is never executed. I'm afraid there are several similar bugs in your code. An I was surprised seeing the use of the register keyword, I havent seen that for a very long period of time. :-)
Have you tried to use a debugger to find the problems???
yagu99 23-Sep-12 19:28pm    
pasztorpisti,
Thanks for the assistance. I didn't use a debugger before making this post, but that is good information and will use one from now on.

Thanks Again,
JW
pasztorpisti 23-Sep-12 19:44pm    
Well, if you havent used a debugger before then read this: A debugger is one of the best friends of a programmer. The most primitive debugging method is logging out the program state with printf() at certain points. I dont recommend this, quite rare when this is the best method. Use a debugger instead.
Here are the things you can do with an average good debugger:
You can place so called 'breakpoints' on every line of your code and the execution of the program is paused if that line is about to be executed and then in the paused state you can decide whats next: for example you can inspect the actual values inside the variables (this is called the 'watch' functionality) you can continue the execution of the program, or you can 'step' the program line by line by telling the debugger to execute only one line and the pause the program again. Basically this is what you can do with a debugger, some advanced techniques that are rarely used: you can attach a condition expression to breakpoints that tell the debugger to start on that breakpoint only when the expression evaluates to true, for example you can tell to stop on a breakpoint only if the x variable contains 5 as a value.
My native OS is windows and I usually write even crossplatform linux code on windows using Visual C++ as a development environment so unfortunately I cant recommend you a good ide on linux but I would advice you something: dont start debugging using the commandline gdb because that is a nightmare, search for a C/C++ IDE that supports debugging and then you can use breakpoints and watch in your source code editor.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900