Susant Sahani ffba215
/*
Susant Sahani ffba215
# SPDX-License-Identifier: LGPL-2.1+
Susant Sahani ffba215
# ~~~
Susant Sahani ffba215
#   Description: libpcap tests
Susant Sahani ffba215
#
Susant Sahani ffba215
#   Author: Susant Sahani <susant@redhat.com>
Susant Sahani ffba215
#   Copyright (c) 2018 Red Hat, Inc.
Susant Sahani ffba215
# ~~~
Susant Sahani ffba215
*/
Susant Sahani ffba215
#include <stdlib.h>
Susant Sahani ffba215
#include <stdarg.h>
Susant Sahani ffba215
#include <string.h>
Susant Sahani ffba215
#include <netinet/in.h>
Susant Sahani ffba215
#include <setjmp.h>
Susant Sahani ffba215
#include <inttypes.h>
Susant Sahani ffba215
#include <cmocka.h>
Susant Sahani ffba215
#include <netdb.h>
Susant Sahani ffba215
#include <arpa/inet.h>
Susant Sahani ffba215
#include <errno.h>
Susant Sahani ffba215
#include <unistd.h>
Susant Sahani ffba215
#include <libnet.h>
Susant Sahani ffba215
#include <netinet/if_ether.h>
Susant Sahani ffba215
#include <sys/socket.h>
Susant Sahani ffba215
#include <netinet/ip.h>
Susant Sahani ffba215
#include <netinet/in.h>
Susant Sahani ffba215
#include <netinet/tcp.h>
Susant Sahani ffba215
#include <arpa/inet.h>
Susant Sahani ffba215
#include <netinet/if_ether.h>
Susant Sahani ffba215
#include <pcap.h>
Susant Sahani ffba215
#include <pthread.h>
Susant Sahani ffba215
#include <sys/time.h>
Susant Sahani ffba215
Susant Sahani ffba215
#define PCAP_FILE "/var/run/libpcap-test.pcap"
Susant Sahani ffba215
Susant Sahani ffba215
pcap_t *handle;
Susant Sahani ffba215
Susant Sahani ffba215
struct UDP_hdr {
Susant Sahani ffba215
        u_short uh_sport;               /* source port */
Susant Sahani ffba215
        u_short uh_dport;               /* destination port */
Susant Sahani ffba215
        u_short uh_ulen;                /* datagram length */
Susant Sahani ffba215
        u_short uh_sum;                 /* datagram checksum */
Susant Sahani ffba215
};
Susant Sahani ffba215
Susant Sahani ffba215
static void assert_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
Susant Sahani ffba215
        unsigned int ipl;
Susant Sahani ffba215
        uint32_t src, dst;
Susant Sahani ffba215
        struct ip *ip;
Susant Sahani ffba215
        struct ether_header *eth_header;
Susant Sahani ffba215
Susant Sahani ffba215
        eth_header = (struct ether_header *) packet;
Susant Sahani ffba215
        if (ntohs(eth_header->ether_type) != ETHERTYPE_IP)
Susant Sahani ffba215
                return;
Susant Sahani ffba215
Susant Sahani ffba215
        packet += sizeof(struct ether_header);
Susant Sahani ffba215
        ip = (struct ip *) packet;
Susant Sahani ffba215
        ipl = ip->ip_hl * 4;
Susant Sahani ffba215
Susant Sahani ffba215
        src = inet_addr("192.168.50.6");
Susant Sahani ffba215
        dst = inet_addr("192.168.50.5");
Susant Sahani ffba215
Susant Sahani ffba215
        assert_memory_equal(&dst, &ip->ip_dst, sizeof(uint32_t));
Susant Sahani ffba215
        assert_memory_equal(&src, &ip->ip_src, sizeof(uint32_t));
Susant Sahani ffba215
Susant Sahani ffba215
        if (ip->ip_p == IPPROTO_UDP) {
Susant Sahani ffba215
                struct UDP_hdr *udp;
Susant Sahani ffba215
Susant Sahani ffba215
                packet += ipl;
Susant Sahani ffba215
Susant Sahani ffba215
                udp = (struct UDP_hdr *) packet;
Susant Sahani ffba215
Susant Sahani ffba215
                printf("UDP src_port=%d dst_port=%d\n", ntohs(udp->uh_sport), ntohs(udp->uh_dport));
Susant Sahani ffba215
Susant Sahani ffba215
                assert_int_equal(2425, ntohs(udp->uh_sport));
Susant Sahani ffba215
                assert_int_equal(2426, ntohs(udp->uh_dport));
Susant Sahani ffba215
        } else if (ip->ip_p == IPPROTO_TCP) {
Susant Sahani ffba215
                struct tcphdr *tcp;
Susant Sahani ffba215
                packet += ipl;
Susant Sahani ffba215
Susant Sahani ffba215
                tcp = (struct tcphdr *) packet;
Susant Sahani ffba215
Susant Sahani ffba215
                printf("TCP src_port=%d dst_port=%d\n", ntohs(tcp->th_sport), ntohs(tcp->th_dport));
Susant Sahani ffba215
Susant Sahani ffba215
                assert_int_equal(2425, ntohs(tcp->th_sport));
Susant Sahani ffba215
                assert_int_equal(2426, ntohs(tcp->th_dport));
Susant Sahani ffba215
        }
Susant Sahani ffba215
}
Susant Sahani ffba215
Susant Sahani ffba215
void *capture_packet_live(void *ptr) {
Susant Sahani ffba215
        char dev[] = "veth-test";
Susant Sahani ffba215
        char error_buffer[PCAP_ERRBUF_SIZE];
Susant Sahani ffba215
        struct bpf_program filter;
Susant Sahani ffba215
        bpf_u_int32 subnet_mask, ip;
Susant Sahani ffba215
        int total_packet_count;
Susant Sahani ffba215
        int r;
Susant Sahani ffba215
Susant Sahani ffba215
        r = pcap_lookupnet(dev, &ip, &subnet_mask, error_buffer);
Susant Sahani ffba215
        assert_true(r >=0);
Susant Sahani ffba215
Susant Sahani ffba215
        handle = pcap_open_live(dev, BUFSIZ, 1, 1000, error_buffer);
Susant Sahani ffba215
        assert_non_null(handle);
Susant Sahani ffba215
Susant Sahani ffba215
        r = pcap_compile(handle, &filter, ptr, 0, ip);
Susant Sahani ffba215
        assert_true(r >= 0);
Susant Sahani ffba215
Susant Sahani ffba215
        r = pcap_setfilter(handle, &filter);
Susant Sahani ffba215
        assert_true(r >= 0);
Susant Sahani ffba215
Susant Sahani ffba215
        pcap_loop(handle, total_packet_count, assert_packet, NULL);
Susant Sahani ffba215
Susant Sahani ffba215
        return 0;
Susant Sahani ffba215
}
Susant Sahani ffba215
Susant Sahani ffba215
void terminate_thread(int signum) {
Susant Sahani ffba215
Susant Sahani ffba215
        pcap_breakloop(handle);
Susant Sahani ffba215
        pcap_close(handle);
Susant Sahani ffba215
Susant Sahani ffba215
        handle = NULL;
Susant Sahani ffba215
        pthread_exit(NULL);
Susant Sahani ffba215
}
Susant Sahani ffba215
Susant Sahani ffba215
static void test_udp_packet_ipv4(void **state) {
Susant Sahani ffba215
        char dst[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
Susant Sahani ffba215
        char src[6] = {0x12,0x34,0x56,0x78,0x9a,0xab};
Susant Sahani ffba215
        char err_buf[LIBNET_ERRBUF_SIZE] = {};
Susant Sahani ffba215
        char buf[1024] = {};
Susant Sahani ffba215
        libnet_t* l;
Susant Sahani ffba215
        int r, i;
Susant Sahani ffba215
        uint32_t len;
Susant Sahani ffba215
        pthread_t pcap_thread;
Susant Sahani ffba215
        struct itimerval tval;
Susant Sahani ffba215
Susant Sahani ffba215
        timerclear(& tval.it_interval); /* zero interval means no reset of timer */
Susant Sahani ffba215
        timerclear(& tval.it_value);
Susant Sahani ffba215
        tval.it_value.tv_sec = 10;      /* 10 second timeout */
Susant Sahani ffba215
Susant Sahani ffba215
        (void) signal(SIGALRM, terminate_thread);
Susant Sahani ffba215
        (void) setitimer(ITIMER_REAL, & tval, NULL);
Susant Sahani ffba215
Susant Sahani ffba215
        r = pthread_create(&pcap_thread, NULL, capture_packet_live, "udp port 2425");
Susant Sahani ffba215
        assert_true(r >=0);
Susant Sahani ffba215
Susant Sahani ffba215
        l = libnet_init(LIBNET_LINK_ADV, "veth-peer", err_buf);
Susant Sahani ffba215
        assert_non_null(l);
Susant Sahani ffba215
        len = sprintf(buf, "1:1:1111111111111:32:hello world%d", 1);
Susant Sahani ffba215
Susant Sahani ffba215
        for (i = 0; i < 5; i++) {
Susant Sahani ffba215
Susant Sahani ffba215
                r = libnet_build_udp(2425, 2426, len + 8, 0, buf, len, l, 0);
Susant Sahani ffba215
                assert_true(r >= 0);
Susant Sahani ffba215
Susant Sahani ffba215
                r = libnet_build_ipv4(20 + 8 + len, 0, 0, 0, 128, 17, 0, inet_addr("192.168.50.6"), inet_addr("192.168.50.5"), NULL, 0, l, 0);
Susant Sahani ffba215
                assert_true(r >= 0);
Susant Sahani ffba215
Susant Sahani ffba215
                r = libnet_build_ethernet(dst, src, 0x0800, NULL, 0, l, 0);
Susant Sahani ffba215
                assert_true(r >= 0);
Susant Sahani ffba215
Susant Sahani ffba215
                r = libnet_write(l);
Susant Sahani ffba215
                assert_true(r >= 0);
Susant Sahani ffba215
Susant Sahani ffba215
                sleep(1);
Susant Sahani ffba215
        }
Susant Sahani ffba215
Susant Sahani ffba215
        libnet_destroy(l);
Susant Sahani ffba215
}
Susant Sahani ffba215
Susant Sahani ffba215
static void test_tcp_packet_ipv4(void **state) {
Susant Sahani ffba215
        char dst[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
Susant Sahani ffba215
        char src[6] = {0x12,0x34,0x56,0x78,0x9a,0xab};
Susant Sahani ffba215
        char errbuf[LIBNET_ERRBUF_SIZE];
Susant Sahani ffba215
        uint8_t *payload, payload_s;
Susant Sahani ffba215
        libnet_ptag_t tcp, ip, eth;
Susant Sahani ffba215
        int c, i, j, seqn, ack;
Susant Sahani ffba215
        char buf[1024] = {};
Susant Sahani ffba215
        pthread_t pcap_thread;
Susant Sahani ffba215
        struct itimerval tval;
Susant Sahani ffba215
        uint32_t len;
Susant Sahani ffba215
        libnet_t *l;
Susant Sahani ffba215
        int r;
Susant Sahani ffba215
Susant Sahani ffba215
        timerclear(& tval.it_interval);
Susant Sahani ffba215
        timerclear(& tval.it_value);
Susant Sahani ffba215
        tval.it_value.tv_sec = 10;
Susant Sahani ffba215
Susant Sahani ffba215
        (void) signal(SIGALRM, terminate_thread);
Susant Sahani ffba215
        (void) setitimer(ITIMER_REAL, & tval, NULL);
Susant Sahani ffba215
Susant Sahani ffba215
        r = pthread_create(&pcap_thread, NULL, capture_packet_live, "tcp port 2425");
Susant Sahani ffba215
        assert_true(r >=0);
Susant Sahani ffba215
Susant Sahani ffba215
        payload_s = 10;
Susant Sahani ffba215
        payload = malloc(payload_s*sizeof(uint8_t));
Susant Sahani ffba215
        assert_non_null(payload);
Susant Sahani ffba215
        memset(payload,0,payload_s);
Susant Sahani ffba215
Susant Sahani ffba215
        l = libnet_init(LIBNET_LINK, "veth-peer", errbuf);
Susant Sahani ffba215
        assert_non_null(l);
Susant Sahani ffba215
Susant Sahani ffba215
        tcp = ip = eth = LIBNET_PTAG_INITIALIZER;
Susant Sahani ffba215
        for (i=0; i<5; i++){
Susant Sahani ffba215
                seqn=i * (LIBNET_TCP_H+payload_s + 1);
Susant Sahani ffba215
                r = libnet_build_tcp(2425, 2426, seqn, seqn + LIBNET_TCP_H + payload_s + 1,
Susant Sahani ffba215
                                     TH_SYN, 32767, 0, 10, LIBNET_TCP_H + payload_s,
Susant Sahani ffba215
                                     payload, payload_s, l, tcp);
Susant Sahani ffba215
                assert_true(r >=0);
Susant Sahani ffba215
Susant Sahani ffba215
                r = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_TCP_H + payload_s,0,242,0,64,IPPROTO_TCP,0,
Susant Sahani ffba215
                                      inet_addr("192.168.50.6"), inet_addr("192.168.50.5"),
Susant Sahani ffba215
                                      NULL,0,l,ip);
Susant Sahani ffba215
                assert_true(r >=0);
Susant Sahani ffba215
Susant Sahani ffba215
                r = libnet_build_ethernet(dst, src, ETHERTYPE_IP, NULL, 0, l, eth);
Susant Sahani ffba215
                assert_true(r >=0);
Susant Sahani ffba215
Susant Sahani ffba215
                r = libnet_write(l);
Susant Sahani ffba215
                assert_true(r >=0);
Susant Sahani ffba215
Susant Sahani ffba215
                sleep(1);
Susant Sahani ffba215
        }
Susant Sahani ffba215
}
Susant Sahani ffba215
Susant Sahani ffba215
int main(int argc, char *argv[]) {
Susant Sahani ffba215
        const struct CMUnitTest libpcap_tests[] = {
Susant Sahani ffba215
                                                   cmocka_unit_test(test_udp_packet_ipv4),
Susant Sahani ffba215
                                                   cmocka_unit_test(test_tcp_packet_ipv4),
Susant Sahani ffba215
        };
Susant Sahani ffba215
Susant Sahani ffba215
        return cmocka_run_group_tests(libpcap_tests, NULL, NULL);
Susant Sahani ffba215
}