- Minimum CMake version: 3.1.0
- Minimum G++ version: 4.8 - Minimum Visual Studio version: VS2012 - Added '-std=c++11' flag to G++ - Removed unused defines - Removed checks for standard library headers - Added CMake detections of '_vsnprintf' and '_snprintf' for Visual Studio 2015 - Removed bnpcap - Force Travis CI to use CMake 3.1.3 and G++5
This commit is contained in:
parent
98f7165e21
commit
ae45207b29
11 changed files with 187 additions and 1065 deletions
15
.travis.yml
15
.travis.yml
|
@ -1,15 +1,22 @@
|
|||
sudo: required
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
os: linux
|
||||
compiler: gcc
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update --fix-missing
|
||||
- sudo apt-get install build-essential zlib1g-dev libmysqlclient-dev liblua5.1-0-dev
|
||||
- (cd /tmp && wget http://www.cmake.org/files/v3.1/cmake-3.1.3.tar.gz && tar zxf cmake-3.1.3.tar.gz)
|
||||
- (cd /tmp/cmake-3.1.3 && cmake . && make && sudo make install) > /dev/null 2>&1
|
||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get -qq install g++-5
|
||||
- export CXX="g++-5" CC="gcc-5"
|
||||
- mkdir build
|
||||
- cd build
|
||||
|
||||
|
@ -17,4 +24,4 @@ script:
|
|||
- cmake -D WITH_MYSQL=true -D WITH_LUA=true ../
|
||||
- make
|
||||
- sudo make install
|
||||
- sudo make uninstall
|
||||
- sudo make uninstall
|
|
@ -1,9 +1,5 @@
|
|||
# Required cmake version
|
||||
cmake_minimum_required(VERSION 2.4.3)
|
||||
|
||||
if(COMMAND cmake_policy)
|
||||
cmake_policy(SET CMP0003 NEW)
|
||||
endif(COMMAND cmake_policy)
|
||||
cmake_minimum_required(VERSION 3.1.0)
|
||||
|
||||
# Put the include dirs which are in the source or build tree
|
||||
# before all other include dirs, so the headers in the sources
|
||||
|
@ -11,17 +7,16 @@ endif(COMMAND cmake_policy)
|
|||
# since cmake 2.4.1
|
||||
set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
|
||||
|
||||
project(pvpgn)
|
||||
project(pvpgn CXX)
|
||||
|
||||
option(WITH_BNETD "compile the bnetd target" ON)
|
||||
option(WITH_D2CS "compile the d2cs target" ON)
|
||||
option(WITH_D2DBS "compile the d2dbs target" ON)
|
||||
option(WITH_ANSI "enforce strict ISO C++ conforming" ON)
|
||||
if(WIN32)
|
||||
option(WITH_WIN32_GUI "enable GUI building (default on)" ON)
|
||||
endif(WIN32)
|
||||
|
||||
option(WITH_LUA "enable Lua support" OFF)
|
||||
if(WIN32)
|
||||
option(WITH_WIN32_GUI "enable GUI building (default on)" ON)
|
||||
endif(WIN32)
|
||||
|
||||
#storage backends flags
|
||||
option(WITH_MYSQL "include MySQL user accounts support" OFF)
|
||||
|
@ -32,29 +27,22 @@ include(ConfigureChecks.cmake)
|
|||
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
# Determine GCC version.
|
||||
message("Determining GCC version.")
|
||||
EXEC_PROGRAM(${CMAKE_CXX_COMPILER}
|
||||
ARGS --version
|
||||
OUTPUT_VARIABLE _GCC_VERSION)
|
||||
STRING(REGEX REPLACE ".* ([0-9])\\.([0-9])\\.([0-9]) .*" "\\1\\2\\3"
|
||||
_GCC_VERSION ${_GCC_VERSION})
|
||||
message(" GCC version is ${_GCC_VERSION}")
|
||||
|
||||
# Add -Wno-longlong if the GCC version is < 4.0.0. Add -pedantic flag
|
||||
# but disable warnings for variadic macros with GCC >= 4.0.0. Earlier
|
||||
# versions warn because of anonymous variadic macros in pedantic mode
|
||||
# but do not have a flag to disable these warnings.
|
||||
if (400 GREATER _GCC_VERSION)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-long-long")
|
||||
else (400 GREATER _GCC_VERSION)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wno-variadic-macros")
|
||||
endif (400 GREATER _GCC_VERSION)
|
||||
|
||||
# Pass CXX flags to flags.
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSEQAN_CXX_FLAGS_=\"${CMAKE_CXX_FLAGS}\"")
|
||||
endif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
# Minimum G++ version: 4.8
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
|
||||
message(FATAL_ERROR "G++ 4.8 or higher required")
|
||||
endif()
|
||||
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pedantic -Wno-variadic-macros")
|
||||
|
||||
# Pass CXX flags to flags.
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSEQAN_CXX_FLAGS_=\"${CMAKE_CXX_FLAGS}\"")
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17.0)
|
||||
message(FATAL_ERROR "Visual Studio 2012 or higher required")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
subdirs(src conf man files)
|
||||
if(WITH_LUA)
|
||||
|
|
|
@ -9,11 +9,10 @@ set(CMAKE_MODULE_PATH
|
|||
# include used modules
|
||||
include(DefineInstallationPaths)
|
||||
include(CheckIncludeFileCXX)
|
||||
include(CheckIncludeFilesCXX)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckTypeSizeCXX)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckMkdirArgs)
|
||||
|
||||
|
@ -35,9 +34,9 @@ else(WIN32)
|
|||
set(D2DBS_DEFAULT_CONF_FILE "${SYSCONFDIR}/d2dbs.conf")
|
||||
endif(WIN32)
|
||||
|
||||
enable_language(C)
|
||||
# library checks
|
||||
find_package(ZLIB REQUIRED)
|
||||
check_library_exists(pcap pcap_open_offline "" HAVE_LIBPCAP)
|
||||
check_library_exists(nsl gethostbyname "" HAVE_LIBNSL)
|
||||
check_library_exists(socket socket "" HAVE_LIBSOCKET)
|
||||
check_library_exists(resolv inet_aton "" HAVE_LIBRESOLV)
|
||||
|
@ -90,66 +89,74 @@ if(WIN32)
|
|||
SET(NETWORK_LIBRARIES ${NETWORK_LIBRARIES} ws2_32)
|
||||
endif(WIN32)
|
||||
|
||||
check_include_files_cxx("cassert;cctype;cerrno;cmath;climits;csignal;cstdarg;cstddef;cstdio;cstdlib;cstring;ctime;deque;exception;fstream;iomanip;iostream;limits;list;map;memory;sstream;stdexcept;string;utility;vector" HAVE_STD_HEADERS)
|
||||
if(NOT HAVE_STD_HEADERS)
|
||||
MESSAGE(FATAL_ERROR "Standard C90/C++98 header missing, you need a fully standard compliant compiler/enviroment.")
|
||||
endif(NOT HAVE_STD_HEADERS)
|
||||
|
||||
check_include_file_cxx(fcntl.h HAVE_FCNTL_H)
|
||||
check_include_file_cxx(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_file_cxx(sys/select.h HAVE_SYS_SELECT_H)
|
||||
check_include_file_cxx(unistd.h HAVE_UNISTD_H)
|
||||
check_include_file_cxx(sys/utsname.h HAVE_SYS_UTSNAME_H)
|
||||
check_include_file_cxx(sys/timeb.h HAVE_SYS_TIMEB_H)
|
||||
check_include_file_cxx(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_file_cxx(sys/param.h HAVE_SYS_PARAM_H)
|
||||
check_include_file_cxx(netinet/in.h HAVE_NETINET_IN_H)
|
||||
message(STATUS "Checking POSIX headers")
|
||||
check_include_file_cxx(arpa/inet.h HAVE_ARPA_INET_H)
|
||||
check_include_file_cxx(netdb.h HAVE_NETDB_H)
|
||||
check_include_file_cxx(termios.h HAVE_TERMIOS_H)
|
||||
check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file_cxx(sys/wait.h HAVE_SYS_WAIT_H)
|
||||
check_include_file_cxx(sys/ioctl.h HAVE_SYS_IOCTL_H)
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
check_include_file_cxx(sys/file.h HAVE_SYS_FILE_H)
|
||||
check_include_file_cxx(poll.h HAVE_POLL_H)
|
||||
check_include_file_cxx(sys/poll.h HAVE_SYS_POLL_H)
|
||||
check_include_file_cxx(sys/stropts.h HAVE_SYS_STROPTS_H)
|
||||
check_include_file_cxx(sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_file_cxx(pwd.h HAVE_PWD_H)
|
||||
check_include_file_cxx(grp.h HAVE_GRP_H)
|
||||
check_include_file_cxx(dir.h HAVE_DIR_H)
|
||||
check_include_file_cxx(dirent.h HAVE_DIRENT_H)
|
||||
check_include_file_cxx(ndir.h HAVE_NDIR_H)
|
||||
check_include_file_cxx(sys/ndir.h HAVE_SYS_NDIR_H)
|
||||
check_include_file_cxx(sys/dir.h HAVE_SYS_DIR_H)
|
||||
check_include_file_cxx(direct.h HAVE_DIRECT_H)
|
||||
check_include_file_cxx(grp.h HAVE_GRP_H)
|
||||
check_include_file_cxx(fcntl.h HAVE_FCNTL_H)
|
||||
check_include_file_cxx(netdb.h HAVE_NETDB_H)
|
||||
check_include_file_cxx(netinet/in.h HAVE_NETINET_IN_H)
|
||||
check_include_file_cxx(poll.h HAVE_POLL_H)
|
||||
check_include_file_cxx(pwd.h HAVE_PWD_H)
|
||||
check_include_file_cxx(sys/mman.h HAVE_SYS_MMAN_H)
|
||||
check_include_files_cxx("sys/types.h;sys/event.h" HAVE_SYS_EVENT_H)
|
||||
check_include_file_cxx(sys/epoll.h HAVE_SYS_EPOLL_H)
|
||||
check_include_file_cxx(sys/resource.h HAVE_SYS_RESOURCE_H)
|
||||
check_include_file_cxx(pcap.h HAVE_PCAP_H)
|
||||
check_include_file_cxx(sys/select.h HAVE_SYS_SELECT_H)
|
||||
check_include_file_cxx(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_file_cxx(sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_file_cxx(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file_cxx(sys/utsname.h HAVE_SYS_UTSNAME_H)
|
||||
check_include_file_cxx(sys/wait.h HAVE_SYS_WAIT_H)
|
||||
check_include_file_cxx(termios.h HAVE_TERMIOS_H)
|
||||
check_include_file_cxx(unistd.h HAVE_UNISTD_H)
|
||||
|
||||
message(STATUS "Checking optional POSIX/required SUS headers")
|
||||
check_include_file_cxx(sys/timeb.h HAVE_SYS_TIMEB_H)
|
||||
|
||||
message(STATUS "Checking FreeBSD-based headers")
|
||||
if (HAVE_SYS_TYPES_H)
|
||||
check_include_file_cxx(sys/event.h HAVE_SYS_EVENT_H)
|
||||
endif()
|
||||
check_include_file_cxx(sys/param.h HAVE_SYS_PARAM_H)
|
||||
|
||||
message(STATUS "Checking BSD headers")
|
||||
check_include_file_cxx(sys/file.h HAVE_SYS_FILE_H)
|
||||
|
||||
message(STATUS "Checking Linux headers")
|
||||
check_include_file_cxx(sys/epoll.h HAVE_SYS_EPOLL_H)
|
||||
|
||||
message(STATUS "Checking Win32 headers")
|
||||
check_include_file_cxx(windows.h HAVE_WINDOWS_H)
|
||||
check_include_file_cxx(winsock2.h HAVE_WINSOCK2_H)
|
||||
check_include_file_cxx(process.h HAVE_PROCESS_H)
|
||||
|
||||
check_type_size_cxx("unsigned char" SIZEOF_UNSIGNED_CHAR)
|
||||
check_type_size_cxx("unsigned short" SIZEOF_UNSIGNED_SHORT)
|
||||
check_type_size_cxx("unsigned int" SIZEOF_UNSIGNED_INT)
|
||||
check_type_size_cxx("unsigned long" SIZEOF_UNSIGNED_LONG)
|
||||
check_type_size_cxx("unsigned long long" SIZEOF_UNSIGNED_LONG_LONG)
|
||||
check_type_size_cxx("signed char" SIZEOF_SIGNED_CHAR)
|
||||
check_type_size_cxx("signed short" SIZEOF_SIGNED_SHORT)
|
||||
check_type_size_cxx("signed int" SIZEOF_SIGNED_INT)
|
||||
check_type_size_cxx("signed long" SIZEOF_SIGNED_LONG)
|
||||
check_type_size_cxx("signed long long" SIZEOF_SIGNED_LONG_LONG)
|
||||
message(STATUS "Checking other headers")
|
||||
check_include_file_cxx(dir.h HAVE_DIR_H)
|
||||
check_include_file_cxx(direct.h HAVE_DIRECT_H)
|
||||
check_include_file_cxx(ndir.h HAVE_NDIR_H)
|
||||
check_include_file_cxx(sys/dir.h HAVE_SYS_DIR_H)
|
||||
check_include_file_cxx(sys/ndir.h HAVE_SYS_NDIR_H)
|
||||
check_include_file_cxx(sys/poll.h HAVE_SYS_POLL_H)
|
||||
#Keep for now
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
|
||||
check_type_size("unsigned char" SIZEOF_UNSIGNED_CHAR)
|
||||
check_type_size("unsigned short" SIZEOF_UNSIGNED_SHORT)
|
||||
check_type_size("unsigned int" SIZEOF_UNSIGNED_INT)
|
||||
check_type_size("unsigned long" SIZEOF_UNSIGNED_LONG)
|
||||
check_type_size("unsigned long long" SIZEOF_UNSIGNED_LONG_LONG)
|
||||
check_type_size("signed char" SIZEOF_SIGNED_CHAR)
|
||||
check_type_size("signed short" SIZEOF_SIGNED_SHORT)
|
||||
check_type_size("signed int" SIZEOF_SIGNED_INT)
|
||||
check_type_size("signed long" SIZEOF_SIGNED_LONG)
|
||||
check_type_size("signed long long" SIZEOF_SIGNED_LONG_LONG)
|
||||
|
||||
check_function_exists(mmap HAVE_MMAP)
|
||||
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
check_function_exists(strdup HAVE_STRDUP)
|
||||
check_function_exists(strtoul HAVE_STRTOUL)
|
||||
check_function_exists(uname HAVE_UNAME)
|
||||
check_function_exists(uname HAVE_UNAME)
|
||||
check_function_exists(fork HAVE_FORK)
|
||||
check_function_exists(getpid HAVE_GETPID)
|
||||
check_function_exists(sigaction HAVE_SIGACTION)
|
||||
|
@ -189,9 +196,9 @@ check_function_exists(setitimer HAVE_SETITIMER)
|
|||
check_function_exists(epoll_create HAVE_EPOLL_CREATE)
|
||||
check_function_exists(getrlimit HAVE_GETRLIMIT)
|
||||
check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF)
|
||||
check_function_exists(_vsnprintf HAVE__VSNPRINTF)
|
||||
check_symbol_exists(_vsnprintf "stdio.h" HAVE__VSNPRINTF)
|
||||
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
|
||||
check_function_exists(_snprintf HAVE__SNPRINTF)
|
||||
check_symbol_exists(_snprintf "stdio.h" HAVE__SNPRINTF)
|
||||
check_function_exists(setpgrp HAVE_SETPGRP)
|
||||
check_function_exists(inet_aton HAVE_INET_ATON)
|
||||
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
# - Check if the files can be included
|
||||
#
|
||||
# CHECK_INCLUDE_FILES_CXX(INCLUDE VARIABLE)
|
||||
#
|
||||
# INCLUDE - list of files to include
|
||||
# VARIABLE - variable to return result
|
||||
#
|
||||
# The following variables may be set before calling this macro to
|
||||
# modify the way the check is run:
|
||||
#
|
||||
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
|
||||
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
|
||||
# CMAKE_REQUIRED_INCLUDES = list of include directories
|
||||
|
||||
MACRO(CHECK_INCLUDE_FILES_CXX INCLUDE VARIABLE)
|
||||
IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
|
||||
SET(CMAKE_CONFIGURABLE_FILE_CONTENT "/* */\n")
|
||||
IF(CMAKE_REQUIRED_INCLUDES)
|
||||
SET(CHECK_INCLUDE_FILES_CXX_INCLUDE_DIRS "-DINCLUDE_DIRECTORIES=${CMAKE_REQUIRED_INCLUDES}")
|
||||
ELSE(CMAKE_REQUIRED_INCLUDES)
|
||||
SET(CHECK_INCLUDE_FILES_CXX_INCLUDE_DIRS)
|
||||
ENDIF(CMAKE_REQUIRED_INCLUDES)
|
||||
SET(CHECK_INCLUDE_FILES_CXX_CONTENT "/* */\n")
|
||||
SET(MACRO_CHECK_INCLUDE_FILES_CXX_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
FOREACH(FILE ${INCLUDE})
|
||||
SET(CMAKE_CONFIGURABLE_FILE_CONTENT
|
||||
"${CMAKE_CONFIGURABLE_FILE_CONTENT}#include <${FILE}>\n")
|
||||
ENDFOREACH(FILE)
|
||||
SET(CMAKE_CONFIGURABLE_FILE_CONTENT
|
||||
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n\nint main(){return 0;}\n")
|
||||
CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
|
||||
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFiles.cxx" @ONLY IMMEDIATE)
|
||||
|
||||
MESSAGE(STATUS "Looking for include files ${VARIABLE}")
|
||||
TRY_COMPILE(${VARIABLE}
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckIncludeFiles.cxx
|
||||
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
|
||||
CMAKE_FLAGS
|
||||
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_INCLUDE_FILES_CXX_FLAGS}
|
||||
"${CHECK_INCLUDE_FILES_CXX_INCLUDE_DIRS}"
|
||||
OUTPUT_VARIABLE OUTPUT)
|
||||
IF(${VARIABLE})
|
||||
MESSAGE(STATUS "Looking for include files ${VARIABLE} - found")
|
||||
SET(${VARIABLE} 1 CACHE INTERNAL "Have include ${VARIABLE}")
|
||||
FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
|
||||
"Determining if files ${INCLUDE} "
|
||||
"exist passed with the following output:\n"
|
||||
"${OUTPUT}\n\n")
|
||||
ELSE(${VARIABLE})
|
||||
MESSAGE(STATUS "Looking for include files ${VARIABLE} - not found.")
|
||||
SET(${VARIABLE} "" CACHE INTERNAL "Have includes ${VARIABLE}")
|
||||
FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
||||
"Determining if files ${INCLUDE} "
|
||||
"exist failed with the following output:\n"
|
||||
"${OUTPUT}\nSource:\n${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
|
||||
ENDIF(${VARIABLE})
|
||||
ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
|
||||
ENDMACRO(CHECK_INCLUDE_FILES_CXX)
|
|
@ -3,89 +3,63 @@ IF (NOT APPLICATION_NAME)
|
|||
SET(APPLICATION_NAME ${PROJECT_NAME})
|
||||
ENDIF (NOT APPLICATION_NAME)
|
||||
|
||||
# Suffix for Linux
|
||||
SET(LIB_SUFFIX
|
||||
CACHE STRING "Define suffix of directory name (32/64)"
|
||||
)
|
||||
|
||||
SET(EXEC_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}"
|
||||
CACHE PATH "Base directory for executables and libraries"
|
||||
FORCE
|
||||
)
|
||||
SET(SHARE_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}/share"
|
||||
CACHE PATH "Base directory for files which go to share/"
|
||||
FORCE
|
||||
)
|
||||
|
||||
SET(DATA_INSTALL_PREFIX
|
||||
"${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The parent directory where applications can install their data" FORCE)
|
||||
# The following are directories where stuff will be installed to
|
||||
CACHE PATH "The parent directory where applications can install their data"
|
||||
FORCE
|
||||
)
|
||||
|
||||
SET(BIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/bin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)"
|
||||
FORCE
|
||||
)
|
||||
|
||||
#***********************************#
|
||||
|
||||
if(WIN32)
|
||||
SET(LOCALSTATE_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/var"
|
||||
CACHE PATH "The ${APPLICATION_NAME} local state install dir (default prefix/var)"
|
||||
FORCE
|
||||
)
|
||||
else()
|
||||
SET(LOCALSTATE_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/var/${APPLICATION_NAME}"
|
||||
CACHE PATH "The ${APPLICATION_NAME} local state install dir (default prefix/var)"
|
||||
FORCE
|
||||
)
|
||||
endif()
|
||||
|
||||
SET(MAN_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/man"
|
||||
CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)"
|
||||
FORCE
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
SET(SBIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)"
|
||||
FORCE
|
||||
)
|
||||
else(WIN32)
|
||||
else()
|
||||
SET(SBIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/sbin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)"
|
||||
FORCE
|
||||
)
|
||||
endif(WIN32)
|
||||
SET(LIB_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
|
||||
FORCE
|
||||
)
|
||||
SET(LIBEXEC_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/libexec"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
|
||||
FORCE
|
||||
)
|
||||
SET(PLUGIN_INSTALL_DIR
|
||||
"${LIB_INSTALL_DIR}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})"
|
||||
FORCE
|
||||
)
|
||||
SET(INCLUDE_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_PREFIX}/include"
|
||||
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
|
||||
FORCE
|
||||
)
|
||||
endif()
|
||||
|
||||
SET(DATA_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}"
|
||||
CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})"
|
||||
FORCE
|
||||
)
|
||||
SET(HTML_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/doc/HTML"
|
||||
CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
|
||||
FORCE
|
||||
)
|
||||
SET(ICON_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/icons"
|
||||
CACHE PATH "The icon install dir (default data/icons/)"
|
||||
FORCE
|
||||
)
|
||||
SET(SOUND_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/sounds"
|
||||
CACHE PATH "The install dir for sound files (default data/sounds)"
|
||||
FORCE
|
||||
)
|
||||
|
||||
SET(LOCALE_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/locale"
|
||||
CACHE PATH "The install dir for translations (default prefix/share/locale)"
|
||||
SET(SHARE_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}/share"
|
||||
CACHE PATH "Base directory for files which go to share/"
|
||||
FORCE
|
||||
)
|
||||
|
||||
|
@ -95,36 +69,10 @@ if(WIN32)
|
|||
CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default conf)"
|
||||
FORCE
|
||||
)
|
||||
else(WIN32)
|
||||
else()
|
||||
SET(SYSCONF_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/etc/${APPLICATION_NAME}"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)"
|
||||
FORCE
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
SET(MAN_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/man"
|
||||
CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)"
|
||||
FORCE
|
||||
)
|
||||
SET(INFO_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/info"
|
||||
CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)"
|
||||
FORCE
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
SET(LOCALSTATE_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/var"
|
||||
CACHE PATH "The ${APPLICATION_NAME} local state install dir (default prefix/var)"
|
||||
FORCE
|
||||
)
|
||||
else(WIN32)
|
||||
SET(LOCALSTATE_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/var/${APPLICATION_NAME}"
|
||||
CACHE PATH "The ${APPLICATION_NAME} local state install dir (default prefix/var)"
|
||||
FORCE
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
endif()
|
|
@ -15,12 +15,10 @@
|
|||
#cmakedefine HAVE_TERMIOS_H
|
||||
#cmakedefine HAVE_SYS_TYPES_H
|
||||
#cmakedefine HAVE_SYS_WAIT_H
|
||||
#cmakedefine HAVE_SYS_IOCTL_H
|
||||
#cmakedefine HAVE_STDINT_H
|
||||
#cmakedefine HAVE_SYS_FILE_H
|
||||
#cmakedefine HAVE_POLL_H
|
||||
#cmakedefine HAVE_SYS_POLL_H
|
||||
#cmakedefine HAVE_SYS_STROPTS_H
|
||||
#cmakedefine HAVE_SYS_STAT_H
|
||||
#cmakedefine HAVE_PWD_H
|
||||
#cmakedefine HAVE_GRP_H
|
||||
|
@ -34,7 +32,6 @@
|
|||
#cmakedefine HAVE_SYS_EVENT_H
|
||||
#cmakedefine HAVE_SYS_EPOLL_H
|
||||
#cmakedefine HAVE_SYS_RESOURCE_H
|
||||
#cmakedefine HAVE_PCAP_H
|
||||
#cmakedefine HAVE_WINDOWS_H
|
||||
#cmakedefine HAVE_WINSOCK2_H
|
||||
#cmakedefine HAVE_PROCESS_H
|
||||
|
|
|
@ -54,10 +54,6 @@ if(WITH_D2DBS)
|
|||
add_subdirectory(d2dbs)
|
||||
endif(WITH_D2DBS)
|
||||
|
||||
if(HAVE_PCAP_H AND HAVE_LIBPCAP)
|
||||
add_subdirectory(bnpcap)
|
||||
endif(HAVE_PCAP_H AND HAVE_LIBPCAP)
|
||||
|
||||
if(CMAKE_TESTING_ENABLED)
|
||||
add_subdirectory(test)
|
||||
endif(CMAKE_TESTING_ENABLED)
|
||||
|
|
|
@ -69,13 +69,13 @@ namespace pvpgn
|
|||
const char * commonfile = "common.xml"; // filename template, actually file name is "common-{lang}.xml"
|
||||
|
||||
/* Array with string translations, each string has array with pair language=translation
|
||||
{
|
||||
original = {
|
||||
{ language = translate },
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
{
|
||||
original = {
|
||||
{ language = translate },
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
*/
|
||||
std::map<std::string, std::map<t_gamelang, std::string> > translations = std::map<std::string, std::map<t_gamelang, std::string> >();
|
||||
|
||||
|
@ -232,7 +232,7 @@ namespace pvpgn
|
|||
// if not found then init
|
||||
//if (it == translations.end())
|
||||
// translations[original] = std::map<t_gamelang, const char *>();
|
||||
|
||||
|
||||
|
||||
// check if translate string has a reference to another translation
|
||||
if (pugi::xml_attribute attr = node.child("translate").attribute("refid"))
|
||||
|
@ -277,8 +277,8 @@ namespace pvpgn
|
|||
try
|
||||
{
|
||||
if (lang = conn_get_gamelang_localized(c))
|
||||
if (!(format = _find_string(fmt, lang)))
|
||||
format = fmt; // if not found use original
|
||||
if (!(format = _find_string(fmt, lang)))
|
||||
format = fmt; // if not found use original
|
||||
|
||||
output = fmt::format(format, args);
|
||||
|
||||
|
@ -314,7 +314,7 @@ namespace pvpgn
|
|||
extern const char * i18n_filename(const char * filename, t_tag gamelang)
|
||||
{
|
||||
// get language string
|
||||
char lang_str[sizeof(t_tag)+1];
|
||||
char lang_str[sizeof(t_tag) + 1];
|
||||
std::memset(lang_str, 0, sizeof(lang_str));
|
||||
tag_uint_to_str(lang_str, gamelang);
|
||||
|
||||
|
@ -343,8 +343,8 @@ namespace pvpgn
|
|||
return tag_str_to_uint(countries[0][0]);
|
||||
|
||||
for (int i = 0; i < (sizeof(countries) / sizeof(*countries)); i++)
|
||||
if (strcasecmp(code, countries[i][0]) == 0)
|
||||
return tag_str_to_uint(countries[i][1]);
|
||||
if (strcasecmp(code, countries[i][0]) == 0)
|
||||
return tag_str_to_uint(countries[i][1]);
|
||||
|
||||
return tag_str_to_uint(countries[0][1]); // default
|
||||
}
|
||||
|
@ -355,13 +355,13 @@ namespace pvpgn
|
|||
|
||||
// force localize by user country
|
||||
if (prefs_get_localize_by_country())
|
||||
if (const char * country = conn_get_country(c))
|
||||
lang = lang_find_by_country(country);
|
||||
if (const char * country = conn_get_country(c))
|
||||
lang = lang_find_by_country(country);
|
||||
|
||||
// if user set own language
|
||||
if (t_account * a = conn_get_account(c))
|
||||
if (const char * l = account_get_userlang(a))
|
||||
lang = tag_str_to_uint(l);
|
||||
if (const char * l = account_get_userlang(a))
|
||||
lang = tag_str_to_uint(l);
|
||||
|
||||
// FIXME: Russian text displays not correctly directly in game in non-russian Starcraft
|
||||
// but most Russians use English Starcraft.
|
||||
|
@ -369,10 +369,10 @@ namespace pvpgn
|
|||
//
|
||||
// Return English text in game for Russian
|
||||
if (t_clienttag clienttag = conn_get_clienttag(c))
|
||||
if (lang == GAMELANG_RUSSIAN_UINT && conn_get_game(c) &&
|
||||
(clienttag == CLIENTTAG_STARCRAFT_UINT || clienttag == CLIENTTAG_BROODWARS_UINT || clienttag == CLIENTTAG_STARJAPAN_UINT || clienttag == CLIENTTAG_SHAREWARE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLORTL_UINT || clienttag == CLIENTTAG_DIABLOSHR_UINT || clienttag == CLIENTTAG_WARCIIBNE_UINT))
|
||||
lang = GAMELANG_ENGLISH_UINT;
|
||||
if (lang == GAMELANG_RUSSIAN_UINT && conn_get_game(c) &&
|
||||
(clienttag == CLIENTTAG_STARCRAFT_UINT || clienttag == CLIENTTAG_BROODWARS_UINT || clienttag == CLIENTTAG_STARJAPAN_UINT || clienttag == CLIENTTAG_SHAREWARE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLORTL_UINT || clienttag == CLIENTTAG_DIABLOSHR_UINT || clienttag == CLIENTTAG_WARCIIBNE_UINT))
|
||||
lang = GAMELANG_ENGLISH_UINT;
|
||||
|
||||
|
||||
return lang;
|
||||
|
@ -437,41 +437,58 @@ namespace pvpgn
|
|||
|
||||
switch (gamelang)
|
||||
{
|
||||
case GAMELANG_RUSSIAN_UINT:
|
||||
// All Blizzard games except Warcraft 3
|
||||
if (clienttag == CLIENTTAG_STARCRAFT_UINT || clienttag == CLIENTTAG_BROODWARS_UINT || clienttag == CLIENTTAG_STARJAPAN_UINT || clienttag == CLIENTTAG_SHAREWARE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLORTL_UINT || clienttag == CLIENTTAG_DIABLOSHR_UINT || clienttag == CLIENTTAG_WARCIIBNE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLO2DV_UINT || clienttag == CLIENTTAG_DIABLO2XP_UINT)
|
||||
{
|
||||
convert_utf8_to_windows1251(buf, buf, MAX_MESSAGE_LEN);
|
||||
}
|
||||
// There is an additional conversion in Starcraft and Diablo 2
|
||||
if (clienttag == CLIENTTAG_STARCRAFT_UINT || clienttag == CLIENTTAG_BROODWARS_UINT || clienttag == CLIENTTAG_STARJAPAN_UINT || clienttag == CLIENTTAG_SHAREWARE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLO2DV_UINT || clienttag == CLIENTTAG_DIABLO2XP_UINT)
|
||||
{
|
||||
convert_windows1252_to_utf8(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
case GAMELANG_RUSSIAN_UINT:
|
||||
// All Blizzard games except Warcraft 3
|
||||
if (clienttag == CLIENTTAG_STARCRAFT_UINT || clienttag == CLIENTTAG_BROODWARS_UINT || clienttag == CLIENTTAG_STARJAPAN_UINT || clienttag == CLIENTTAG_SHAREWARE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLORTL_UINT || clienttag == CLIENTTAG_DIABLOSHR_UINT || clienttag == CLIENTTAG_WARCIIBNE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLO2DV_UINT || clienttag == CLIENTTAG_DIABLO2XP_UINT)
|
||||
{
|
||||
convert_utf8_to_windows1251(buf, buf, MAX_MESSAGE_LEN);
|
||||
}
|
||||
return buf;
|
||||
// There is an additional conversion in Starcraft and Diablo 2
|
||||
if (clienttag == CLIENTTAG_STARCRAFT_UINT || clienttag == CLIENTTAG_BROODWARS_UINT || clienttag == CLIENTTAG_STARJAPAN_UINT || clienttag == CLIENTTAG_SHAREWARE_UINT ||
|
||||
clienttag == CLIENTTAG_DIABLO2DV_UINT || clienttag == CLIENTTAG_DIABLO2XP_UINT)
|
||||
{
|
||||
convert_windows1252_to_utf8(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Text conversion for Russian text
|
||||
*/
|
||||
/*
|
||||
* Text conversion for Russian text
|
||||
*/
|
||||
#ifndef REGION_CONVERT_RUSSIAN
|
||||
|
||||
typedef struct ConvLetter {
|
||||
char win1251;
|
||||
int unicode;
|
||||
typedef struct ConvLetter
|
||||
{
|
||||
char win1251;
|
||||
int unicode;
|
||||
} Letter;
|
||||
|
||||
static Letter g_letters[] = { { 0x82, 0x201A }, { 0x83, 0x0453 }, { 0x84, 0x201E }, { 0x85, 0x2026 }, { 0x86, 0x2020 }, { 0x87, 0x2021 }, { 0x88, 0x20AC }, { 0x89, 0x2030 }, { 0x8A, 0x0409 }, { 0x8B, 0x2039 }, { 0x8C, 0x040A }, { 0x8D, 0x040C }, { 0x8E, 0x040B }, { 0x8F, 0x040F }, { 0x90, 0x0452 }, { 0x91, 0x2018 }, { 0x92, 0x2019 }, { 0x93, 0x201C }, { 0x94, 0x201D }, { 0x95, 0x2022 }, { 0x96, 0x2013 }, { 0x97, 0x2014 }, { 0x99, 0x2122 }, { 0x9A, 0x0459 }, { 0x9B, 0x203A }, { 0x9C, 0x045A }, { 0x9D, 0x045C }, { 0x9E, 0x045B }, { 0x9F, 0x045F }, { 0xA0, 0x00A0 }, { 0xA1, 0x040E }, { 0xA2, 0x045E }, { 0xA3, 0x0408 }, { 0xA4, 0x00A4 }, { 0xA5, 0x0490 }, { 0xA6, 0x00A6 }, { 0xA7, 0x00A7 }, { 0xA8, 0x0401 }, { 0xA9, 0x00A9 }, { 0xAA, 0x0404 }, { 0xAB, 0x00AB }, { 0xAC, 0x00AC }, { 0xAD, 0x00AD }, { 0xAE, 0x00AE }, { 0xAF, 0x0407 }, { 0xB0, 0x00B0 }, { 0xB1, 0x00B1 }, { 0xB2, 0x0406 }, { 0xB3, 0x0456 }, { 0xB4, 0x0491 }, { 0xB5, 0x00B5 }, { 0xB6, 0x00B6 }, { 0xB7, 0x00B7 }, { 0xB8, 0x0451 }, { 0xB9, 0x2116 }, { 0xBA, 0x0454 }, { 0xBB, 0x00BB }, { 0xBC, 0x0458 }, { 0xBD, 0x0405 }, { 0xBE, 0x0455 }, { 0xBF, 0x0457 } };
|
||||
|
||||
static Letter g_letters[] = {
|
||||
{ static_cast<char>(0x82), 0x201A }, { static_cast<char>(0x83), 0x0453 }, { static_cast<char>(0x84), 0x201E }, { static_cast<char>(0x85), 0x2026 },
|
||||
{ static_cast<char>(0x86), 0x2020 }, { static_cast<char>(0x87), 0x2021 }, { static_cast<char>(0x88), 0x20AC }, { static_cast<char>(0x89), 0x2030 },
|
||||
{ static_cast<char>(0x8A), 0x0409 }, { static_cast<char>(0x8B), 0x2039 }, { static_cast<char>(0x8C), 0x040A }, { static_cast<char>(0x8D), 0x040C },
|
||||
{ static_cast<char>(0x8E), 0x040B }, { static_cast<char>(0x8F), 0x040F }, { static_cast<char>(0x90), 0x0452 }, { static_cast<char>(0x91), 0x2018 },
|
||||
{ static_cast<char>(0x92), 0x2019 }, { static_cast<char>(0x93), 0x201C }, { static_cast<char>(0x94), 0x201D }, { static_cast<char>(0x95), 0x2022 },
|
||||
{ static_cast<char>(0x96), 0x2013 }, { static_cast<char>(0x97), 0x2014 }, { static_cast<char>(0x99), 0x2122 }, { static_cast<char>(0x9A), 0x0459 },
|
||||
{ static_cast<char>(0x9B), 0x203A }, { static_cast<char>(0x9C), 0x045A }, { static_cast<char>(0x9D), 0x045C }, { static_cast<char>(0x9E), 0x045B },
|
||||
{ static_cast<char>(0x9F), 0x045F }, { static_cast<char>(0xA0), 0x00A0 }, { static_cast<char>(0xA1), 0x040E }, { static_cast<char>(0xA2), 0x045E },
|
||||
{ static_cast<char>(0xA3), 0x0408 }, { static_cast<char>(0xA4), 0x00A4 }, { static_cast<char>(0xA5), 0x0490 }, { static_cast<char>(0xA6), 0x00A6 },
|
||||
{ static_cast<char>(0xA7), 0x00A7 }, { static_cast<char>(0xA8), 0x0401 }, { static_cast<char>(0xA9), 0x00A9 }, { static_cast<char>(0xAA), 0x0404 },
|
||||
{ static_cast<char>(0xAB), 0x00AB }, { static_cast<char>(0xAC), 0x00AC }, { static_cast<char>(0xAD), 0x00AD }, { static_cast<char>(0xAE), 0x00AE },
|
||||
{ static_cast<char>(0xAF), 0x0407 }, { static_cast<char>(0xB0), 0x00B0 }, { static_cast<char>(0xB1), 0x00B1 }, { static_cast<char>(0xB2), 0x0406 },
|
||||
{ static_cast<char>(0xB3), 0x0456 }, { static_cast<char>(0xB4), 0x0491 }, { static_cast<char>(0xB5), 0x00B5 }, { static_cast<char>(0xB6), 0x00B6 },
|
||||
{ static_cast<char>(0xB7), 0x00B7 }, { static_cast<char>(0xB8), 0x0451 }, { static_cast<char>(0xB9), 0x2116 }, { static_cast<char>(0xBA), 0x0454 },
|
||||
{ static_cast<char>(0xBB), 0x00BB }, { static_cast<char>(0xBC), 0x0458 }, { static_cast<char>(0xBD), 0x0405 }, { static_cast<char>(0xBE), 0x0455 },
|
||||
{ static_cast<char>(0xBF), 0x0457 } };
|
||||
|
||||
// https://code.google.com/p/convert-utf8-to-cp1251/
|
||||
int convert_utf8_to_windows1251(const char* utf8, char* windows1251, size_t n)
|
||||
{
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
add_executable(bnpcap bnpcap.cpp)
|
||||
target_link_libraries(bnpcap common pcap)
|
||||
|
||||
install(TARGETS bnpcap DESTINATION ${BINDIR})
|
|
@ -1,769 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001 Marco Ziech (mmz@gmx.net)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include "common/setup_before.h"
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
||||
#include <pcap.h>
|
||||
|
||||
#include "compat/pgetopt.h"
|
||||
#include "compat/psock.h"
|
||||
#include "common/init_protocol.h"
|
||||
#include "common/bnet_protocol.h"
|
||||
#include "common/udp_protocol.h"
|
||||
#include "common/packet.h"
|
||||
#include "common/eventlog.h"
|
||||
#include "common/hexdump.h"
|
||||
#include "common/list.h"
|
||||
#include "common/version.h"
|
||||
#include "common/util.h"
|
||||
#include "common/xalloc.h"
|
||||
#include "common/setup_after.h"
|
||||
|
||||
using namespace pvpgn;
|
||||
|
||||
/* FIXME: everywhere: add checks for NULL pointers */
|
||||
|
||||
char *filename = NULL;
|
||||
pcap_t *pc;
|
||||
char ebuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
|
||||
int bnpcap_dodebug = 0;
|
||||
int bnpcap_beverbose = 0;
|
||||
|
||||
unsigned int listen_port = 6112;
|
||||
|
||||
/********************* CONNECTIONS ********************/
|
||||
|
||||
typedef enum {
|
||||
tcp_state_none,
|
||||
tcp_state_syn,
|
||||
tcp_state_ack,
|
||||
tcp_state_ok
|
||||
} t_tcp_state;
|
||||
|
||||
typedef struct {
|
||||
/* It's IPV4 */
|
||||
unsigned int ip;
|
||||
unsigned short port;
|
||||
} t_bnpcap_addr;
|
||||
|
||||
/* To track connections ... */
|
||||
typedef struct {
|
||||
t_bnpcap_addr client;
|
||||
t_bnpcap_addr server;
|
||||
t_packet_class cclass;
|
||||
t_tcp_state tcpstate;
|
||||
int incomplete;
|
||||
int clientoff;
|
||||
t_packet *clientpkt;
|
||||
int serveroff;
|
||||
t_packet *serverpkt;
|
||||
t_list * packets;
|
||||
} t_bnpcap_conn;
|
||||
|
||||
typedef struct {
|
||||
t_packet_dir dir;
|
||||
struct timeval tv;
|
||||
unsigned int id;
|
||||
t_packet *p;
|
||||
} t_bnpcap_packet;
|
||||
|
||||
t_list * conns;
|
||||
t_list * udppackets;
|
||||
|
||||
struct timeval packettime;
|
||||
|
||||
static unsigned int current_packet_id = 1;
|
||||
|
||||
/*********************** HEADERS **********************/
|
||||
|
||||
/* FIXME: don't assume that's always true */
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
/************************** TCP ***********************/
|
||||
|
||||
typedef struct {
|
||||
u16 sport;
|
||||
u16 dport;
|
||||
u32 seqno;
|
||||
u32 ackno;
|
||||
u16 stuff; /* Data offset, various flags */
|
||||
u16 window;
|
||||
u16 checksum;
|
||||
u16 urgp; /* Urgent Pointer (if URG flag set) */
|
||||
/* options */
|
||||
} t_tcp_header_raw;
|
||||
|
||||
typedef struct {
|
||||
unsigned short sport;
|
||||
unsigned short dport;
|
||||
unsigned int seqno;
|
||||
unsigned int ackno;
|
||||
unsigned char doffset;
|
||||
unsigned short flags;
|
||||
#define TCP_URG 0x20 /* Urgent pointer field significant */
|
||||
#define TCP_ACK 0x10 /* Acknowlegdement field significant */
|
||||
#define TCP_PSH 0x08 /* Push function */
|
||||
#define TCP_RST 0x04 /* Reset connection */
|
||||
#define TCP_SYN 0x02 /* Synchronize sequence numbers */
|
||||
#define TCP_FIN 0x01 /* No more data from sender (finish) */
|
||||
unsigned short window;
|
||||
unsigned short checksum;
|
||||
unsigned short urgp;
|
||||
/* options */
|
||||
} t_tcp_header;
|
||||
|
||||
/******************************** UDP ************************/
|
||||
|
||||
typedef struct {
|
||||
u16 sport;
|
||||
u16 dport;
|
||||
u16 len;
|
||||
u16 checksum;
|
||||
} t_ip_udp_header_raw;
|
||||
|
||||
typedef struct {
|
||||
unsigned short sport;
|
||||
unsigned short dport;
|
||||
unsigned short len;
|
||||
unsigned short checksum;
|
||||
} t_ip_udp_header;
|
||||
|
||||
/******************************** IP *************************/
|
||||
|
||||
typedef struct {
|
||||
u8 versionihl;
|
||||
u8 tos;
|
||||
u16 len;
|
||||
u16 id;
|
||||
u16 flagsoffset;
|
||||
u8 ttl;
|
||||
u8 protocol;
|
||||
u16 checksum;
|
||||
u32 src;
|
||||
u32 dst;
|
||||
/* options */
|
||||
} t_ip_header_raw;
|
||||
|
||||
typedef struct {
|
||||
unsigned char version;
|
||||
unsigned char ihl;
|
||||
unsigned char tos;
|
||||
unsigned short len;
|
||||
unsigned short id;
|
||||
unsigned char flags;
|
||||
#define IP_DF 0x02 /* 1 == Don't fragment */
|
||||
#define IP_MF 0x01 /* 1 == More fragments */
|
||||
unsigned short offset;
|
||||
unsigned char ttl;
|
||||
unsigned char protocol;
|
||||
unsigned short checksum;
|
||||
unsigned int src;
|
||||
unsigned int dst;
|
||||
/* options */
|
||||
} t_ip_header;
|
||||
|
||||
/******************************* ETHERNET *****************************/
|
||||
|
||||
typedef struct {
|
||||
u8 dst[6]; /* Ethernet hardware address */
|
||||
u8 src[6]; /* Ethernet hardware address */
|
||||
u16 type; /* Ethernet_II: protocol type */
|
||||
/* FIXME: Ethernet [802.2|802.3|SNAP]: maybe something else (eg. length) */
|
||||
} t_ether_raw;
|
||||
|
||||
/************************************************************************/
|
||||
/************************* CONNECTION FUNCTIONS *************************/
|
||||
|
||||
static t_bnpcap_conn * bnpcap_conn_new(t_bnpcap_addr const *s, t_bnpcap_addr const *d)
|
||||
{
|
||||
t_bnpcap_conn * c;
|
||||
|
||||
c = (t_bnpcap_conn *)xmalloc(sizeof(t_bnpcap_conn)); /* avoid warning */
|
||||
if (!c) {
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "xalloc failed: %s", std::strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (d->port == listen_port || d->port == 6200) { /* FIXME: That's dirty: We assume the server is on port 6112 */
|
||||
std::memcpy(&c->client, s, sizeof(t_bnpcap_addr));
|
||||
std::memcpy(&c->server, d, sizeof(t_bnpcap_addr));
|
||||
}
|
||||
else {
|
||||
std::memcpy(&c->client, d, sizeof(t_bnpcap_addr));
|
||||
std::memcpy(&c->server, s, sizeof(t_bnpcap_addr));
|
||||
}
|
||||
c->cclass = packet_class_init;
|
||||
c->packets = list_create();
|
||||
c->incomplete = 0;
|
||||
c->tcpstate = tcp_state_none;
|
||||
c->clientoff = 0;
|
||||
c->clientpkt = NULL;
|
||||
c->serveroff = 0;
|
||||
c->serverpkt = NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void bnpcap_conn_set_class(t_bnpcap_conn *c, t_packet_class cclass)
|
||||
{
|
||||
c->cclass = cclass;
|
||||
}
|
||||
|
||||
static t_packet_class bnpcap_conn_get_class(t_bnpcap_conn *c)
|
||||
{
|
||||
return c->cclass;
|
||||
}
|
||||
|
||||
static t_bnpcap_conn * bnpcap_conn_find(t_bnpcap_addr const *s, t_bnpcap_addr const *d)
|
||||
{
|
||||
t_elem * curr;
|
||||
|
||||
LIST_TRAVERSE(conns, curr) {
|
||||
t_bnpcap_conn *c;
|
||||
|
||||
c = (t_bnpcap_conn*)elem_get_data(curr);
|
||||
if (((c->client.ip == s->ip) && (c->client.port == s->port)) &&
|
||||
((c->server.ip == d->ip) && (c->server.port == d->port))) {
|
||||
return c;
|
||||
}
|
||||
else if (((c->client.ip == d->ip) && (c->client.port == d->port)) &&
|
||||
((c->server.ip == s->ip) && (c->server.port == s->port))) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static t_packet_dir bnpcap_conn_get_dir(t_bnpcap_conn const * c, t_bnpcap_addr const *s, t_bnpcap_addr const *d)
|
||||
{
|
||||
if (((c->client.ip == s->ip) && (c->client.port == s->port)) &&
|
||||
((c->server.ip == d->ip) && (c->server.port == d->port)))
|
||||
return packet_dir_from_client;
|
||||
else
|
||||
return packet_dir_from_server;
|
||||
}
|
||||
|
||||
static int bnpcap_conn_add_packet(t_bnpcap_conn *c, t_bnpcap_packet *bp) {
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "id=%u ", bp->id);
|
||||
list_append_data(c->packets, bp);
|
||||
packet_add_ref(bp->p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnpcap_conn_packet(unsigned int sip, unsigned short sport, unsigned int dip, unsigned short dport, unsigned char const * data, unsigned int len)
|
||||
{
|
||||
t_bnpcap_addr s;
|
||||
t_bnpcap_addr d;
|
||||
t_bnpcap_conn *c;
|
||||
t_bnpcap_packet *bp;
|
||||
|
||||
s.ip = sip;
|
||||
s.port = sport;
|
||||
d.ip = dip;
|
||||
d.port = dport;
|
||||
|
||||
if ((c = bnpcap_conn_find(&s, &d))) {
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "adding packet to existing connection");
|
||||
if (c->tcpstate == tcp_state_ack) {
|
||||
c->tcpstate = tcp_state_ok;
|
||||
}
|
||||
else if (c->tcpstate == tcp_state_syn) {
|
||||
c->incomplete = 1; /* ACK missing */
|
||||
c->tcpstate = tcp_state_ok;
|
||||
}
|
||||
}
|
||||
else {
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "adding packet to incomplete connection");
|
||||
c = bnpcap_conn_new(&s, &d);
|
||||
bnpcap_conn_set_class(c, packet_class_raw); /* we don't know the init sequence */
|
||||
c->incomplete = 1;
|
||||
c->tcpstate = tcp_state_ok;
|
||||
list_append_data(conns, c);
|
||||
}
|
||||
if (c->tcpstate != tcp_state_ok) {
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "connection got packet in wrong state!");
|
||||
}
|
||||
if (bnpcap_conn_get_class(c) == packet_class_init) {
|
||||
if (len > 1) {
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "init packet larger than 1 byte");
|
||||
}
|
||||
switch (data[0]) {
|
||||
case CLIENT_INITCONN_CLASS_BNET:
|
||||
bnpcap_conn_set_class(c, packet_class_bnet);
|
||||
break;
|
||||
case CLIENT_INITCONN_CLASS_FILE:
|
||||
bnpcap_conn_set_class(c, packet_class_file);
|
||||
break;
|
||||
case 0xf7: // W3 matchmaking hack
|
||||
eventlog(eventlog_level_info, __FUNCTION__, "matchmaking packet");
|
||||
bnpcap_conn_set_class(c, packet_class_bnet);
|
||||
break;
|
||||
default:
|
||||
bnpcap_conn_set_class(c, packet_class_raw);
|
||||
}
|
||||
}
|
||||
else {
|
||||
t_packet *p;
|
||||
unsigned int off;
|
||||
unsigned char const *datap = data;
|
||||
int always_complete = 0;
|
||||
|
||||
|
||||
if (bnpcap_conn_get_class(c) == packet_class_raw)
|
||||
always_complete = 1; /* There is no size field */
|
||||
if (bnpcap_conn_get_class(c) == packet_class_file)
|
||||
always_complete = 1; /* Size field isn't always there */
|
||||
|
||||
if (always_complete) {
|
||||
/* packet is always complete */
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "packet is always complete (class=%d)", bnpcap_conn_get_class(c));
|
||||
bp = (t_bnpcap_packet *)xmalloc(sizeof(t_bnpcap_packet)); /* avoid warning */
|
||||
if (!bp) {
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "xalloc failed: %s", std::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
bp->dir = bnpcap_conn_get_dir(c, &s, &d);
|
||||
bp->p = packet_create(bnpcap_conn_get_class(c));
|
||||
bp->id = current_packet_id++;
|
||||
if (!bp->p) {
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "packet_create failed");
|
||||
return -1;
|
||||
}
|
||||
std::memcpy(&bp->tv, &packettime, sizeof(struct timeval));
|
||||
packet_set_size(bp->p, len);
|
||||
std::memcpy(packet_get_raw_data(bp->p, 0), data, len);
|
||||
bnpcap_conn_add_packet(c, bp);
|
||||
if ((packet_get_class(bp->p) == packet_class_file) && (packet_get_type(bp->p) == SERVER_FILE_REPLY)) {
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "file transfer initiated (setting to raw)");
|
||||
bnpcap_conn_set_class(c, packet_class_raw);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* read out saved state */
|
||||
if (bnpcap_conn_get_dir(c, &s, &d) == packet_dir_from_client) {
|
||||
p = c->clientpkt;
|
||||
off = c->clientoff;
|
||||
}
|
||||
else {
|
||||
p = c->serverpkt;
|
||||
off = c->serveroff;
|
||||
}
|
||||
while ((datap - data) < (signed)len) {
|
||||
if (!p) {
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "creating new packet");
|
||||
p = packet_create(bnpcap_conn_get_class(c));
|
||||
if (!p) {
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "packet_create failed");
|
||||
return -1;
|
||||
}
|
||||
packet_set_size(p, packet_get_header_size(p)); /* set it to the minimum for now */
|
||||
off = 0;
|
||||
}
|
||||
if (off < packet_get_header_size(p)) {
|
||||
unsigned int l = (packet_get_header_size(p) - off);
|
||||
/* (len-(datap-data)) : remaining bytes in buffer */
|
||||
if ((len - (datap - data)) < l)
|
||||
l = (len - (datap - data));
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "filling up header (adding %d to %d to get %d)", l, off, packet_get_header_size(p));
|
||||
std::memcpy(packet_get_raw_data(p, off), datap, l);
|
||||
datap = datap + l;
|
||||
off = off + l;
|
||||
}
|
||||
else {
|
||||
unsigned int l = (packet_get_size(p) - off);
|
||||
if ((len - (datap - data)) < l)
|
||||
l = (len - (datap - data));
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "filling up packet (0x%04x:%s) (adding %d to %d to get %d)", packet_get_type(p), packet_get_type_str(p, bnpcap_conn_get_dir(c, &s, &d)), l, off, packet_get_size(p));
|
||||
std::memcpy(packet_get_raw_data(p, off), datap, l);
|
||||
datap = datap + l;
|
||||
off = off + l;
|
||||
}
|
||||
if ((off >= packet_get_header_size(p)) && (off >= packet_get_size(p))) {
|
||||
/* packet is complete */
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "packet is complete");
|
||||
bp = (t_bnpcap_packet *)xmalloc(sizeof(t_bnpcap_packet)); /* avoid warning */
|
||||
if (!bp) {
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "xalloc failed: %s", std::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if ((off != packet_get_size(p)) && (bnpcap_dodebug)) {
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "packet size differs (%d != %d) (offset=0x%04lx)", off, packet_get_size(p), datap - data);
|
||||
hexdump(stderr, data, len);
|
||||
/* std::memcpy(packet_get_raw_data(p,0),data,packet_get_size(p)); */
|
||||
}
|
||||
bp->dir = bnpcap_conn_get_dir(c, &s, &d);
|
||||
bp->p = p;
|
||||
bp->id = current_packet_id++;
|
||||
std::memcpy(&bp->tv, &packettime, sizeof(struct timeval));
|
||||
bnpcap_conn_add_packet(c, bp);
|
||||
if (packet_get_size(p) == 0)
|
||||
datap = data + len; /* if size is invalid, drop the rest of the stream packet */
|
||||
p = NULL;
|
||||
off = 0;
|
||||
}
|
||||
} /* while */
|
||||
/* write back saved state */
|
||||
if ((off > 0) && (bnpcap_dodebug)) {
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "saving %d bytes in packet buffer (p=0x%08lx)", off, (long)p);
|
||||
}
|
||||
if (bnpcap_conn_get_dir(c, &s, &d) == packet_dir_from_client) {
|
||||
c->clientpkt = p;
|
||||
c->clientoff = off;
|
||||
}
|
||||
else {
|
||||
c->serverpkt = p;
|
||||
c->serveroff = off;
|
||||
}
|
||||
} /* !always_complete */
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/******************************** LAYERS ********************************/
|
||||
|
||||
/********************************* TCP **********************************/
|
||||
|
||||
static int bnpcap_tcp2tcp(t_tcp_header * d, t_tcp_header_raw const * s)
|
||||
{
|
||||
d->sport = htons(s->sport);
|
||||
d->dport = htons(s->dport);
|
||||
d->seqno = htonl(s->seqno);
|
||||
d->ackno = htonl(s->ackno);
|
||||
d->doffset = (htons(s->stuff) & 0xF000) >> 12;
|
||||
d->flags = (htons(s->stuff) & 0x0FFF);
|
||||
d->window = htons(s->window);
|
||||
d->checksum = htons(s->checksum);
|
||||
d->urgp = htons(s->urgp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnpcap_process_tcp(t_ip_header const * ip, unsigned char const *data, unsigned int len)
|
||||
{
|
||||
t_tcp_header_raw const *raw;
|
||||
t_tcp_header h;
|
||||
|
||||
raw = (t_tcp_header_raw const *)data; /* avoid warning */
|
||||
bnpcap_tcp2tcp(&h, raw);
|
||||
if (h.doffset < 5) {
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "tcp header too small (%u 32-bit words)", h.doffset);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
char fstr[32] = "";
|
||||
|
||||
if (h.flags & TCP_URG)
|
||||
std::strcat(fstr, "U");
|
||||
if (h.flags & TCP_ACK)
|
||||
std::strcat(fstr, "A");
|
||||
if (h.flags & TCP_PSH)
|
||||
std::strcat(fstr, "P");
|
||||
if (h.flags & TCP_RST)
|
||||
std::strcat(fstr, "R");
|
||||
if (h.flags & TCP_SYN)
|
||||
std::strcat(fstr, "S");
|
||||
if (h.flags & TCP_FIN)
|
||||
std::strcat(fstr, "F");
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "tcp: sport=%u dport=%u seqno=0x%08x ackno=0x%08x window=0x%08x len=%d (%s)", h.sport, h.dport, h.seqno, h.ackno, h.window, ((signed)len - (h.doffset * 4)), fstr);
|
||||
if (((signed)len - (h.doffset * 4)) <= 0) {
|
||||
eventlog(eventlog_level_info, __FUNCTION__, "empty packet (%d)", ((signed)len - (h.doffset * 4)));
|
||||
/* handle sync packets */
|
||||
if (h.flags & TCP_SYN) {
|
||||
t_bnpcap_addr s, d;
|
||||
|
||||
s.ip = ip->src; s.port = h.sport;
|
||||
d.ip = ip->dst; d.port = h.dport;
|
||||
if (h.flags & TCP_ACK) {
|
||||
t_bnpcap_conn *c = bnpcap_conn_find(&s, &d);
|
||||
|
||||
if (c) {
|
||||
if (c->tcpstate == tcp_state_syn)
|
||||
c->tcpstate = tcp_state_ack;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!bnpcap_conn_find(&s, &d)) {
|
||||
t_bnpcap_conn *c;
|
||||
|
||||
c = bnpcap_conn_new(&s, &d);
|
||||
c->tcpstate = tcp_state_syn;
|
||||
list_append_data(conns, c);
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "created new connection with SYN");
|
||||
}
|
||||
else {
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "got SYN in connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (((h.sport != listen_port) && (h.dport != listen_port)) && ((h.sport != 6200) && (h.dport != 6200))) {
|
||||
eventlog(eventlog_level_info, __FUNCTION__, "other packet (%d)", ((signed)len - (h.doffset * 4)));
|
||||
}
|
||||
else {
|
||||
eventlog(eventlog_level_info, __FUNCTION__, "valid packet (%d)", ((signed)len - (h.doffset * 4)));
|
||||
bnpcap_conn_packet(ip->src, h.sport, ip->dst, h.dport, data + (h.doffset * 4), len - (h.doffset * 4));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************ UDP ********************************/
|
||||
|
||||
static int bnpcap_udp2udp(t_ip_udp_header *d, t_ip_udp_header_raw const *s)
|
||||
{
|
||||
d->sport = ntohs(s->sport);
|
||||
d->dport = ntohs(s->dport);
|
||||
d->len = ntohs(s->len);
|
||||
d->checksum = ntohs(s->checksum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnpcap_process_udp(unsigned char const *data, unsigned int len)
|
||||
{
|
||||
t_ip_udp_header_raw const *raw;
|
||||
t_ip_udp_header h;
|
||||
t_bnpcap_packet *bp;
|
||||
|
||||
raw = (t_ip_udp_header_raw const *)data; /* avoid warning */
|
||||
bnpcap_udp2udp(&h, raw);
|
||||
|
||||
bp = (t_bnpcap_packet *)xmalloc(sizeof(t_bnpcap_packet)); /* avoid warning */
|
||||
if (!bp) {
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "xalloc failed: %s", std::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (h.dport == listen_port || h.dport == 6200) {
|
||||
bp->dir = packet_dir_from_client;
|
||||
}
|
||||
else {
|
||||
bp->dir = packet_dir_from_server;
|
||||
}
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "sport=%u dport=%u len=%u(%d)", h.sport, h.dport, h.len, len);
|
||||
bp->id = current_packet_id++;
|
||||
std::memcpy(&bp->tv, &packettime, sizeof(struct timeval));
|
||||
bp->p = packet_create(packet_class_udp);
|
||||
if (!bp->p) {
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "packet_create failed");
|
||||
return -1;
|
||||
}
|
||||
packet_set_size(bp->p, h.len - sizeof(t_ip_udp_header_raw));
|
||||
std::memcpy(packet_get_raw_data(bp->p, 0), data + sizeof(t_ip_udp_header_raw), h.len - sizeof(t_ip_udp_header_raw));
|
||||
eventlog(eventlog_level_error, __FUNCTION__, "id=%u ", bp->id);
|
||||
list_append_data(udppackets, bp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************ IP *********************************/
|
||||
|
||||
static int bnpcap_ip2ip(t_ip_header * d, t_ip_header_raw const * s)
|
||||
{
|
||||
d->version = ((s->versionihl & 0xf0) >> 4);
|
||||
d->ihl = s->versionihl & 0x0f;
|
||||
d->tos = s->tos;
|
||||
d->len = ntohs(s->len);
|
||||
d->id = ntohs(s->id);
|
||||
d->offset = ntohl(s->flagsoffset);
|
||||
d->flags = ((d->offset & 0xE000) >> 13);
|
||||
d->offset = ((d->offset & 0x1FFF));
|
||||
d->ttl = s->ttl;
|
||||
d->protocol = s->protocol;
|
||||
d->checksum = ntohs(s->checksum);
|
||||
d->src = ntohl(s->src);
|
||||
d->dst = ntohl(s->dst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int bnpcap_process_ip(unsigned char const *data, unsigned int len)
|
||||
{
|
||||
/* FIXME: handle IP fragmentation */
|
||||
/* FIXME: use identification field to pass the datagram in the right order */
|
||||
t_ip_header_raw const *raw;
|
||||
t_ip_header h;
|
||||
|
||||
raw = (t_ip_header_raw const *)data; /* avoid warning */
|
||||
bnpcap_ip2ip(&h, raw);
|
||||
if (h.version != 4) {
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "ip version %u not supported (ihl=%u, raw=0x%02x)", h.version, h.ihl, raw->versionihl);
|
||||
return 1;
|
||||
}
|
||||
else if (h.ihl < 5) {
|
||||
/* an IP header must be at least 5 words */
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "ip header to small (%u 32-bit words)", h.ihl);
|
||||
return 1;
|
||||
}
|
||||
else if (h.len > len) {
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "ip len larger than packet (%d > %d)", h.len, len);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
char fstr[32] = "";
|
||||
|
||||
if (h.flags & IP_DF)
|
||||
std::strcat(fstr, "D");
|
||||
if (h.flags & IP_MF)
|
||||
std::strcat(fstr, "M");
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "ip: len=%u(%u) src=%08x dst=%08x protocol=%u offset=0x%08x id=0x%08x (%s)", h.len, len, h.src, h.dst, h.protocol, h.offset, h.id, fstr);
|
||||
if (h.protocol == 6) {
|
||||
/* This is TCP */
|
||||
return bnpcap_process_tcp(&h, data + (h.ihl * 4), h.len - (h.ihl * 4));
|
||||
}
|
||||
else if (h.protocol == 17) {
|
||||
/* This is UDP */
|
||||
return bnpcap_process_udp(data + (h.ihl * 4), h.len - (h.ihl * 4));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************* ETHERNET ******************************/
|
||||
|
||||
static int bnpcap_process_ether(unsigned char const *data, unsigned int len)
|
||||
{ /* Well, first parse the ethernet header (I hope you use Ethernet_II :) ... */
|
||||
t_ether_raw const *raw;
|
||||
|
||||
raw = (t_ether_raw const *)data; /* avoid warning */
|
||||
if (ntohs(raw->type) == 0x0800) {
|
||||
/* This is IP */
|
||||
return bnpcap_process_ip(data + sizeof(t_ether_raw), len - sizeof(t_ether_raw));
|
||||
}
|
||||
else {
|
||||
eventlog(eventlog_level_warn, __FUNCTION__, "unsupported protocol 0x%04x", ntohs(raw->type));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If you want to use other hardware protocols like PPP add them here ... */
|
||||
|
||||
/**************************** PACKET/PCAP *********************************/
|
||||
|
||||
static void bnpcap_process_packet(u_char * private_, const struct pcap_pkthdr * p, u_char const * data)
|
||||
{
|
||||
unsigned int pl = p->len;
|
||||
|
||||
if (private_) private_ = NULL; // hack to eliminate compiler warning
|
||||
|
||||
std::memcpy(&packettime, &p->ts, sizeof(struct timeval));
|
||||
eventlog(eventlog_level_debug, __FUNCTION__, "packet: len=%d caplen=%d", p->len, p->caplen);
|
||||
/* FIXME: check if it's ethernet */
|
||||
bnpcap_process_ether(data, pl);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void bnpcap_usage(void) {
|
||||
std::printf("BNPCAP - A tool to convert pcap battle.net dumps to a human-readable format.\n");
|
||||
std::printf("Version " PVPGN_VERSION " --- Copyright (c) 2001 Marco Ziech (mmz@gmx.net)\n");
|
||||
std::printf("This software makes use of libpcap.\n\n");
|
||||
std::printf("Usage: bnpcap [-d] [-v] [-p PORT] <pcap-filename>\n");
|
||||
std::printf(" -d Print out debugging information\n");
|
||||
std::printf(" -v Be more verbose\n");
|
||||
std::printf(" -p PORT Specify port to process (Default: 6112)\n\n");
|
||||
}
|
||||
|
||||
/******************************* MAIN *************************************/
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
t_elem * currconn;
|
||||
t_elem * currudp;
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "dvp:")) != -1) {
|
||||
switch (c) {
|
||||
case 'p':
|
||||
str_to_uint(optarg, &listen_port);
|
||||
break;
|
||||
case 'd':
|
||||
bnpcap_dodebug = 1;
|
||||
break;
|
||||
case 'v':
|
||||
bnpcap_beverbose = 1;
|
||||
break;
|
||||
case '?':
|
||||
std::printf("unrecognized option '%c'\n", optopt);
|
||||
break;
|
||||
default:
|
||||
std::printf("getopt returned \'%c\'\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
filename = argv[optind];
|
||||
}
|
||||
else {
|
||||
bnpcap_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
pc = pcap_open_offline(filename, ebuf);
|
||||
if (!pc) {
|
||||
std::fprintf(stderr, "pcap_open_offline: %s\n", ebuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eventlog_set(stderr);
|
||||
eventlog_clear_level();
|
||||
if (bnpcap_dodebug)
|
||||
eventlog_add_level("debug");
|
||||
if (bnpcap_beverbose || bnpcap_dodebug)
|
||||
eventlog_add_level("info");
|
||||
eventlog_add_level("warn");
|
||||
eventlog_add_level("error");
|
||||
eventlog_add_level("fatal");
|
||||
|
||||
conns = list_create();
|
||||
udppackets = list_create();
|
||||
pcap_dispatch(pc, 0, bnpcap_process_packet, NULL);
|
||||
|
||||
std::printf("### This packet dump was created by bnpcap.\n");
|
||||
LIST_TRAVERSE(conns, currconn) {
|
||||
t_bnpcap_conn *c;
|
||||
char cstr[64];
|
||||
char sstr[64];
|
||||
t_elem * currpacket;
|
||||
|
||||
c = (t_bnpcap_conn*)elem_get_data(currconn);
|
||||
snprintf(cstr, 64, "%u.%u.%u.%u:%u", ((c->client.ip & 0xFF000000) >> 24), ((c->client.ip & 0x00FF0000) >> 16), ((c->client.ip & 0x0000FF00) >> 8), ((c->client.ip & 0x000000FF)), c->client.port);
|
||||
snprintf(sstr, 64, "%u.%u.%u.%u:%u", ((c->server.ip & 0xFF000000) >> 24), ((c->server.ip & 0x00FF0000) >> 16), ((c->server.ip & 0x0000FF00) >> 8), ((c->server.ip & 0x000000FF)), c->server.port);
|
||||
std::printf("## %s connection: client=%s server=%s\n", (c->incomplete ? "incomplete" : "complete"), cstr, sstr);
|
||||
LIST_TRAVERSE(c->packets, currpacket) {
|
||||
t_bnpcap_packet * bp;
|
||||
|
||||
bp = (t_bnpcap_packet*)elem_get_data(currpacket);
|
||||
std::printf("# %u packet from %s: type=0x%04x(%s) length=%d class=%s\n", bp->id/*bp->tv.tv_sec*/, (bp->dir == packet_dir_from_client ? "client" : "server"), packet_get_type(bp->p), packet_get_type_str(bp->p, bp->dir), packet_get_size(bp->p), packet_get_class_str(bp->p));
|
||||
hexdump(stdout, packet_get_raw_data(bp->p, 0), packet_get_size(bp->p));
|
||||
std::printf("\n");
|
||||
}
|
||||
}
|
||||
std::printf("## udp packets\n");
|
||||
LIST_TRAVERSE(udppackets, currudp) {
|
||||
t_bnpcap_packet *bp;
|
||||
|
||||
bp = (t_bnpcap_packet*)elem_get_data(currudp);
|
||||
std::printf("# %u packet from %s: type=0x%04x(%s) length=%d class=%s\n", bp->id/*bp->tv.tv_sec*/, (bp->dir == packet_dir_from_client ? "client" : "server"), packet_get_type(bp->p), packet_get_type_str(bp->p, bp->dir), packet_get_size(bp->p), packet_get_class_str(bp->p));
|
||||
hexdump(stdout, packet_get_raw_data(bp->p, 0), packet_get_size(bp->p));
|
||||
std::printf("\n");
|
||||
}
|
||||
pcap_close(pc);
|
||||
return 0;
|
||||
}
|
|
@ -416,9 +416,6 @@
|
|||
# define HAVE_SYS_FILE_H 1
|
||||
#endif
|
||||
|
||||
/* Define if you have the <sys/ioctl.h> header file. */
|
||||
/* #undef HAVE_SYS_IOCTL_H */
|
||||
|
||||
/* Define if you have the <sys/mman.h> header file. */
|
||||
/* #undef HAVE_SYS_MMAN_H */
|
||||
|
||||
|
@ -445,9 +442,6 @@
|
|||
/* Define if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define if you have the <sys/stropts.h> header file. */
|
||||
/* #undef HAVE_SYS_STROPTS_H */
|
||||
|
||||
/* Define if you have the <sys/time.h> header file. */
|
||||
/* #undef HAVE_SYS_TIME_H */ /* MinGW has this header, but confilcts with compat/gettimeofday.h */
|
||||
|
||||
|
|
Loading…
Reference in a new issue