2013년 10월 3일 목요일

[Libpcap] Libpcap 정리


#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h> // for TCP protocol in transport layer
#include <arpa/inet.h> // include for inet_ntoa()

#include <netinet/in.h> // defined TCP Procotol Type information
                           /* TCP 및 IP Protocol 에 관련된 정보 포함.
                              대표적으로 well-known port number 및 IP 체계 */

#include <pcap.h> // pcap func used errbuf[], errbuf size = 256
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>

#define PCAP_CNT_MAX 1
#define PCAP_SNAPSHOT 1024
#define PCAP_TIMEOUT 100
#define FILTER_RULE "host 192.168.100.100" // Filtering taget IP and Port Number

void packet_view(unsigned char* user, const struct pcap_pkthdr *h, const unsigned char *p);

int main(int argc, char* argv[]) {
char* dev;
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 net;
bpf_u_int32 mask;                         // struct in_addr은 <netinet/in.h>에 정의.
struct in_addr net_addr, mask_addr;
pcap_t *pd;                                 // struct bpf_program은 <pcap-bpf.h>에 정의.
struct bpf_program fcode;
/* struct bpf_program {
u_int bf_len;
struct bpf_insn *bf_insns;
 } */

/* pcap_lookupdev is find network interface. if finding network interface, it return that found network interface name.
    pcap_lookupdev : fail => return null / success => char* pointer (NIC name) */

if(!(dev = pcap_lookupdev(errbuf))) {
perror(errbuf);
exit(1);
}

if(pcap_lookupnet(dev, &net, &mask, errbuf) < 0) {
perror(errbuf);
exit(1);
}

/* pcap_lookupnet이 반환하는 net, mask 값은 network address, 즉 정수형으로 이루어져있기에 이 값을 숫자 사이에 점을 찍는 IP주소표시법으로 구성된 ASCII 문자열을 가리키는 문자열 포인터를 리턴하는 inet_ntoa()를 이용하여 일반적인 IP주소 형태로 바꾸어 출력함. */

net_addr.s_addr = net;
mask_addr.s_addr = mask;

printf("Device : %s\n", dev);
printf("Net Address : %s\n", inet_ntoa(net_addr)); // 네트워크 주소(정수형) => ASCII (우리가 알고있는 IP주소)
printf("Netmask : %s\n", inet_ntoa(mask_addr));

// pcap_open_live (NIC, capture MAX byte, timeout, errbuf)).
   pcap_open_live is open packet capture interface and that pointer return */

if((pd = pcap_open_live(dev, PCAP_SNAPSHOT, 1, PCAP_TIMEOUT, errbuf)) == NULL) {
perror(errbuf);
exit(1);
}

if(pcap_compile(pd, &fcode, FILTER_RULE, 0, mask) < 0) {
perror(pcap_geterr(pd));
exit(1);
}

if(pcap_setfilter(pd, &fcode) < 0) {
perror(pcap_geterr(pd));
exit(1);
}

// packet read 관련 API에서는 패킷을 읽었을때, Demultiplexing이 되지 않은 완전한 구조의 패킷을 넘겨줌
if(pcap_loop(pd, PCAP_CNT_MAX, packet_view, 0) < 0) {
perror(pcap_geterr(pd));
exit(1);
}
pcap_close(pd);
return 0;

}

void packet_view(unsigned char* user, const struct pcap_pkthdr *h, const unsigned char *p) {
struct ip *iph;
struct tcphdr *tcph;
struct udphdr *udph;
struct ether_header *etherh;
unsigned short e_type;
int cnt;

/* ethernet header와 IP header의 경우 demultiplexing 과정을 거치기 위해 상위 layer의 protocol type을 지정함. ethernet header의 경우 ether_type, IP header는 ip_p가 각 상위 layer의 protocol type을 알려주기 위해 사용됨. 해당 내용은 OSI 7계층의 encapsulation 참조 */

etherh = (struct ether_header *)p;
e_type = ntohs(etherh->ether_type);

printf("-----------------------------------------  \n");
printf("[[ Layer 2 :: Ethernet Header ]]\n");
        // out Ehternet Header information
printf("[ Destination hardware address :: %02x", etherh->ether_dhost[0]);

for(cnt = 1; cnt < ETHER_ADDR_LEN; cnt++)
printf(":%02x", etherh->ether_dhost[cnt]);

printf("]\n[ Source hardware address      :: %02x", etherh->ether_shost[0]);

for(cnt = 1; cnt < ETHER_ADDR_LEN; cnt++)
printf(":%02x", etherh->ether_shost[cnt]);
printf("]\n[ Type :: %x ]\n", etherh->ether_type);

printf("\t-----------------------------------------  \n");
p += sizeof(struct ether_header);

// IP, ARP, RARP Header analyze
if (e_type == ETHERTYPE_IP) {

iph = (struct ip *)p;

printf("\t[IP Packet!]\n");
printf("\t-----------------------------------------  \n");
printf("\t[ IP version                :: %d ]\n", iph->ip_v);
printf("\t[ Header Length             :: %d ]\n", iph->ip_hl);
printf("\t[ Type of Service           :: %d ]\n", iph->ip_tos);
printf("\t[ Total Length              :: %d ]\n", iph->ip_len);
printf("\t[ Identification            :: %d ]\n", iph->ip_id);
printf("\t[ Flags  ================== ::  ]\n");

if ((iph->ip_off) == IP_RF)
printf("\t[      || Reserved flagment :: 0x%x ]\n", IP_RF);
else if((iph->ip_off) == IP_DF)
printf("\t[      || Don't  flagment   :: 0x%x ]\n", IP_DF);

else if((iph->ip_off) == IP_MF)
printf("\t[      || More flagment     :: 0x%x ]\n", IP_MF);

else
printf("\t[      || Not support               ]\n");

printf("\t[        ========================== ]\n");
printf("\t[ Fragment Offset           :: %d ]\n", iph->ip_off);
printf("\t[           TTL             :: %d ]\n", iph->ip_ttl);
printf("\t[         Protocol          :: %d ]\n", iph->ip_p);
printf("\t[ Header Checksum           :: %d ]\n", iph->ip_sum);
printf("\t[ Source      IP address    :: %s ]\n", inet_ntoa(iph->ip_src));
printf("\t[ Destination IP address    :: %s ]\n", inet_ntoa(iph->ip_dst));
printf("\t-----------------------------------------  \n");

/* TCP Header analyze.
   Transport layer의 type을 알려주는 ip_p는 <netinet/ip.h>, IPPTORO_TCP의 내용은 <netinet/in.h> 참조. */
if (iph->ip_p == IPPROTO_TCP) {

tcph = (struct tcphdr *)(p + iph->ip_hl *4) ;

printf("\t\t[ TCP Packet!]\n");
printf("\t\t-----------------------------------------  \n");
printf("\t\t[ Source      Port :: %d ]\n", ntohs(tcph->source));
printf("\t\t[ Destination Port :: %d ]\n", ntohs(tcph->dest));
}

else if (iph->ip_p == IPPROTO_UDP) {

udph = (struct udphdr *)(p + iph->ip_hl *4) ;

printf("\t\t[ UDP Packet!]\n");
printf("\t\t-----------------------------------------  \n");
printf("\t\t[ Source      Port :: %d ]\n", ntohs(udph->source));
printf("\t\t[ Destination Port :: %d ]\n", ntohs(udph->dest));
}
}

else if(e_type == ETHERTYPE_ARP) {
printf("ARP!!!\n");
}

else if(e_type == ETHERTYPE_REVARP) {
printf("RARP!!!\n");
}

else {
printf("Not Captured packet!\n");
}

}

spring에서 mariadb로 연동후 웹에서 접근시 jdbc 오류가 발생할때

* 본문은 [코드로 배우는 스프링 웹 프로젝트, 구멍가게 코딩단 지음] 도서를 공부하면서 정리한 글임을 밝힙니다.