1# 2# - Find libpcap 3# Find the native PCAP includes and library 4# 5# PCAP_INCLUDE_DIRS - where to find pcap.h, etc. 6# PCAP_LIBRARIES - List of libraries when using pcap. 7# PCAP_FOUND - True if pcap found. 8 9include(FindWSWinLibs) 10FindWSWinLibs("libpcap-*" "PCAP_HINTS") 11 12# 13# First, try pkg-config on platforms other than Windows. 14# 15if(NOT WIN32) 16 find_package(PkgConfig) 17 pkg_search_module(PC_PCAP libpcap) 18endif() 19 20if(NOT PC_PCAP_FOUND AND NOT WIN32) 21 # 22 # That didn't work. Try to retrieve hints from pcap-config. 23 # Do not use it on Windows as pcap-config is a shell script. 24 # 25 find_program(PCAP_CONFIG pcap-config) 26 if(PCAP_CONFIG) 27 # 28 # We have pcap-config; use it. 29 # 30 # First, get the include directory. 31 # 32 execute_process(COMMAND "${PCAP_CONFIG}" "--cflags" 33 RESULT_VARIABLE PCAP_CONFIG_RESULT 34 OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT 35 OUTPUT_STRIP_TRAILING_WHITESPACE 36 ) 37 if(NOT PCAP_CONFIG_RESULT EQUAL 0) 38 message(FATAL_ERROR "pcap-config --cflags failed") 39 endif() 40 # 41 # Assumes there's exactly one -I flag in the output 42 # of pcap-config --cflags. That *should* be the case. 43 # Note that the hint might be bogus, on macOS it could be 44 # -I/usr/local/include even though the header isn't 45 # there (it may be under /usr/include or it may be 46 # buried in the Xcode app bundle). 47 # 48 string(REGEX REPLACE "^-I" "" PCAP_CONFIG_INCLUDE_DIRS "${PCAP_CONFIG_OUTPUT}") 49 50 # Now, get the library search path. 51 execute_process(COMMAND "${PCAP_CONFIG}" "--libs" 52 RESULT_VARIABLE PCAP_CONFIG_RESULT 53 OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT 54 OUTPUT_STRIP_TRAILING_WHITESPACE 55 ) 56 if(NOT PCAP_CONFIG_RESULT EQUAL 0) 57 message(FATAL_ERROR "pcap-config --libs failed") 58 endif() 59 separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) 60 set(PCAP_CONFIG_LIBRARY_DIRS "") 61 foreach(_arg IN LISTS LIBS_LIST) 62 # At most one -L path is expected for -lpcap. 63 if(_arg MATCHES "^-L") 64 string(REGEX REPLACE "^-L" "" _dir ${_arg}) 65 list(APPEND PCAP_CONFIG_LIBRARY_DIRS ${_dir}) 66 endif() 67 endforeach() 68 69 if(UNIX AND CMAKE_FIND_LIBRARY_SUFFIXES STREQUAL ".a") 70 # Now, get the library directories and libraries for static linking. 71 # (XXX - what about AIX?) 72 execute_process(COMMAND "${PCAP_CONFIG}" "--libs" "--static" 73 RESULT_VARIABLE PCAP_CONFIG_RESULT 74 OUTPUT_VARIABLE PCAP_CONFIG_OUTPUT 75 ) 76 if(NOT PCAP_CONFIG_RESULT EQUAL 0) 77 message(FATAL_ERROR "pcap-config --libs --static failed") 78 endif() 79 separate_arguments(LIBS_LIST UNIX_COMMAND ${PCAP_CONFIG_OUTPUT}) 80 set(PCAP_CONFIG_STATIC_LIBRARY_DIRS "") 81 set(PCAP_CONFIG_STATIC_LIBRARIES "") 82 foreach(_arg IN LISTS LIBS_LIST) 83 if(_arg MATCHES "^-L") 84 # Add this directory to the library directory hints. 85 string(REGEX REPLACE "^-L" "" _dir ${_arg}) 86 list(APPEND PCAP_CONFIG_STATIC_LIBRARY_DIRS ${_dir}) 87 elseif(_arg MATCHES "^-l") 88 # Add this library to the requirements for static linking. 89 string(REGEX REPLACE "^-l" "" _lib ${_arg}) 90 list(APPEND PCAP_CONFIG_STATIC_LIBRARIES ${_lib}) 91 endif() 92 endforeach() 93 endif() 94 endif() 95endif() 96 97# 98# Locate the actual include directory. For pkg-config the 99# PC_PCAP_INCLUDE_DIRS variable could be empty if the default 100# header search path is sufficient to locate the header file. 101# For macOS, the directory returned by pcap-config is wrong, so 102# this will make sure to find a valid path. 103# 104find_path(PCAP_INCLUDE_DIR 105 NAMES 106 pcap/pcap.h 107 pcap.h 108 HINTS 109 ${PC_PCAP_INCLUDE_DIRS} 110 ${PCAP_CONFIG_INCLUDE_DIRS} 111 "${PCAP_HINTS}/Include" 112) 113 114# On Windows we load wpcap.dll explicitly and probe its functions in 115# capture\capture-wpcap.c. We don't want to link with pcap.lib since 116# that would bring in the non-capturing (null) pcap.dll from the vcpkg 117# library. 118if(WIN32) 119 set(_pkg_required_vars PCAP_INCLUDE_DIR) 120else() 121 find_library(PCAP_LIBRARY 122 NAMES 123 pcap 124 HINTS 125 ${PC_PCAP_LIBRARY_DIRS} 126 ${PCAP_CONFIG_LIBRARY_DIRS} 127 ) 128 set(_pkg_required_vars PCAP_LIBRARY PCAP_INCLUDE_DIR) 129endif() 130 131if(UNIX AND CMAKE_FIND_LIBRARY_SUFFIXES STREQUAL ".a") 132 # Try to find the static library (XXX - what about AIX?) 133 if(PC_PCAP_FOUND) 134 set(_pcap_static_libraries ${PC_PCAP_STATIC_LIBRARIES}) 135 elseif(PCAP_CONFIG) 136 set(_pcap_static_libraries ${PCAP_CONFIG_STATIC_LIBRARIES}) 137 else() 138 # 139 # No pkg-config nor pcap-config found, hope that this single library is 140 # sufficient for static linking. 141 # 142 set(_pcap_static_libraries pcap) 143 endif() 144 145 set(PCAP_STATIC_LIBRARIES "") 146 foreach(_lib IN LISTS _pcap_static_libraries) 147 # 148 # Try to find that library, so we get its full path, as 149 # we do with dynamic libraries. 150 # 151 string(MAKE_C_IDENTIFIER "PCAP_STATIC_${_lib}_LIBRARY" _libvar) 152 find_library(${_libvar} ${_lib} 153 HINTS 154 ${PC_PCAP_STATIC_LIBRARY_DIRS} 155 ${PCAP_CONFIG_STATIC_LIBRARY_DIRS} 156 ) 157 set(_libpath ${${_libvar}}) 158 if(_libpath) 159 list(APPEND PCAP_STATIC_LIBRARIES ${_libpath}) 160 endif() 161 endforeach() 162endif() 163 164include(FindPackageHandleStandardArgs) 165find_package_handle_standard_args(PCAP DEFAULT_MSG ${_pkg_required_vars}) 166mark_as_advanced(${_pkg_required_vars}) 167 168if(PCAP_FOUND) 169 set(PCAP_INCLUDE_DIRS ${PCAP_INCLUDE_DIR}) 170 if(UNIX AND CMAKE_FIND_LIBRARY_SUFFIXES STREQUAL ".a") 171 # Link with static libpcap and its transitive dependencies. 172 set(PCAP_LIBRARIES ${PCAP_STATIC_LIBRARIES}) 173 else() 174 set(PCAP_LIBRARIES ${PCAP_LIBRARY}) 175 endif() 176 177 #Functions 178 include( CMakePushCheckState ) 179 include( CheckFunctionExists ) 180 include( CheckVariableExists ) 181 182 cmake_push_check_state() 183 set( CMAKE_REQUIRED_INCLUDES ${PCAP_INCLUDE_DIRS} ) 184 set( CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARIES} ) 185 186 include(CheckSymbolExists) 187 188 if(WIN32) 189 # 190 # Prepopulate some values. WinPcap 3.1 and later, and Npcap, have these 191 # in their SDK, and compilation checks on Windows can be slow. We check 192 # whether they're present at run time, when we load wpcap.dll, and work 193 # around their absence or report an error. 194 # 195 set(HAVE_PCAP_FREECODE TRUE) 196 set(HAVE_PCAP_CREATE TRUE) 197 set(HAVE_PCAP_FREE_DATALINKS TRUE) 198 set(HAVE_PCAP_OPEN TRUE) 199 set(HAVE_PCAP_SETSAMPLING TRUE) 200 set(HAVE_PCAP_SET_TSTAMP_PRECISION TRUE) 201 set(HAVE_PCAP_SET_TSTAMP_TYPE TRUE) 202 else(WIN32) 203 # 204 # Make sure we have at least libpcap 0.8, because we we require at 205 # least libpcap 0.8's APIs. 206 # 207 # We check whether pcap_lib_version is defined in the pcap header, 208 # using it as a proxy for all the 0.8 API's. if not, we fail. 209 # 210 check_symbol_exists( pcap_lib_version ${PCAP_INCLUDE_DIR}/pcap.h HAVE_PCAP_LIB_VERSION ) 211 if( NOT HAVE_PCAP_LIB_VERSION ) 212 message(FATAL_ERROR "You need libpcap 0.8 or later") 213 endif( NOT HAVE_PCAP_LIB_VERSION ) 214 215 check_function_exists( "pcap_freecode" HAVE_PCAP_FREECODE ) 216 check_function_exists( "pcap_create" HAVE_PCAP_CREATE ) 217 check_function_exists( "pcap_free_datalinks" HAVE_PCAP_FREE_DATALINKS ) 218 check_function_exists( "pcap_open" HAVE_PCAP_OPEN ) 219 if( HAVE_PCAP_OPEN ) 220 # 221 # XXX - this *should* be checked for independently of checking 222 # for pcap_open(), as you might have pcap_setsampling() without 223 # remote capture support. 224 # 225 # However, 1) the sampling options are treated as remote options 226 # in the GUI and and 2) having pcap_setsampling() doesn't mean 227 # you have sampling support. libpcap needs a way to indicate 228 # whether a given device supports sampling, and the GUI should 229 # be changed to decouple them. 230 # 231 # (Actually, libpcap needs a general mechanism to offer options 232 # for particular devices, and Wireshark needs to use that 233 # mechanism. The former is a work in progress.) 234 # 235 # (Note: another work in progress is support for remote 236 # capturing using pcap_create()/pcap_activate(), which we 237 # also need to support once it's available.) 238 # 239 check_function_exists( "pcap_setsampling" HAVE_PCAP_SETSAMPLING ) 240 endif( HAVE_PCAP_OPEN ) 241 endif(WIN32) 242 243 if( HAVE_PCAP_CREATE ) 244 # 245 # If we have pcap_create(), we have pcap_set_buffer_size(), and 246 # can set the capture buffer size. 247 # 248 # Otherwise, if this is Windows, we have pcap_setbuff(), and can 249 # set the capture buffer size. 250 # 251 set( CAN_SET_CAPTURE_BUFFER_SIZE TRUE ) 252 endif() 253 check_function_exists( "pcap_set_tstamp_precision" HAVE_PCAP_SET_TSTAMP_PRECISION ) 254 check_function_exists( "pcap_set_tstamp_type" HAVE_PCAP_SET_TSTAMP_TYPE ) 255 # Remote pcap checks 256 if( HAVE_PCAP_OPEN ) 257 set( HAVE_PCAP_REMOTE 1 ) 258 endif() 259 260 cmake_pop_check_state() 261endif() 262 263if(PCAP_FOUND AND NOT TARGET pcap::pcap) 264 if(WIN32) 265 add_library(pcap::pcap INTERFACE IMPORTED) 266 set_target_properties(pcap::pcap PROPERTIES 267 INTERFACE_INCLUDE_DIRECTORIES "${PCAP_INCLUDE_DIRS}" 268 ) 269 else() 270 add_library(pcap::pcap UNKNOWN IMPORTED) 271 set_target_properties(pcap::pcap PROPERTIES 272 IMPORTED_LOCATION "${PCAP_LIBRARIES}" 273 INTERFACE_INCLUDE_DIRECTORIES "${PCAP_INCLUDE_DIRS}" 274 ) 275 endif() 276endif() 277