pax_global_header00006660000000000000000000000064147702503330014516gustar00rootroot0000000000000052 comment=e4ca22d542bc36a4027d09f1b307949c6d54b8d9 logswan-2.1.15/000077500000000000000000000000001477025033300132565ustar00rootroot00000000000000logswan-2.1.15/.gitignore000066400000000000000000000000061477025033300152420ustar00rootroot00000000000000build logswan-2.1.15/AUTHORS000066400000000000000000000001421477025033300143230ustar00rootroot00000000000000Logswan is developed by: Frederic Cambus Site: https://www.cambus.net logswan-2.1.15/CMakeLists.txt000066400000000000000000000052601477025033300160210ustar00rootroot00000000000000# # Logswan 2.1.15 # Copyright (c) 2015-2025, Frederic Cambus # https://www.logswan.org # # Created: 2015-05-31 # Last Updated: 2025-03-24 # # Logswan is released under the BSD 2-Clause license. # See LICENSE file for details. # # SPDX-License-Identifier: BSD-2-Clause # cmake_minimum_required(VERSION 3.10) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) project(logswan C) include(CheckFunctionExists) include(GNUInstallDirs) # Conditional build options set(ENABLE_SECCOMP 0 CACHE BOOL "Enable building with seccomp") # Check if system has pledge and strtonum list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_OPENBSD_SOURCE) check_function_exists(pledge HAVE_PLEDGE) check_function_exists(strtonum HAVE_STRTONUM) if(ENABLE_SECCOMP) # Check if system has seccomp message(STATUS "Looking for seccomp") find_path(SECCOMP NAMES "linux/seccomp.h") if(SECCOMP) message(STATUS "Looking for seccomp - found") add_definitions(-DHAVE_SECCOMP) else() message(STATUS "Looking for seccomp - not found") endif() endif(ENABLE_SECCOMP) # Additional include directories for compat functions + dependencies include_directories("compat") include_directories("deps/hll") # libmaxminddb find_path(GEOIP2_INCLUDE_DIRS maxminddb.h) find_library(GEOIP2_LIBRARIES NAMES maxminddb REQUIRED) include_directories(${GEOIP2_INCLUDE_DIRS}) # Jansson find_path(JANSSON_INCLUDE_DIRS jansson.h) find_library(JANSSON_LIBRARIES NAMES jansson REQUIRED) include_directories(${JANSSON_INCLUDE_DIRS}) set(DEPS deps/hll/hll.c deps/MurmurHash3/MurmurHash3.c) set(SRC src/logswan.c src/config.c src/continents.c src/countries.c src/output.c src/parse.c) if(NOT HAVE_PLEDGE) set(SRC ${SRC} compat/pledge.c) endif() if(NOT HAVE_STRTONUM) set(SRC ${SRC} compat/strtonum.c) endif() set(GEOIP2DIR ${CMAKE_INSTALL_PREFIX}/share/dbip CACHE PATH "Path to GeoIP2 databases") set(GEOIP2DB "dbip-country-lite.mmdb" CACHE PATH "GeoIP2 database file") add_definitions(-D_GNU_SOURCE -Wall -Wextra -pedantic) add_definitions(-DGEOIP2DIR="${GEOIP2DIR}/") add_definitions(-DGEOIP2DB="${GEOIP2DB}") add_executable(logswan ${SRC} ${DEPS}) target_link_libraries(logswan ${GEOIP2_LIBRARIES} ${JANSSON_LIBRARIES} m) install(TARGETS logswan DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES man/logswan.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1/) enable_testing() add_test(logswan logswan) add_test(usage logswan -h) add_test(version logswan -v) add_test(processing logswan ${PROJECT_SOURCE_DIR}/tests/logswan.log) add_test(invalid logswan ${PROJECT_SOURCE_DIR}/tests/invalid.log) add_test(geolocation logswan -g -d ${PROJECT_SOURCE_DIR}/tests/logswan.mmdb ${PROJECT_SOURCE_DIR}/tests/logswan.log) logswan-2.1.15/ChangeLog000066400000000000000000000251631477025033300150370ustar00rootroot00000000000000Logswan 2.1.15 (2025-03-24) - Add link to Gentoo package in the README - Add initial RPM spec file - Bump cmake_minimum_required to 3.5, to allow building with CMake 4.0 - Bump cmake_minimum_required to 3.10 to be more future proof Logswan 2.1.14 (2023-03-30) - Add missing void to the usage() function definition - Move manual page to the man directory Logswan 2.1.13 (2022-07-28) - Remove useless backslashes in usage() - Add entries with IPv6 remote hosts to exercise the IPv6 code paths - Add an invalid.log log file with invalid lines, for testing purposes - Add a few more test cases in CMakeLists.txt - Also generate data for IPv6 addresses in the MMDB test database - Regenerate the example MMDB database and JSON example output Logswan 2.1.12 (2021-12-02) - Fix a use-after-free (read) triggered by strcmp(3) calls. The parse_request() function didn't zero out the parsed_request struct between each call. Since the parsing loop was switched to using getline(3) instead of a fixed size buffer to process log lines, it could reference already freed memory in certain cases. Thanks to Brian Carpenter (@geeknik) for finding and reporting the issue. Logswan 2.1.11 (2021-11-16) - Bump CMake minimum required version to 2.8.12 - Add SPDX short license identifier in source files - Use CMAKE_C_STANDARD instead of hardcoding compiler flags - Switch to using getline(3) instead of fgets(3) - Call hll_init() after doing getopt() processing Logswan 2.1.10 (2021-02-15) - Only call MMDB_close if the GeoIP option was enabled. This fixes a crash on program exit on OpenBSD when running without the GeoIP option enabled. Logswan 2.1.9 (2021-02-15) - Stop forcing FORTIFY_SOURCE=2, it should be package builders decision - Add link to Homebrew package in the README - Remove unused countryId variable - Remove dead increments for argc and argv - Rename variables to get rid of all camelCase occurrences - Remove the measuring Logswan memory usage section from the README - Try to harmonize usage information everywhere - Rename the displayUsage() function to usage() - Rename all the parse*() functions to use snake_case - Get rid of global variables, move all declarations to main() Logswan 2.1.8 (2020-10-19) - Make displayUsage() static - Removing some leading whitespace characters - Constify methods and protocols names array - Constify countries and continents names and ID arrays - Enable FORTIFY_SOURCE level 2 - Call memset() to set all entry_data struct fields to zero Logswan 2.1.7 (2020-09-17) - Add a Perl program to generate an example MMDB database for testing - Add a new test case to exercise the IP geolocation codepaths - Add support for seccomp on arm - Add missing test for __NR_mmap, the mmap syscall doesn't exist on arm Logswan 2.1.6 (2020-07-03) - Validate architectures for seccomp - Minor code shuffling, for consistency with other codebases - Add seccomp support on i386, tested on glibc and musl - Remove entry for "Netherlands Antilles" in country table - Swaziland was officially renamed to Eswatini in 2018 - Macedonia was officially renamed to North Macedonia in February 2019 - Rename Vatican City to Vatican to be consistent with GeoNames naming - Rename Aland to Aland Islands to be consistent with GeoNames naming Logswan 2.1.5 (2020-06-12) - Switch the GEOIP2DIR example to point to '/var/db/dbip' - Use CLOCK_REALTIME if CLOCK_MONOTONIC is not available - Remove unneeded and includes - Add missing include - Remove useless _POSIX_SOURCE define - Remove useless _POSIX_C_SOURCE 199309L define - Define _GNU_SOURCE in CMakeLists.txt to avoid cluttering source files - No need to set HAVE_SECCOMP to 1, defining it is enough - Remove some unneeded seccomp related includes Logswan 2.1.4 (2020-03-27) - Move GEOIP2DB definition to CMakeLists.txt, allowing build time customization - Display database path name in error message - Remove direct link to GeoLite2 databases - Add dependencies installation instruction for Fedora - Change GEOIP2DB default value to "dbip-country-lite.mmdb" - Change GEOIP2DIR default value to "${CMAKE_INSTALL_PREFIX}/share/dbip" - Mention that DB-IP IP to Country Lite database is now the recommended option Logswan 2.1.3 (2020-01-17) - Add a new test target, to test log processing - Move printed statistics after the actual output - Use OpenBSD style(9) for function prototypes and declarations - Remove seccomp mention in README as it is currently disabled by default Logswan 2.1.2 (2019-11-19) - Add ENABLE_SECCOMP build option, to allow building seccomp support conditionally - Disable seccomp by default, it needs more testing on non !amd64 platforms - Use ${CMAKE_INSTALL_BINDIR} instead of hardcoding 'bin' Logswan 2.1.1 (2019-10-30) - Check if system has seccomp in CMakeLists.txt - Use the HAVE_SECCOMP macro to check whether or not to enable seccomp - Define and use a GEOIP2DB macro to specify GeoLite2 database name - Add a switch (-d) to allow specifying path to a GeoIP2 database file - Define and use a LOGSWAN_SYSCALL_ALLOW macro to make code more readable - Adding missing #include guard in seccomp.h header file - Use __NR_ instead of SYS_ prefix in LOGSWAN_SYSCALL_ALLOW - Fix the build on aarch64 Linux, where the open() syscall does not exist - Add error checking for both prctl() calls Logswan 2.1.0 (2019-10-23) - Add FALLTHROUGH comments where appropriate - Add support for parsing HTTP/3 requests - Add initial seccomp support on Linux, tested on musl and glibc systems Logswan 2.0.4 (2019-08-16) - Adding #include guard in compat header file - Add an example log file and regenerate output example - Add dependencies installation instructions for NetBSD and FreeBSD - Add final dots for options descriptions - Add final dot when printing results summary - Use EXIT_SUCCESS and EXIT_FAILURE macros for return values - Add a trailing newline when printing JSON output Logswan 2.0.3 (2018-10-15) - Use -std=c11, Logswan requires a C11 compiler for libmaxminddb - Enable support for parsing HTTP/2.0 requests, for real this time - Revert back to using INT64_MAX for strtonum() maxval, as maxval is long long and using UINT64_MAX caused bandwidth parsing to always fail (Thanks James Loh for reporting the issue) - Move maps of countries and continents to separate files Logswan 2.0.2 (2018-08-05) - Use UINT64_MAX for strtonum() maxval - Add missing headers and reorder includes - Add support for HTTP/2.0 Logswan 2.0.1 (2018-06-27) - Do not use -Werror by default - Do not always call inet_pton two times per log line, this speeds things up - Use bool types for isIPv4 and isIPv6 - Use the monotonic clock to determine runtime - Move conditional includes for 'pledge' and 'strtonum' in compat.h Logswan 2.0.0 (2018-03-16) - Use type off_t for results struct member fileSize - Reflect OpenBSD's pledge() changes - Switch to using libmaxminddb and GeoIP2/GeoLite2 databases - Add Antarctica to the list of continents Logswan 1.07 (2017-02-14) - Harmonize arrays names - Remove array of months, it's currently unused and will likely remain so - Simplify internal JSON array and object names - Use OpenBSD style(9) for function prototypes and declarations - Revert back to using strtok, at least for now - Do not use EXIT_SUCCESS and EXIT_FAILURE macros anymore - Fix implicit function declaration error on NetBSD (Thanks Maya Rashish) - Remove now useless variables initialization and unnecessary includes - Do not add an extra new line when displaying usage or version Logswan 1.06 (2016-12-17) - Relicensed under the BSD 2-Clause license - Use strtok_r instead of strtok to tokenize lines - Do not attempt to increment countries and continents arrays if there is no GeoIP database loaded - Harmonize variable names for the GeoIP databases - GeoIP lookups are now disabled by default (add a -g switch to enable) - Use fstat on open file descriptor instead of using stat before opening the input file - Count the log line as invalid if parsedLine.remoteHost is NULL - Pass results structure by reference, not by value - Initialize some uninitialized variables - Headers cleanup Logswan 1.05 (2016-02-25) - Documentation update (notes on measuring Logswan memory usage) - Add additional include directories for compat functions + dependencies to avoid using relative path in includes - Check that *lineBuffer is not NUL before attempting to parse log line - Perform GeoIP lookup and HLL add in the same if block - Increment IPv4 and IPv6 hits counters individually and conditionally - Use CMake to check if the system has OpenBSD's pledge available and link pledge conditionally using a null implementation when compiled on non OpenBSD systems - Adding an array of months, for the upcoming split log functionalities Logswan 1.04 (2016-01-10) - Moving global variables into main - Using 'size_t' instead of 'int' for array indexes in for loops - Using 'uint32_t' for all non 'uint64_t' integers - Do not increment hits and processed lines counter for each parsed line, compute total only once when everything is parsed - Setting 'CMAKE_BUILD_TYPE' to 'Release' and formatting fixes - Sanitize CMake script to build under NetBSD (Thanks Kamil Rytarowski) - Initializing some uninitialized variables - Renaming 'DATADIR' variables to 'GEOIPDIR' Logswan 1.03 (2016-01-01) - Remove header display and do not print name of processed file - Print results to stderr instead of stdout - Output JSON data to stdout instead of creating a new file - Define GeoIP databases path in CMakeLists.txt - Adding log file name in the JSON output - Removing some hardcoded values and replacing them with constants defined in config.h - Breaking the loop when a match is found in the request parser - Using enumeration constants instead of macros - Process GeoIP continent information - Re-ordering protocols and methods with more common occurrences on top of the list, allowing to break earlier when iterating through the array - Adding support for reading logs from standard input - Renaming 'definitions' files to 'config' - Increasing countries array size, as an attempt to be future-proof - Initial support for using pledge() on OpenBSD - Documentation updates (HLL precision, Features list, GeoIP databases) - Updated JSON output example - Added a manual page Logswan 1.02 (2015-11-02) - Renaming 'resource' variable to 'request' in the 'logLine' struct - Do not attempt to parse empty date tokens - Do not attempt to parse empty request tokens (Thanks Brian Carpenter for reporting the issue) Logswan 1.01 (2015-10-01) - Documentation updates - Fixing segfault when request data is empty or malformed (Thanks Jonathan Armani for reporting and proposing a fix) Logswan 1.00 (2015-09-28) - Initial release logswan-2.1.15/LICENSE000066400000000000000000000024411477025033300142640ustar00rootroot00000000000000Copyright (c) 2015-2025, Frederic Cambus All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. logswan-2.1.15/README.md000066400000000000000000000132371477025033300145430ustar00rootroot00000000000000``` _____ .xiX*****Xix. .X7' '4Xk, dXl 'XX. . xXXl XXl . 4XXX XX' . ,x iX' _,,xxii | ²| ,iX7,xiiXXXXXXXl | .xi,xiXXXXXXXXXXXX: . ..iXXiXXXXXXXXXXXXXXX7. . .xXXXXXXXXXXXXXXX'XXXX7 . | ,XXXXXXXXXXXXXXXX'XXX7' | : .XXXXX7*'"' 2XXX7'XX7' | __/ \ _____ ____ \XX' _____ 47' ___ ___ _____ __ .\\_ \___/ _ \__/ _/_______\ _/______/ / \ \____/ _ \___/ \ _____ . / __ Y _ __ \__ _________ _____ \/\/ ____ _ _ ______ \/ __/// :/ / | \ |' \/ \/ \/ \/ Y \/ \ \ : |\______/\_________/____| /\____ /\_____/\_____/\____|____/\____\___/ | +--------------------- \____/ --- \____/ ----:----------------------h7/dS!----+ . | : : . : | | . Logswan . | | : . | |_|_______________________|__| | : . ``` # Logswan Logswan is a fast Web log analyzer using probabilistic data structures. It is targeted at very large log files, typically APIs logs. It has constant memory usage regardless of the log file size, and takes approximatively 4MB of RAM. Unique visitors counting is performed using two HyperLogLog counters (one for IPv4, and another one for IPv6), providing a relative accuracy of 0.10%. String representations of IP addresses are used and preferred as they offer better precision. Project design goals include: speed, memory-usage efficiency, and keeping the code as simple as possible. Logswan is **opinionated software**: - It only supports the Common Log Format, in order to keep the parsing code simple. It can of course process the Combined Log Format as well (referer and user agent fields will be discarded) - It does not split results per day, but log files can be split prior to being processed - Input file size and bandwidth usage are reported in bytes, there are no plans to format or round them Logswan is written with security in mind and is running sandboxed on OpenBSD (using pledge). Experimental seccomp support is available for selected architectures and can be enabled by setting the `ENABLE_SECCOMP` variable to `1` when invoking CMake. It has also been extensively fuzzed using AFL and Honggfuzz. ## Features Currently implemented features: - Counting used bandwidth - Counting number of processed lines / invalid lines - Counting number of hits (IPv4 and IPv6 hits) - Counting visits (unique IP addresses for both IPv4 and IPv6) - GeoIP lookups (for both IPv4 and IPv6) - Hourly hits distribution - HTTP method distribution - HTTP protocol distribution - HTTP status codes distribution ## Dependencies Logswan uses the `CMake` build system and requires `Jansson` and `libmaxminddb` libraries and header files. ## Installing dependencies - OpenBSD: `pkg_add -r cmake jansson libmaxminddb` - NetBSD: `pkgin in cmake jansson libmaxminddb` - FreeBSD: `pkg install cmake jansson libmaxminddb` - macOS: `brew install cmake jansson libmaxminddb` - Alpine Linux: `apk add cmake gcc make musl-dev jansson-dev libmaxminddb-dev` - Debian / Ubuntu: `apt-get install build-essential cmake libjansson-dev libmaxminddb-dev` - Fedora: `dnf install cmake gcc make jansson-devel libmaxminddb-devel` ## Building mkdir build cd build cmake .. make Logswan has been successfully built and tested on OpenBSD, NetBSD, FreeBSD, macOS, and Linux with both Clang and GCC. ## Packages Logswan packages are available for: - [OpenBSD][1] - [NetBSD][2] - [FreeBSD][3] - [Debian][4] - [Ubuntu][5] - [Void Linux][6] - [Gentoo][7] - [Homebrew][8] ### GeoIP2 databases Logswan looks for GeoIP2 databases in `${CMAKE_INSTALL_PREFIX}/share/dbip` by default, which points to `/usr/local/share/dbip`. A custom directory can be set using the `GEOIP2DIR` variable when invoking CMake: cmake -DGEOIP2DIR=/var/db/dbip . The free Creative Commons licensed DB-IP IP to Country Lite database can be downloaded [here][9]. Alternatively, GeoLite2 Country database from MaxMind can be downloaded free of charge [here][10], but require accepting an EULA and is not freely licensed. ## Usage logswan [-ghv] [-d db] logfile If file is a single dash (`-'), logswan reads from the standard input. The options are as follows: -d db Specify path to a GeoIP database. -g Enable GeoIP lookups. -h Display usage. -v Display version. Logswan outputs JSON data to **stdout**. ## License Logswan is released under the BSD 2-Clause license. See `LICENSE` file for details. ## Author Logswan is developed by Frederic Cambus. - Site: https://www.cambus.net ## Resources Project homepage: https://www.logswan.org GitHub: https://github.com/fcambus/logswan [1]: https://openports.pl/path/www/logswan [2]: https://pkgsrc.se/www/logswan [3]: https://www.freshports.org/www/logswan [4]: https://packages.debian.org/search?keywords=logswan [5]: https://packages.ubuntu.com/search?keywords=logswan [6]: https://github.com/void-linux/void-packages/tree/master/srcpkgs/logswan [7]: https://packages.gentoo.org/packages/www-misc/logswan [8]: https://formulae.brew.sh/formula/logswan [9]: https://db-ip.com/db/lite.php [10]: https://dev.maxmind.com/geoip/geoip2/geolite2/ logswan-2.1.15/THANKS000066400000000000000000000003241477025033300141700ustar00rootroot00000000000000- Antti Kiuru for the Logswan ASCII logo - Ted Unangst and Todd Miller for strtonum.c - Austin Appleby for the MurmurHash3 hash function - Artem Zaytsev for the HyperLogLog C library (https://github.com/avz/hll) logswan-2.1.15/compat/000077500000000000000000000000001477025033300145415ustar00rootroot00000000000000logswan-2.1.15/compat/compat.h000066400000000000000000000011301477025033300161700ustar00rootroot00000000000000#ifndef COMPAT_H #define COMPAT_H #ifndef HAVE_PLEDGE #include "pledge.h" #endif #ifndef HAVE_STRTONUM #include "strtonum.h" #endif /* Use CLOCK_REALTIME if CLOCK_MONOTONIC is not available */ #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC CLOCK_REALTIME #endif #ifndef timespecsub #define timespecsub(tsp, usp, vsp) \ do { \ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ if ((vsp)->tv_nsec < 0) { \ (vsp)->tv_sec--; \ (vsp)->tv_nsec += 1000000000L; \ } \ } while (0) #endif #endif /* COMPAT_H */ logswan-2.1.15/compat/pledge.c000066400000000000000000000001601477025033300161420ustar00rootroot00000000000000int pledge(const char *promises, const char *execpromises) { (void)promises; (void)execpromises; return 0; } logswan-2.1.15/compat/pledge.h000066400000000000000000000000501477025033300161450ustar00rootroot00000000000000int pledge(const char *, const char *); logswan-2.1.15/compat/strtonum.c000066400000000000000000000033501477025033300166010ustar00rootroot00000000000000/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; int error = 0; char *ep; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) { error = INVALID; } else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } logswan-2.1.15/compat/strtonum.h000066400000000000000000000001071477025033300166030ustar00rootroot00000000000000long long strtonum(const char *, long long, long long, const char **); logswan-2.1.15/deps/000077500000000000000000000000001477025033300142115ustar00rootroot00000000000000logswan-2.1.15/deps/MurmurHash3/000077500000000000000000000000001477025033300163675ustar00rootroot00000000000000logswan-2.1.15/deps/MurmurHash3/MurmurHash3.c000066400000000000000000000023371477025033300207160ustar00rootroot00000000000000/*----------------------------------------------------------------------------- MurmurHash3 was written by Austin Appleby, and is placed in the public domain. The author hereby disclaims copyright to this source code. */ #include "MurmurHash3.h" #define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r))) uint32_t MurmurHash3_x86_32(const void *key, uint32_t len, uint32_t seed) { const uint8_t *data = (const uint8_t *)key; const int32_t nblocks = (int32_t)len / 4; uint32_t h1 = seed; int i; const uint32_t c1 = 0xcc9e2d51; const uint32_t c2 = 0x1b873593; const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4); for(i = -nblocks; i; i++) { uint32_t k1 = blocks[i]; k1 *= c1; k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; h1 = ROTL32(h1, 13); h1 = h1 * 5 + 0xe6546b64; } const uint8_t * tail = (const uint8_t *)(data + nblocks * 4); uint32_t k1 = 0; switch(len & 3) { case 3: k1 ^= (uint32_t)tail[2] << 16; /* FALLTHROUGH */ case 2: k1 ^= (uint32_t)tail[1] << 8; /* FALLTHROUGH */ case 1: k1 ^= tail[0]; k1 *= c1; k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; }; h1 ^= len; h1 ^= h1 >> 16; h1 *= 0x85ebca6b; h1 ^= h1 >> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >> 16; return h1; } logswan-2.1.15/deps/MurmurHash3/MurmurHash3.h000066400000000000000000000002321477025033300207130ustar00rootroot00000000000000#ifndef _MURMURHASH3_H_ #define _MURMURHASH3_H_ #include uint32_t MurmurHash3_x86_32(const void * key, uint32_t len, uint32_t seed); #endif logswan-2.1.15/deps/hll/000077500000000000000000000000001477025033300147705ustar00rootroot00000000000000logswan-2.1.15/deps/hll/LICENSE000066400000000000000000000020611477025033300157740ustar00rootroot00000000000000Copyright (c) 2015 Artem Zaytsev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. logswan-2.1.15/deps/hll/hll.c000066400000000000000000000051071477025033300157160ustar00rootroot00000000000000#include #include #include #include #include #include "../MurmurHash3/MurmurHash3.h" #include "hll.h" static __inline uint8_t _hll_rank(uint32_t hash, uint8_t bits) { uint8_t i; for(i = 1; i <= 32 - bits; i++) { if(hash & 1) break; hash >>= 1; } return i; } int hll_init(struct HLL *hll, uint8_t bits) { if(bits < 4 || bits > 20) { errno = ERANGE; return -1; } hll->bits = bits; hll->size = (size_t)1 << bits; hll->registers = calloc(hll->size, 1); return 0; } void hll_destroy(struct HLL *hll) { free(hll->registers); hll->registers = NULL; } static __inline void _hll_add_hash(struct HLL *hll, uint32_t hash) { uint32_t index = hash >> (32 - hll->bits); uint8_t rank = _hll_rank(hash, hll->bits); if(rank > hll->registers[index]) { hll->registers[index] = rank; } } void hll_add(struct HLL *hll, const void *buf, size_t size) { uint32_t hash = MurmurHash3_x86_32((const char *)buf, (uint32_t)size, 0x5f61767a); _hll_add_hash(hll, hash); } double hll_count(const struct HLL *hll) { double alpha_mm; uint32_t i; switch (hll->bits) { case 4: alpha_mm = 0.673; break; case 5: alpha_mm = 0.697; break; case 6: alpha_mm = 0.709; break; default: alpha_mm = 0.7213 / (1.0 + 1.079 / (double)hll->size); break; } alpha_mm *= ((double)hll->size * (double)hll->size); double sum = 0; for(i = 0; i < hll->size; i++) { sum += 1.0 / (1 << hll->registers[i]); } double estimate = alpha_mm / sum; if (estimate <= 5.0 / 2.0 * (double)hll->size) { int zeros = 0; for(i = 0; i < hll->size; i++) zeros += (hll->registers[i] == 0); if(zeros) estimate = (double)hll->size * log((double)hll->size / zeros); } else if (estimate > (1.0 / 30.0) * 4294967296.0) { estimate = -4294967296.0 * log(1.0 - (estimate / 4294967296.0)); } return estimate; } int hll_merge(struct HLL *dst, const struct HLL *src) { uint32_t i; if(dst->bits != src->bits) { errno = EINVAL; return -1; } for(i = 0; i < dst->size; i++) { if(src->registers[i] > dst->registers[i]) dst->registers[i] = src->registers[i]; } return 0; } int hll_load(struct HLL *hll, const void *registers, size_t size) { uint8_t bits = 0; size_t s = size; while(s) { if(s & 1) break; bits++; s >>= 1; } if(!bits || ((size_t)1 << bits) != size) { errno = EINVAL; return -1; } if(hll_init(hll, bits) == -1) return -1; memcpy(hll->registers, registers, size); return 0; } extern uint32_t _hll_hash(const struct HLL *hll) { return MurmurHash3_x86_32(hll->registers, (uint32_t)hll->size, 0); } logswan-2.1.15/deps/hll/hll.h000066400000000000000000000010721477025033300157200ustar00rootroot00000000000000#ifndef AVZ_HLL_H #define AVZ_HLL_H #include #include struct HLL { uint8_t bits; size_t size; uint8_t *registers; }; extern int hll_init(struct HLL *hll, uint8_t bits); extern int hll_load(struct HLL *hll, const void *registers, size_t size); extern void hll_destroy(struct HLL *hll); extern int hll_merge(struct HLL *dst, const struct HLL *src); extern void hll_add(struct HLL *hll, const void *buf, size_t size); extern double hll_count(const struct HLL *hll); extern uint32_t _hll_hash(const struct HLL *hll); #endif /* AVZ_HLL_H */ logswan-2.1.15/examples/000077500000000000000000000000001477025033300150745ustar00rootroot00000000000000logswan-2.1.15/examples/logswan.json000066400000000000000000000036601477025033300174460ustar00rootroot00000000000000{ "date": "2022-05-06 16:13:26", "generator": "Logswan 2.1.12", "file_name": "logswan.log", "file_size": 10172, "processed_lines": 68, "invalid_lines": 0, "bandwidth": 592748, "runtime": 0.0077210000000000004, "hits": { "ipv4": 34, "ipv6": 34, "total": 68 }, "visits": { "ipv4": 7, "ipv6": 7, "total": 14 }, "continents": [ { "data": "EU", "name": "Europe", "hits": 28 }, { "data": "NA", "name": "North America", "hits": 28 }, { "data": "OC", "name": "Oceania", "hits": 12 } ], "countries": [ { "data": "AU", "name": "Australia", "hits": 12 }, { "data": "DE", "name": "Germany", "hits": 2 }, { "data": "FR", "name": "France", "hits": 26 }, { "data": "US", "name": "United States", "hits": 28 } ], "hours": [ { "data": 10, "hits": 4 }, { "data": 11, "hits": 8 }, { "data": 12, "hits": 26 }, { "data": 13, "hits": 4 }, { "data": 14, "hits": 10 }, { "data": 15, "hits": 2 }, { "data": 16, "hits": 4 }, { "data": 18, "hits": 10 } ], "methods": [ { "data": "GET", "hits": 66 }, { "data": "HEAD", "hits": 2 } ], "protocols": [ { "data": "HTTP/1.1", "hits": 66 }, { "data": "HTTP/1.0", "hits": 2 } ], "status": [ { "data": 200, "hits": 44 }, { "data": 404, "hits": 24 } ] } logswan-2.1.15/examples/logswan.log000066400000000000000000000236741477025033300172650ustar00rootroot000000000000001.1.1.1 - - [09/Dec/2018:10:59:20 +0100] "HEAD / HTTP/1.1" 200 8142 "" "curl/7.62.0" 1.1.1.1 - - [09/Dec/2018:10:59:26 +0100] "GET / HTTP/1.1" 200 8142 "" "curl/7.62.0" 1.1.1.1 - - [09/Dec/2018:11:00:02 +0100] "GET /robots.txt HTTP/1.1" 404 0 "" "curl/7.62.0" 1.1.1.1 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 1.1.1.1 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 1.1.1.1 - - [09/Dec/2018:11:06:23 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 2.2.2.2 - - [09/Dec/2018:12:36:38 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "curl/7.62.0" 2.2.2.2 - - [09/Dec/2018:12:36:47 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:51 +0100] "GET /files/logswan-1.01.tar.gz HTTP/1.1" 200 14790 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:53 +0100] "GET /files/logswan-1.02.tar.gz HTTP/1.1" 200 14931 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:55 +0100] "GET /files/logswan-1.03.tar.gz HTTP/1.1" 200 16485 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:57 +0100] "GET /files/logswan-1.04.tar.gz HTTP/1.1" 200 16913 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:00 +0100] "GET /files/logswan-1.05.tar.gz HTTP/1.1" 200 17392 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:02 +0100] "GET /files/logswan-1.06.tar.gz HTTP/1.1" 200 17589 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:05 +0100] "GET /files/logswan-1.07.tar.gz HTTP/1.1" 200 18697 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:13 +0100] "GET /files/logswan-2.0.0.tar.gz HTTP/1.1" 200 20683 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:16 +0100] "GET /files/logswan-2.0.1.tar.gz HTTP/1.1" 200 21336 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:18 +0100] "GET /files/logswan-2.0.2.tar.gz HTTP/1.1" 200 21367 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:21 +0100] "GET /files/logswan-2.0.3.tar.gz HTTP/1.1" 200 21799 "" "Wget/1.19.5 (openbsd6.4)" 3.3.3.3 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 3.3.3.3 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 4.4.4.4 - - [09/Dec/2018:14:32:28 +0100] "GET / HTTP/1.1" 200 8142 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 5.5.5.5 - - [09/Dec/2018:15:21:57 +0100] "GET / HTTP/1.0" 200 8142 "" "Lynx/2.8.9rel.1 libwww-FM/2.14 SSL-MM/1.4.1" 6.6.6.6 - - [09/Dec/2018:16:49:12 +0100] "GET / HTTP/1.1" 200 8142 "https://www.logswan.org/" "Dillo/3.0.5" 6.6.6.6 - - [09/Dec/2018:16:49:12 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Dillo/3.0.5" 7.7.7.7 - - [09/Dec/2018:18:17:29 +0100] "GET / HTTP/1.1" 200 8142 "" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:31 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "NetSurf/3.8 (OpenBSD)" ::ffff:101:101 - - [09/Dec/2018:10:59:20 +0100] "HEAD / HTTP/1.1" 200 8142 "" "curl/7.62.0" ::ffff:101:101 - - [09/Dec/2018:10:59:26 +0100] "GET / HTTP/1.1" 200 8142 "" "curl/7.62.0" ::ffff:101:101 - - [09/Dec/2018:11:00:02 +0100] "GET /robots.txt HTTP/1.1" 404 0 "" "curl/7.62.0" ::ffff:101:101 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:101:101 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:101:101 - - [09/Dec/2018:11:06:23 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:202:202 - - [09/Dec/2018:12:36:38 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "curl/7.62.0" ::ffff:202:202 - - [09/Dec/2018:12:36:47 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:51 +0100] "GET /files/logswan-1.01.tar.gz HTTP/1.1" 200 14790 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:53 +0100] "GET /files/logswan-1.02.tar.gz HTTP/1.1" 200 14931 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:55 +0100] "GET /files/logswan-1.03.tar.gz HTTP/1.1" 200 16485 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:57 +0100] "GET /files/logswan-1.04.tar.gz HTTP/1.1" 200 16913 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:00 +0100] "GET /files/logswan-1.05.tar.gz HTTP/1.1" 200 17392 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:02 +0100] "GET /files/logswan-1.06.tar.gz HTTP/1.1" 200 17589 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:05 +0100] "GET /files/logswan-1.07.tar.gz HTTP/1.1" 200 18697 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:13 +0100] "GET /files/logswan-2.0.0.tar.gz HTTP/1.1" 200 20683 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:16 +0100] "GET /files/logswan-2.0.1.tar.gz HTTP/1.1" 200 21336 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:18 +0100] "GET /files/logswan-2.0.2.tar.gz HTTP/1.1" 200 21367 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:21 +0100] "GET /files/logswan-2.0.3.tar.gz HTTP/1.1" 200 21799 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:303:303 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:303:303 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:404:404 - - [09/Dec/2018:14:32:28 +0100] "GET / HTTP/1.1" 200 8142 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:505:505 - - [09/Dec/2018:15:21:57 +0100] "GET / HTTP/1.0" 200 8142 "" "Lynx/2.8.9rel.1 libwww-FM/2.14 SSL-MM/1.4.1" ::ffff:606:606 - - [09/Dec/2018:16:49:12 +0100] "GET / HTTP/1.1" 200 8142 "https://www.logswan.org/" "Dillo/3.0.5" ::ffff:606:606 - - [09/Dec/2018:16:49:12 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Dillo/3.0.5" ::ffff:707:707 - - [09/Dec/2018:18:17:29 +0100] "GET / HTTP/1.1" 200 8142 "" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:31 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "NetSurf/3.8 (OpenBSD)" logswan-2.1.15/logswan.spec000066400000000000000000000021001477025033300155750ustar00rootroot00000000000000Name: logswan Version: 2.1.15 Release: 1%{?dist} Summary: Fast Web log analyzer using probabilistic data structures License: BSD-2-Clause URL: https://github.com/fcambus/logswan Source0: %{url}/releases/download/%{version}/%{name}-%{version}.tar.gz BuildRequires: jansson-devel BuildRequires: libmaxminddb-devel BuildRequires: cmake BuildRequires: gcc %description Logswan is a fast Web log analyzer using probabilistic data structures. It is targeted at very large log files, typically APIs logs. It has constant memory usage regardless of the log file size, and takes approximatively 4MB of RAM. Unique visitors counting is performed using two HyperLogLog counters (one for IPv4, and another one for IPv6), providing a relative accuracy of 0.10%. Project design goals include : speed, memory-usage efficiency, and keeping the code as simple as possible. %prep %autosetup %build %cmake . %cmake_build %install %cmake_install %check %files %{_bindir}/%{name} %{_mandir}/man1/%{name}.1* %license LICENSE %doc README.md logswan-2.1.15/man/000077500000000000000000000000001477025033300140315ustar00rootroot00000000000000logswan-2.1.15/man/logswan.1000066400000000000000000000047651477025033300156010ustar00rootroot00000000000000.\" .\" Copyright (c) 2015-2025, Frederic Cambus .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions are met: .\" .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .Dd $Mdocdate: March 22 2025 $ .Dt LOGSWAN 1 .Os .Sh NAME .Nm logswan .Nd fast Web log analyzer using probabilistic data structures .Sh SYNOPSIS .Nm .Op Fl ghv .Op Fl d Ar db .Ar logfile .Sh DESCRIPTION .Nm is a fast Web log analyzer using probabilistic data structures. It is targeted at very large log files, typically APIs logs. It has constant memory usage regardless of the log file size, and takes approximatively 4MB of RAM. .Pp Unique visitors counting is performed using two HyperLogLog counters (one for IPv4, and another one for IPv6), providing a relative accuracy of 0.10%. .Pp If .Ar file is a single dash (`-'), .Nm reads from the standard input. .Pp The options are as follows: .Bl -tag -width Ds .It Fl d Ar db Specify path to a GeoIP database. .It Fl g Enable GeoIP lookups. .It Fl h Display usage. .It Fl v Display version. .El .Sh EXAMPLES The following script can be used to process all log files in the current directory and save the output in a file: .Bd -literal -offset indent #!/bin/sh for file in $(ls *.log) do logswan $file > $file.json done exit 0 .Ed .Sh AUTHORS .Nm was written by .An Frederic Cambus . logswan-2.1.15/src/000077500000000000000000000000001477025033300140455ustar00rootroot00000000000000logswan-2.1.15/src/config.c000066400000000000000000000007651477025033300154660ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ const char *methods_names[] = { "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "CONNECT", "PATCH" }; const char *protocols_names[] = { "HTTP/1.1", "HTTP/1.0", "HTTP/2.0", "HTTP/3" }; logswan-2.1.15/src/config.h000066400000000000000000000010611477025033300154610ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-11-16 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #ifndef CONFIG_H #define CONFIG_H #define VERSION "Logswan 2.1.15" enum { HLL_BITS = 20, STATUS_CODE_MAX = 512, CONTINENTS = 7, COUNTRIES = 250, METHODS = 9, PROTOCOLS = 4 }; extern char *methods_names[]; extern char *protocols_names[]; #endif /* CONFIG_H */ logswan-2.1.15/src/continents.c000066400000000000000000000007721477025033300164030ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ const char *continents_id[] = { "AF", "AN", "AS", "EU", "NA", "OC", "SA" }; const char *continents_names[] = { "Africa", "Antarctica", "Asia", "Europe", "North America", "Oceania", "South America" }; logswan-2.1.15/src/continents.h000066400000000000000000000006461477025033300164100ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #ifndef CONTINENTS_H #define CONTINENTS_H extern char *continents_id[]; extern char *continents_names[]; #endif /* CONTINENTS */ logswan-2.1.15/src/countries.c000066400000000000000000000132511477025033300162260ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ const char *countries_id[] = { "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW" }; const char *countries_names[] = { "Andorra", "United Arab Emirates", "Afghanistan", "Antigua and Barbuda", "Anguilla", "Albania", "Armenia", "Angola", "Antarctica", "Argentina", "American Samoa", "Austria", "Australia", "Aruba", "Aland Islands", "Azerbaijan", "Bosnia and Herzegovina", "Barbados", "Bangladesh", "Belgium", "Burkina Faso", "Bulgaria", "Bahrain", "Burundi", "Benin", "Saint Barthelemy", "Bermuda", "Brunei", "Bolivia", "Bonaire", "Brazil", "Bahamas", "Bhutan", "Bouvet Island", "Botswana", "Belarus", "Belize", "Canada", "Cocos (Keeling) Islands", "Democratic Republic of the Congo", "Central African Republic", "Republic of the Congo", "Switzerland", "Ivory Coast", "Cook Islands", "Chile", "Cameroon", "China", "Colombia", "Costa Rica", "Cuba", "Cape Verde", "Curacao", "Christmas Island", "Cyprus", "Czech Republic", "Germany", "Djibouti", "Denmark", "Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia", "Egypt", "Western Sahara", "Eritrea", "Spain", "Ethiopia", "Finland", "Fiji", "Falkland Islands", "Micronesia", "Faroe Islands", "France", "Gabon", "United Kingdom", "Grenada", "Georgia", "French Guiana", "Guernsey", "Ghana", "Gibraltar", "Greenland", "Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece", "South Georgia and the South Sandwich Islands", "Guatemala", "Guam", "Guinea-Bissau", "Guyana", "Hong Kong", "Heard Island and McDonald Islands", "Honduras", "Croatia", "Haiti", "Hungary", "Indonesia", "Ireland", "Israel", "Isle of Man", "India", "British Indian Ocean Territory", "Iraq", "Iran", "Iceland", "Italy", "Jersey", "Jamaica", "Jordan", "Japan", "Kenya", "Kyrgyzstan", "Cambodia", "Kiribati", "Comoros", "Saint Kitts and Nevis", "North Korea", "South Korea", "Kuwait", "Cayman Islands", "Kazakhstan", "Laos", "Lebanon", "Saint Lucia", "Liechtenstein", "Sri Lanka", "Liberia", "Lesotho", "Lithuania", "Luxembourg", "Latvia", "Libya", "Morocco", "Monaco", "Moldova", "Montenegro", "Saint Martin", "Madagascar", "Marshall Islands", "North Macedonia", "Mali", "Myanmar", "Mongolia", "Macao", "Northern Mariana Islands", "Martinique", "Mauritania", "Montserrat", "Malta", "Mauritius", "Maldives", "Malawi", "Mexico", "Malaysia", "Mozambique", "Namibia", "New Caledonia", "Niger", "Norfolk Island", "Nigeria", "Nicaragua", "Netherlands", "Norway", "Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama", "Peru", "French Polynesia", "Papua New Guinea", "Philippines", "Pakistan", "Poland", "Saint Pierre and Miquelon", "Pitcairn Islands", "Puerto Rico", "Palestine", "Portugal", "Palau", "Paraguay", "Qatar", "Reunion", "Romania", "Serbia", "Russia", "Rwanda", "Saudi Arabia", "Solomon Islands", "Seychelles", "Sudan", "Sweden", "Singapore", "Saint Helena", "Slovenia", "Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino", "Senegal", "Somalia", "Suriname", "South Sudan", "Sao Tome and Principe", "El Salvador", "Sint Maarten", "Syria", "Eswatini", "Turks and Caicos Islands", "Chad", "French Southern Territories", "Togo", "Thailand", "Tajikistan", "Tokelau", "East Timor", "Turkmenistan", "Tunisia", "Tonga", "Turkey", "Trinidad and Tobago", "Tuvalu", "Taiwan", "Tanzania", "Ukraine", "Uganda", "U.S. Minor Outlying Islands", "United States", "Uruguay", "Uzbekistan", "Vatican", "Saint Vincent and the Grenadines", "Venezuela", "British Virgin Islands", "U.S. Virgin Islands", "Vietnam", "Vanuatu", "Wallis and Futuna", "Samoa", "Kosovo", "Yemen", "Mayotte", "South Africa", "Zambia", "Zimbabwe" }; logswan-2.1.15/src/countries.h000066400000000000000000000006421477025033300162330ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #ifndef COUNTRIES_H #define COUNTRIES_H extern char *countries_id[]; extern char *countries_names[]; #endif /* COUNTRIES */ logswan-2.1.15/src/logswan.c000066400000000000000000000162221477025033300156660ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2023-03-13 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SECCOMP #include #include #include "seccomp.h" #endif #include #include "compat.h" #include "config.h" #include "continents.h" #include "countries.h" #include "hll.h" #include "output.h" #include "parse.h" static void usage(void) { printf("logswan [-ghv] [-d db] logfile\n\n" "The options are as follows:\n\n" " -d db Specify path to a GeoIP database.\n" " -g Enable GeoIP lookups.\n" " -h Display usage.\n" " -v Display version.\n"); } int main(int argc, char *argv[]) { struct timespec begin, end, elapsed; struct HLL unique_ipv4, unique_ipv6; struct results results; struct date parsed_date; struct logline parsed_line; struct request parsed_request; struct stat logfile_stat; struct sockaddr_in ipv4; struct sockaddr_in6 ipv6; uint64_t bandwidth; uint32_t status_code; uint32_t hour; int gai_error, mmdb_error; int opt; const char *errstr; char *linebuffer = NULL; size_t linesize = 0; char *input; char *db = NULL; bool geoip = false; bool is_ipv4, is_ipv6; MMDB_s geoip2; MMDB_lookup_result_s lookup; FILE *logfile; if (pledge("stdio rpath", NULL) == -1) { err(EXIT_FAILURE, "pledge"); } #ifdef HAVE_SECCOMP if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("Can't initialize seccomp"); return EXIT_FAILURE; } if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &logswan)) { perror("Can't load seccomp filter"); return EXIT_FAILURE; } #endif while ((opt = getopt(argc, argv, "d:ghv")) != -1) { switch (opt) { case 'd': db = optarg; break; case 'g': geoip = true; break; case 'h': usage(); return EXIT_SUCCESS; case 'v': printf("%s\n", VERSION); return EXIT_SUCCESS; } } if (optind < argc) { input = argv[optind]; } else { usage(); return EXIT_SUCCESS; } hll_init(&unique_ipv4, HLL_BITS); hll_init(&unique_ipv6, HLL_BITS); /* Starting timer */ clock_gettime(CLOCK_MONOTONIC, &begin); /* Initializing GeoIP */ if (geoip) { if (!db) db = GEOIP2DIR GEOIP2DB; if (MMDB_open(db, MMDB_MODE_MMAP, &geoip2) != MMDB_SUCCESS) err(EXIT_FAILURE, "Can't open database (%s)", db); } /* Open log file */ if (!strcmp(input, "-")) { /* Read from standard input */ logfile = stdin; } else { /* Attempt to read from file */ if (!(logfile = fopen(input, "r"))) { perror("Can't open log file"); return EXIT_FAILURE; } } /* Get log file size */ if (fstat(fileno(logfile), &logfile_stat)) { perror("Can't stat log file"); return EXIT_FAILURE; } memset(&results, 0, sizeof(struct results)); results.file_name = input; results.file_size = logfile_stat.st_size; while (getline(&linebuffer, &linesize, logfile) != -1) { /* Parse and tokenize line */ parse_line(&parsed_line, linebuffer); /* Detect if remote host is IPv4 or IPv6 */ if (parsed_line.remote_host) { /* Do not feed NULL tokens to inet_pton */ if ((is_ipv4 = inet_pton(AF_INET, parsed_line.remote_host, &ipv4.sin_addr))) { is_ipv6 = false; } else { is_ipv6 = inet_pton(AF_INET6, parsed_line.remote_host, &ipv6.sin6_addr); if (!is_ipv6) { results.invalid_lines++; continue; } } } else { /* Invalid line */ results.invalid_lines++; continue; } if (is_ipv4) { /* Increment hits counter */ results.hits_ipv4++; /* Unique visitors */ hll_add(&unique_ipv4, parsed_line.remote_host, strlen(parsed_line.remote_host)); } if (is_ipv6) { /* Increment hits counter */ results.hits_ipv6++; /* Unique visitors */ hll_add(&unique_ipv6, parsed_line.remote_host, strlen(parsed_line.remote_host)); } if (geoip) { MMDB_entry_data_s entry_data; memset(&entry_data, 0, sizeof(MMDB_entry_data_s)); lookup = MMDB_lookup_string(&geoip2, parsed_line.remote_host, &gai_error, &mmdb_error); MMDB_get_value(&lookup.entry, &entry_data, "country", "iso_code", NULL); if (entry_data.has_data) { /* Increment countries array */ for (size_t loop = 0; loop < COUNTRIES; loop++) { if (!strncmp(countries_id[loop], entry_data.utf8_string, 2)) { results.countries[loop]++; break; } } } MMDB_get_value(&lookup.entry, &entry_data, "continent", "code", NULL); if (entry_data.has_data) { /* Increment continents array */ for (size_t loop = 0; loop < CONTINENTS; loop++) { if (!strncmp(continents_id[loop], entry_data.utf8_string, 2)) { results.continents[loop]++; break; } } } } /* Hourly distribution */ if (parsed_line.date) { parse_date(&parsed_date, parsed_line.date); if (parsed_date.hour) { hour = strtonum(parsed_date.hour, 0, 23, &errstr); if (!errstr) { results.hours[hour]++; } } } /* Parse request */ if (parsed_line.request) { parse_request(&parsed_request, parsed_line.request); if (parsed_request.method) { for (size_t loop = 0; loop < METHODS; loop++) { if (!strcmp(methods_names[loop], parsed_request.method)) { results.methods[loop]++; break; } } } if (parsed_request.protocol) { for (size_t loop = 0; loop < PROTOCOLS; loop++) { if (!strcmp(protocols_names[loop], parsed_request.protocol)) { results.protocols[loop]++; break; } } } } /* Count HTTP status codes occurrences */ if (parsed_line.status_code) { status_code = strtonum(parsed_line.status_code, 0, STATUS_CODE_MAX-1, &errstr); if (!errstr) { results.status[status_code]++; } } /* Increment bandwidth usage */ if (parsed_line.object_size) { bandwidth = strtonum(parsed_line.object_size, 0, INT64_MAX, &errstr); if (!errstr) { results.bandwidth += bandwidth; } } } /* Counting hits and processed lines */ results.hits = results.hits_ipv4 + results.hits_ipv6; results.processed_lines = results.hits + results.invalid_lines; /* Counting unique visitors */ results.visits_ipv4 = hll_count(&unique_ipv4); results.visits_ipv6 = hll_count(&unique_ipv6); results.visits = results.visits_ipv4 + results.visits_ipv6; /* Stopping timer */ clock_gettime(CLOCK_MONOTONIC, &end); timespecsub(&end, &begin, &elapsed); results.runtime = elapsed.tv_sec + elapsed.tv_nsec / 1E9; /* Generate timestamp */ time_t now = time(NULL); strftime(results.timestamp, 20, "%Y-%m-%d %H:%M:%S", localtime(&now)); /* Printing results */ fprintf(stdout, "%s\n", output(&results)); fprintf(stderr, "Processed %" PRIu64 " lines in %f seconds.\n", results.processed_lines, results.runtime); /* Clean up */ free(linebuffer); fclose(logfile); if (geoip) MMDB_close(&geoip2); hll_destroy(&unique_ipv4); hll_destroy(&unique_ipv6); return EXIT_SUCCESS; } logswan-2.1.15/src/output.c000066400000000000000000000073311477025033300155550ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include "config.h" #include "continents.h" #include "countries.h" #include "output.h" char *output(struct results *results) { json_t *output = json_object(); json_t *hits = json_object(); json_t *visits = json_object(); json_t *continents = json_array(); json_t *countries = json_array(); json_t *hours = json_array(); json_t *status = json_array(); json_t *methods = json_array(); json_t *protocols = json_array(); for (size_t loop = 0; loop < CONTINENTS; loop++) { if (results->continents[loop]) { json_array_append_new( continents, json_pack("{s:s, s:s, s:i}", "data", continents_id[loop], "name", continents_names[loop], "hits", results->continents[loop])); } } for (size_t loop = 0; loop < COUNTRIES; loop++) { if (results->countries[loop]) { json_array_append_new( countries, json_pack("{s:s, s:s, s:i}", "data", countries_id[loop], "name", countries_names[loop], "hits", results->countries[loop])); } } for (size_t loop = 0; loop < 24; loop++) { if (results->hours[loop]) { json_array_append_new( hours, json_pack("{s:i, s:i}", "data", loop, "hits", results->hours[loop])); } } for (size_t loop = 0; loop < STATUS_CODE_MAX; loop++) { if (results->status[loop]) { json_array_append_new( status, json_pack("{s:i, s:i}", "data", loop, "hits", results->status[loop])); } } for (size_t loop = 0; loop < METHODS; loop++) { if (results->methods[loop]) { json_array_append_new( methods, json_pack("{s:s, s:i}", "data", methods_names[loop], "hits", results->methods[loop])); } } for (size_t loop = 0; loop < PROTOCOLS; loop++) { if (results->protocols[loop]) { json_array_append_new( protocols, json_pack("{s:s, s:i}", "data", protocols_names[loop], "hits", results->protocols[loop])); } } json_object_set_new(hits, "ipv4", json_integer(results->hits_ipv4)); json_object_set_new(hits, "ipv6", json_integer(results->hits_ipv6)); json_object_set_new(hits, "total", json_integer(results->hits)); json_object_set_new(visits, "ipv4", json_integer(results->visits_ipv4)); json_object_set_new(visits, "ipv6", json_integer(results->visits_ipv6)); json_object_set_new(visits, "total", json_integer(results->visits)); json_object_set_new(output, "date", json_string(results->timestamp)); json_object_set_new(output, "generator", json_string(VERSION)); json_object_set_new(output, "file_name", json_string(results->file_name)); json_object_set_new(output, "file_size", json_integer(results->file_size)); json_object_set_new(output, "processed_lines", json_integer(results->processed_lines)); json_object_set_new(output, "invalid_lines", json_integer(results->invalid_lines)); json_object_set_new(output, "bandwidth", json_integer(results->bandwidth)); json_object_set_new(output, "runtime", json_real(results->runtime)); json_object_set_new(output, "hits", hits); json_object_set_new(output, "visits", visits); json_object_set_new(output, "continents", continents); json_object_set_new(output, "countries", countries); json_object_set_new(output, "hours", hours); json_object_set_new(output, "methods", methods); json_object_set_new(output, "protocols", protocols); json_object_set_new(output, "status", status); return json_dumps(output, JSON_INDENT(3) | JSON_PRESERVE_ORDER); } logswan-2.1.15/src/output.h000066400000000000000000000016261477025033300155630ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #ifndef OUTPUT_H #define OUTPUT_H #include #include #include "config.h" struct results { char *file_name; off_t file_size; uint64_t invalid_lines; uint64_t processed_lines; uint64_t bandwidth; uint64_t hits; uint64_t hits_ipv4; uint64_t hits_ipv6; uint64_t visits; uint64_t visits_ipv4; uint64_t visits_ipv6; uint64_t continents[CONTINENTS]; uint64_t countries[COUNTRIES]; uint64_t hours[24]; uint64_t methods[METHODS]; uint64_t protocols[PROTOCOLS]; uint64_t status[STATUS_CODE_MAX]; double runtime; char timestamp[20]; }; char *output(struct results *); #endif /* OUTPUT_H */ logswan-2.1.15/src/parse.c000066400000000000000000000026541477025033300153320ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-12-02 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include "parse.h" void parse_date(struct date *parsed_date, char *date) { parsed_date->day = strtok(date, "/"); parsed_date->month = strtok(NULL, "/"); parsed_date->year = strtok(NULL, ":"); parsed_date->hour = strtok(NULL, ":"); parsed_date->minute = strtok(NULL, ":"); parsed_date->second = strtok(NULL, " "); } void parse_line(struct logline *parsed_line, char *linebuffer) { if (*linebuffer) { /* Remote host */ parsed_line->remote_host = strtok(linebuffer, " "); /* User-identifier */ strtok(NULL, " "); /* User ID */ strtok(NULL, "["); /* Date */ parsed_line->date = strtok(NULL, "]"); /* Requested resource */ strtok(NULL, "\""); parsed_line->request = strtok(NULL, "\""); /* HTTP status codes */ parsed_line->status_code = strtok(NULL, " "); /* Returned object size */ parsed_line->object_size = strtok(NULL, " \""); } } void parse_request(struct request *parsed_request, char *request) { char *pch = strrchr(request, ' '); memset(parsed_request, 0, sizeof(*parsed_request)); if (pch) { parsed_request->protocol = pch + 1; parsed_request->method = strtok(request, " "); } } logswan-2.1.15/src/parse.h000066400000000000000000000013631477025033300153330ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2021-02-15 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #ifndef PARSE_H #define PARSE_H struct date { char *day; char *month; char *year; char *hour; char *minute; char *second; }; struct logline { char *remote_host; char *date; char *request; char *status_code; char *object_size; }; struct request { char *method; char *resource; char *protocol; }; void parse_date(struct date *, char *); void parse_line(struct logline *, char *); void parse_request(struct request *, char *); #endif /* PARSE_H */ logswan-2.1.15/src/seccomp.h000066400000000000000000000045711477025033300156560ustar00rootroot00000000000000/* * Logswan 2.1.15 * Copyright (c) 2015-2025, Frederic Cambus * https://www.logswan.org * * Created: 2015-05-31 * Last Updated: 2020-09-17 * * Logswan is released under the BSD 2-Clause license. * See LICENSE file for details. * * SPDX-License-Identifier: BSD-2-Clause */ #ifndef SECCOMP_H #define SECCOMP_H #include #include #include #include #include #include #include #if defined(__i386__) #define SECCOMP_AUDIT_ARCH AUDIT_ARCH_I386 #elif defined(__x86_64__) #define SECCOMP_AUDIT_ARCH AUDIT_ARCH_X86_64 #elif defined(__arm__) #define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM #elif defined(__aarch64__) #define SECCOMP_AUDIT_ARCH AUDIT_ARCH_AARCH64 #else #error "Seccomp is only supported on i386, x86_64, arm, and aarch64 architectures." #endif #define LOGSWAN_SYSCALL_ALLOW(syscall) \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##syscall, 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) static struct sock_filter filter[] = { /* Validate architecture */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, arch)), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), /* Load syscall */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), LOGSWAN_SYSCALL_ALLOW(brk), LOGSWAN_SYSCALL_ALLOW(clock_gettime), /* i386 glibc */ LOGSWAN_SYSCALL_ALLOW(close), LOGSWAN_SYSCALL_ALLOW(dup), LOGSWAN_SYSCALL_ALLOW(exit_group), LOGSWAN_SYSCALL_ALLOW(fcntl), #if defined(__NR_fcntl64) LOGSWAN_SYSCALL_ALLOW(fcntl64), /* i386 musl */ #endif LOGSWAN_SYSCALL_ALLOW(fstat), #if defined(__NR_fstat64) LOGSWAN_SYSCALL_ALLOW(fstat64), /* i386 glibc */ #endif LOGSWAN_SYSCALL_ALLOW(ioctl), LOGSWAN_SYSCALL_ALLOW(lseek), #if defined(__NR__llseek) LOGSWAN_SYSCALL_ALLOW(_llseek), /* i386 glibc */ #endif #if defined(__NR_open) LOGSWAN_SYSCALL_ALLOW(open), #endif LOGSWAN_SYSCALL_ALLOW(openat), #if defined(__NR_mmap) LOGSWAN_SYSCALL_ALLOW(mmap), #endif #if defined(__NR_mmap2) LOGSWAN_SYSCALL_ALLOW(mmap2), /* i386 glibc */ #endif LOGSWAN_SYSCALL_ALLOW(munmap), LOGSWAN_SYSCALL_ALLOW(read), LOGSWAN_SYSCALL_ALLOW(write), LOGSWAN_SYSCALL_ALLOW(writev), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) }; struct sock_fprog logswan = { .len = sizeof(filter)/sizeof(filter[0]), .filter = filter }; #endif /* SECCOMP_H */ logswan-2.1.15/tests/000077500000000000000000000000001477025033300144205ustar00rootroot00000000000000logswan-2.1.15/tests/invalid.log000066400000000000000000000002751477025033300165550ustar00rootroot000000000000001.1.x.1 - - [09/Dec/2018:10:59:20 +0100] "HEAD / HTTP/1.1" 200 8142 "" "curl/7.62.0" ::ffff:1x1:101 - - [09/Dec/2018:10:59:20 +0100] "HEAD / HTTP/1.1" 200 8142 "" "curl/7.62.0" - - >o_/ logswan-2.1.15/tests/logswan.log000066400000000000000000000236741477025033300166110ustar00rootroot000000000000001.1.1.1 - - [09/Dec/2018:10:59:20 +0100] "HEAD / HTTP/1.1" 200 8142 "" "curl/7.62.0" 1.1.1.1 - - [09/Dec/2018:10:59:26 +0100] "GET / HTTP/1.1" 200 8142 "" "curl/7.62.0" 1.1.1.1 - - [09/Dec/2018:11:00:02 +0100] "GET /robots.txt HTTP/1.1" 404 0 "" "curl/7.62.0" 1.1.1.1 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 1.1.1.1 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 1.1.1.1 - - [09/Dec/2018:11:06:23 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 2.2.2.2 - - [09/Dec/2018:12:36:38 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "curl/7.62.0" 2.2.2.2 - - [09/Dec/2018:12:36:47 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:51 +0100] "GET /files/logswan-1.01.tar.gz HTTP/1.1" 200 14790 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:53 +0100] "GET /files/logswan-1.02.tar.gz HTTP/1.1" 200 14931 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:55 +0100] "GET /files/logswan-1.03.tar.gz HTTP/1.1" 200 16485 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:36:57 +0100] "GET /files/logswan-1.04.tar.gz HTTP/1.1" 200 16913 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:00 +0100] "GET /files/logswan-1.05.tar.gz HTTP/1.1" 200 17392 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:02 +0100] "GET /files/logswan-1.06.tar.gz HTTP/1.1" 200 17589 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:05 +0100] "GET /files/logswan-1.07.tar.gz HTTP/1.1" 200 18697 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:13 +0100] "GET /files/logswan-2.0.0.tar.gz HTTP/1.1" 200 20683 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:16 +0100] "GET /files/logswan-2.0.1.tar.gz HTTP/1.1" 200 21336 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:18 +0100] "GET /files/logswan-2.0.2.tar.gz HTTP/1.1" 200 21367 "" "Wget/1.19.5 (openbsd6.4)" 2.2.2.2 - - [09/Dec/2018:12:37:21 +0100] "GET /files/logswan-2.0.3.tar.gz HTTP/1.1" 200 21799 "" "Wget/1.19.5 (openbsd6.4)" 3.3.3.3 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 3.3.3.3 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" 4.4.4.4 - - [09/Dec/2018:14:32:28 +0100] "GET / HTTP/1.1" 200 8142 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 4.4.4.4 - - [09/Dec/2018:14:32:29 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" 5.5.5.5 - - [09/Dec/2018:15:21:57 +0100] "GET / HTTP/1.0" 200 8142 "" "Lynx/2.8.9rel.1 libwww-FM/2.14 SSL-MM/1.4.1" 6.6.6.6 - - [09/Dec/2018:16:49:12 +0100] "GET / HTTP/1.1" 200 8142 "https://www.logswan.org/" "Dillo/3.0.5" 6.6.6.6 - - [09/Dec/2018:16:49:12 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Dillo/3.0.5" 7.7.7.7 - - [09/Dec/2018:18:17:29 +0100] "GET / HTTP/1.1" 200 8142 "" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" 7.7.7.7 - - [09/Dec/2018:18:17:31 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "NetSurf/3.8 (OpenBSD)" ::ffff:101:101 - - [09/Dec/2018:10:59:20 +0100] "HEAD / HTTP/1.1" 200 8142 "" "curl/7.62.0" ::ffff:101:101 - - [09/Dec/2018:10:59:26 +0100] "GET / HTTP/1.1" 200 8142 "" "curl/7.62.0" ::ffff:101:101 - - [09/Dec/2018:11:00:02 +0100] "GET /robots.txt HTTP/1.1" 404 0 "" "curl/7.62.0" ::ffff:101:101 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:101:101 - - [09/Dec/2018:11:06:22 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:101:101 - - [09/Dec/2018:11:06:23 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:202:202 - - [09/Dec/2018:12:36:38 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "curl/7.62.0" ::ffff:202:202 - - [09/Dec/2018:12:36:47 +0100] "GET /files/logswan-1.00.tar.gz HTTP/1.1" 200 14571 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:51 +0100] "GET /files/logswan-1.01.tar.gz HTTP/1.1" 200 14790 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:53 +0100] "GET /files/logswan-1.02.tar.gz HTTP/1.1" 200 14931 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:55 +0100] "GET /files/logswan-1.03.tar.gz HTTP/1.1" 200 16485 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:36:57 +0100] "GET /files/logswan-1.04.tar.gz HTTP/1.1" 200 16913 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:00 +0100] "GET /files/logswan-1.05.tar.gz HTTP/1.1" 200 17392 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:02 +0100] "GET /files/logswan-1.06.tar.gz HTTP/1.1" 200 17589 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:05 +0100] "GET /files/logswan-1.07.tar.gz HTTP/1.1" 200 18697 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:13 +0100] "GET /files/logswan-2.0.0.tar.gz HTTP/1.1" 200 20683 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:16 +0100] "GET /files/logswan-2.0.1.tar.gz HTTP/1.1" 200 21336 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:18 +0100] "GET /files/logswan-2.0.2.tar.gz HTTP/1.1" 200 21367 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:202:202 - - [09/Dec/2018:12:37:21 +0100] "GET /files/logswan-2.0.3.tar.gz HTTP/1.1" 200 21799 "" "Wget/1.19.5 (openbsd6.4)" ::ffff:303:303 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:303:303 - - [09/Dec/2018:13:16:24 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36" ::ffff:404:404 - - [09/Dec/2018:14:32:28 +0100] "GET / HTTP/1.1" 200 8142 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/assets/css/style.css" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:404:404 - - [09/Dec/2018:14:32:29 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "Mozilla/5.0 (X11; OpenBSD amd64; rv:63.0) Gecko/20100101 Firefox/63.0" ::ffff:505:505 - - [09/Dec/2018:15:21:57 +0100] "GET / HTTP/1.0" 200 8142 "" "Lynx/2.8.9rel.1 libwww-FM/2.14 SSL-MM/1.4.1" ::ffff:606:606 - - [09/Dec/2018:16:49:12 +0100] "GET / HTTP/1.1" 200 8142 "https://www.logswan.org/" "Dillo/3.0.5" ::ffff:606:606 - - [09/Dec/2018:16:49:12 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "Dillo/3.0.5" ::ffff:707:707 - - [09/Dec/2018:18:17:29 +0100] "GET / HTTP/1.1" 200 8142 "" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/css/style.css HTTP/1.1" 200 5466 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/bkg.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:30 +0100] "GET /assets/images/blacktocat.png HTTP/1.1" 404 0 "https://www.logswan.org/" "NetSurf/3.8 (OpenBSD)" ::ffff:707:707 - - [09/Dec/2018:18:17:31 +0100] "GET /favicon.ico HTTP/1.1" 404 0 "" "NetSurf/3.8 (OpenBSD)" logswan-2.1.15/tests/logswan.mmdb000066400000000000000000000135771477025033300167500ustar00rootroot00000000000000V      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a#bcdefghijklmnopqrstuvwxyz{|}~ **O*     * !"$8%&'(2)*+,-./01345679:;<i=>?b@TABCDEFGHIJKLMSNOPQRUVWXYZ[\]^_`acdefghjklmnropqstuvwxyz{|}~ *%     * !"#$O&>'()*+,-./0123456789:;<=*?@ABCDEFGHIJKLMNOPQRSTU*WXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~IcontinentDcodeBOCGcountryHiso_codeBAUEnamesBenIAustralia  BEU  BFR )BenFFrance  BNA  BUS )BenMUnited States  @  BDE )BenGGermanyMaxMind.com[binary_format_major_version[binary_format_minor_versionKbuild_epochbuMdatabase_typeGLogswanKdescriptionBen]Logswan IP geolocation test dataJip_versionIlanguagesBenJnode_countKrecord_size logswan-2.1.15/tests/logswan.pl000077500000000000000000000034431477025033300164360ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; use MaxMind::DB::Writer::Tree; use Text::CSV; my %types = ( names => 'map', continent => 'map', country => 'map', code => 'utf8_string', iso_code => 'utf8_string', en => 'utf8_string' ); my $tree = MaxMind::DB::Writer::Tree->new( ip_version => 6, record_size => 32, database_type => 'Logswan', languages => ['en'], description => { en => 'Logswan IP geolocation test data' }, map_key_type_callback => sub { $types{ $_[0] } } ); my $au = { continent => { code => "OC" }, country => { iso_code => "AU", names => { en => "Australia" } } }; my $de = { continent => { code => "EU" }, country => { iso_code => "DE", names => { en => "Germany" } } }; my $fr = { continent => { code => "EU" }, country => { iso_code => "FR", names => { en => "France" } } }; my $us = { continent => { code => "NA" }, country => { iso_code => "US", names => { en => "United States" } } }; $tree->insert_network( '1.1.1.1/32', $au ); $tree->insert_network( '2.2.2.2/32', $fr ); $tree->insert_network( '3.3.3.3/32', $us ); $tree->insert_network( '4.4.4.4/32', $us ); $tree->insert_network( '5.5.5.5/32', $de ); $tree->insert_network( '6.6.6.6/32', $us ); $tree->insert_network( '7.7.7.7/32', $us ); $tree->insert_network( '::ffff:101:101/128', $au ); $tree->insert_network( '::ffff:202:202/128', $fr ); $tree->insert_network( '::ffff:303:303/128', $us ); $tree->insert_network( '::ffff:404:404/128', $us ); $tree->insert_network( '::ffff:505:505/128', $de ); $tree->insert_network( '::ffff:606:606/128', $us ); $tree->insert_network( '::ffff:707:707/128', $us ); open my $db, '>:raw', 'logswan.mmdb'; $tree->write_tree($db);