From 8104688879e4cdc1110fd302a282dbdf4295fe05 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 7 Feb 2023 09:40:54 +0100 Subject: [PATCH] wpcap/tests: Initial tests. --- configure | 1 + configure.ac | 1 + dlls/wpcap/tests/Makefile.in | 4 + dlls/wpcap/tests/wpcap.c | 374 +++++++++++++++++++++++++++++++++++ 4 files changed, 380 insertions(+) create mode 100644 dlls/wpcap/tests/Makefile.in create mode 100644 dlls/wpcap/tests/wpcap.c diff --git a/configure b/configure index aae3f417b67..6ff6d462894 100755 --- a/configure +++ b/configure @@ -21833,6 +21833,7 @@ wine_fn_config_makefile dlls/wow64win enable_wow64win wine_fn_config_makefile dlls/wpc enable_wpc wine_fn_config_makefile dlls/wpc/tests enable_tests wine_fn_config_makefile dlls/wpcap enable_wpcap +wine_fn_config_makefile dlls/wpcap/tests enable_tests wine_fn_config_makefile dlls/ws2_32 enable_ws2_32 wine_fn_config_makefile dlls/ws2_32/tests enable_tests wine_fn_config_makefile dlls/wsdapi enable_wsdapi diff --git a/configure.ac b/configure.ac index 3d996c34fae..84fadd08853 100644 --- a/configure.ac +++ b/configure.ac @@ -3201,6 +3201,7 @@ WINE_CONFIG_MAKEFILE(dlls/wow64win) WINE_CONFIG_MAKEFILE(dlls/wpc) WINE_CONFIG_MAKEFILE(dlls/wpc/tests) WINE_CONFIG_MAKEFILE(dlls/wpcap) +WINE_CONFIG_MAKEFILE(dlls/wpcap/tests) WINE_CONFIG_MAKEFILE(dlls/ws2_32) WINE_CONFIG_MAKEFILE(dlls/ws2_32/tests) WINE_CONFIG_MAKEFILE(dlls/wsdapi) diff --git a/dlls/wpcap/tests/Makefile.in b/dlls/wpcap/tests/Makefile.in new file mode 100644 index 00000000000..c2f8fce6da8 --- /dev/null +++ b/dlls/wpcap/tests/Makefile.in @@ -0,0 +1,4 @@ +TESTDLL = wpcap.dll + +C_SRCS = \ + wpcap.c diff --git a/dlls/wpcap/tests/wpcap.c b/dlls/wpcap/tests/wpcap.c new file mode 100644 index 00000000000..017d3b77a4e --- /dev/null +++ b/dlls/wpcap/tests/wpcap.c @@ -0,0 +1,374 @@ +/* + * Unit test for wpcap functions + * + * Copyright 2022 Hans Leidekker for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#define WIN32_NO_STATUS +#include + +#include "wine/test.h" + +#define PCAP_MMAP_32BIT 2 +#define PCAP_ERRBUF_SIZE 256 +#define PCAP_ERROR_PERM_DENIED -8 + +typedef struct pcap pcap_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_dumper pcap_dumper_t; + +struct pcap_if +{ + struct pcap_if *next; + char *name; +}; + +struct pcap_stat +{ + unsigned int ps_recv; + unsigned int ps_drop; + unsigned int ps_ifdrop; + unsigned int ps_capt; + unsigned int ps_sent; + unsigned int ps_netdrop; +}; + +struct bpf_insn +{ + unsigned short code; + unsigned char jt; + unsigned char jf; + unsigned int k; +}; + +struct bpf_program +{ + unsigned int bf_len; + struct bpf_insn *bf_insns; +}; + +struct pcap_pkthdr +{ + struct + { + int tv_sec; + int tv_usec; + } ts; + unsigned int caplen; + unsigned int len; +}; + +static int (CDECL *ppcap_activate)( pcap_t * ); +static void (CDECL *ppcap_breakloop)( pcap_t * ); +static int (CDECL *ppcap_bufsize)( pcap_t * ); +static int (CDECL *ppcap_can_set_rfmon)( pcap_t * ); +static void (CDECL *ppcap_close)( pcap_t * ); +static int (CDECL *ppcap_compile)( pcap_t *, struct bpf_program *, const char *, int, unsigned int ); +static pcap_t * (CDECL *ppcap_create)( const char *, char * ); +static int (CDECL *ppcap_datalink)( pcap_t * ); +static int (CDECL *ppcap_datalink_name_to_val)( const char * ); +static const char * (CDECL *ppcap_datalink_val_to_description)( int ); +static const char * (CDECL *ppcap_datalink_val_to_name)( int ); +static int (CDECL *ppcap_dispatch)( pcap_t *, int, + void (CALLBACK *)(unsigned char *, const struct pcap_pkthdr *, const unsigned char *), + unsigned char * ); +static pcap_dumper_t * (CDECL *ppcap_dump_open)( pcap_t *, const char * ); +static void (CDECL *ppcap_dump)( unsigned char *, const struct pcap_pkthdr *, const unsigned char * ); +static void (CDECL *ppcap_dump_close)( pcap_dumper_t * ); +static int (CDECL *ppcap_findalldevs)( pcap_if_t **, char * ); +static void (CDECL *ppcap_freealldevs)( pcap_if_t * ); +static void (CDECL *ppcap_free_datalinks)( int * ); +static void (CDECL *ppcap_free_tstamp_types)( int * ); +static void (CDECL *ppcap_freecode)( struct bpf_program * ); +static void * (CDECL *ppcap_get_airpcap_handle)( pcap_t * ); +static int (CDECL *ppcap_get_tstamp_precision)( pcap_t * ); +static char * (CDECL *ppcap_geterr)( pcap_t * ); +static int (CDECL *ppcap_getnonblock)( pcap_t *, char * ); +static int (CDECL *ppcap_init)( unsigned int, char * ); +static const char * (CDECL *ppcap_lib_version)( void ); +static int (CDECL *ppcap_list_datalinks)( pcap_t *, int ** ); +static int (CDECL *ppcap_list_tstamp_types)( pcap_t *, int ** ); +static char * (CDECL *ppcap_lookupdev)( char * ); +static int (CDECL *ppcap_lookupnet)( const char *, unsigned int *, unsigned int *, char * ); +static int (CDECL *ppcap_loop)( pcap_t *, int, + void (CALLBACK *)(unsigned char *, const struct pcap_pkthdr *, const unsigned char *), + unsigned char * ); +static int (CDECL *ppcap_set_buffer_size)( pcap_t *, int ); +static int (CDECL *ppcap_set_datalink)( pcap_t *, int ); +static int (CDECL *ppcap_set_promisc)( pcap_t *, int ); +static int (CDECL *ppcap_set_timeout)( pcap_t *, int ); +static int (CDECL *ppcap_set_tstamp_precision)( pcap_t *, int ); +static int (CDECL *ppcap_setfilter)( pcap_t *, struct bpf_program * ); +static int (CDECL *ppcap_snapshot)( pcap_t * ); +static int (CDECL *ppcap_stats)( pcap_t *, struct pcap_stat * ); +static int CDECL (*ppcap_tstamp_type_name_to_val)( const char * ); +static const char * (CDECL *ppcap_tstamp_type_val_to_description)( int ); +static const char * (CDECL *ppcap_tstamp_type_val_to_name)( int ); + +static void CALLBACK capture_callback( unsigned char *user, const struct pcap_pkthdr *hdr, const unsigned char *bytes ) +{ + trace( "user %p hdr %p byte %p\n", user, hdr, bytes ); +} + +static void test_capture( void ) +{ + char errbuf[PCAP_ERRBUF_SIZE], *dev, *err; + pcap_t *pcap; + void *aircap; + struct pcap_stat stats; + unsigned int net, mask; + struct bpf_program program; + int ret, *links, *types; + + dev = ppcap_lookupdev( errbuf ); + ok( dev != NULL, "got NULL (%s)\n", errbuf ); + + pcap = ppcap_create( dev, errbuf ); + ok( pcap != NULL, "got NULL (%s)\n", errbuf ); + + ret = ppcap_set_promisc( pcap, 1 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_set_timeout( pcap, 100 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_set_tstamp_precision( pcap, 0 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_can_set_rfmon( pcap ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_getnonblock( pcap, errbuf ); + ok( ret == -3, "got %d\n", ret ); + + ret = ppcap_datalink( pcap ); + ok( ret == -3, "got %d\n", ret ); + + err = ppcap_geterr( pcap ); + ok( err != NULL, "got NULL\n" ); + + ret = ppcap_set_buffer_size( pcap, 2097152 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_activate( pcap ); + if (ret == PCAP_ERROR_PERM_DENIED) + { + skip( "no permission\n" ); + ppcap_close( pcap ); + return; + } + ok( !ret, "got %d\n", ret ); + + ret = ppcap_set_buffer_size( pcap, 256000 ); + ok( ret == -4, "got %d\n", ret ); + + ret = ppcap_bufsize( pcap ); + ok( ret > 0, "got %d\n", ret ); + + ret = ppcap_getnonblock( pcap, errbuf ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_get_tstamp_precision( pcap ); + trace( "pcap_get_tstamp_precision %d\n", ret ); + + ret = ppcap_datalink( pcap ); + trace( "pcap_datalink %d\n", ret ); + + links = NULL; + ret = ppcap_list_datalinks( pcap, &links ); + ok( ret > 0, "got %d\n", ret ); + ok( links != NULL, "got NULL\n" ); + + ret = ppcap_set_datalink( pcap, links[0] ); + ok( !ret, "got %d\n", ret ); + ppcap_free_datalinks( links ); + + types = NULL; + ret = ppcap_list_tstamp_types( pcap, &types ); + ok( ret > 0, "got %d\n", ret ); + ok( types != NULL, "got NULL\n" ); + ppcap_free_tstamp_types( types ); + + net = mask = 0; + ret = ppcap_lookupnet( dev, &net, &mask, errbuf ); + ok( !ret, "got %d\n", ret ); + + memset( &program, 0, sizeof(program) ); + ret = ppcap_compile( pcap, &program, "", 1, 0xffffff ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_setfilter( pcap, &program ); + ok( !ret, "got %d\n", ret ); + ppcap_freecode( &program ); + + ret = ppcap_snapshot( pcap ); + ok( ret > 0, "got %d\n", ret ); + + ret = ppcap_dispatch( pcap, 1, capture_callback, NULL ); + ok( ret >= 0, "got %d\n", ret ); + + aircap = ppcap_get_airpcap_handle( pcap ); + ok( aircap == NULL, "got %p\n", aircap ); + + memset( &stats, 0, sizeof(stats) ); + ret = ppcap_stats( pcap, &stats ); + ok( !ret, "got %d\n", ret ); + ppcap_close( pcap ); +} + +static void test_datalink( void ) +{ + const char *str; + int ret; + + str = ppcap_datalink_val_to_name( 0 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "NULL"), "got %s\n", wine_dbgstr_a(str) ); + + ret = ppcap_datalink_name_to_val( str ); + ok( !ret, "got %d\n", ret ); + + str = ppcap_datalink_val_to_description( 0 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "BSD loopback"), "got %s\n", wine_dbgstr_a(str) ); + + str = ppcap_datalink_val_to_name( 1 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "EN10MB"), "got %s\n", wine_dbgstr_a(str) ); + + ret = ppcap_datalink_name_to_val( str ); + ok( ret == 1, "got %d\n", ret ); + + str = ppcap_datalink_val_to_description( 1 ); + ok( str != NULL, "got NULL\n" ); + ok( !strcmp(str, "Ethernet"), "got %s\n", wine_dbgstr_a(str) ); +} + +static void CALLBACK dump_callback( unsigned char *user, const struct pcap_pkthdr *hdr, const unsigned char *bytes ) +{ + trace( "user %p hdr %p bytes %p\n", user, hdr, bytes ); + ppcap_dump( user, hdr, bytes ); +} + +static void test_dump( void ) +{ + char errbuf[PCAP_ERRBUF_SIZE], path[MAX_PATH], filename[MAX_PATH]; + pcap_t *pcap; + pcap_if_t *devs; + pcap_dumper_t *dumper; + int ret; + + devs = NULL; + ret = ppcap_findalldevs( &devs, errbuf ); + ok( !ret, "got %d (%s)\n", ret, errbuf ); + ok( devs != NULL, "got NULL\n" ); + + pcap = ppcap_create( devs->name, errbuf ); + ok( pcap != NULL, "got NULL (%s)\n", errbuf ); + + ret = ppcap_set_timeout( pcap, 100 ); + ok( !ret, "got %d\n", ret ); + + ret = ppcap_activate( pcap ); + if (ret == PCAP_ERROR_PERM_DENIED) + { + skip( "no permission\n" ); + ppcap_freealldevs( devs ); + ppcap_close( pcap ); + return; + } + ok( !ret, "got %d\n", ret ); + + ret = ppcap_bufsize( pcap ); + ok( ret > 0, "got %d\n", ret ); + + GetTempPathA( sizeof(path), path ); + GetTempFileNameA( path, "cap", 0, filename ); + + dumper = ppcap_dump_open( pcap, filename ); + ok( dumper != NULL, "got NULL\n" ); + + ret = ppcap_dispatch( pcap, 1, dump_callback, NULL ); + ok( ret >= 0, "got %d\n", ret ); + + ppcap_dump_close( dumper ); + ppcap_freealldevs( devs ); + ppcap_close( pcap ); + DeleteFileA( filename ); +} + +START_TEST( wpcap ) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + HMODULE module = LoadLibraryW( L"wpcap.dll" ); + if (!module) + { + win_skip( "wpcap.dll not found\n" ); + return; + } + ppcap_activate = (void *)GetProcAddress( module, "pcap_activate" ); + ppcap_breakloop = (void *)GetProcAddress( module, "pcap_breakloop" ); + ppcap_bufsize = (void *)GetProcAddress( module, "pcap_bufsize" ); + ppcap_can_set_rfmon = (void *)GetProcAddress( module, "pcap_can_set_rfmon" ); + ppcap_close = (void *)GetProcAddress( module, "pcap_close" ); + ppcap_compile = (void *)GetProcAddress( module, "pcap_compile" ); + ppcap_create = (void *)GetProcAddress( module, "pcap_create" ); + ppcap_datalink = (void *)GetProcAddress( module, "pcap_datalink" ); + ppcap_datalink_name_to_val = (void *)GetProcAddress( module, "pcap_datalink_name_to_val" ); + ppcap_datalink_val_to_description = (void *)GetProcAddress( module, "pcap_datalink_val_to_description" ); + ppcap_datalink_val_to_name = (void *)GetProcAddress( module, "pcap_datalink_val_to_name" ); + ppcap_dispatch = (void *)GetProcAddress( module, "pcap_dispatch" ); + ppcap_dump_open = (void *)GetProcAddress( module, "pcap_dump_open" ); + ppcap_dump = (void *)GetProcAddress( module, "pcap_dump" ); + ppcap_dump_close = (void *)GetProcAddress( module, "pcap_dump_close" ); + ppcap_get_airpcap_handle = (void *)GetProcAddress( module, "pcap_get_airpcap_handle" ); + ppcap_get_tstamp_precision = (void *)GetProcAddress( module, "pcap_get_tstamp_precision" ); + ppcap_geterr = (void *)GetProcAddress( module, "pcap_geterr" ); + ppcap_getnonblock = (void *)GetProcAddress( module, "pcap_getnonblock" ); + ppcap_findalldevs = (void *)GetProcAddress( module, "pcap_findalldevs" ); + ppcap_freealldevs = (void *)GetProcAddress( module, "pcap_freealldevs" ); + ppcap_free_datalinks = (void *)GetProcAddress( module, "pcap_free_datalinks" ); + ppcap_free_tstamp_types = (void *)GetProcAddress( module, "pcap_free_tstamp_types" ); + ppcap_freecode = (void *)GetProcAddress( module, "pcap_freecode" ); + ppcap_init = (void *)GetProcAddress( module, "pcap_init" ); + ppcap_lib_version = (void *)GetProcAddress( module, "pcap_lib_version" ); + ppcap_list_datalinks = (void *)GetProcAddress( module, "pcap_list_datalinks" ); + ppcap_list_tstamp_types = (void *)GetProcAddress( module, "pcap_list_tstamp_types" ); + ppcap_lookupdev = (void *)GetProcAddress( module, "pcap_lookupdev" ); + ppcap_lookupnet = (void *)GetProcAddress( module, "pcap_lookupnet" ); + ppcap_loop = (void *)GetProcAddress( module, "pcap_loop" ); + ppcap_set_buffer_size = (void *)GetProcAddress( module, "pcap_set_buffer_size" ); + ppcap_set_datalink = (void *)GetProcAddress( module, "pcap_set_datalink" ); + ppcap_set_promisc = (void *)GetProcAddress( module, "pcap_set_promisc" ); + ppcap_set_timeout = (void *)GetProcAddress( module, "pcap_set_timeout" ); + ppcap_set_tstamp_precision = (void *)GetProcAddress( module, "pcap_set_tstamp_precision" ); + ppcap_setfilter = (void *)GetProcAddress( module, "pcap_setfilter" ); + ppcap_snapshot = (void *)GetProcAddress( module, "pcap_snapshot" ); + ppcap_stats = (void *)GetProcAddress( module, "pcap_stats" ); + ppcap_tstamp_type_name_to_val = (void *)GetProcAddress( module, "pcap_tstamp_type_name_to_val" ); + ppcap_tstamp_type_val_to_description = (void *)GetProcAddress( module, "pcap_tstamp_type_val_to_description" ); + ppcap_tstamp_type_val_to_name = (void *)GetProcAddress( module, "pcap_tstamp_type_val_to_name" ); + + trace( "lib version %s\n", ppcap_lib_version() ); + trace( "supports PCAP_MMAP_32BIT: %s\n", (ppcap_init(PCAP_MMAP_32BIT, errbuf) < 0) ? "no" : "yes" ); + + test_capture(); + test_datalink(); + test_dump(); +}