안 쓰던 블로그

pcap 프로그래밍-TCP, UDP 패킷 분석 TCP, UDP reader 본문

Network

pcap 프로그래밍-TCP, UDP 패킷 분석 TCP, UDP reader

proqk 2020. 9. 26. 21:50
반응형

이전 글

헤더들 정보: foxtrotin.tistory.com/324

ARP 패킷 만들고 전송하기: foxtrotin.tistory.com/323

RP 스니핑 프로그램 ARP reader: foxtrotin.tistory.com/325

 

pcap 함수

pcap_findalldevs(&alldevs, errbuf)

네트워크 이더넷들을 찾는 함수

 

alldevs에 찾은 이더넷 정보 저장하며, 에러 시 errbuf에 에러를 저장한다


pcap_freealldevs(alldevs)

해당 네트워크를 제외한 다른 네트워크를 해제하기 위한 함수

 

pcap_open_live(name, 65536, 1, 1000, errbuf)

실제 네트워크 이더넷의 패킷을 캡처 하는 함수

 

name: 장치이름

65536: 패킷의 길이

1: 모든 패킷을 잡을 수 있는 promisc모드로 설정

1000: 패킷을 읽는 시간

errbuf: 에러버퍼

pcap_next_ex(adhandle, &header, &pkt_data)

캡처된 패킷의 데이터를 불러오는 함수


tcp.h구조

struct tcphdr
  {
    __extension__ union
    {
      struct
      {
        uint16_t th_sport;      /* source port */
        uint16_t th_dport;      /* destination port */
        tcp_seq th_seq;         /* sequence number */
        tcp_seq th_ack;         /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
        uint8_t th_x2:4;        /* (unused) */
        uint8_t th_off:4;       /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
        uint8_t th_off:4;       /* data offset */
        uint8_t th_x2:4;        /* (unused) */
# endif
        uint8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH        0x08
# define TH_ACK 0x10
# define TH_URG 0x20
        uint16_t th_win;        /* window */
        uint16_t th_sum;        /* checksum */
        uint16_t th_urp;        /* urgent pointer */
      };
      struct
      {
        uint16_t source;
        uint16_t dest;
        uint32_t seq;
        uint32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
        uint16_t res1:4;
        uint16_t doff:4;
        uint16_t fin:1;
        uint16_t syn:1;
        uint16_t rst:1;
        uint16_t psh:1;
        uint16_t ack:1;
        uint16_t urg:1;
        uint16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
        uint16_t doff:4;
        uint16_t res1:4;
        uint16_t res2:2;
        uint16_t urg:1;
        uint16_t ack:1;
        uint16_t psh:1;
        uint16_t rst:1;
        uint16_t syn:1;
        uint16_t fin:1;
# else
#  error "Adjust your <bits/endian.h> defines"
# endif
        uint16_t window;
        uint16_t check;
        uint16_t urg_ptr;
      };
    };
};

tcp.h에서 tcphdr구조체 부분을 사용한다

 

udp.h구조

struct udphdr
{
  __extension__ union
  {
    struct
    {
      uint16_t uh_sport;        /* source port */
      uint16_t uh_dport;        /* destination port */
      uint16_t uh_ulen;         /* udp length */
      uint16_t uh_sum;          /* udp checksum */
    };
    struct
    {
      uint16_t source;
      uint16_t dest;
      uint16_t len;
      uint16_t check;
    };
  };
};

tcp 헤더

Source Port Number: 송신자 포트 번호

Destination Port Number: 접속하고자 하는 목적지 대상 서버 포트번호
Sequence Number: 데이터의 순서를 나타내는 번호, 분할된 패킷의 경우 데이터 재조합에 사용
Acknowledge Number: 다음에 수신할 데이터 번호이며 해당 번호를 통해 전체 데이터 중 몇번째 데이터 인지를 파악하게 된다
Header Length(Offset): TCP헤더 길이
Reserved: 예약된 필드로 사용되지 않는 경우 0
Control Flags(CodeBits): 6개의 비트로 구성 
Window Size: 한 번에 받을 수 있는 패킷 사이즈를 의미하며, 2개 pc간에 윈도우 사이즈가 다른 경우 작은 사이즈에 맞추어 데이터를 송신한다
TCP Checksum: 헤더 값의 에러 발생여부를 검사

 

 

UDP 헤더

Source Port: 출발지 포트 번호

Destination Prot: 도착지 포트 번호

Length: 데이터를 포함한 헤더 길이

Checksum: UDP 체크섬


전체 코드

#include <arpa/inet.h>
#include <net/ethernet.h> //ethernet
#include <netinet/ip.h> //ip
#include <netinet/tcp.h> //tcp
#include <netinet/udp.h> //udp
#include <cstdio>
#include <iostream>
#include <cstring>
#include <pcap.h> //pcap

using namespace std;

void dump_pkt(const u_char *pkt_data, struct pcap_pkthdr* header);

void usage(){
    printf("syntax: pcap-test <interface>\n");
    printf("sample: pcap-test wlan0\n");
}

int main(int argc, char* argv[]){
    if (argc != 2){
        usage();
        return -1;
    }

    char* dev = argv[1]; //argv[0]: file name, argv[1]: data
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t* handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
    if(handle==nullptr){
        fprintf(stderr, "pcap_open_live(%s) return nullptr - %s\n", dev, errbuf);
        return -1;
    }

    while(true){ //packet capture
        struct pcap_pkthdr* header;
        const u_char* packet;
        int res = pcap_next_ex(handle, &header, &packet);
        if(res==0) continue;
        if(res==-1 || res==-2){
            printf("pcap_next_ex return %d(%s)\n", res, pcap_geterr(handle));
            break;
        }
        dump_pkt(packet, header);
    }
    pcap_close(handle);    
}

void dump_pkt(const u_char *pkt_data, struct pcap_pkthdr* header){
    struct ether_header *eth_hdr = (struct ether_header *)pkt_data; //get ether_header from captured packet
    u_int16_t eth_type = ntohs(eth_hdr->ether_type); //get ether_type from eth_header

    //if type is not IP, return function
    if(eth_type!=ETHERTYPE_IP) return;

    struct ip *ip_hdr = (struct ip *)(pkt_data+sizeof(ether_header)); //ip header struct

    u_int8_t ip_type = ip_hdr->ip_p; //get ip type from ip header
    u_int8_t ip_offset = ip_hdr->ip_hl; //get ip offset

    printf("\nIP Packet Info====================================\n");

    //print pkt length
    printf("%u bytes captured\n", header->caplen); //captured header len

    //print mac addr
    u_int8_t *dst_mac = eth_hdr->ether_dhost; //dst mac addr
    u_int8_t *src_mac = eth_hdr->ether_shost; //src mac addr

    printf("Dst MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
        dst_mac[0],dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]);

    printf("Src MAC : %02x:%02x:%02x:%02x:%02x:%02x\n",
        src_mac[0],src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]);
    
    //print ip addr
    char src_ip[16], dst_ip[16];
    char* tmp = inet_ntoa(ip_hdr->ip_src); //get src ip from ip header
    strcpy(src_ip, tmp);
    tmp = inet_ntoa(ip_hdr->ip_dst);
    strcpy(dst_ip, tmp);

    printf("Src IP : %s\n", src_ip);
    printf("Dst IP : %s\n", dst_ip);

    //print payload
    u_int32_t payload_len = header->caplen - sizeof(ether_header) - ip_offset*4;
    u_int32_t max = payload_len >= 16 ? 16 : payload_len; //get 16bytes
    const u_char* pkt_payload = pkt_data + sizeof(ether_header)+ip_offset*4;
    printf("Payload : ");

    if(!payload_len){
        printf("No payload\n");
    }else{
        for(int i=0;i<max;i++) printf("%02x ", *(pkt_payload+i));
        printf("\n");
    }
    
    
    if(ip_hdr->ip_p == IPPROTO_TCP){
        printf("\nThis is TCP Packet====================\n");
        struct tcphdr *tcp_hdr = (struct tcphdr *)(pkt_data+ip_hdr->ip_hl*4); //TCP header

        //SHOW IP TCP INfo
        printf("Src Port : %d\n", ntohs(tcp_hdr->source));
        printf("Dst Port : %d\n", ntohs(tcp_hdr->dest));
    }
    else if(ip_hdr->ip_p == IPPROTO_UDP){
        printf("\nThis is UDP Packet====================\n");
        struct udphdr *udp_hdr = (struct udphdr *)(pkt_data+ip_hdr->ip_hl*4); //UDP header

        //SHOW IP TCP INfo
        printf("Src Port : %d\n", ntohs(udp_hdr->source));
        printf("Dst Port : %d\n", ntohs(udp_hdr->dest));
    }
}

 

 

 

tcp패킷이 아니면 패킷 정보만 보여주다가, tcp 패킷이 잡히자 포트 번호까지 출력하고 있는 모습

udp패킷이면 udp패킷의 정보를 보여준다

 

반응형
Comments