½ÇÁ¦ libpcapÀ» ÀÌ¿ëÇÏ´Â ¸¹Àº ÀÀ¿ëÀÌ ÀÖ½À´Ï´Ù. À§¿¡¼ ¾ð±ÞÇÑ tcpdump°¡ ±× ´ëÇ¥ÀûÀÎ ¿¹À̸ç, ÀÌ°Í ¿Ü¿¡ ¸¹Àº ³×Æ®¿öÅ© ¸ð´ÏÅ͸µ Åø, °ø°³ ³×Æ®¿öÅ© IDS(Intrusion Detection System) ÀÎ Snort, ÆÐŶÀ» ĸÃÄÇÏ´Â ¸¹Àº ÀÀ¿ëµéÀÌ libpcapÀ» ÀÌ¿ëÇÏ¿© ´Ù¾çÇÑ OS¿¡ Æ÷ÆÃµÇ¾î ÀÖ½À´Ï´Ù. www.tcpdump.org/related.html¿¡ °¡¸é ÀÀ¿ëÀÇ ¿¹µéÀ» º¼ ¼ö ÀÖ½À´Ï´Ù.
±×·³ libpcapÀ» ÀÌ¿ëÇÑ °£´ÜÇÑ ¿¹¸¦ º¸À̰ڽÀ´Ï´Ù. ¾Æ·¡ ¼Ò½º´Â ip±â¹Ý tcp, udp, icmpÀÇ ÆÐŶÀ» Àâ¾Æ¼ °¢ ÇÁ·ÎÅäÄÝ Çʵ庰·Î ÇÁ¸°Æ®ÇØÁÖ´Â ¼Ò½ºÀÔ´Ï´Ù.
¸ÕÀú IP, TCP, UDPÀÇ °¢ HEADER FORMATÀ» ÂüÁ¶ÇϽñ⠹ٶø´Ï´Ù.
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Internet Datagram Header <RFC791> |
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ TCP Header Format <RFC793> |
0 7 8 15 16 23 24 31 +--------+--------+--------+--------+ | Source | Destination | | Port | Port | +--------+--------+--------+--------+ | | | | Length | Checksum | +--------+--------+--------+--------+ | | data octets ... +---------------- ... User Datagram Header Format <RFC768> |
#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; int rflag; int eflag; 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, temp_char; register unsigned int i; chcnt = 0; if(rflag) { while(length--) { printf("%02x ", *(p++)); if( (++chcnt % 16) == 0 ) printf("\n"); } 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"); // Ethernet 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"); } printf("%02x",*p++); }*/ } else { if(eflag) { printf("\n\n=================== Datalink layer ===================\n"); for(j=0; j<ETH_ALEN; j++) { printf("%X", ep->ether_shost[j]); if(j != 5) printf(":"); } printf(" ------> "); for(j=0; j<ETH_ALEN; j++){ printf("%X", ep->ether_dhost[j]); if(j != 5) printf(":"); } printf("\nether_type -> %x\n", ntohs(ep->ether_type)); } iph = (struct iphdr *) p; i = 0; if (ntohs(ep->ether_type) == ETHERTYPE_IP) { // ip ÆÐŶÀΰ¡? printf("\n\n=================== IP HEADER ===================\n"); printf("%s -----> ", inet_ntoa(iph->saddr)); printf("%s\n", inet_ntoa(iph->daddr)); printf("Version: %d\n", iph->version); printf("Herder Length: %d\n", iph->ihl); printf("Service: %#x\n",iph->tos); printf("Total Length: %d\n", ntohs(iph->tot_len)); printf("Identification : %d\n", ntohs(iph->id)); printf("Fragment Offset: %d\n", ntohs(iph->frag_off)); printf("Time to Live: %d\n", iph->ttl); printf("Checksum: %d\n", ntohs(iph->check)); 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("Source Port: %d\n", ntohs(tcph->source)); printf("Destination Port: %d\n", ntohs(tcph->dest)); printf("Sequence Number: %d\n", ntohl(tcph->seq)); printf("Acknowledgement Number: %d\n", ntohl(tcph->ack_seq)); printf("Data Offset: %d\n", tcph->doff); printf("Window: %d\n", ntohs(tcph->window)); printf("URG:%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(HEX) =================\n"); 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"); } if (pflag) { tcpdata = (unsigned char *) (p + (iph->ihl*4) + (tcph->doff * 4)); printf("\n=================== TCP DATA(CHAR) =================\n"); for(temp = (iph->ihl * 4) + (tcph->doff * 4); temp <= ntohs(iph->tot_len) - 1; temp++) { temp_char = *tcpdata; if ( (temp_char == 0x0d) && ( *(tcpdata+1) == 0x0a ) ) { fprintf(stdout,"\n"); tcpdata += 2; temp++; continue; } temp_char = ( ( temp_char >= ' ' ) && ( temp_char < 0x7f ) )? temp_char : '.'; printf("%c", temp_char); tcpdata++; } } printf("\n>>>>> 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("Source Port : %d\n",ntohs(udph->source)); printf("Destination Port : %d\n", ntohs(udph->dest)); printf("Length : %d\n", ntohs(udph->len)); printf("Checksum : %x\n", ntohs(udph->check)); printf("\n=================== UDP DATA(HEX) ================\n"); chcnt = 0; for(temp = (iph->ihl*4)+8; temp<=ntohs(iph->tot_len) -1; temp++) { printf("%02x ", *(udpdata++)); if( (++chcnt % 16) == 0) printf("\n"); } 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++) { temp_char = *udpdata; if ( (temp_char == 0x0d) && ( *(udpdata+1) == 0x0a ) ) { fprintf(stdout,"\n"); udpdata += 2; temp++; continue; } temp_char = ( ( temp_char >= ' ' ) && ( temp_char < 0x7f ) )? temp_char : '.'; printf("%c", temp_char); udpdata++; } } printf("\n>>>>> 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("Type : %d\n", icmph->icmp_type); printf("Code : %d\n", icmph->icmp_code); printf("Checksum : %02x\n", icmph->icmp_cksum); printf("ID : %d\n", icmph->icmp_id); printf("Seq : %d\n", icmph->icmp_seq); printf("\n=================== ICMP DATA(HEX) =================\n"); chcnt = 0; for(temp = (iph->ihl * 4) + 8; temp <= ntohs(iph->tot_len) - 1; temp++) { printf("%02x ", *(icmpdata++)); if( (++chcnt % 16) == 0 ) printf("\n"); } printf("\n>>>>> 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 : noh_pa filter_rule [-pch]\n"); fprintf(stdout," -p : µ¥ÀÌŸ¸¦ ¹®ÀÚ·Î Ãâ·ÂÇÑ´Ù.\n"); fprintf(stdout," -c : ÁÖ¾îÁø ¼ýÀÚ¸¸ÅÀÇ ÆÐŶ¸¸ ´ýÇÁÇÑ´Ù\n"); fprintf(stdout," -e : datalink layer¸¦ Ãâ·ÂÇÑ´Ù.\n"); fprintf(stdout," -r : ÀâÀº ÆÐŶÀ» »ýÀ¸·Î Âï´Â´Ù.\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 = 1514, size, packetcnt; bpf_u_int32 myself, localnet, netmask; unsigned char *pcap_userdata; filter_rule = argv[1]; /* example : "src host xxx.xxx.xxx.xxx and tcp port 80" */ signal(SIGINT,sig_int); opterr = 0; if(argc-1 < 1) { 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 number %s",optarg); exit(1); } break; case 'e' : eflag = 1; break; case 'r' : 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); } |