[C/C++] 패킷 캡처

Alexandria·2024년 3월 4일
0

C lang

목록 보기
9/14
post-thumbnail

1. 환경

1.1. libpcap

libpcap-dev를 설치한다.

$ sudo apt -y install libpcap-dev

컴파일 시 libpcap.so을 링킹하여 컴파일한다.

1.2. libtins

libtins-dev를 설치한다.

$ sudo apt -y install libtins-dev

컴파일 시 libtins.so을 링킹하여 컴파일한다.

2. 네트워크 어댑터

2.1. libpcap

네트워크 인터페이스들을 얻고 사용을 다하면 해제해주자.

#include <pcap.h>

int main(void) {
    char errbuf[PCAP_ERRBUF_SIZE] = {"\0"};
    pcap_if_t *alldevs, *d;

    if (pcap_findalldevs(&alldevs, errbuf) == PCAP_ERROR) {
        printf("pcap_findalldevs error : %s\n", errbuf);
        return PCAP_ERROR;
    }
    ...
    pcap_freealldevs(alldevs);
    return 0;
}

반복문을 통해 인터페이스에 접근할 수 있다.

#include <pcap.h>

int main(void) {
    ...

    for (d = alldevs; d; d = d->next) {
        printf("%s\t: %s\n", d->name, d->description);
    }
    ...
}

인터페이스에 할당된 IP 주소를 확인해보자.

#include <pcap.h>

int main(void) {
    ...
    for (d = alldevs; d; d = d->next) {
        for (struct pcap_addr *p = d->addresses; p; p = p->next) {
            if (p->addr->sa_family == AF_INET) {
                printf("%s\t: %s\n", d->name, d->description);
                printf(" - IP Address  : %s\n", inet_ntoa(((struct sockaddr_in *)p->addr)->sin_addr));
            }
        }
    }
    ...
}

인터페이스에 할당된 MAC 주소를 확인해보자.

#include <pcap.h>

int main(void) {
    ...
    for (d = alldevs; d; d = d->next) {
        for (struct pcap_addr *p = d->addresses; p; p = p->next) {
            if (p->addr->sa_family == AF_INET) {
                ...
                int sock = socket(AF_INET, SOCK_DGRAM, 0);
                if (sock == INVALID_SOCKET) break;

                struct ifreq ifr;
                ifr.ifr_ifru.ifru_addr.sa_family = p->addr->sa_family;
                strncpy(ifr.ifr_ifrn.ifrn_name, d->name, strlen(d->name));
                if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) printf(" - MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned char)ifr.ifr_ifru.ifru_hwaddr.sa_data[0], (unsigned char)ifr.ifr_ifru.ifru_hwaddr.sa_data[1], (unsigned char)ifr.ifr_ifru.ifru_hwaddr.sa_data[2], (unsigned char)ifr.ifr_ifru.ifru_hwaddr.sa_data[3], (unsigned char)ifr.ifr_ifru.ifru_hwaddr.sa_data[4], (unsigned char)ifr.ifr_ifru.ifru_hwaddr.sa_data[5]);
            }
        }
    }
    ...
}

네트워크 주소와 서브넷 마스크를 확인해보자.

#include <pcap.h>

int main(void) {
    ...
    for (d = alldevs; d; d = d->next) {
        for (struct pcap_addr *p = d->addresses; p; p = p->next) {
            if (p->addr->sa_family == AF_INET) {
                ...
                bpf_u_int32 net, mask;
                if (pcap_lookupnet(d->name, &net, &mask, errbuf) == PCAP_ERROR) {
                    printf("Couldn't get network/netmask address for device %s: %s\n", d->name, errbuf);
                    return PCAP_ERROR;
                }
                struct in_addr ip_addr;
                ip_addr.s_addr = net;
                printf(" - Network     : %s\n", inet_ntoa(ip_addr));
                ip_addr.s_addr = mask;
                printf(" - Subnet mask : %s\n", inet_ntoa(ip_addr));
            }
        }
    }
    ...
}

2.2. libtins

네트워크 인터페이스 정보를 얻은 후 반복문을 통해 정보를 출력해보자.

#include <tins/tins.h>
#include <iostream>

int main(void) {
    std::vector<Tins::NetworkInterface> NetworkInterfaceVector(Tins::NetworkInterface::all());
    for(int i = 0; i < NetworkInterfaceVector.size(); ++i) std::cout << i << ' ' << NetworkInterfaceVector[i].name() << '\t' << NetworkInterfaceVector[i].ipv4_address() << '\t' << NetworkInterfaceVector[i].hw_address() << std::endl;
    return 0;
}

3. 패킷 캡처

3.1. libpcap

자신에게 오는 패킷(Promiscuous mode가 0)만 캡처해보자.

#include <pcap.h>

#define PROMISCUOUS 0

void capture(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet) {
    printf("Packet Captured!!\n");
}

int main(void) {
    char errbuf[PCAP_ERRBUF_SIZE] = {"\0"};
    const char *interface = "ens33";
    
    pcap_t *pcd = pcap_open_live(interface, BUFSIZ, PROMISCUOUS, 1000, errbuf);
    if (pcd == NULL) {
        printf("Couldn't open device %s: %s\n", interface, errbuf);
        return PCAP_ERROR;
    }

    pcap_loop(pcd, 0, capture, NULL);
    return 0;
}

원하는 패킷만 캡처하기 위해 필터링을 적용해보자.

#include <pcap.h>

#define PROMISCUOUS 0

void capture(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet) {
    printf("Packet Captured!!\n");
}

int main(void) {
    char errbuf[PCAP_ERRBUF_SIZE] = {"\0"};
    const char *interface = "ens33";
    
    pcap_t *pcd = pcap_open_live(interface, BUFSIZ, PROMISCUOUS, 1000, errbuf);
    if (pcd == NULL) {
        printf("Couldn't open device %s: %s\n", interface, errbuf);
        return PCAP_ERROR;
    }

    bpf_u_int32 net, mask;
    if (pcap_lookupnet(interface, &net, &mask, errbuf) == PCAP_ERROR) {
        printf("Couldn't get network/netmask address for device %s: %s\n", interface, errbuf);
        return PCAP_ERROR;
    }

    struct bpf_program filter_code;
    const char *filter = "tcp port 80";

    if (pcap_compile(pcd, &filter_code, filter, 0, net) == PCAP_ERROR) {
        printf("Couldn't parse filter %s: %s\n", filter, pcap_geterr(pcd));
        return -1;
    }
    if (pcap_setfilter(pcd, &filter_code) == PCAP_ERROR) {
        printf("Couldn't install filter %s: %s\n", filter, pcap_geterr(pcd));
        return -1;
    }

    pcap_loop(pcd, 0, capture, NULL);
    return 0;
}

3.2. libtins

자신에게 오는 패킷(Promiscuous mode가 false)만 캡처해보자.

#include <tins/tins.h>
#include <iostream>

#define PROMISCUOUS false

bool capture(Tins::PDU &Packet) {
    printf("Packet Captured!!\n");
    return true;
}

int main(void) {
    Tins::SnifferConfiguration config;
    config.set_immediate_mode(true);
    config.set_promisc_mode(false);

    Tins::Sniffer sniffer("ens33", config);
    sniffer.sniff_loop(capture);
    return 0;
}

원하는 패킷만 캡처하기 위해 필터링을 적용해보자.

#include <tins/tins.h>
#include <iostream>

#define PROMISCUOUS false

bool capture(Tins::PDU &Packet) {
    printf("Packet Captured!!\n");
    return true;
}

int main(void) {
    Tins::SnifferConfiguration config;
    config.set_immediate_mode(true);
    config.set_promisc_mode(false);
    config.set_filter("port 80 and src 192.168.0.30");

    Tins::Sniffer sniffer("ens33", config);
    sniffer.sniff_loop(capture);
    return 0;
}

4. 패킷 분석

4.1. libpcap

ETHERNET 헤더는 14byte로 구성되어 있다.

TypeByte
Destination MAC Address6
Source MAC Address6
Type2
struct ethhdr *ethernet_header = (struct ethhdr *)packet;
printf("Ethernet Header (%d)\n", 14);
printf("   |-Destination Address\t: %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", ethernet_header->h_dest[0] , ethernet_header->h_dest[1] , ethernet_header->h_dest[2] , ethernet_header->h_dest[3] , ethernet_header->h_dest[4] , ethernet_header->h_dest[5] );
printf("   |-Source Address\t\t: %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", ethernet_header->h_source[0] , ethernet_header->h_source[1] , ethernet_header->h_source[2] , ethernet_header->h_source[3] , ethernet_header->h_source[4] , ethernet_header->h_source[5] );
printf("   |-Protocol\t\t\t: %u \n",(unsigned short)ethernet_header->h_proto);

IP 헤더는 20byte로 구성되어 있다.

TypeByte
Version0.5
Header Length0.5
Type Of Service1
Total Length2
Identification2
Fragmentation Offset2 (Flags + Offset)
TTL1
Protocol1
Checksum2
Source IP Address4
Destination IP Address4
struct iphdr *ip_header = (struct iphdr *)(packet + ETHERNET_HEADER_LEN);
struct sockaddr_in source,dest;
memset(&source, 0, sizeof(source));
memset(&dest, 0, sizeof(dest));
source.sin_addr.s_addr  = ip_header->saddr;
dest.sin_addr.s_addr    = ip_header->daddr;

printf("IP Header (%d)\n", IP_HEADER_LEN);
printf("   |-IP Version\t\t\t: %d\n",(unsigned int)ip_header->version);
printf("   |-IP Header Length\t\t: %d bytes (%d)\n",((unsigned int)(ip_header->ihl))*4, (unsigned int)ip_header->ihl);
printf("   |-Type Of Service\t\t: %d\n",(unsigned int)ip_header->tos);
printf("   |-IP Total Length\t\t: %d  Bytes(Size of Packet)\n",ntohs(ip_header->tot_len));
printf("   |-Identification\t\t: %d\n",ntohs(ip_header->id));
printf("   |-TTL\t\t\t: %d\n",(unsigned int)ip_header->ttl);
printf("   |-Protocol\t\t\t: %d\n",ip_header->protocol);
printf("   |-Checksum\t\t\t: %d\n",ntohs(ip_header->check));
printf("   |-Source IP\t\t\t: %s\n" , inet_ntoa(source.sin_addr) );
printf("   |-Destination IP\t\t: %s\n" , inet_ntoa(dest.sin_addr) );

ICMP 헤더는 8byte로 구성되어 있다.

TypeByte
Type1
Code1
Checksum2
Identifier2
Sequence number2
struct iphdr *ip_header     = (struct iphdr *)(packet  + ETHERNET_HEADER_LEN);
struct icmphdr *icmp_header = (struct icmphdr *)(packet + IP_HEADER_LEN  + ETHERNET_HEADER_LEN);
int total_len               = (ntohs(ip_header->tot_len) + ETHERNET_HEADER_LEN);
int icmp_header_size        =  ETHERNET_HEADER_LEN + IP_HEADER_LEN + ICMP_HEADER_LEN;
int icmp_data_size          = total_len - icmp_header_size;
printf("\n\n***********************ICMP Packet (%d)*************************\n", total_len);
ethernet_parse(packet);
ip_parse(packet);
printf("ICMP Header (%d)\n", ICMP_HEADER_LEN);
printf("   |-Type\t\t\t: %d",(unsigned int)(icmp_header->type));
if((unsigned int)(icmp_header->type) == 11){printf("  (TTL Expired)\n");}
else if((unsigned int)(icmp_header->type) == ICMP_ECHOREPLY){printf("  (ICMP Echo Reply)\n");}
else printf("\n");
printf("   |-Code\t\t\t: %d\n",(unsigned int)(icmp_header->code));
printf("   |-Checksum\t\t\t: %d (%d)\n",ntohs(icmp_header->checksum), icmp_header->checksum);
printf("   |-Identifier (BE)\t\t: 0x%02X%02X\n", (packet + icmp_header_size)[-4], (packet + icmp_header_size)[-3]);
printf("   |-Identifier (LE)\t\t: 0x%02X%02X\n", (packet + icmp_header_size)[-3], (packet + icmp_header_size)[-4]);
printf("   |-Sequence number (BE)\t: 0x%02X%02X\n", (packet + icmp_header_size)[-2], (packet + icmp_header_size)[-1]);
printf("   |-Sequence number (LE)\t: 0x%02X%02X\n", (packet + icmp_header_size)[-1], (packet + icmp_header_size)[-2]);
printf("Data Payload (%d)\n", icmp_data_size);   
PrintData(packet + icmp_header_size , icmp_data_size );

TCP 헤더는 20byte와 Options로 구성되어 있다.

TypeByte
Source Port2
Destination Port2
Sequence Number4
Acknowledge Number4
Flag2 (Header Length + Flag)
Window2
Checksum2
Urgent Pointer2
Optionsn
struct tcphdr *tcp_header   =(struct tcphdr*)(packet + IP_HEADER_LEN + ETHERNET_HEADER_LEN);
struct iphdr *ip_header     = (struct iphdr *)(packet  + ETHERNET_HEADER_LEN);
int tcp_header_size         =  ETHERNET_HEADER_LEN + IP_HEADER_LEN + (unsigned int)tcp_header->doff*4;
int total_len               = (ntohs(ip_header->tot_len) + ETHERNET_HEADER_LEN);
int tcp_data_size           = total_len - tcp_header_size;
printf("\n\n***********************TCP Packet (%d)*************************\n", total_len); 
printf("TCP Header (%d)\n", (unsigned int)tcp_header->doff*4);
printf("   |-Source Port\t\t: %u\n",ntohs(tcp_header->source));
printf("   |-Destination Port\t\t: %u\n",ntohs(tcp_header->dest));
printf("   |-Sequence Number\t\t: %u\n",ntohl(tcp_header->seq));
printf("   |-Acknowledge Number\t\t: %u\n",ntohl(tcp_header->ack_seq));
printf("   |-Header Length\t\t: %d DWORDS or %d BYTES\n" ,(unsigned int)tcp_header->doff,(unsigned int)tcp_header->doff*4);
printf("   |-Urgent Flag\t\t: %d\n",(unsigned int)tcp_header->urg);
printf("   |-Acknowledgement Flag\t: %d\n",(unsigned int)tcp_header->ack);
printf("   |-Push Flag\t\t\t: %d\n",(unsigned int)tcp_header->psh);
printf("   |-Reset Flag\t\t\t: %d\n",(unsigned int)tcp_header->rst);
printf("   |-Synchronise Flag\t\t: %d\n",(unsigned int)tcp_header->syn);
printf("   |-Finish Flag\t\t: %d\n",(unsigned int)tcp_header->fin);
printf("   |-Window\t\t\t: %d\n",ntohs(tcp_header->window));
printf("   |-Checksum\t\t\t: %d\n",ntohs(tcp_header->check));
printf("   |-Urgent Pointer\t\t: %d\n",tcp_header->urg_ptr);
printf("Data Payload (%d)\n", tcp_data_size);   
PrintData(packet + tcp_header_size , tcp_data_size );

UDP 헤더는 8byte로 구성되어 있다.

TypeByte
Source Port2
Destination Port2
UDP Length2
UDP Checksum2
struct udphdr *udp_header   = (struct udphdr*)(packet + IP_HEADER_LEN  + ETHERNET_HEADER_LEN);
struct iphdr *ip_header     = (struct iphdr *)(packet  + ETHERNET_HEADER_LEN);
int udp_header_size         =  ETHERNET_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN;
int total_len               = (ntohs(ip_header->tot_len) + ETHERNET_HEADER_LEN);
int udp_data_size           = total_len - udp_header_size;
printf("\n\n***********************UDP Packet (%d)*************************\n", UDP_HEADER_LEN);
printf("UDP Header (%d)\n", UDP_HEADER_LEN);
printf("   |-Source Port\t\t: %d\n" , ntohs(udp_header->source));
printf("   |-Destination Port\t\t: %d\n" , ntohs(udp_header->dest));
printf("   |-UDP Length\t\t\t: %d\n" , ntohs(udp_header->len));
printf("   |-UDP Checksum\t\t: %d\n" , ntohs(udp_header->check));
printf("Data Payload (%d)\n", udp_data_size);   
PrintData(packet + udp_header_size , udp_data_size );

전체 코드는 다음과 같다.

#include <pcap.h>
#include <string.h>
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>

#define PROMISCUOUS 0

void PrintData (const u_char* data , int Size)
{
    int i , j;
    for(i=0 ; i < Size ; i++){
        if( i!=0 && i%16==0){
            printf("         ");
            for(j=i-16 ; j<i ; j++){
                if(data[j]>=32 && data[j]<=128) printf("%c",(unsigned char)data[j]); //if its a number or alphabet
                else printf("."); //otherwise print a dot
            }
            printf("\n");
        }
        if(i%16==0) printf("   ");
            printf(" %02X",(unsigned int)data[i]);
        if( i==Size-1){
            for(j=0;j<15-i%16;j++){printf("   ");}
            printf("         ");
            for(j=i-i%16 ; j<=i ; j++){
                if(data[j]>=32 && data[j]<=128) {printf("%c",(unsigned char)data[j]);}
                else{printf(".");}
            }
            printf("\n" );
        }
    }
}

void capture(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet) {
    int ETHERNET_HEADER_LEN = 14;
    int IP_HEADER_LEN       = 20;
    int ICMP_HEADER_LEN     = 8;
    int UDP_HEADER_LEN      = 8;
    struct ethhdr *ethernet_header = (struct ethhdr *)packet;
    printf("Ethernet Header (%d)\n", ETHERNET_HEADER_LEN);
    printf("   |-Destination Address\t: %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", ethernet_header->h_dest[0] , ethernet_header->h_dest[1] , ethernet_header->h_dest[2] , ethernet_header->h_dest[3] , ethernet_header->h_dest[4] , ethernet_header->h_dest[5] );
    printf("   |-Source Address\t\t: %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", ethernet_header->h_source[0] , ethernet_header->h_source[1] , ethernet_header->h_source[2] , ethernet_header->h_source[3] , ethernet_header->h_source[4] , ethernet_header->h_source[5] );
    printf("   |-Protocol\t\t\t: %u \n",(unsigned short)ethernet_header->h_proto);

    if ((unsigned short)ethernet_header->h_proto == 0x8)
    {
        struct iphdr *ip_header = (struct iphdr *)(packet + ETHERNET_HEADER_LEN);
        struct sockaddr_in source,dest;
        memset(&source, 0, sizeof(source));
        memset(&dest, 0, sizeof(dest));
        source.sin_addr.s_addr = ip_header->saddr;
        dest.sin_addr.s_addr = ip_header->daddr;

        printf("IP Header (%d)\n", IP_HEADER_LEN);
        printf("   |-IP Version\t\t\t: %d\n",(unsigned int)ip_header->version);
        printf("   |-IP Header Length\t\t: %d bytes (%d)\n",((unsigned int)(ip_header->ihl))*4, (unsigned int)ip_header->ihl);
        printf("   |-Type Of Service\t\t: %d\n",(unsigned int)ip_header->tos);
        printf("   |-IP Total Length\t\t: %d  Bytes(Size of Packet)\n",ntohs(ip_header->tot_len));
        printf("   |-Identification\t\t: %d\n",ntohs(ip_header->id));
        printf("   |-TTL\t\t\t: %d\n",(unsigned int)ip_header->ttl);
        printf("   |-Protocol\t\t\t: %d\n",ip_header->protocol);
        printf("   |-Checksum\t\t\t: %d\n",ntohs(ip_header->check));
        printf("   |-Source IP\t\t\t: %s\n" , inet_ntoa(source.sin_addr) );
        printf("   |-Destination IP\t\t: %s\n" , inet_ntoa(dest.sin_addr) );

        switch (((struct iphdr*)(packet + sizeof(struct ethhdr)))->protocol) {
            case IPPROTO_ICMP: //1
            {
                struct iphdr *ip_header     = (struct iphdr *)(packet  + ETHERNET_HEADER_LEN);
                struct icmphdr *icmp_header = (struct icmphdr *)(packet + IP_HEADER_LEN  + ETHERNET_HEADER_LEN);
                int total_len               = (ntohs(ip_header->tot_len) + ETHERNET_HEADER_LEN);
                int icmp_header_size        = ETHERNET_HEADER_LEN + IP_HEADER_LEN + ICMP_HEADER_LEN;
                int icmp_data_size          = total_len - icmp_header_size;
                printf("\n\n***********************ICMP Packet (%d)*************************\n", total_len);
                printf("ICMP Header (%d)\n", ICMP_HEADER_LEN);
                printf("   |-Type\t\t\t: %d",(unsigned int)(icmp_header->type));
                if((unsigned int)(icmp_header->type) == 11){printf("  (TTL Expired)\n");}
                else if((unsigned int)(icmp_header->type) == ICMP_ECHOREPLY){printf("  (ICMP Echo Reply)\n");}
                else printf("\n");
                printf("   |-Code\t\t\t: %d\n",(unsigned int)(icmp_header->code));
                printf("   |-Checksum\t\t\t: %d (%d)\n",ntohs(icmp_header->checksum), icmp_header->checksum);
                printf("   |-Identifier (BE)\t\t: 0x%02X%02X\n", (packet + icmp_header_size)[-4], (packet + icmp_header_size)[-3]);
                printf("   |-Identifier (LE)\t\t: 0x%02X%02X\n", (packet + icmp_header_size)[-3], (packet + icmp_header_size)[-4]);
                printf("   |-Sequence number (BE)\t: 0x%02X%02X\n", (packet + icmp_header_size)[-2], (packet + icmp_header_size)[-1]);
                printf("   |-Sequence number (LE)\t: 0x%02X%02X\n", (packet + icmp_header_size)[-1], (packet + icmp_header_size)[-2]);
                printf("Data Payload (%d)\n", icmp_data_size);   
                PrintData(packet + icmp_header_size , icmp_data_size );
                break;
            }
            case IPPROTO_TCP: //6
            {
                struct tcphdr *tcp_header   =(struct tcphdr*)(packet + IP_HEADER_LEN + ETHERNET_HEADER_LEN);
                struct iphdr *ip_header     = (struct iphdr *)(packet  + ETHERNET_HEADER_LEN);
                int tcp_header_size         =  ETHERNET_HEADER_LEN + IP_HEADER_LEN + (unsigned int)tcp_header->doff*4;
                int total_len               = (ntohs(ip_header->tot_len) + ETHERNET_HEADER_LEN);
                int tcp_data_size           = total_len - tcp_header_size;
                printf("\n\n***********************TCP Packet (%d)*************************\n", total_len); 
                printf("TCP Header (%d)\n", (unsigned int)tcp_header->doff*4);
                printf("   |-Source Port\t\t: %u\n",ntohs(tcp_header->source));
                printf("   |-Destination Port\t\t: %u\n",ntohs(tcp_header->dest));
                printf("   |-Sequence Number\t\t: %u\n",ntohl(tcp_header->seq));
                printf("   |-Acknowledge Number\t\t: %u\n",ntohl(tcp_header->ack_seq));
                printf("   |-Header Length\t\t: %d DWORDS or %d BYTES\n" ,(unsigned int)tcp_header->doff,(unsigned int)tcp_header->doff*4);
                printf("   |-Urgent Flag\t\t: %d\n",(unsigned int)tcp_header->urg);
                printf("   |-Acknowledgement Flag\t: %d\n",(unsigned int)tcp_header->ack);
                printf("   |-Push Flag\t\t\t: %d\n",(unsigned int)tcp_header->psh);
                printf("   |-Reset Flag\t\t\t: %d\n",(unsigned int)tcp_header->rst);
                printf("   |-Synchronise Flag\t\t: %d\n",(unsigned int)tcp_header->syn);
                printf("   |-Finish Flag\t\t: %d\n",(unsigned int)tcp_header->fin);
                printf("   |-Window\t\t\t: %d\n",ntohs(tcp_header->window));
                printf("   |-Checksum\t\t\t: %d\n",ntohs(tcp_header->check));
                printf("   |-Urgent Pointer\t\t: %d\n",tcp_header->urg_ptr);
                printf("Data Payload (%d)\n", tcp_data_size);   
                PrintData(packet + tcp_header_size , tcp_data_size );
                break;
            }
            case IPPROTO_UDP: //17
            {
                struct udphdr *udp_header   = (struct udphdr*)(packet + IP_HEADER_LEN  + ETHERNET_HEADER_LEN);
                struct iphdr *ip_header     = (struct iphdr *)(packet  + ETHERNET_HEADER_LEN);
                int udp_header_size         =  ETHERNET_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN;
                int total_len               = (ntohs(ip_header->tot_len) + ETHERNET_HEADER_LEN);
                int udp_data_size           = total_len - udp_header_size;
                printf("\n\n***********************UDP Packet (%d)*************************\n", UDP_HEADER_LEN);
                printf("UDP Header (%d)\n", UDP_HEADER_LEN);
                printf("   |-Source Port\t\t: %d\n" , ntohs(udp_header->source));
                printf("   |-Destination Port\t\t: %d\n" , ntohs(udp_header->dest));
                printf("   |-UDP Length\t\t\t: %d\n" , ntohs(udp_header->len));
                printf("   |-UDP Checksum\t\t: %d\n" , ntohs(udp_header->check));
                printf("Data Payload (%d)\n", udp_data_size);   
                PrintData(packet + udp_header_size , udp_data_size );
                break;
            }
            default:
                break;
        }
    }
}

int main(void) {
    char errbuf[PCAP_ERRBUF_SIZE] = {"\0"};
    const char *interface = "ens33";
    
    pcap_t *pcd = pcap_open_live(interface, BUFSIZ, PROMISCUOUS, 1000, errbuf);
    if (pcd == NULL) {
        printf("Couldn't open device %s: %s\n", interface, errbuf);
        return PCAP_ERROR;
    }

    bpf_u_int32 net, mask;
    if (pcap_lookupnet(interface, &net, &mask, errbuf) == PCAP_ERROR) {
        printf("Couldn't get network/netmask address for device %s: %s\n", interface, errbuf);
        return PCAP_ERROR;
    }

    pcap_loop(pcd, 0, capture, NULL);
    return 0;
}

4.2. libtins

ETHERNET 헤더는 14byte로 구성되어 있다.

TypeByte
Destination MAC Address6
Source MAC Address6
Type2
const Tins::EthernetII EthernetPacket  = Packet.rfind_pdu<Tins::EthernetII>();
std::cout << "\nEthernet Header (" << EthernetPacket.header_size() << ")" << std::endl;
std::cout << "   |-Source Address\t\t: " << EthernetPacket.src_addr() << std::endl;
std::cout << "   |-Destination Address\t: " << EthernetPacket.dst_addr() << std::endl;

IP 헤더는 20byte로 구성되어 있다.

TypeByte
Version0.5
Header Length0.5
Type Of Service1
Total Length2
Identification2
Fragmentation Offset2 (Flags + Offset)
TTL1
Protocol1
Checksum2
Source IP Address4
Destination IP Address4
const Tins::IP IP = Packet.rfind_pdu<Tins::IP>();
std::cout << "IP Header (" << IP.header_size() << ")" << std::endl;
std::cout << "   |-IP Version\t\t\t: " << (unsigned int)IP.version() << std::endl;
std::cout << "   |-Type Of Service\t\t: " << (unsigned int)IP.tos() << std::endl;
std::cout << "   |-IP Total Length\t\t: " << ntohs(IP.tot_len()) << std::endl;
std::cout << "   |-Identification\t\t: " << ntohs(IP.id()) << std::endl;
std::cout << "   |-TTL\t\t\t: " << (unsigned int)IP.ttl() << std::endl;
std::cout << "   |-Protocol\t\t\t: " << (unsigned int)IP.protocol() << std::endl;
std::cout << "   |-Checksum\t\t\t: " << ntohs(IP.checksum()) << std::endl;
std::cout << "   |-Source IP\t\t\t: " << IP.src_addr() << std::endl;
std::cout << "   |-Destination IP\t\t: " << IP.dst_addr() << std::endl;

ICMP 헤더는 8byte로 구성되어 있다.

TypeByte
Type1
Code1
Checksum2
Identifier2
Sequence number2
const Tins::ICMP ICMP = Packet.rfind_pdu<Tins::ICMP>();
std::cout << "ICMP Header (" << ICMP.header_size() << ")" << std::endl;
std::cout << "   |-Type\t\t\t: " << (unsigned int)ICMP.type() << std::endl;
std::cout << "   |-Code\t\t\t: " << (unsigned int)ICMP.code() << std::endl;
std::cout << "   |-Checksum\t\t\t: " << ntohs(ICMP.code()) << std::endl;
std::cout << "   |-Identifier\t\t\t: " << ntohs(ICMP.id()) << std::endl;
std::cout << "   |-Sequence number\t\t: " << ntohs(ICMP.sequence()) << std::endl;

const Tins::RawPDU &RawPDU = ICMP.rfind_pdu<Tins::RawPDU>();
const Tins::RawPDU::payload_type &Data = RawPDU.payload();
std::cout << "Payload (" << RawPDU.payload_size() << ")" << std::endl;
PrintData(&RawPDU.payload().front(), RawPDU.payload_size());

TCP 헤더는 20byte와 Options로 구성되어 있다.

TypeByte
Source Port2
Destination Port2
Sequence Number4
Acknowledge Number4
Flag2 (Header Length + Flag)
Window2
Checksum2
Urgent Pointer2
Optionsn
const Tins::TCP TCP = Packet.rfind_pdu<Tins::TCP>();
std::cout << "TCP Header (" << TCP.header_size() << ")" << std::endl;
std::cout << "   |-Source Port\t\t: " << TCP.sport() << std::endl;
std::cout << "   |-Destination Port\t\t: " << TCP.dport() << std::endl;
std::cout << "   |-Sequence Number\t\t: " << ntohl(TCP.seq()) << std::endl;
std::cout << "   |-Acknowledge Port\t\t: " << ntohl(TCP.ack_seq()) << std::endl;
std::cout << "   |-Urgent Flag\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::URG) << std::endl;
std::cout << "   |-Acknowledgement Flag\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::ACK) << std::endl;
std::cout << "   |-Push Flag\t\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::PSH) << std::endl;
std::cout << "   |-Reset Flag\t\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::RST) << std::endl;
std::cout << "   |-Synchronise Flag\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::SYN) << std::endl;
std::cout << "   |-Finish Flag\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::FIN) << std::endl;
std::cout << "   |-Window\t\t\t: " << ntohs(TCP.window()) << std::endl;
std::cout << "   |-Checksum\t\t\t: " << ntohs(TCP.checksum()) << std::endl;
std::cout << "   |-Urgent Pointer\t\t: " << TCP.urg_ptr() << std::endl;

const Tins::RawPDU &RawPDU = TCP.rfind_pdu<Tins::RawPDU>();
const Tins::RawPDU::payload_type &Data = RawPDU.payload();
std::cout << "Payload (" << RawPDU.payload_size() << ")" << std::endl;
PrintData(&RawPDU.payload().front(), RawPDU.payload_size());

UDP 헤더는 8byte로 구성되어 있다.

TypeByte
Source Port2
Destination Port2
UDP Length2
UDP Checksum2
const Tins::UDP UDP = Packet.rfind_pdu<Tins::UDP>();
std::cout << "UDP Header (" << UDP.header_size() << ")" << std::endl;
std::cout << "   |-Source Port\t\t: " << UDP.sport() << std::endl;
std::cout << "   |-Destination Port\t\t: " << UDP.dport() << std::endl;
std::cout << "   |-Checksum\t\t\t: " << ntohs(UDP.checksum()) << std::endl;

const Tins::RawPDU &RawPDU = UDP.rfind_pdu<Tins::RawPDU>();
const Tins::RawPDU::payload_type &Data = RawPDU.payload();
std::cout << "Payload (" << RawPDU.payload_size() << ")" << std::endl;
PrintData(&RawPDU.payload().front(), RawPDU.payload_size());

전체 코드는 다음과 같다.

#include <tins/tins.h>
#include <iostream>

#define PROMISCUOUS false

void PrintData(const u_char* data , int Size)
{
    int i , j;
    for(i=0 ; i < Size ; i++){
        if( i!=0 && i%16==0){
            printf("         ");
            for(j=i-16 ; j<i ; j++){
                if(data[j]>=32 && data[j]<=128) printf("%c",(unsigned char)data[j]); //if its a number or alphabet
                else printf("."); //otherwise print a dot
            }
            printf("\n");
        }
        if(i%16==0) printf("   ");
            printf(" %02X",(unsigned int)data[i]);
        if( i==Size-1){
            for(j=0;j<15-i%16;j++){printf("   ");}
            printf("         ");
            for(j=i-i%16 ; j<=i ; j++){
                if(data[j]>=32 && data[j]<=128) {printf("%c",(unsigned char)data[j]);}
                else{printf(".");}
            }
            printf("\n" );
        }
    }
}

bool capture(Tins::PDU &Packet) {
    const Tins::EthernetII EthernetPacket  = Packet.rfind_pdu<Tins::EthernetII>();
    std::cout << "\nEthernet Header (" << EthernetPacket.header_size() << ")" << std::endl;
    std::cout << "   |-Source Address\t\t: " << EthernetPacket.src_addr() << std::endl;
    std::cout << "   |-Destination Address\t: " << EthernetPacket.dst_addr() << std::endl;

    const Tins::IP IP = Packet.rfind_pdu<Tins::IP>();
    std::cout << "IP Header (" << IP.header_size() << ")" << std::endl;
    std::cout << "   |-IP Version\t\t\t: " << (unsigned int)IP.version() << std::endl;
    std::cout << "   |-Type Of Service\t\t: " << (unsigned int)IP.tos() << std::endl;
    std::cout << "   |-IP Total Length\t\t: " << ntohs(IP.tot_len()) << std::endl;
    std::cout << "   |-Identification\t\t: " << ntohs(IP.id()) << std::endl;
    std::cout << "   |-TTL\t\t\t: " << (unsigned int)IP.ttl() << std::endl;
    std::cout << "   |-Protocol\t\t\t: " << (unsigned int)IP.protocol() << std::endl;
    std::cout << "   |-Checksum\t\t\t: " << ntohs(IP.checksum()) << std::endl;
    std::cout << "   |-Source IP\t\t\t: " << IP.src_addr() << std::endl;
    std::cout << "   |-Destination IP\t\t: " << IP.dst_addr() << std::endl;

    switch ((unsigned)IP.protocol()) {
        case IPPROTO_ICMP:
        {
            const Tins::ICMP ICMP = Packet.rfind_pdu<Tins::ICMP>();
            std::cout << "ICMP Header (" << ICMP.header_size() << ")" << std::endl;
            std::cout << "   |-Type\t\t\t: " << (unsigned int)ICMP.type() << std::endl;
            std::cout << "   |-Code\t\t\t: " << (unsigned int)ICMP.code() << std::endl;
            std::cout << "   |-Checksum\t\t\t: " << ntohs(ICMP.code()) << std::endl;
            std::cout << "   |-Identifier\t\t\t: " << ntohs(ICMP.id()) << std::endl;
            std::cout << "   |-Sequence number\t\t: " << ntohs(ICMP.sequence()) << std::endl;

            const Tins::RawPDU &RawPDU = ICMP.rfind_pdu<Tins::RawPDU>();
            const Tins::RawPDU::payload_type &Data = RawPDU.payload();
            std::cout << "Payload (" << RawPDU.payload_size() << ")" << std::endl;
            PrintData(&RawPDU.payload().front(), RawPDU.payload_size());
            break;
        }
        case IPPROTO_TCP:
        {
            const Tins::TCP TCP = Packet.rfind_pdu<Tins::TCP>();
            std::cout << "TCP Header (" << TCP.header_size() << ")" << std::endl;
            std::cout << "   |-Source Port\t\t: " << TCP.sport() << std::endl;
            std::cout << "   |-Destination Port\t\t: " << TCP.dport() << std::endl;
            std::cout << "   |-Sequence Number\t\t: " << ntohl(TCP.seq()) << std::endl;
            std::cout << "   |-Acknowledge Port\t\t: " << ntohl(TCP.ack_seq()) << std::endl;
            std::cout << "   |-Urgent Flag\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::URG) << std::endl;
            std::cout << "   |-Acknowledgement Flag\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::ACK) << std::endl;
            std::cout << "   |-Push Flag\t\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::PSH) << std::endl;
            std::cout << "   |-Reset Flag\t\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::RST) << std::endl;
            std::cout << "   |-Synchronise Flag\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::SYN) << std::endl;
            std::cout << "   |-Finish Flag\t\t: " << (unsigned int)TCP.get_flag(Tins::TCP::Flags::FIN) << std::endl;
            std::cout << "   |-Window\t\t\t: " << ntohs(TCP.window()) << std::endl;
            std::cout << "   |-Checksum\t\t\t: " << ntohs(TCP.checksum()) << std::endl;
            std::cout << "   |-Urgent Pointer\t\t: " << TCP.urg_ptr() << std::endl;

            const Tins::RawPDU &RawPDU = TCP.rfind_pdu<Tins::RawPDU>();
            const Tins::RawPDU::payload_type &Data = RawPDU.payload();
            std::cout << "Payload (" << RawPDU.payload_size() << ")" << std::endl;
            PrintData(&RawPDU.payload().front(), RawPDU.payload_size());
            break;
        }
        case IPPROTO_UDP:
        {
            const Tins::UDP UDP = Packet.rfind_pdu<Tins::UDP>();
            std::cout << "UDP Header (" << UDP.header_size() << ")" << std::endl;
            std::cout << "   |-Source Port\t\t: " << UDP.sport() << std::endl;
            std::cout << "   |-Destination Port\t\t: " << UDP.dport() << std::endl;
            std::cout << "   |-Checksum\t\t\t: " << ntohs(UDP.checksum()) << std::endl;

            const Tins::RawPDU &RawPDU = UDP.rfind_pdu<Tins::RawPDU>();
            const Tins::RawPDU::payload_type &Data = RawPDU.payload();
            std::cout << "Payload (" << RawPDU.payload_size() << ")" << std::endl;
            PrintData(&RawPDU.payload().front(), RawPDU.payload_size());
            break;
        }
        default:
            break;
    }
    return true;
}

int main(void) {
    Tins::SnifferConfiguration config;
    config.set_immediate_mode(true);
    config.set_promisc_mode(false);

    Tins::Sniffer sniffer("ens33", config);
    sniffer.sniff_loop(capture);
    return 0;
}
profile
IT 도서관

0개의 댓글

관련 채용 정보