[C/C++] 패킷 생성

Alexandria·2024년 3월 4일
0

C lang

목록 보기
10/14
post-thumbnail

1. 환경

1.1. libnet

libnet-dev를 설치한다.

$ sudo apt -y install libnet-dev

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

1.2. libtins

libtins-dev를 설치한다.

$ sudo apt -y install libtins-dev

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

2. ICMP

2.1. libnet

libnet_t 구조체를 선언 후 초기화한다.

char errbuf[LIBNET_ERRBUF_SIZE]    = { '\0' };
libnet_t *l = NULL;
if ((l = libnet_init(LIBNET_RAW4, "ens33", errbuf)) == NULL) {
    fprintf(stderr, "libnet_init() failed: %s", errbuf);
    return -1; 
}

libnet_destroy(l);
l   = NULL;

ICMP Echo request 패킷을 생성해보자.

데이터는 a부터 z를 넣어본다.

libnet_ptag_t ip = LIBNET_PTAG_INITIALIZER;
unsigned char databuf[27]    = { '\0' };
for (int i = 0; i < 26; i++) databuf[i] = i + 0x61;

libnet_ptag_t icmp  = LIBNET_PTAG_INITIALIZER;
if ((icmp = libnet_build_icmpv4_echo(ICMP_ECHO, 0, 0, 666, 666, databuf, sizeof(databuf) - 1, l, 0)) == -1) {
    fprintf(stderr, "Can't build ICMP header: %s\n", libnet_geterror(l));
    return -1;
}

ICMP 프로토콜이 담길 IP 프로토콜을 생성한다.

출발지 주소는 임의의 난수값을 이용해보자.

unsigned long dst_ip;
if ((dst_ip = libnet_name2addr4(l, "192.168.0.2", LIBNET_DONT_RESOLVE)) == -1) {
    fprintf(stderr, "libnet_name2addr4 error");
    return -1;
}

if (libnet_seed_prand(l) == -1) {
    fprintf(stderr, "libnet_seed_prand error");
    return -1;
}

if ((icmp = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H + sizeof(databuf) - 1, 0, 666, 0, 64, IPPROTO_ICMP, 0, libnet_get_prand(LIBNET_PRu32), dst_ip, NULL, 0, l, 0)) == -1) {
    fprintf(stderr, "Can't build IP header: %s\n", libnet_geterror(l));
    return -1;
}

이후 패킷을 보낸다.

if (libnet_write(l) == -1) fprintf(stderr, "Write error: %s\n", libnet_geterror(l));

전체 코드는 다음과 같다.

#include <libnet.h>

int main(void) {
    char errbuf[LIBNET_ERRBUF_SIZE]    = { '\0' };
    libnet_t *l = NULL;
    if ((l = libnet_init(LIBNET_RAW4, "ens33", errbuf)) == NULL) {
        fprintf(stderr, "libnet_init() failed: %s", errbuf);
        return -1; 
    }

    libnet_ptag_t ip = LIBNET_PTAG_INITIALIZER;
    unsigned char databuf[27]    = { '\0' };
    for (int i = 0; i < 26; i++) databuf[i] = i + 0x61;

    libnet_ptag_t icmp  = LIBNET_PTAG_INITIALIZER;
    if ((icmp = libnet_build_icmpv4_echo(ICMP_ECHO, 0, 0, 666, 666, databuf, sizeof(databuf) - 1, l, 0)) == -1) {
        fprintf(stderr, "Can't build ICMP header: %s\n", libnet_geterror(l));
        return -1;
    }

    unsigned long dst_ip;
    if ((dst_ip = libnet_name2addr4(l, "192.168.0.2", LIBNET_DONT_RESOLVE)) == -1) {
        fprintf(stderr, "libnet_name2addr4 error");
        return -1;
    }

    if (libnet_seed_prand(l) == -1) {
        fprintf(stderr, "libnet_seed_prand error");
        return -1;
    }

    if ((icmp = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H + sizeof(databuf) - 1, 0, 666, 0, 64, IPPROTO_ICMP, 0, libnet_get_prand(LIBNET_PRu32), dst_ip, NULL, 0, l, 0)) == -1) {
        fprintf(stderr, "Can't build IP header: %s\n", libnet_geterror(l));
        return -1;
    }

    if (libnet_write(l) == -1) fprintf(stderr, "Write error: %s\n", libnet_geterror(l));

    libnet_destroy(l);
    l   = NULL;
    return 0;
}

2.2. libtins

Ethernet II를 생성해보자. Ethernet II의 첫번째 인자가 목적지이고, 두번째 인자가 출발지이다.

Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
Tins::EthernetII ethernet = Tins::EthernetII("ff:ff:ff:ff:ff:ff", iface.hw_address());

IP 프로토콜을 생성한다. IP의 첫번째 인자가 목적지이고, 두번째 인자가 출발지이다.

Tins::IP ip = Tins::IP(Tins::IPv4Address("192.168.0.2"), iface.ipv4_address());

ICMP Echo request 패킷을 생성해보자.

데이터는 a부터 z를 넣어본다.

Tins::ICMP icmp = Tins::ICMP()/Tins::RawPDU("abcdefghijklmnopqrstuvwxyz");
icmp.code(Tins::ICMP::ECHO_REQUEST);

생성한 각 프로토콜을 합쳐준다.

ethernet /= ip;
ethernet /= icmp;

이후 패킷을 보낸다.

Tins::PacketSender sender;
sender.send(ethernet, iface);

전체 코드는 다음과 같다.

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

int main(void) {
    Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
    Tins::EthernetII ethernet = Tins::EthernetII("ff:ff:ff:ff:ff:ff", iface.hw_address());
    Tins::IP ip = Tins::IP(Tins::IPv4Address("192.168.0.2"), iface.ipv4_address());
    Tins::ICMP icmp = Tins::ICMP()/Tins::RawPDU("abcdefghijklmnopqrstuvwxyz");
    icmp.code(Tins::ICMP::ECHO_REQUEST);

    ethernet /= ip;
    ethernet /= icmp;

    Tins::PacketSender sender;
    sender.send(ethernet, iface);
    return 0;
}

3. TCP

3.1. libnet

libnet_t 구조체를 선언 후 초기화한다.

char errbuf[LIBNET_ERRBUF_SIZE]    = { '\0' };
libnet_t *l = NULL;
if ((l = libnet_init(LIBNET_RAW4, "ens33", errbuf)) == NULL) {
    fprintf(stderr, "libnet_init() failed: %s", errbuf);
    return -1; 
}

libnet_destroy(l);
l   = NULL;
return 0;

TCP 프로토콜을 생성한다.

출발지 포트는 임의의 난수값을 이용해보자.

if (libnet_seed_prand(l) == -1) {
    fprintf(stderr, "libnet_seed_prand error");
    return -1;
}

const char *data            = "Hello TCP";
unsigned short data_length  = strlen(data);
libnet_ptag_t tcp           = LIBNET_PTAG_INITIALIZER;
if ((tcp = libnet_build_tcp(libnet_get_prand(LIBNET_PRu16), 80, 0, 0, TH_SYN, 64240, 0, 0, LIBNET_TCP_H + 20 + data_length, (uint8_t*)data, data_length, l, 0)) == -1) {
    fprintf(stderr, "Can't build TCP header: %s\n", libnet_geterror(l));
    return -1;
}

TCP 프로토콜이 담길 IP 프로토콜을 생성한다.

unsigned long src_ip;
if ((src_ip = libnet_get_ipaddr4(l)) == -1) {
    fprintf(stderr, "libnet_get_ipaddr4 error");
    return -1;
}
unsigned long dst_ip;
if ((dst_ip = libnet_name2addr4(l, "192.168.0.2", LIBNET_DONT_RESOLVE)) == -1) {
    fprintf(stderr, "libnet_name2addr4 error");
    return -1;
}

if ((libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_TCP_H + data_length, 0, 666, 0, 64, IPPROTO_TCP, 0, src_ip, dst_ip, NULL, 0, l, 0)) == -1) {
    fprintf(stderr, "Can't build IP header: %s\n", libnet_geterror(l));
    return -1;
}

이후 패킷을 보낸다.

if (libnet_write(l) == -1) fprintf(stderr, "Write error: %s\n", libnet_geterror(l));

전체 코드는 다음과 같다.

#include <libnet.h>

int main(void) {
    char errbuf[LIBNET_ERRBUF_SIZE]    = { '\0' };
    libnet_t *l = NULL;
    if ((l = libnet_init(LIBNET_RAW4, "ens33", errbuf)) == NULL) {
        fprintf(stderr, "libnet_init() failed: %s", errbuf);
        return -1; 
    }

    if (libnet_seed_prand(l) == -1) {
        fprintf(stderr, "libnet_seed_prand error");
        return -1;
    }

    const char *data            = "Hello TCP";
    unsigned short data_length  = strlen(data);
    libnet_ptag_t tcp           = LIBNET_PTAG_INITIALIZER;
    if ((tcp = libnet_build_tcp(libnet_get_prand(LIBNET_PRu16), 80, 0, 0, TH_SYN, 64240, 0, 0, LIBNET_TCP_H + 20 + data_length, (uint8_t*)data, data_length, l, 0)) == -1) {
        fprintf(stderr, "Can't build TCP header: %s\n", libnet_geterror(l));
        return -1;
    }

    unsigned long src_ip;
    if ((src_ip = libnet_get_ipaddr4(l)) == -1) {
        fprintf(stderr, "libnet_get_ipaddr4 error");
        return -1;
    }
    unsigned long dst_ip;
    if ((dst_ip = libnet_name2addr4(l, "192.168.0.2", LIBNET_DONT_RESOLVE)) == -1) {
        fprintf(stderr, "libnet_name2addr4 error");
        return -1;
    }

    if ((libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_TCP_H + data_length, 0, 666, 0, 64, IPPROTO_TCP, 0, src_ip, dst_ip, NULL, 0, l, 0)) == -1) {
        fprintf(stderr, "Can't build IP header: %s\n", libnet_geterror(l));
        return -1;
    }

    if (libnet_write(l) == -1) fprintf(stderr, "Write error: %s\n", libnet_geterror(l));

    libnet_destroy(l);
    l   = NULL;
    return 0;
}

3.2. libtins

Ethernet II를 생성해보자. Ethernet II의 첫번째 인자가 목적지이고, 두번째 인자가 출발지이다.

Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
Tins::EthernetII ethernet = Tins::EthernetII("ff:ff:ff:ff:ff:ff", iface.hw_address());

IP 프로토콜을 생성한다. IP의 첫번째 인자가 목적지이고, 두번째 인자가 출발지이다.

Tins::IP ip = Tins::IP(Tins::IPv4Address("192.168.0.2"), iface.ipv4_address());

TCP 패킷을 생성해보자.

데이터는 a부터 z를 넣어본다.

Tins::TCP tcp = Tins::TCP(80, 1004)/Tins::RawPDU("abcdefghijklmnopqrstuvwxyz");

생성한 각 프로토콜을 합쳐준다.

ethernet /= ip;
ethernet /= tcp;

이후 패킷을 보낸다.

Tins::PacketSender sender;
sender.send(ethernet, iface);

전체 코드는 다음과 같다.

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

int main(void) {
    Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
    Tins::EthernetII ethernet = Tins::EthernetII("ff:ff:ff:ff:ff:ff", iface.hw_address());
    Tins::IP ip = Tins::IP(Tins::IPv4Address("192.168.0.2"), iface.ipv4_address());
    Tins::TCP tcp = Tins::TCP(80, 1004)/Tins::RawPDU("abcdefghijklmnopqrstuvwxyz");

    ethernet /= ip;
    ethernet /= tcp;

    Tins::PacketSender sender;
    sender.send(ethernet, iface);
    return 0;
}

4. UDP

4.1. libnet

libnet_t 구조체를 선언 후 초기화한다.

char errbuf[LIBNET_ERRBUF_SIZE]    = { '\0' };
libnet_t *l = NULL;
if ((l = libnet_init(LIBNET_RAW4, "ens33", errbuf)) == NULL) {
    fprintf(stderr, "libnet_init() failed: %s", errbuf);
    return -1; 
}

libnet_destroy(l);
l   = NULL;
return 0;

UDP 프로토콜을 생성한다.

출발지 포트는 임의의 난수값을 이용해보자.

if (libnet_seed_prand(l) == -1) {
    fprintf(stderr, "libnet_seed_prand error");
    return -1;
}

const char *data            = "Hello UDP";
unsigned short data_length  = strlen(data);
libnet_ptag_t udp           = LIBNET_PTAG_INITIALIZER;
if ((udp = libnet_build_udp(libnet_get_prand(LIBNET_PRu16), 80, LIBNET_UDP_H + data_length, 0, (uint8_t*)data, data_length, l, 0)) == -1) {
    fprintf(stderr, "Can't build UDP header: %s\n", libnet_geterror(l));
    return -1;
}

UDP 프로토콜이 담길 IP 프로토콜을 생성한다.

unsigned long src_ip;
if ((src_ip = libnet_get_ipaddr4(l)) == -1) {
    fprintf(stderr, "libnet_get_ipaddr4 error");
    return -1;
}
unsigned long dst_ip;
if ((dst_ip = libnet_name2addr4(l, "192.168.0.2", LIBNET_DONT_RESOLVE)) == -1) {
    fprintf(stderr, "libnet_name2addr4 error");
    return -1;
}

if ((libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + data_length, 0, 666, 0, 64, IPPROTO_UDP, 0, src_ip, dst_ip, NULL, 0, l, 0)) == -1) {
    fprintf(stderr, "Can't build IP header: %s\n", libnet_geterror(l));
    return -1;
}

이후 패킷을 보낸다.

if (libnet_write(l) == -1) fprintf(stderr, "Write error: %s\n", libnet_geterror(l));

전체 코드는 다음과 같다.

#include <libnet.h>

int main(void) {
    char errbuf[LIBNET_ERRBUF_SIZE]    = { '\0' };
    libnet_t *l = NULL;
    if ((l = libnet_init(LIBNET_RAW4, "ens33", errbuf)) == NULL) {
        fprintf(stderr, "libnet_init() failed: %s", errbuf);
        return -1; 
    }

    if (libnet_seed_prand(l) == -1) {
        fprintf(stderr, "libnet_seed_prand error");
        return -1;
    }

    const char *data            = "Hello UDP";
    unsigned short data_length  = strlen(data);
    libnet_ptag_t udp           = LIBNET_PTAG_INITIALIZER;
    if ((udp = libnet_build_udp(libnet_get_prand(LIBNET_PRu16), 80, LIBNET_UDP_H + data_length, 0, (uint8_t*)data, data_length, l, 0)) == -1) {
        fprintf(stderr, "Can't build UDP header: %s\n", libnet_geterror(l));
        return -1;
    }

    unsigned long src_ip;
    if ((src_ip = libnet_get_ipaddr4(l)) == -1) {
        fprintf(stderr, "libnet_get_ipaddr4 error");
        return -1;
    }
    unsigned long dst_ip;
    if ((dst_ip = libnet_name2addr4(l, "192.168.0.2", LIBNET_DONT_RESOLVE)) == -1) {
        fprintf(stderr, "libnet_name2addr4 error");
        return -1;
    }

    if ((libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + data_length, 0, 666, 0, 64, IPPROTO_UDP, 0, src_ip, dst_ip, NULL, 0, l, 0)) == -1) {
        fprintf(stderr, "Can't build IP header: %s\n", libnet_geterror(l));
        return -1;
    }

    if (libnet_write(l) == -1) fprintf(stderr, "Write error: %s\n", libnet_geterror(l));

    libnet_destroy(l);
    l   = NULL;
    return 0;
}

4.2. libtins

Ethernet II를 생성해보자. Ethernet II의 첫번째 인자가 목적지이고, 두번째 인자가 출발지이다.

Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
Tins::EthernetII ethernet = Tins::EthernetII("ff:ff:ff:ff:ff:ff", iface.hw_address());

IP 프로토콜을 생성한다. IP의 첫번째 인자가 목적지이고, 두번째 인자가 출발지이다.

Tins::IP ip = Tins::IP(Tins::IPv4Address("192.168.0.2"), iface.ipv4_address());

UDP 패킷을 생성해보자.

데이터는 a부터 z를 넣어본다.

Tins::UDP udp = Tins::UDP(80, 1004)/Tins::RawPDU("abcdefghijklmnopqrstuvwxyz");

생성한 각 프로토콜을 합쳐준다.

ethernet /= ip;
ethernet /= udp;

이후 패킷을 보낸다.

Tins::PacketSender sender;
sender.send(ethernet, iface);

전체 코드는 다음과 같다.

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

int main(void) {
    Tins::NetworkInterface iface = Tins::NetworkInterface::default_interface();
    Tins::EthernetII ethernet = Tins::EthernetII("ff:ff:ff:ff:ff:ff", iface.hw_address());
    Tins::IP ip = Tins::IP(Tins::IPv4Address("192.168.0.2"), iface.ipv4_address());
    Tins::UDP udp = Tins::UDP(80, 1004)/Tins::RawPDU("abcdefghijklmnopqrstuvwxyz");

    ethernet /= ip;
    ethernet /= udp;

    Tins::PacketSender sender;
    sender.send(ethernet, iface);
    return 0;
}
profile
IT 도서관

0개의 댓글

관련 채용 정보