libpcap-dev를 설치한다.
$ sudo apt -y install libpcap-dev
컴파일 시 libpcap.so
을 링킹하여 컴파일한다.
libtins-dev를 설치한다.
$ sudo apt -y install libtins-dev
컴파일 시 libtins.so
을 링킹하여 컴파일한다.
네트워크 인터페이스
들을 얻고 사용을 다하면 해제해주자.
#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));
}
}
}
...
}
네트워크 인터페이스
정보를 얻은 후 반복문을 통해 정보를 출력해보자.
#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;
}
자신에게 오는 패킷(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;
}
자신에게 오는 패킷(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;
}
ETHERNET
헤더는 14byte로 구성되어 있다.
Type | Byte |
---|---|
Destination MAC Address | 6 |
Source MAC Address | 6 |
Type | 2 |
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로 구성되어 있다.
Type | Byte |
---|---|
Version | 0.5 |
Header Length | 0.5 |
Type Of Service | 1 |
Total Length | 2 |
Identification | 2 |
Fragmentation Offset | 2 (Flags + Offset) |
TTL | 1 |
Protocol | 1 |
Checksum | 2 |
Source IP Address | 4 |
Destination IP Address | 4 |
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로 구성되어 있다.
Type | Byte |
---|---|
Type | 1 |
Code | 1 |
Checksum | 2 |
Identifier | 2 |
Sequence number | 2 |
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로 구성되어 있다.
Type | Byte |
---|---|
Source Port | 2 |
Destination Port | 2 |
Sequence Number | 4 |
Acknowledge Number | 4 |
Flag | 2 (Header Length + Flag) |
Window | 2 |
Checksum | 2 |
Urgent Pointer | 2 |
Options | n |
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로 구성되어 있다.
Type | Byte |
---|---|
Source Port | 2 |
Destination Port | 2 |
UDP Length | 2 |
UDP Checksum | 2 |
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;
}
ETHERNET 헤더
는 14byte로 구성되어 있다.
Type | Byte |
---|---|
Destination MAC Address | 6 |
Source MAC Address | 6 |
Type | 2 |
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로 구성되어 있다.
Type | Byte |
---|---|
Version | 0.5 |
Header Length | 0.5 |
Type Of Service | 1 |
Total Length | 2 |
Identification | 2 |
Fragmentation Offset | 2 (Flags + Offset) |
TTL | 1 |
Protocol | 1 |
Checksum | 2 |
Source IP Address | 4 |
Destination IP Address | 4 |
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로 구성되어 있다.
Type | Byte |
---|---|
Type | 1 |
Code | 1 |
Checksum | 2 |
Identifier | 2 |
Sequence number | 2 |
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로 구성되어 있다.
Type | Byte |
---|---|
Source Port | 2 |
Destination Port | 2 |
Sequence Number | 4 |
Acknowledge Number | 4 |
Flag | 2 (Header Length + Flag) |
Window | 2 |
Checksum | 2 |
Urgent Pointer | 2 |
Options | n |
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로 구성되어 있다.
Type | Byte |
---|---|
Source Port | 2 |
Destination Port | 2 |
UDP Length | 2 |
UDP Checksum | 2 |
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;
}