안 쓰던 블로그
pcap 프로그래밍-TCP, UDP 패킷 분석 TCP, UDP reader 본문
이전 글
헤더들 정보: 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패킷의 정보를 보여준다
'Network' 카테고리의 다른 글
[해결] Vagrant 설치 에러 There was an error while executing `VBoxManage`, a CLI used by Vagrant (0) | 2021.05.03 |
---|---|
google cloud platform에서 instance 만들기 (0) | 2020.11.10 |
pcap 프로그래밍-ARP 패킷 분석 ARP reader (0) | 2020.09.25 |
pcap 프로그래밍-ether_addr, ether_header, ip_header, tcp_header, arphdr 구조체 (0) | 2020.09.25 |
pcap 프로그래밍-ARP 패킷 만들고 보내기 (1) | 2020.09.25 |