본문 바로가기
네트워크

libnet 라이브러리

by 상레알 2010. 8. 20.


libnet 레퍼런스
 libnet 라이브러리는 응용 프로그램이 패킷을 생성하여 보낼 수 있게 해주는 라이브러리로, 직접 패킷을 생성하는 것보다 훨씬 간단하게 패킷을 생성하여 보낼 수 있으며, 보통 Libpcap과 함께 쓰인다. 이 두라이브러리를 이용하면 ping과 traceroute 같은 프로그램을 쉽게 작성할 수 있다고 한다.

libnet이 지원하는 함수 

메모리의 패킷 관리 함수, 주소 확인 함수, 패킷 구조 생성 함수, 패킷 생성함수등이 있다.

libnet이 지원하는 프로토콜로는

2계층은 ARP와 이더넷 , 3계층은 ICMP,IGMP, IPv4, 4계층은 TCP, UDP, 7계층은 RIP, OSPF,DNS 이 있다.


☆ Memory Alllocation and Initialization

libnet을 이용한 프로그램을 작성하기 위한 첫번째 단계는 패킷을 위한 메모릴를 할당하는거라고 한다.

IP-layer 인터페이스를 사용하면서 30 Byte의 Payload를 갖는 단순한 TCP 패킷을 생성하려고 한다면, 70 Bytes(IP Header + TCP header + Payload)가 필요할 것이다.

Link-layer 인터페이스를 사용하면서 30 Byte의 Payload를 갖는 단순한 TCP 패킷을 생성하려고 한다면, 84 Bytes(Ethemet header + IP header + TCP header + Payload)가 필요할 것이다.

작업이 끝냇을 경우는 libnet_destroy_packet()을 이용하여 메모리를 해체해 주어야 한다. (프로그램의 끝이나, garbage collection 경우)

☆ Network Initialization

이 단계는 네트워크 전송 인터페이스를 얻어오는 것이다.

○ IP-lay : 인터페이스 : libnet_open_raw_sock() (usally IPPROTO_RAW)
                                (return : a raw socket with IP_HDRINCL set )

○ Link-layer 인터페이스 : libnet_open_link_interface()

☆ Packet Construction

○  패킷은 모듈별로 생성되어 진다.
○ 각 Protocol Layer 별로 libnet_build로 시작하는 함수들이 있어야만 한다.
○ IP-layer : libn et_build_ip(), libnet_build_tcp()
○ link-layer : libnet_build_ethernet()
○ libnet_build_ethernet() : 0의 offset으로 버퍼의 시작부를 채워진다.
○ libnet_build_ip() : 적절한 위치에 IP header를 생성하기 위해서 14 byte(ETH_H) offset으로 채워진다.
○ libnet_build_tcp() : 시작 부분으로 부터 34 byte(ETH_H + IP_H) offset을 가지고 채워진다.

☆ Packet Checksums

○ 패킷을 생성하는 마지막 단계로 hecksum을 계산하는 것이다.
○ Raw IP interface의 경우, Transportlayer checksum 만을 계산하는 것이 필요하다.
○ Link-layer interface 의 경우, IP checksum만을 계산하는 것이 필요하다.
○ Checksum은 libnet_do_checksum()을 통해서 계산되어진다.

☆ Packet Injection

○ 마지막 단계로 네트워크에 패킷을 전송하는 것이다.
○ IP_layer interface : libnet_write_ip()
○ Link-layer interface : libnet_write_link_layer()
○ return : 성공시 (전송된 바이트수), 실패시 (-1)

*--------------------------------------------------------------------
기  능 : link-layer api / ICMP hostmask packet
컴파일 : # gcc -Wall `libnet-config --defines` libnet_ex2.c
           -o libnet_ex2 `libnet-config --libs`
실  행 : # ./libnet_ex2 [-i interface] -s 출발지IP주소 -d 목적지IP주소
--------------------------------------------------------------------*/

#include <libnet.h>

void usage(char *);

u_char enet_src[6] = {0x0d, 0x0e, 0x0a, 0x0d, 0x00, 0x00};
u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

int main(int argc, char *argv[])
{
    int packet_size,                    /* size of our packet */
        c;                              /* misc */
    u_long src_ip, dst_ip;              /* source ip, dest ip */
    u_char *packet;                     /* pointer to our packet buffer */
    char err_buf[LIBNET_ERRBUF_SIZE];   /* error buffer */
    u_char *device;                     /* pointer to the device to use */
    struct libnet_link_int *network;    /* pointer to link interface struct */

    printf("libnet example code:\tmodule 2\n\n");
    printf("packet injection interface:\tlink layer\n");
    printf("packet type:\t\t\tICMP net mask [no payload]\n");

    device = NULL;
    src_ip  = 0;
    dst_ip  = 0;

    while((c = getopt(argc, argv, "i:d:s:")) != EOF)
    {
        switch(c)
        {
         case 'd':
             if(!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
             {
              libnet_error(LIBNET_ERR_FATAL, "Bad destination IP address: %s\n", optarg);
             }
             break;
         case 'i':
             device = optarg;
             break;
         case 's':
             if(!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
             {
              libnet_error(LIBNET_ERR_FATAL, "Bad source IP address: %s\n", optarg);
             }
             break;
         default:
             exit(EXIT_FAILURE);
       }
    }

   if(!src_ip || !dst_ip)
    {
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }

   /*
    *  Step 1: Network Initialization (interchangable with step 2).
    */
    if(device == NULL)
    {
        struct sockaddr_in sin;
        /*
        *  Try to locate a device.
        */
        if(libnet_select_device(&sin, &device, err_buf) == -1)
        {
         libnet_error(LIBNET_ERR_FATAL, "libnet_select_device failed: %s\n", err_buf);
        }
        printf("device:\t\t\t\t%s\n", device);
    }

    if((network = libnet_open_link_interface(device, err_buf)) == NULL)
    {
        libnet_error(LIBNET_ERR_FATAL, "libnet_open_link_interface: %s\n", err_buf);
    }

    /*
    *  We're going to build an ICMP packet with no payload using the
    *  link-layer API, so this time we need memory for a ethernet header
    *  as well as memory for the ICMP and IP headers.
    */
    packet_size = LIBNET_IP_H + LIBNET_ETH_H + LIBNET_ICMP_MASK_H;

    /*
    *  Step 2: Memory Initialization (interchangable with step 1).
    */
    if(libnet_init_packet(packet_size, &packet) == -1)
    {
        libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
    }

   /*
    *  Step 3: Packet construction (ethernet header).
    */
   libnet  _build_ethernet(enet_dst,
                    enet_src,
                    ETHERTYPE_IP,
                    NULL,
                          0,
                    packet);

   /*
    *  Step 4: Packet construction (IP header).
    */
    libnet_build_ip(ICMP_MASK_H,
              0,                      /* IP tos */
              242,                    /* IP ID */
              0,                      /* Frag */
              64,                     /* TTL */
              IPPROTO_ICMP,           /* Transport protocol */
              src_ip,                 /* Source IP */
              dst_ip,                 /* Destination IP */
              NULL,                   /* Pointer to payload (none) */
              0,
              packet + LIBNET_ETH_H); /* Packet header memory */

    /*
   *  Step 5: Packet construction (ICMP header).
    */
    libnet_build_icmp_mask(ICMP_MASKREPLY,      /* type */
                  0,                      /* code */
                  242,                    /* id */
                  0,                      /* seq */
                  0xffffffff,             /* mask */
                  NULL,                   /* payload */
                  0,                      /* payload_s */
                  packet + LIBNET_ETH_H + LIBNET_IP_H);

    /*
    *  Step 6: Packet checksums (ICMP header *AND* IP header).
    */
    if(libnet_do_checksum(packet + ETH_H, IPPROTO_ICMP, LIBNET_ICMP_MASK_H) == -1)
    {
        libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }
    if(libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1)
   {
       libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }

    /*
    *  Step 7: Packet injection.
    */
    c = libnet_write_link_layer(network, device, packet, packet_size);
    if(c < packet_size)
    {
        libnet_error(LN_ERR_WARNING, "libnet_write_link_layer only wrote %d bytes\n", c);
    }
    else
    {
        printf("construction and injection completed, wrote all %d bytes\n", c);
    }

    /*
    *  Shut down the interface.
    */
    if(libnet_close_link_interface(network) == -1)
    {  
        libnet_error(LN_ERR_WARNING, "libnet_close_link_interface couldn't close the interface");
    }

    /*
    *  Free packet memory.
    */
    libnet_destroy_packet(&packet);

    return(c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
}

void usage(char *name)
{
    fprintf(stderr, "usage: %s [-i interface] -s s_ip -d d_ip\n", name);
}