소켓프로그래밍

리눅스 패킷분석기

blackbearwow 2024. 3. 7. 02:18

간단한 패킷 분석기를 만들었다. 리눅스에서 작동하는 코드다.

// packetCapture.cpp
// g++ -o packetCapture.out packetCapture.cpp; sudo ./packetCapture.out
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
using namespace std;
// The packet length
#define PCKT_LEN 8192

typedef struct {
    unsigned short htype;
    unsigned short ptype;
    unsigned char hlen;
    unsigned char plen;
    unsigned short opcode;
    unsigned char sender_mac[6];
    unsigned char sender_ip[4];
    unsigned char target_mac[6];
    unsigned char target_ip[4];
}arp_packet;

void error(char* msg);
void arpReceived(arp_packet* recv_arp_pkt);
void ipReceived(struct iphdr* iphdr);

int main() {
    int sock;
    struct ifreq if_idx;
    struct sockaddr_ll dest_addr;
    struct ether_header ethhdr;
    char buffer[1600];

    if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))==-1)
        error((char*)"socket");
    strncpy(if_idx.ifr_name, "eno1", IFNAMSIZ);
    if(ioctl(sock, SIOCGIFINDEX, &if_idx)<0)
        error((char*)"ioctl");
    
    struct ether_header* recv_ethhdr = (struct ether_header*)buffer;
    arp_packet* recv_arp_pkt = (arp_packet*)(buffer+sizeof(struct ether_header));
    struct iphdr* iphdr = (struct iphdr*)(buffer+sizeof(struct ether_header));
    while (true) {
        if(recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL)<0)
            error((char*)"recvfrom");
        switch(ntohs(recv_ethhdr->ether_type)) {
            case ETH_P_ARP:
                arpReceived(recv_arp_pkt);
                break;
            case ETH_P_IP:
                ipReceived(iphdr);
                break;
            default:
                cout << "unknown packet received" << endl;
        }
    }

    return 0;
}

void arpReceived(arp_packet* recv_arp_pkt) {
    switch(ntohs(recv_arp_pkt->opcode)) {
        case 0x0001:
            cout << "arp request capture" << endl;
            break;
        case 0x0002:
            cout << "arp reply received" << endl;
    }
}

void ipReceived(struct iphdr* iphdr) {
    cout.width(3); cout << (iphdr->saddr & 0xff) << ".";
    cout.width(3); cout << ((iphdr->saddr & 0xff00) >> 8) << ".";
    cout.width(3); cout << ((iphdr->saddr & 0xff0000) >> 16) << ".";
    cout.width(3); cout << ((iphdr->saddr & 0xff000000) >> 24) << " to ";
    cout.width(3); cout << (iphdr->daddr & 0xff) << ".";
    cout.width(3); cout << ((iphdr->daddr & 0xff00) >> 8) << ".";
    cout.width(3); cout << ((iphdr->daddr & 0xff0000) >> 16) << ".";
    cout.width(3); cout << ((iphdr->daddr & 0xff000000) >> 24) << " ";
    switch(iphdr->protocol) {
        case 0x06: {
            struct tcphdr* tcphdr = (struct tcphdr*)((char*)iphdr + sizeof(struct iphdr));
            cout << "TCP " << ntohs(tcphdr->source) << " -> " << ntohs(tcphdr->dest) <<endl;
        }
        break;
        case 0x11: {
            struct udphdr* udphdr = (struct udphdr*)((char*)iphdr + sizeof(struct iphdr));
            cout << "UDP " << ntohs(udphdr->source) << " -> " << ntohs(udphdr->dest) << endl;
        }
        break;
        case 0x01:
            cout << "ICMP " << endl;
            break;
        case 0x02:
            cout << "IGMP " << endl;
            break;
        default:
            cout << "unknown IP protocol" << endl;
            break;
    }
}

void error(char* msg)
{
    perror(msg);
    exit(1);
}