#########################################################
   pcap library Ͽ Ŷ ƺ v0.3 
                                                       
  ۾ : 뱤                                       
  e-mail : djstop@orgio.net
  homepage : http://myhome.shinbiro.com/~nkm24
  tcpdump, libpcap ҽ   ִ  : ftp://ftp.ee.lbl.gov
#########################################################

 ý, Ʈ α׷ ̰ Ұ  ̰͵ ϱ  
ҽ   ϴ OSԴϴ.
  Ű Ÿ ִٸ ̷ α׷   
 .   ý, Ʈ α׷ ϰ   پⰡ
Ͻ е  ̷ ª ̳   Ҵ  
   ÷ ϴ. ⿡ ϴ   socket ̿
Ʈ α׷  ٸ Դϴ.

 Ʈ α׷ ϱ     ҽ  ֽϴ.
 Ʈ    ߴ  tcpdumpԴϴ.   Ʈ
 Ŷ Ƽ ؽƮ  ؼ ִ α׷..
׷     Ʈ Ŷ Ƽ   ְڱϰ  .

׷ Ŷ   󸶳    ڽϴ.

int main(int argc, char *argv[])
{
	.
	.
	.
	.
	.
	
	opterr = 0;
	
	if (device == NULL ) {
	    if ( (device = pcap_lookupdev(ebuf) ) == NULL) {
	        perror(ebuf);           
   	        exit(-1);
   	    }
   	}
		
	pd = pcap_open_live(device, snaplen, PROMISCUOUS, 1000, ebuf);
	if(pd == NULL) {
   	    perror(ebuf);          
   	    exit(-1);
   	}

	if(pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
   	    perror(ebuf);
   	    exit(-1);
   	}
	
	setuid(getuid());
	
	if(pcap_compile(pd, &fcode, filter_rule, 0, netmask) < 0) {
   	    perror(ebuf);
   	    exit(-1);
   	}
	
	if(pcap_setfilter(pd, &fcode) < 0) {
   	    perror(ebuf);
   	    exit(-1);
   	}
	
	fflush(stderr);
	
	printer = lookup_printer(pcap_datalink(pd));
	pcap_userdata = 0;
	
	if(pcap_loop(pd, packetcnt, printer, pcap_userdata) < 0) {
   	    perror("pcap_loop error");
   	    exit(-1);
   	}
	
	pcap_close(pd);
	exit(0);
}

Ʈ  Ŷ   pcap library   Լ ϱ⸸ 
ϸ ˴ϴ. ʴ ?

	device = pcap_lookupdev(ebuf);
	
  ӽ Ʈ ̽  ԼԴϴ. Ŷ 
Ʈ ̽ ؾ ?  ̳  ٺ̽  ȣ 
 ̽  ˴ϴ.  eth0̰...
i ɼ ̽    ֽϴ.

	pd = pcap_open_live(device, snaplen, PROMISCUOUS, 1000, ebuf)
	
 Լ  ⸦ ִ  ϴ  snaplen Ŷ 
̽ ,  datalink Ŷ ũ⸦ Ͽ ϴ κи
 Ǵ Դϴ.    Ÿ 
ʿ . ͱ  ̸ ø ˴ϴ. 
PROMISCUOUS 1̸ Ʈ ̽   Ŷ ްڴٴ
ǹԴϴ.  带 ڼϰ ϸ lan  Ŷ broadcastingǸ
ϴ  Ʈ ̽  Ʈ ٸ ȣƮ Ŷ ϴ ϰ
˴ϴ.  ׷, Ʈ ̽ ⺻ ڽ Ŷ
ްԲ Ǿֽϴ. ׷Ƿ ٸ ȣƮ Ŷ  Ǵ Դϴ.
׷ promiscuous ̽ 带 ٲٰ Ǹ  Ŷ ޾Ƶ̰
Ǵ Դϴ. ۸ α׷   带 ϰ ˴ϴ.
 ° ڴ Ŷ ۷ ޵  ٷ ޵Ǵ  ƴ϶
  ð Ѱ  ۰  ä  α׷
޵Ǵ Դϴ. 


	pcap_lookupnet(device, &localnet, &netmask, ebuf)
	
 Ŷ ĸ ̽ Ʈ ּҿ  ũ Ѱݴϴ.

	pcap_compile(pd, &fcode, filter_rule, 0, netmask)	
	
 ͷ꿡   α׷ ϰ Ǵµ 츮 ϴ Ŷ
ͷ ־߸ ϴ Ŷ   ֽϴ.  tcpdump ϴ 
ͷ ⿡ Դϴ.   "tcp port 80" ... ڼ ͷ꿡  
 tcpdump ޴    ֽϴ.

	pcap_setfilter(pd, &fcode)
	
 ռ   α׷ Ŷ ĸ ̽ о̰ ˴ϴ.
̷ Ͽ ϴ Ŷ  غ ϰ ˴ϴ.	

	printer = lookup_printer(pcap_datalink(pd));
	
 Ŷ ĸ ̽ datalink  Ѱ ޾ ̿  
Լ͸ Ҵϰ ˴ϴ.

	pcap_loop(pd, packetcnt, printer, pcap_userdata)
	
   Ŷ Ƽ  Լ  ִ ԼԴϴ.
packetcnt ŭ Ŷ Ƽ    printer ġ Լ 
ϰ ˴ϴ. packetcnt 0 ϸ Ѵ Լ մϴ.

 ڼ  Ѵٸ Ƽ콺   unp(unix network programming)
  26忡 pcap library    ֽϴ.

׷  pcap library ̿  Ʈ ip tcp, udp, icmp Ŷ
Ƽ ؽƮ ʵ庰 ѷִ ҽ  սô.
 ҽ  tcpdump ҽ  밡 α׷  ̸ 
ҽ   ּ ϰڽϴ.

##################################################################################
#include <sys/time.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include <pcap/pcap.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>

#define	 PROMISCUOUS 1

struct   iphdr    *iph;
struct   tcphdr  *tcph;
struct   udphdr *udph;
struct   icmp     *icmph;
static   pcap_t   *pd;
int sockfd;

int pflag;      // DATA ڷ  .
int rflag;      // DATA   .
int eflag;     // DATALINK layer print option
int cflag;     // Ŷ  ڸŭ ְ Ѵ.
int chcnt;    // ڸ   ī ٿ 

char	*device, *filter_rule;

void packet_analysis(unsigned char *, const struct pcap_pkthdr *, 
                    const unsigned char *);

struct printer {
   pcap_handler f;
   int type;
};
   
/* datalink type  Ҹ Լ 
   ϵ  ü                       
 Data-link level type codes. 
#define DLT_NULL		0	 no link-layer encapsulation 
#define DLT_EN10MB	1	 Ethernet (10Mb) 
#define DLT_EN3MB		2	 Experimental Ethernet (3Mb)
#define DLT_AX25		3	 Amateur Radio AX.25
#define DLT_PRONET	4	 Proteon ProNET Token Ring
#define DLT_CHAOS		5	 Chaos
#define DLT_IEEE802	6	 IEEE 802 Networks
#define DLT_ARCNET	7	 ARCNET
#define DLT_SLIP		8	 Serial Line IP
#define DLT_PPP		9	 Point-to-point Protocol
#define DLT_FDDI		10	 FDDI
#define DLT_ATM_RFC1483	11	 LLC/SNAP encapsulated atm
#define DLT_RAW		12	 raw IP
#define DLT_SLIP_BSDOS	13	 BSD/OS Serial Line IP
#define DLT_PPP_BSDOS	14	 BSD/OS Point-to-point Protocol
bpf.h  ȭϿ    ǵǾ ִ.		*/

static struct printer printers[] = {
   { packet_analysis, DLT_IEEE802 },
   { packet_analysis, DLT_EN10MB  },
   { NULL, 0 },
};
   
/*  datalink type   Լ ϰ ȴ.
    ̴ pcap_handler Լ   Եȴ. */
static pcap_handler lookup_printer(int type) 
{
	struct printer *p;
    
	for(p=printers; p->f; ++p)
   	    if(type == p->type)
	        return p->f;
	        
	perror("unknown data link type");
}


/* pcap_loop()  Ŷ   ҷ Լ
   pcap_handler  Լ ϰ ֱ ̴ */
void packet_analysis(unsigned char *user, const struct pcap_pkthdr *h, 
                    const unsigned char *p)
{
    	int j, temp;
	unsigned int length = h->len;
	struct ether_header *ep;
	unsigned short ether_type;
	unsigned char *tcpdata, *udpdata,*icmpdata;
	register unsigned int i;
	
	chcnt = 0;
	
	//  Ŷ ״  	
	if(rflag) {
	    while(length--) {
	        printf("%02x ", *(p++));
	        if( (++chcnt % 16) == 0 ) printf("\n\t");
	    }
	    fprintf(stdout, "\n");
	    return;
	}

	length -= sizeof(struct ether_header);
	
	// ethernet header mapping
	ep = (struct ether_header *)p;
	// ethernet header 14 bytes ǳ  
	p += sizeof(struct ether_header);
	// datalink type
	ether_type = ntohs(ep->ether_type);
	
	printf("\n");
	// lan frame IEEE802ΰ ether_typeʵ尡 ʵ尡 ȴ.
	if(ether_type <= 1500) {
	    ;
	    /*while(length--) {
		if(++is_llchdr <= 3) {
		    fprintf(stdout,"%02x",*p++);
		    continue;
		}
		if(++next_line == 16) {
		    next_line = 0;	
		    printf("\n\t");
		}
		printf("%02x",*p++);
	    }*/
	}
	else 
	{    
	    if(eflag) {
	    	printf("\n\n    =================== Datalink layer ===================\n\t");
	    	for(j=0; j<ETH_ALEN; j++){ 
		    printf("%X", ep->ether_dhost[j]); 
		    if(j != 5) printf(":");
	    	}
	    	printf("  ------> ");
	    	for(j=0; j<ETH_ALEN; j++) {
		    printf("%X", ep->ether_shost[j]);
	        	    if(j != 5) printf(":");
	    	}	
	    	printf("\n\tether_type -> %x\n", ntohs(ep->ether_type));
	    }

	    iph = (struct iphdr *) p;
	    i = 0;
	    if (ntohs(ep->ether_type) == ETHERTYPE_IP) {	// ip Ŷΰ?
		// packet capturing  ȭ鿡 ϴ κ
	        	printf("\n\n    ===================    IP HEADER   ===================\n");
		printf("\t%s -----> ",   inet_ntoa(iph->saddr));
		printf("%s\n", inet_ntoa(iph->daddr));
		printf("\tVersion:         %d\n", iph->version);
		printf("\tHerder Length:   %d\n", iph->ihl);
		printf("\tService:         %#x\n",iph->tos);
		printf("\tTotal Length:    %d\n", ntohs(iph->tot_len)); 
		printf("\tIdentification : %d\n", ntohs(iph->id));
		printf("\tFragment Offset: %d\n", ntohs(iph->frag_off)); 
		printf("\tTime to Live:    %d\n", iph->ttl);
		printf("\tChecksum:        %d\n", ntohs(iph->check));
	
		/* packet ipκ ǳʶ  tcp header  ȴ.                            */
		if(iph->protocol == IPPROTO_TCP) {
		        tcph = (struct tcphdr *) (p + iph->ihl * 4);
		        // tcp data 
		        tcpdata = (unsigned char *) (p + (iph->ihl*4) + (tcph->doff * 4));
	                        printf("\n\n    ===================   TCP HEADER   ===================\n");
	       	        printf("\tSource Port:              %d\n", ntohs(tcph->source));
		        printf("\tDestination Port:         %d\n", ntohs(tcph->dest));
		        printf("\tSequence Number:          %d\n", ntohl(tcph->seq));
		        printf("\tAcknowledgement Number:   %d\n", ntohl(tcph->ack_seq));
		        printf("\tData Offset:              %d\n", tcph->doff);
		        printf("\tWindow:                   %d\n", ntohs(tcph->window));
		        printf("\tURG:%d ACK:%d PSH:%d RST:%d SYN:%d FIN:%d\n", 
			tcph->urg, tcph->ack, tcph->psh, tcph->rst, 
			tcph->syn, tcph->fin, ntohs(tcph->check), 
			ntohs(tcph->urg_ptr));
		        printf("\n    ===================   TCP DATA(HEXA)  =================\n\t"); 
		        chcnt = 0;
		        for(temp = (iph->ihl * 4) + (tcph->doff * 4); temp <= ntohs(iph->tot_len) - 1; temp++) {
	   		    printf("%02x ", *(tcpdata++));
			    if( (++chcnt % 16) == 0 ) printf("\n\t");
		        }
		        if (pflag) {
			   printf("\n    ===================   TCP DATA(CHAR)  =================\n"); 
		                   tcpdata = (unsigned char *) ((p + iph->ihl*4) + (tcph->doff*4));
			   for(temp = (iph->ihl * 4) + (tcph->doff * 4); temp <= ntohs(iph->tot_len) - 1; temp++)
	   		        printf("%c", *(tcpdata++));
	                        }
		        printf("\n\t\t<<<<< End of Data >>>>>\n");
	        	}
		else if(iph->protocol == IPPROTO_UDP) {
	    	    udph = (struct udphdr *) (p + iph->ihl * 4);
		    udpdata = (unsigned char *) (p + iph->ihl*4) + 8;
		    printf("\n    ==================== UDP HEADER =====================\n");
		    printf("\tSource Port :      %d\n",ntohs(udph->source));
		    printf("\tDestination Port : %d\n", ntohs(udph->dest));
		    printf("\tLength :           %d\n", ntohs(udph->len));
	   	    printf("\tChecksum :         %x\n", ntohs(udph->check));
	            	    printf("\n    ===================  UDP DATA(HEXA)  ================\n\t");	 
		    chcnt = 0;
		    for(temp = (iph->ihl*4)+8; temp<=ntohs(iph->tot_len) -1; temp++) {
		       printf("%02x ", *(udpdata++));
		       if( (++chcnt % 16) == 0) printf("\n\t"); 
		    }

		    udpdata = (unsigned char *) (p + iph->ihl*4) + 8;
		    if(pflag) {
		        printf("\n===================  UDP DATA(CHAR)  ================\n");	 
		        for(temp = (iph->ihl*4)+8; temp<=ntohs(iph->tot_len) -1; temp++) 
		            printf("%c", *(udpdata++));
		    }
		    
		    printf("\n\t\t<<<<< End of Data >>>>>\n");
		}	  
		else if(iph->protocol == IPPROTO_ICMP) {
		        icmph = (struct icmp *) (p + iph->ihl * 4);
		        icmpdata = (unsigned char *) (p + iph->ihl*4) + 8;
	                        printf("\n\n    ===================   ICMP HEADER   ===================\n");
	       	        printf("\tType :                    %d\n", icmph->icmp_type);
		        printf("\tCode :                    %d\n", icmph->icmp_code);
		        printf("\tChecksum :                %02x\n", icmph->icmp_cksum);
		        printf("\tID :                      %d\n", icmph->icmp_id);
		        printf("\tSeq :                     %d\n", icmph->icmp_seq);
		        printf("\n    ===================   ICMP DATA(HEXA)  =================\n\t"); 
		        chcnt = 0;
		        for(temp = (iph->ihl * 4) + 8; temp <= ntohs(iph->tot_len) - 1; temp++) {
	   	            printf("%02x ", *(icmpdata++));
		            if( (++chcnt % 16) == 0 ) printf("\n\t");
		        }
		        printf("\n\t\t<<<<< End of Data >>>>>\n");
	              }
	    }	
	}
}

void sig_int(int sig)
{
    printf("Bye!!\n");
    pcap_close(pd);
    close(sockfd);
    exit(0);
}

void usage(void)
{
    fprintf(stdout," Usage : pa filter_rule [-pch]\n");
    fprintf(stdout,"         -p  :  Ÿ ڷ Ѵ.\n");
    fprintf(stdout,"         -c  :  ־ ڸŭ Ŷ Ѵ\n");
    fprintf(stdout,"	  -e  :  datalink layer Ѵ.\n");
    fprintf(stdout,"	  -e  :   Ŷ  ´.\n");
    fprintf(stdout,"         -h  :  \n");
}

int main(int argc, char *argv[])
{
	struct	bpf_program fcode;
	pcap_handler printer;
	char	ebuf[PCAP_ERRBUF_SIZE];
	int	c, i, snaplen = 512, size, packetcnt;
	bpf_u_int32 myself, localnet, netmask;
	unsigned char	*pcap_userdata;
		
	filter_rule = argv[1];		// ex) src host xxx.xxx.xxx.xxx and tcp port 80
	
	signal(SIGINT,sig_int);	// signal hanlder  
	
	opterr = 0;
	
	if(argc-1 < 1) {		// option check
	    usage(); 
	    exit(1);
	}
	
	while( (c = getopt(argc, argv,"i:c:pher")) != -1) {
	    switch(c) {
	    	case 'i'  :			// Ŷ ĸ   
	    	        device = optarg	
	    	        break;
	    	case 'p' : 		// ͸ ڷ ϴ ɼ
		        pflag = 1; 
		        break;
	    	case 'c' : 		// Ϸ Ŷ 
		        cflag = 1; 
		        packetcnt = atoi(optarg);
		        if(packetcnt <= 0) {
			fprintf(stderr,"invalid pacet number %s",optarg);
			exit(1);
		        }
		        break;
		case 'e' :      		// ͸ũ  
		        eflag = 1;
		        break;		
		case 'r' :      		//  Ŷ ξ 16  ´.
		        rflag = 1;
		        break;		
	    	case 'h' :			// 
		        usage();
		        exit(1);
	    }
	}	    
	
	if (device == NULL ) {
	    if ( (device = pcap_lookupdev(ebuf) ) == NULL) {
	        perror(ebuf);           
   	        exit(-1);
   	    }
   	}
   	fprintf(stdout, "device = %s\n", device);
	
	pd = pcap_open_live(device, snaplen, PROMISCUOUS, 1000, ebuf);
	if(pd == NULL) {
   	    perror(ebuf);          
   	    exit(-1);
   	}
	
	i = pcap_snapshot(pd);
	if(snaplen < i) {
   	    perror(ebuf);                            
  	    exit(-1);
   	}
	
	if(pcap_lookupnet(device, &localnet, &netmask, ebuf) < 0) {
   	    perror(ebuf);
   	    exit(-1);
   	}
	
	setuid(getuid());
	
	if(pcap_compile(pd, &fcode, filter_rule, 0, netmask) < 0) {
   	    perror(ebuf);
   	    exit(-1);
   	}
	
	if(pcap_setfilter(pd, &fcode) < 0) {
   	    perror(ebuf);
   	    exit(-1);
   	}
	
	fflush(stderr);
	
	printer = lookup_printer(pcap_datalink(pd));
	pcap_userdata = 0;
	
	if(pcap_loop(pd, packetcnt, printer, pcap_userdata) < 0) {
   	    perror("pcap_loop error");
   	    exit(-1);
   	}
	
	pcap_close(pd);
	exit(0);
}


##################################################################################

   Ȩ ÷ ֽϴ.
 κ̳ 輱   ҽ ļ   ƿƼ   
   . ׷ 츮  Ű   ִ  
 α׷ ϴ  ...^^

 ҽ ؼ ϱ ؼ pcap library ־ ϸ 
Ƹ   /usr/lib/libpcap.a ȭϷ  Դϴ.
Ʒ  ũ Ͻø ˴ϴ.
Ͻ bpf.h ٴ ޼   /usr/include/pcap/net/bpf.h  
/usr/include/net/bpf.h 縦 ֽø ˴ϴ.

#cp /usr/include/pcap/net/bpf.h /usr/include/net
#gcc -g -o noh_pa noh_pa.c -lpcap
#./noh_pa "src host xxx.xxx.xxx.xxx and tcp port 80" -i eth0 -e -p

׸ tcp/ip õ  䱸Ǵ ҽ̹Ƿ å  ø鼭 α׷
Ͻô  Ͻ Դϴ.

⼭ ܼ Ŷ Ƽ ִ  ġ    ø
Ŷ   ٸ ȣƮ   ֽϴ.
pcap_library ҽ ļ    ְ raw socket ̿  
ֽϴ. 
raw socket ̿ϴ ǥ δ ping α׷   ֽϴ.
unp ø ҽ  ִµ ̸  мϽø icmp ƴ϶ ip,tcp,udp
Ŷ     ֽϴ.
 ȭϵ 캸  ݺ  ü ִµ ̸
ϸ ˴ϴ.  ҽ include κ ȭϵԴϴ. 
 ٸ ݵ Ŀ °   شٸ ...

 Ȩ ø icmp ̵ Ŷ   Ͽ ش ȣƮ   
ҽ ֽϴ. ٶϴ.

Ұ  ҽ  α׷  Ϸ е鿡 ̳  
Ǿ ϴ ٷԴϴ.