├── .gitignore ├── CMakeLists.txt ├── INSTALL.txt ├── LICENSE.txt ├── README.md ├── TODO.md ├── cmake ├── CMakeLists.txt └── LibAddrConfig.cmake ├── debian ├── README.Debian ├── README.source ├── changelog ├── compat ├── control ├── copyright ├── libaddr-dev.install ├── libaddr-doc.install ├── libaddr.install ├── rules └── source │ └── options ├── doc ├── CMakeLists.txt ├── footer.html ├── ifaces.1 ├── libaddr-logo-500x500.png ├── libaddr-logo.png ├── libaddr-logo.svg ├── libaddr.doxy.in └── libaddr.png ├── libaddr ├── CMakeLists.txt ├── addr.cpp ├── addr.h ├── addr_parser.cpp ├── addr_parser.h ├── addr_range.cpp ├── addr_range.h ├── addr_unix.cpp ├── addr_unix.h ├── exception.h ├── iface.cpp ├── iface.h ├── route.cpp ├── route.h ├── validator_address.cpp ├── validator_address.h ├── version.cpp └── version.h.in ├── mk ├── tests ├── CMakeLists.txt ├── catch_global.cpp ├── catch_interfaces.cpp ├── catch_ipv4.cpp ├── catch_ipv6.cpp ├── catch_log_for_test.cpp ├── catch_main.cpp ├── catch_main.h ├── catch_range.cpp ├── catch_routes.cpp ├── catch_unix.cpp └── catch_validator.cpp └── tools ├── CMakeLists.txt ├── ifaces.cpp ├── ipv4_routes.cpp └── validate_ip.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | *.sw? 3 | seed.txt 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | # 3 | # https://snapwebsites.org/project/libaddr 4 | # contact@m2osw.com 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | 24 | cmake_minimum_required(VERSION 3.10.2) 25 | 26 | project(addr_project) 27 | 28 | enable_language(C) 29 | enable_language(CXX) 30 | 31 | # 32 | # Include support modules 33 | # (must be included in a project even though it is not made 34 | # specific to that project) 35 | # 36 | find_package(SnapCMakeModules REQUIRED) 37 | find_package(AdvGetOpt REQUIRED) 38 | find_package(CppThread REQUIRED) 39 | find_package(LibExcept REQUIRED) 40 | find_package(LibUtf8 REQUIRED) 41 | find_package(SnapDev REQUIRED) 42 | 43 | SnapGetVersion(LIBADDR ${CMAKE_CURRENT_SOURCE_DIR}) 44 | 45 | include_directories( 46 | ${PROJECT_BINARY_DIR} 47 | ${PROJECT_SOURCE_DIR} 48 | ) 49 | 50 | add_subdirectory(cmake) 51 | add_subdirectory(libaddr) 52 | add_subdirectory(tools) 53 | add_subdirectory(doc) 54 | add_subdirectory(tests) 55 | 56 | # vim: ts=4 sw=4 et 57 | -------------------------------------------------------------------------------- /INSTALL.txt: -------------------------------------------------------------------------------- 1 | 2 | ABOUT libaddr 3 | ============= 4 | 5 | The [libaddr](https://snapwebsites.org/project/libaddr) 6 | project is found online on the 7 | [Snap! C++ Websites](https://snapwebsites.org/) website. 8 | 9 | That page has some basic documentation and latest information about the 10 | library. 11 | 12 | 13 | INSTALLING UNDER UBUNTU 16.04+ 14 | ============================== 15 | 16 | Packages are available on launchpad in the 17 | [snapcpp PPA](https://code.launchpad.net/~snapcpp/+archive/ppa/+packages). 18 | You may want to consider using the packages directly instead of attempting 19 | to compile `libaddr` yourself. It should save you a lot of time. 20 | 21 | If the packages are not available for your version, check out the 22 | [github source](https://github.com/m2osw/libaddr) instead. 23 | 24 | Fixes or improvements are always welcome. All tests should run against 25 | your improvements to prove that they work as expected. 26 | 27 | 28 | REQUIREMENTS 29 | ============ 30 | 31 | The library requirements are: 32 | 33 | * cmake -- the tool to generate the Makefile (no auto-tool or configure!) 34 | * make -- to run the Makefile (whatever version compatible with cmake) 35 | * gcc & g++ -- to compile everything 36 | * gcov & lcov -- to run coverage tests and generate HTML as output 37 | * doxygen -- currently required with the new cmake scheme 38 | * dot (optional) -- recommanded if you want more complete documentations 39 | 40 | 41 | BUILDING 42 | ======== 43 | 44 | The following are the basic steps once all the necessary requirements were 45 | installed on your system: 46 | 47 | tar xf snapcmakemodules_x.y.z.tar.gz 48 | tar xf libaddr-x.y.z.tar.gz 49 | mkdir BUILD 50 | cd BUILD 51 | cmake -DCMAKE_MODULE_PATH=../snapCMakeModules/Modules ../libaddr 52 | make 53 | sudo make install 54 | 55 | To install the package exactly where you would like it to be, you will 56 | want to make sure that the cmake tool is called with the correct 57 | installation prefix. 58 | 59 | 60 | COMMAND LINE TEST 61 | ================= 62 | 63 | The tests are running using `make` with the `run_libaddr_tests` target. 64 | This will run all the tests. All the tests are currently created inside 65 | one binary file using `catch.cpp`. 66 | 67 | 68 | vim: tw=4 sw=4 et syntax=markdown 69 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | 3 | https://snapwebsites.org/project/libaddr 4 | contact@m2osw.com 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Introduction 3 | ============ 4 | 5 | `libaddr` is an easy to use C++ library that parses IP addresses to objects. 6 | This includes parsing IPv4 and IPv6 addresses, with a port or a CIDR mask. 7 | 8 | 9 | IPv4 support 10 | ============ 11 | 12 | The IPv4 support is limited to the 4 number dot notation (A.B.C.D). 13 | 14 | 15 | IPv6 support 16 | ============ 17 | 18 | IPv6 requires square brackets as we otherwise view the colon (:) as 19 | the port separator. So something like [::1]:123 will work. Just ::1 20 | will be an error. 21 | 22 | 23 | Port support 24 | ============ 25 | 26 | We support basic port notation by separating the address and port with 27 | a colon. 28 | 29 | You may define a port range by separating two decimal numbers by a dash (-). 30 | For example 1-1023 would define all reserved ports. 31 | 32 | Multiports is also available. You can write multiple ports separated by 33 | commas. This is useful if you want to handle a certain number of specific 34 | ports that are not clearly defined in a range. For example 1.2.3.4:80,443 35 | references IPv4 address 1.2.3.4 and ports 80 and 443. 36 | 37 | 38 | Mask support (CIDR) 39 | =================== 40 | 41 | Masks are written after a slash (/). 42 | 43 | A mask can be one decimal number, in which case it represents the number 44 | of bits from left to right that are set to 1. 45 | 46 | The mask can also be an address. In case of an address, it has to use the 47 | same format as the first part (IPv4/IPv4 or IPv6/IPv6). Such a mask can 48 | be absolutely anything. (i.e. 85.85.85.85 would clear all even bits of 49 | an IPv4 address). 50 | 51 | More or less from the time IPv6 was designed, the use of an address as 52 | a mask has been deprecated. The library still supports such, however, by 53 | default that feature is now turned off. Make sure to set the 54 | `addr::allow_t::ALLOW_ADDRESS_MASK` parameter to true before parsing an 55 | address if you want to allow such a feature (not recommanded). 56 | 57 | 58 | Known Bugs 59 | ========== 60 | 61 | It is possible to write an IPv4 address using the IPv6 syntax: 62 | 63 | ::ffff:192.168.1.1 64 | 65 | Even though you write this IP address using the IPv6 syntax, the `is_ipv4()` 66 | function will return true, which is expected. This can cause problems if 67 | you really needed an IPv6 address, though. The library does not really have 68 | the means, at the moment, to tell you whether it parsed an IPv4 or an IPv6 69 | address. 70 | 71 | Bugs 72 | ==== 73 | 74 | Submit bug reports and patches on 75 | [github](https://github.com/m2osw/libaddr/issues). 76 | 77 | 78 | _This file is part of the [snapcpp project](https://snapwebsites.org/)._ 79 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | * Use the advgetopt in all the tools. 3 | 4 | * Add support for adding our own set of "service to port" or 5 | "port to service"--i.e. `getservbyname()` or `getservbyport()` 6 | 7 | When nmap is installed, there is a much bigger services file here: 8 | 9 | /usr/share/nmap/nmap-services 10 | 11 | I think nmap comes with a library. Either way, reading their file is not 12 | complicated. However, we probably do not want to force the installtion of 13 | that package. The nmap package can be installed by the build system and we 14 | can change the format to our own at build time. 15 | 16 | There is a list from IANA here: 17 | 18 | http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt 19 | 20 | which is pretty complete. It includes deprecated numbers. 21 | 22 | The default system feature does not allow for growth without editing the 23 | system supplied `/etc/services` file. We would like to have our own 24 | protocols added to a directory which our functions can parse. 25 | 26 | The function can first check with the default system functions and then 27 | search our files if the data was not found in the system file. 28 | 29 | Note 1: This is probably not very important in the Snap! environment because 30 | nearly each system connects to the communicator daemon and the 31 | supported protocols are all handled under the hood in this case. 32 | 33 | Note 2: The current implementation of the `addr_parser` is an all or nothing 34 | scheme, but if the port is a string (such as ":http"), then the 35 | system will succeed; however, if it is set to ":cd" (from our 36 | communicator daemon protocol), then it fails. 37 | 38 | * Think about re-writing the parser using a lexer and a yacc. I think that 39 | would give us much more room for easier expansion of the parser. 40 | 41 | We have several issues at the moment with distinguishing between commas 42 | separating addresses or ports, etc. which I think would be easier to 43 | resolve with a full fledge parser. 44 | 45 | -------------------------------------------------------------------------------- /cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | # 3 | # https://snapwebsites.org/project/libaddr 4 | # contact@m2osw.com 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | 24 | project(libaddr_cmake) 25 | 26 | install( 27 | FILES 28 | LibAddrConfig.cmake 29 | 30 | DESTINATION 31 | share/cmake/LibAddr 32 | ) 33 | 34 | # vim: ts=4 sw=4 et nocindent 35 | -------------------------------------------------------------------------------- /cmake/LibAddrConfig.cmake: -------------------------------------------------------------------------------- 1 | # - Find LibAddr 2 | # 3 | # LIBADDR_FOUND - System has LibAddr 4 | # LIBADDR_INCLUDE_DIRS - The LibAddr include directories 5 | # LIBADDR_LIBRARIES - The libraries needed to use LibAddr 6 | # LIBADDR_DEFINITIONS - Compiler switches required for using LibAddr 7 | # 8 | # License: 9 | # 10 | # Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 11 | # 12 | # https://snapwebsites.org/project/libaddr 13 | # contact@m2osw.com 14 | # 15 | # This program is free software: you can redistribute it and/or modify 16 | # it under the terms of the GNU General Public License as published by 17 | # the Free Software Foundation, either version 3 of the License, or 18 | # (at your option) any later version. 19 | # 20 | # This program is distributed in the hope that it will be useful, 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | # GNU General Public License for more details. 24 | # 25 | # You should have received a copy of the GNU General Public License 26 | # along with this program. If not, see . 27 | 28 | find_path( 29 | LIBADDR_INCLUDE_DIR 30 | libaddr/addr.h 31 | 32 | PATHS 33 | ENV LIBADDR_INCLUDE_DIR 34 | ) 35 | find_library( 36 | LIBADDR_LIBRARY 37 | addr 38 | 39 | PATHS 40 | ${LIBADDR_LIBRARY_DIR} 41 | ENV LIBADDR_LIBRARY 42 | ) 43 | 44 | mark_as_advanced( 45 | LIBADDR_INCLUDE_DIR 46 | LIBADDR_LIBRARY 47 | ) 48 | 49 | set(LIBADDR_INCLUDE_DIRS ${LIBADDR_INCLUDE_DIR}) 50 | set(LIBADDR_LIBRARIES ${LIBADDR_LIBRARY}) 51 | 52 | include(FindPackageHandleStandardArgs) 53 | find_package_handle_standard_args( 54 | LibAddr 55 | REQUIRED_VARS 56 | LIBADDR_INCLUDE_DIR 57 | LIBADDR_LIBRARY 58 | ) 59 | 60 | # vim: ts=4 sw=4 et 61 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | libaddr for Debian 2 | ------------------ 3 | 4 | The libaddr fills a need for an actual library to parse IP addresses in C++. 5 | It looks like eveyone is always re-writing this code to parse IP with masks 6 | or ports. Okay, it's relatively easy, but I'm sure a lot of people struggle 7 | with such things and probably never write a test to make sure it works 8 | exactly as expected. 9 | 10 | -- Alexis Wilke Wed, 18 Jan 2017 13:53:01 -0800 11 | -------------------------------------------------------------------------------- /debian/README.source: -------------------------------------------------------------------------------- 1 | libaddr for Debian 2 | ------------------ 3 | 4 | `libaddr` requires the `snapCMakeModules` package in order to be compiled. 5 | It also depends on the `libexcept` library. 6 | 7 | The `SnapDoxygen` package can be ignored (commented out) if you do not need 8 | to regenerate the documentation. (Also comment out the line: 9 | `add_subdirectory( doc )`) 10 | 11 | The `tests` directory makes use of `catch.hpp`. If you do not have it, you 12 | can just comment that line out as well. Under a Debian system, you can install 13 | `catch.hpp` with: 14 | 15 | sudo apt-get install catch 16 | 17 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | libaddr (1.0.37.0~jammy) jammy; urgency=high 2 | 3 | * Fixed the tests and added a few more to slightly better coverage. 4 | 5 | -- Alexis Wilke Sun, 02 Jun 2024 20:28:11 -0700 6 | 7 | libaddr (1.0.36.0~jammy) jammy; urgency=high 8 | 9 | * Added the --version command line option to ifaces tool. 10 | * Added a manual page for the ifaces tool. 11 | 12 | -- Alexis Wilke Sat, 18 Nov 2023 10:38:19 -0800 13 | 14 | libaddr (1.0.35.0~jammy) jammy; urgency=high 15 | 16 | * Added tool to list interfaces with filtering support. 17 | * Added support for default IP address as "*". 18 | * Enhanced output of ip4_route. 19 | * Added a 5 minutes cache for the iface class. 20 | * Added missing #include 21 | * Added some #pragma -Wrestrict for lunar. 22 | * Bumped copyright to 2023. 23 | * Changed compat to latest (15). 24 | * Removed boost dependency. 25 | 26 | -- Alexis Wilke Sat, 12 Nov 2022 17:43:55 -0800 27 | 28 | libaddr (1.0.34.1~jammy) jammy; urgency=high 29 | 30 | * Bumped build version to rebuild on Launchpad. 31 | 32 | -- Alexis Wilke Sat, 12 Nov 2022 17:43:55 -0800 33 | 34 | libaddr (1.0.34.0~bionic) bionic; urgency=high 35 | 36 | * Added a set_group()/get_group() for Unix file-based sockets. 37 | 38 | -- Alexis Wilke Sat, 05 Nov 2022 10:56:32 -0700 39 | 40 | libaddr (1.0.33.0~bionic) bionic; urgency=high 41 | 42 | * Added a set_mode()/get_mode() for Unix file-based sockets. 43 | 44 | -- Alexis Wilke Fri, 04 Nov 2022 21:48:18 -0700 45 | 46 | libaddr (1.0.32.0~bionic) bionic; urgency=high 47 | 48 | * Added the to_cidr() to the addr_range class. 49 | * Added the optimize_vector() to remove equal/included addresses. 50 | * Renamed the unix.h as addr_unix.h so it works with gnu++17. 51 | * Added support of comments within the address. 52 | * Added support for comments introduced by ';'. 53 | * Added support for set_port() with a string. 54 | * Fixed the CIDR/mask parsing when the address was an IPv4 in an IPv6. 55 | * Output the mask "if needed" (if exactly 128 or 32). 56 | * Redesigned the ip to string code to use flags instead of an enum. 57 | * Added a sento() for UDP packets. 58 | * Added flags to know what was defined in the parser. 59 | * Added the .dirs files. 60 | * Various clean ups. 61 | 62 | -- Alexis Wilke Mon, 24 Oct 2022 20:37:15 -0700 63 | 64 | libaddr (1.0.31.1~bionic) bionic; urgency=high 65 | 66 | * For newer versions of g++, #include . 67 | 68 | -- Alexis Wilke Mon, 11 Jul 2022 11:45:39 -0700 69 | 70 | libaddr (1.0.31.0~bionic) bionic; urgency=high 71 | 72 | * Added support for newlines between addresses. 73 | * Added support for a '#' comment introducer (along the newline feature). 74 | * Added the to_string() on the addr_range class. 75 | * Added the to_string() for the addr_range::vector_t type. 76 | * Added support for address ranges in the parser (-). 77 | * Added ability to forbid address like masks (default now). 78 | * Correctly implemented the SORT_NO_EMPTY check. 79 | * Added support for ostream << operator including manip like parameters. 80 | * Added test to verify the input port as string. 81 | * Added error messages in the validator_address object. 82 | * Added cppthread as a dependency to support validator_address errors. 83 | * Redesign parsing of validator_address parameters. 84 | * Changed the set_protocol() to make use of getprotobyname_r(). 85 | * Added a set_mask_count() to allow for a number instead of a 128 bit mask. 86 | * Allow for applying the reversed mask (i.e. addr |= ~mask). 87 | * Moved the network_type_t and string_ip_t outside of the addr class. 88 | * Fixed the range compare() function so it actually works. 89 | * Enhanced the parsing of IPv6 vs. IPv4 addresses. 90 | * Tested and fixed the sorting of IPs by the parser. 91 | * Added a range "is_defined()" if one of "from" or "to" is set. 92 | * Added a swap of the boundaries in addr_range. 93 | * Fixed union_if_possible() tests as "from" or "to" may be undefined. 94 | * Enhanced many tests and updated them to pass with the new features. 95 | 96 | -- Alexis Wilke Sat, 11 Jun 2022 21:19:18 -0700 97 | 98 | libaddr (1.0.30.0~bionic) bionic; urgency=high 99 | 100 | * Removed cppthread as a dependency. It's not required. 101 | 102 | -- Alexis Wilke Fri, 20 May 2022 07:32:39 -0700 103 | 104 | libaddr (1.0.29.0~bionic) bionic; urgency=high 105 | 106 | * Added a function to test an IP to know whether it's a broadcast IP. 107 | * Fixed documentation about the STRING_IP_... enumeration. 108 | * Added an advgetopt validator for IP addresses. 109 | * Made sure headers all use <...> for #include. 110 | * Support attaching an interface to an address. 111 | * Fixed compat to v10. 112 | * Cleaned up the cmake file. 113 | 114 | -- Alexis Wilke Fri, 20 May 2022 07:15:47 -0700 115 | 116 | libaddr (1.0.28.0~bionic) bionic; urgency=high 117 | 118 | * Added the Environment Variable Intro. 119 | 120 | -- Alexis Wilke Sat, 05 Mar 2022 21:15:53 -0800 121 | 122 | libaddr (1.0.27.0~bionic) bionic; urgency=high 123 | 124 | * Hold the original hostname in case it is rquired for SNI. 125 | * Added a get_family() function. 126 | * Renamed f_private_network_defined as just f_private_network. 127 | * Added a missing set_protocol() in the addr_parser. 128 | 129 | -- Alexis Wilke Tue, 01 Mar 2022 21:02:10 -0800 130 | 131 | libaddr (1.0.26.0~bionic) bionic; urgency=high 132 | 133 | * Properly clean up once done with tests. 134 | 135 | -- Alexis Wilke Sun, 13 Feb 2022 14:12:09 -0800 136 | 137 | libaddr (1.0.25.1~bionic) bionic; urgency=high 138 | 139 | * Bumped build version to rebuild on Launchpad. 140 | 141 | -- Alexis Wilke Sun, 13 Feb 2022 13:54:16 -0800 142 | 143 | libaddr (1.0.25.0~bionic) bionic; urgency=high 144 | 145 | * Implemented the sort so we can have IPv6 first, because we are expected 146 | to give priority to IPv6 addresses. 147 | * Added a sort flag to avoid having empty ranges returned. 148 | * Added a function to compute the size of a valid CIDR mask. 149 | * Added a function to convert the IP into an unsigned int128 value. 150 | * Allow the match() function to return true if this IP is ANY. 151 | * Added the is_next() and is_previous() functions. 152 | * Renamed the addr_parser::flag_t as allow_t. 153 | * Added an is_ipv4() on the range, if to & from are IPv4, it returns true. 154 | * Added a from_cidr() function to convert an address with a mask into an 155 | addr_range object. 156 | * Added a function to marge two ranges if they overlap or are adjacent. 157 | 158 | -- Alexis Wilke Sun, 13 Feb 2022 12:05:33 -0800 159 | 160 | libaddr (1.0.24.0~bionic) bionic; urgency=high 161 | 162 | * Removed the MULTI_ADDRESSES_COMMAS_AND_SPACES. 163 | * Added the ADDRESS_LOOKUP to allow DNS lookup or not. 164 | 165 | -- Alexis Wilke Sun, 30 Jan 2022 10:38:35 -0800 166 | 167 | libaddr (1.0.23.2~bionic) bionic; urgency=high 168 | 169 | * Bumped build version to rebuild on Launchpad. 170 | 171 | -- Alexis Wilke Sun, 29 Aug 2021 16:29:15 -0700 172 | 173 | libaddr (1.0.23.1~bionic) bionic; urgency=high 174 | 175 | * Bumped build version to rebuild on Launchpad. 176 | 177 | -- Alexis Wilke Sun, 29 Aug 2021 15:49:36 -0700 178 | 179 | libaddr (1.0.23.0~bionic) bionic; urgency=high 180 | 181 | * Fix Unix address copying, the strncpy() can generate error on Ubuntu 20.04. 182 | 183 | -- Alexis Wilke Tue, 24 Aug 2021 17:25:01 -0700 184 | 185 | libaddr (1.0.22.1~bionic) bionic; urgency=high 186 | 187 | * Bumped build version to rebuild on Launchpad. 188 | 189 | -- Alexis Wilke Tue, 24 Aug 2021 16:59:07 -0700 190 | 191 | libaddr (1.0.22.0~bionic) bionic; urgency=high 192 | 193 | * Added support for a Unix address. 194 | * Fixed a test which maximum size was wrong (interface name can be 15 chars). 195 | * Fixed the get_service() test, under UDP, 80 & 443 are not known. 196 | 197 | -- Alexis Wilke Tue, 20 Jul 2021 16:27:01 -0700 198 | 199 | libaddr (1.0.21.1~bionic) bionic; urgency=high 200 | 201 | * Bumped build version to rebuild on Launchpad. 202 | 203 | -- Alexis Wilke Fri, 04 Jun 2021 21:39:02 -0700 204 | 205 | libaddr (1.0.21.0~bionic) bionic; urgency=high 206 | 207 | * Updated the NOTUSED() with an underscore. 208 | * Fixed the mk script. 209 | 210 | -- Alexis Wilke Fri, 04 Jun 2021 14:07:30 -0700 211 | 212 | libaddr (1.0.20.5~bionic) bionic; urgency=high 213 | 214 | * Recompile against newer versions. 215 | 216 | -- Alexis Wilke Sat, 29 May 2021 18:38:40 -0700 217 | 218 | libaddr (1.0.20.4~bionic) bionic; urgency=high 219 | 220 | * Recompile against newer versions. 221 | 222 | -- Alexis Wilke Sat, 15 May 2021 11:04:23 -0700 223 | 224 | libaddr (1.0.20.3~bionic) bionic; urgency=high 225 | 226 | * Bump version to recompile against cppthread. 227 | * Updated copyright notices to 2021. 228 | * Adde the -r option to the mk script. 229 | 230 | -- Alexis Wilke Mon, 15 Mar 2021 22:59:54 -0700 231 | 232 | libaddr (1.0.20.2~bionic) bionic; urgency=high 233 | 234 | * Bump version to recompile against cppthread. 235 | 236 | -- Alexis Wilke Fri, 15 Jan 2021 20:37:11 -0800 237 | 238 | libaddr (1.0.20.1~bionic) bionic; urgency=high 239 | 240 | * Bump version to get the advgetopt/snaplogger group name change. 241 | 242 | -- Alexis Wilke Fri, 20 Nov 2020 08:44:52 -0800 243 | 244 | libaddr (1.0.20.0~bionic) bionic; urgency=high 245 | 246 | * Updated validate-ip tool to compile against the new version of advgetopt. 247 | 248 | -- Alexis Wilke Fri, 13 Nov 2020 19:51:24 -0800 249 | 250 | libaddr (1.0.19.1~bionic) bionic; urgency=high 251 | 252 | * Bump version to get an ARM version. 253 | 254 | -- Alexis Wilke Tue, 26 May 2020 21:19:56 -0700 255 | 256 | libaddr (1.0.19.0~bionic) bionic; urgency=high 257 | 258 | * Create a bionic version. 259 | 260 | -- Alexis Wilke Fri, 01 May 2020 00:16:08 -0800 261 | 262 | libaddr (1.0.19.0~xenial) xenial; urgency=high 263 | 264 | * Fixed the `validate_ip.cpp` to use the new name of the exit exception in 265 | the advgetopt library. 266 | 267 | -- Alexis Wilke Mon, 28 Sep 2019 22:59:59 -0800 268 | 269 | libaddr (1.0.18.0~xenial) xenial; urgency=high 270 | 271 | * Fix: Default address and port are now used after testing for emptiness. 272 | * Cleaned up the exceptions (name, use macros). 273 | * Modernize the `mk` script. 274 | * Renamed the test `unittest` (planned unification). 275 | * Added the #include poison.h to all .cpp files. 276 | * Started moving things around so we have the library and tools separated. 277 | * Moved header files out of the sub-libaddr directory. 278 | * Renamed the "src" directory as "libaddr". 279 | * Actually implemented the validate_ip command line tool. 280 | * Added new dependencies (AdvGetOpt, LibUtf8, SnapDev). 281 | * Updated the dev/coverage script to work with the new folders. 282 | * Avoid showing errno in one emit_error() when errno == 0. 283 | 284 | -- Alexis Wilke Mon, 2 Sep 2019 03:17:02 -0800 285 | 286 | libaddr (1.0.17.0~xenial) xenial; urgency=high 287 | 288 | * Upgraded tests to compile against snapcatch2 instead of catch1.x 289 | 290 | -- Alexis Wilke Sat, 20 Jul 2019 21:47:27 -0800 291 | 292 | libaddr (1.0.16.0~xenial) xenial; urgency=high 293 | 294 | * Added a PROJECT_BRIEF to the documentation. 295 | * Added in=C++ to the MAPPING_EXTENSION. 296 | 297 | -- Alexis Wilke Tue, 11 Jun 2019 23:41:17 -0800 298 | 299 | libaddr (1.0.15.1~xenial) xenial; urgency=high 300 | 301 | * Bump version to get a recompile on launchpad. 302 | 303 | -- Alexis Wilke Sat, 11 May 2019 18:24:00 -0800 304 | 305 | libaddr (1.0.15.0~xenial) xenial; urgency=high 306 | 307 | * Added a class to allow for reading interface names. 308 | 309 | -- Alexis Wilke Sun, 23 Sep 2018 21:13:58 -0800 310 | 311 | libaddr (1.0.14.1~xenial) xenial; urgency=high 312 | 313 | * Bump version to get a recompile on launchpad. 314 | 315 | -- Alexis Wilke Fri, 27 Jul 2018 00:45:54 -0800 316 | 317 | libaddr (1.0.14.0~xenial) xenial; urgency=high 318 | 319 | * Made code -Weffc++ compatible. 320 | 321 | -- Alexis Wilke Wed, 25 Jul 2018 18:40:25 -0800 322 | 323 | libaddr (1.0.13.2~xenial) xenial; urgency=high 324 | 325 | * Bump version to recompile without the -fsanitizer flags. 326 | 327 | -- Alexis Wilke Wed, 27 Jun 2018 19:46:10 -0800 328 | 329 | libaddr (1.0.13.1~xenial) xenial; urgency=high 330 | 331 | * Bump version to recompile with the -fsanitizer flags. 332 | 333 | -- Alexis Wilke Tue, 26 Jun 2018 20:03:27 -0800 334 | 335 | libaddr (1.0.13.0~xenial) xenial; urgency=high 336 | 337 | * Added a class to read the Linux routes (from /proc/net/route). 338 | * Added a tool to show what routes were read to make sure it worked. 339 | * Fixed the get_mask(), it should have been const all along. 340 | * Fixed the is_default() function, it now works with IPv4 as well. 341 | * Fixed the find_addr_interface() function so the correct default is returned. 342 | * Updated the tests to check the route class. 343 | 344 | -- Alexis Wilke Sun, 10 Jun 2018 17:20:24 -0700 345 | 346 | libaddr (1.0.12.0~xenial) xenial; urgency=high 347 | 348 | * Fixed the IPv4 mask bytes order. 349 | * Fixed the find_addr_interface() default, it was supposed to be `true`. 350 | 351 | -- Alexis Wilke Sat, 9 Jun 2018 00:02:02 -0700 352 | 353 | libaddr (1.0.11.0~xenial) xenial; urgency=high 354 | 355 | * Finally broke the class in two: addr and iface. 356 | * Replaced the is_computer_interface_address() with using the new and 357 | improved find_addr_interface() so we have additional info, not just 358 | true/false. 359 | * Added an is_default() function since that's is true when we setup 360 | an addr object. That way you can detect an uninitialized addr. 361 | * Updated the tests accordingly. They still need to to be enhanced to 362 | cover 100% of the code. 363 | 364 | -- Alexis Wilke Thu, 31 Mar 2018 00:02:02 -0700 365 | 366 | libaddr (1.0.10.0~xenial) xenial; urgency=high 367 | 368 | * Added a function to convert a string to an IP address. 369 | * Added a test to verify that function. 370 | * Fixed an exception, return a 'state' error instead of an 'argument'. 371 | * Many small clean ups. 372 | 373 | -- Alexis Wilke Thu, 31 Mar 2018 00:02:02 -0700 374 | 375 | libaddr (1.0.9.2~xenial) xenial; urgency=high 376 | 377 | * Fixed the license information, it is MIT everywhere now as expected. 378 | * Fixed the debian/copyright file, some paths did not exist. 379 | * Added the C/C++ language tests in the main CMakeLists.txt. 380 | * Fixed the INSTALL.txt, which was a verbatim copy from libtld. 381 | * Fixed several URLs. 382 | * Cleaned up some lines by removing useless comments. 383 | 384 | -- Alexis Wilke Thu, 5 Mar 2018 23:53:59 -0700 385 | 386 | libaddr (1.0.9.1~xenial) xenial; urgency=high 387 | 388 | * Fixed the protocol to the snapwebsites.org. 389 | 390 | -- Alexis Wilke Thu, 8 Feb 2018 00:52:52 -0700 391 | 392 | libaddr (1.0.9.0~xenial) xenial; urgency=high 393 | 394 | * Bumped copyright notice. 395 | * Cleaned up the README.md file. 396 | 397 | -- Alexis Wilke Sun, 28 Jan 2018 23:51:06 -0700 398 | 399 | libaddr (1.0.8.0~xenial) xenial; urgency=high 400 | 401 | * Fixed the tests, the tags need to be between '[' ... ']'. 402 | 403 | -- Alexis Wilke Fri, 24 Feb 2017 20:52:22 -0700 404 | 405 | libaddr (1.0.7.0~xenial) xenial; urgency=high 406 | 407 | * Changed -1LL with std::numeric_limits::max() which is better. 408 | 409 | -- Alexis Wilke Mon, 20 Feb 2017 16:29:22 -0700 410 | 411 | libaddr (1.0.6.0~xenial) xenial; urgency=high 412 | 413 | * SNAP-289: Applied a fixed where variable 's' representing a socket is 414 | now checked for validity before using setsockop(). 415 | 416 | -- Alexis Wilke Wed, 25 Jan 2017 23:07:22 -0700 417 | 418 | libaddr (1.0.5.0~xenial) xenial; urgency=high 419 | 420 | * Fixed the cmake file, the library name is "addr", not "tld". 421 | * Added port 80 as one I can use to run the coverage tests. 422 | * Fixed the STRIP_FROM_PATH in the doxy file. 423 | * Fixed the path to the version.h in the doxy file. 424 | * Fixed the cmake to properly install the libaddr include files. 425 | * Fixed the documentation further. 426 | * Broke up the header file into one file per class and exceptions. 427 | * Added a couple of match() functions to the addr_range class. 428 | * Added some socket related functions, although those should be moved 429 | to a socket class of our future "libsnapnetwork" library... 430 | * Updated the tests accordingly. We still have 100% coverage. 431 | * Various clean ups. 432 | 433 | -- Alexis Wilke Mon, 23 Jan 2017 11:40:22 -0700 434 | 435 | libaddr (1.0.4.0~xenial) xenial; urgency=medium 436 | 437 | * Put two default addresses and mask: one for IPv4 and one for IPv6. 438 | * Test the commas & spaces first. 439 | * Try to use the mask, if present, to know whether we deal with an 440 | IPv4 or IPv6 address if we cannot otherwise know. 441 | * Define a default address in case it is empty and not marked required. 442 | * Updated the test accordingly. 443 | * Added documentation. 444 | 445 | -- Alexis Wilke Sun, 22 Jan 2017 02:55:22 -0700 446 | 447 | libaddr (1.0.3.0~xenial) xenial; urgency=medium 448 | 449 | * Added a couple of tests to verify that a CIDR larger than 1000 generates 450 | an error. 451 | * Enhanced the coverage script so it publishes the coverage data. 452 | * Various clean ups. 453 | 454 | -- Alexis Wilke Sat, 21 Jan 2017 17:31:22 -0700 455 | 456 | libaddr (1.0.2.0~xenial) xenial; urgency=medium 457 | 458 | * The library does not offer a static (.a) version. 459 | 460 | -- Alexis Wilke Sat, 21 Jan 2017 17:31:22 -0700 461 | 462 | libaddr (1.0.1.0~xenial) xenial; urgency=medium 463 | 464 | * Fixed the mask_count test which would return an overflow error. 465 | * Added a test in case the mask is an interger which is way too large. 466 | 467 | -- Alexis Wilke Sat, 21 Jan 2017 16:05:22 -0700 468 | 469 | libaddr (1.0.0.0~xenial) xenial; urgency=medium 470 | 471 | * First release of libaddr. 472 | 473 | -- Alexis Wilke Wed, 18 Jan 2017 13:46:22 -0700 474 | 475 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 15 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: libaddr 2 | Priority: extra 3 | Maintainer: Alexis Wilke 4 | Build-Depends: cmake, 5 | cppthread-dev (>= 1.1.12.1~jammy), 6 | debhelper, 7 | doxygen, 8 | graphviz, 9 | libadvgetopt-dev (>= 2.0.4.0~jammy), 10 | libexcept-dev (>= 1.1.4.0~jammy), 11 | libutf8-dev (>= 1.0.6.0~jammy), 12 | snapcatch2 (>= 2.9.1.0~jammy), 13 | snapcmakemodules (>= 1.0.35.3~jammy), 14 | snapdev (>= 1.1.20.0~jammy) 15 | Standards-Version: 3.9.4 16 | Section: libs 17 | Homepage: https://snapwebsites.org/project/libaddr 18 | Vcs-Git: https://github.com/m2osw/snapcpp.git 19 | Vcs-Browser: https://github.com/m2osw/libaddr 20 | 21 | Package: libaddr 22 | Architecture: any 23 | Section: libs 24 | Depends: ${shlibs:Depends}, ${misc:Depends} 25 | Description: C++ library to convert IP addresses. 26 | Runtime library of the libaddr project. 27 | . 28 | This library is used by C++ applications to convert IP addresses between 29 | text notations and binary and vice versa. It supports IPv4 and IPv6, port 30 | notation, port range, multi-ports, and CIDR masks. 31 | 32 | Package: libaddr-dev 33 | Architecture: any 34 | Section: libdevel 35 | Depends: libaddr (= ${binary:Version}), ${misc:Depends} 36 | Description: C++ library to convert IP addresses. 37 | Development library of the libaddr project. 38 | . 39 | This library is used by C++ applications to convert IP addresses between 40 | text notations and binary and vice versa. It supports IPv4 and IPv6, port 41 | notation, port range, multi-ports, and CIDR masks. 42 | 43 | Package: libaddr-doc 44 | Architecture: all 45 | Section: doc 46 | Depends: ${misc:Depends} 47 | Description: C++ library to convert IP addresses. 48 | Documentation of the libaddr project. 49 | . 50 | This library is used by C++ applications to convert IP addresses between 51 | text notations and binary and vice versa. It supports IPv4 and IPv6, port 52 | notation, port range, multi-ports, and CIDR masks. 53 | 54 | # vim: ts=4 sw=4 et 55 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: libaddr 3 | Upstream-Contact: Alexis Wilke 4 | https://www.m2osw.com/contact 5 | Source: https://snapwebsites.org/project/libaddr 6 | License: MIT 7 | Disclaimer: This package is part of the Snap! C++ system. It is not a native Debian package. 8 | Copyright: 9 | Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 10 | 11 | Files: CMakeLists.txt cmake/* debian/* dev/* doc/* src/* tests/* 12 | Copyright: Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 13 | License: MIT 14 | -------------------------------------------------------------------------------- /debian/libaddr-dev.install: -------------------------------------------------------------------------------- 1 | usr/include/* 2 | usr/lib/lib*.so 3 | usr/share/cmake/* 4 | -------------------------------------------------------------------------------- /debian/libaddr-doc.install: -------------------------------------------------------------------------------- 1 | usr/share/doc/libaddr/* 2 | -------------------------------------------------------------------------------- /debian/libaddr.install: -------------------------------------------------------------------------------- 1 | usr/bin 2 | usr/lib/lib*.so.* 3 | doc/ifaces.1 usr/share/man/man1/ 4 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | %: 13 | dh $@ --parallel 14 | 15 | override_dh_auto_configure: 16 | dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release 17 | 18 | -------------------------------------------------------------------------------- /debian/source/options: -------------------------------------------------------------------------------- 1 | tar-ignore = "tmp" 2 | tar-ignore = ".git" 3 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | # 3 | # https://snapwebsites.org/project/libaddr 4 | # contact@m2osw.com 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | 24 | 25 | ## 26 | ## Documentation 27 | ## 28 | project(documentation) 29 | 30 | find_package(SnapDoxygen) 31 | 32 | AddDoxygenTarget(libaddr 33 | ${LIBADDR_VERSION_MAJOR} 34 | ${LIBADDR_VERSION_MINOR} 35 | ${LIBADDR_VERSION_PATCH} 36 | ) 37 | 38 | # vim: ts=4 sw=4 et 39 | -------------------------------------------------------------------------------- /doc/footer.html: -------------------------------------------------------------------------------- 1 |
2 |

This document is part of the Snap! Websites Project.

3 |

Copyright by Made to Order Software Corp.

4 |
5 | -------------------------------------------------------------------------------- /doc/ifaces.1: -------------------------------------------------------------------------------- 1 | .TH IFACES 1 "November 2023" "ifaces 1.x" "User Commands" 2 | .SH NAME 3 | ifaces \- List interface names 4 | .SH SYNOPSIS 5 | .B ifaces 6 | [\fIOPTION\fR] 7 | .SH DESCRIPTION 8 | The \fBifaces(1)\fR tool prints out the list of interfaces available on your 9 | computer. 10 | 11 | .SH "COMMAND LINE OPTIONS" 12 | .TP 13 | \fB\-\-asterisk\fR 14 | Print an asterisk (*) for the default address (instead of 0.0.0.0 or ::). 15 | 16 | .TP 17 | \fB\-d\fR, \fB\-\-default\fR 18 | Only print information about the default interface. 19 | 20 | .TP 21 | \fB\-h\fR, \fB\-\-help\fR 22 | Print a brief document about the tool usage, then exit. 23 | 24 | .TP 25 | \fB\-\-hide\-headers\fR 26 | Do not print the headers of the output table. 27 | 28 | .TP 29 | \fB\-\-loopback\fR 30 | Only print the name of the loopback interface (usually "lo"). 31 | 32 | .TP 33 | \fB\-\-name-only\fR 34 | Only print the interface names. No address, columns, headers. 35 | 36 | .TP 37 | \fB\-\-private\fR 38 | Only print private interfaces. 39 | 40 | .TP 41 | \fB\-\-public\fR 42 | Only print public interfaces. 43 | 44 | .SH AUTHOR 45 | Written by Alexis Wilke . 46 | .SH "REPORTING BUGS" 47 | Report bugs to . 48 | .br 49 | iplock home page: . 50 | .SH COPYRIGHT 51 | Copyright \(co 2023-2025 Made to Order Software Corp. All Rights Reserved 52 | .br 53 | License: GPLv3 54 | .br 55 | This is free software: you are free to change and redistribute it. 56 | .br 57 | There is NO WARRANTY, to the extent permitted by law. 58 | .SH "SEE ALSO" 59 | .BR ipv4-routes (1), 60 | .BR validate-ip (1) 61 | -------------------------------------------------------------------------------- /doc/libaddr-logo-500x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m2osw/libaddr/63df3cb67f95d5221b9d3502f292da686f8acd1b/doc/libaddr-logo-500x500.png -------------------------------------------------------------------------------- /doc/libaddr-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m2osw/libaddr/63df3cb67f95d5221b9d3502f292da686f8acd1b/doc/libaddr-logo.png -------------------------------------------------------------------------------- /doc/libaddr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m2osw/libaddr/63df3cb67f95d5221b9d3502f292da686f8acd1b/doc/libaddr.png -------------------------------------------------------------------------------- /libaddr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | # 3 | # https://snapwebsites.org/project/libaddr 4 | # contact@m2osw.com 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a 7 | # copy of this software and associated documentation files (the 8 | # "Software"), to deal in the Software without restriction, including 9 | # without limitation the rights to use, copy, modify, merge, publish, 10 | # distribute, sublicense, and/or sell copies of the Software, and to 11 | # permit persons to whom the Software is furnished to do so, subject to 12 | # the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included 15 | # in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | 26 | ## 27 | ## addr library 28 | ## 29 | project(addr) 30 | 31 | configure_file( 32 | version.h.in 33 | ${PROJECT_BINARY_DIR}/version.h 34 | ) 35 | 36 | add_library(${PROJECT_NAME} SHARED 37 | addr.cpp 38 | addr_parser.cpp 39 | addr_range.cpp 40 | addr_unix.cpp 41 | iface.cpp 42 | route.cpp 43 | validator_address.cpp 44 | version.cpp 45 | ) 46 | 47 | target_include_directories(${PROJECT_NAME} 48 | PUBLIC 49 | ${ADVGETOPT_INCLUDE_DIRS} 50 | ${CPPTHREAD_INCLUDE_DIRS} 51 | ${LIBEXCEPT_INCLUDE_DIRS} 52 | ${LIBUTF8_INCLUDE_DIRS} 53 | ) 54 | 55 | target_link_libraries(${PROJECT_NAME} 56 | ${ADVGETOPT_LIBRARIES} 57 | ${CPPTHREAD_LIBRARIES} 58 | ${LIBEXCEPT_LIBRARIES} 59 | ${LIBUTF8_LIBRARIES} 60 | ) 61 | 62 | set_target_properties(${PROJECT_NAME} PROPERTIES 63 | VERSION 64 | ${LIBADDR_VERSION_MAJOR}.${LIBADDR_VERSION_MINOR} 65 | 66 | SOVERSION 67 | ${LIBADDR_VERSION_MAJOR} 68 | ) 69 | 70 | install( 71 | TARGETS 72 | ${PROJECT_NAME} 73 | 74 | LIBRARY DESTINATION 75 | lib 76 | ) 77 | 78 | install( 79 | FILES 80 | addr.h 81 | addr_parser.h 82 | addr_range.h 83 | addr_unix.h 84 | exception.h 85 | iface.h 86 | route.h 87 | ${CMAKE_CURRENT_BINARY_DIR}/version.h 88 | 89 | DESTINATION 90 | include/libaddr 91 | ) 92 | 93 | 94 | # vim: ts=4 sw=4 et 95 | -------------------------------------------------------------------------------- /libaddr/addr.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief The various libaddr classes. 27 | * 28 | * This header includes the base addr class used to handle one binary 29 | * address. 30 | */ 31 | 32 | // C++ 33 | // 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | 43 | // C 44 | // 45 | #include 46 | 47 | 48 | 49 | namespace addr 50 | { 51 | 52 | 53 | 54 | 55 | /** \brief Initialize an IPv6 address as such. 56 | * 57 | * This function initializes a sockaddr_in6 with all zeroes except 58 | * for the sin6_family which is set to AF_INET6. 59 | * 60 | * return The initialized IPv6 address. 61 | */ 62 | constexpr sockaddr_in6 init_in6() 63 | { 64 | sockaddr_in6 in6 = sockaddr_in6(); 65 | in6.sin6_family = AF_INET6; 66 | return in6; 67 | } 68 | 69 | 70 | /** \brief Result of a compare between IP addresses. 71 | * 72 | * This enumeration includes compare results between IP addresses. 73 | * 74 | * The results can also be used by the addr_range class which explains 75 | * the possible range like results. 76 | */ 77 | enum class compare_t 78 | { 79 | COMPARE_EQUAL, // lhs == rhs 80 | COMPARE_SMALLER, // lhs < rhs 81 | COMPARE_LARGER, // lhs > rhs 82 | COMPARE_OVERLAP_SMALL_VS_LARGE, // lhs is before rhs with an overlap 83 | COMPARE_OVERLAP_LARGE_VS_SMALL, // rhs is before lhs with an overlap 84 | COMPARE_INCLUDED, // rhs is included in lhs 85 | COMPARE_INCLUDES, // lhs is included in rhs 86 | COMPARE_PRECEDES, // lhs is just before rhs 87 | COMPARE_FOLLOWS, // lhs is just after rhs 88 | COMPARE_FIRST, // lhs is defined, rhs is empty 89 | COMPARE_LAST, // lhs is empty, rhs is defined 90 | COMPARE_IPV4_VS_IPV6, // lhs is an IPv4, rhs an IPv6 91 | COMPARE_IPV6_VS_IPV4, // lhs is an IPv6, rhs an IPv4 92 | COMPARE_UNORDERED, // lhs and rhs are both empty or are not ranges 93 | }; 94 | 95 | 96 | enum class network_type_t 97 | { 98 | NETWORK_TYPE_UNDEFINED, 99 | NETWORK_TYPE_PRIVATE, 100 | NETWORK_TYPE_CARRIER, 101 | NETWORK_TYPE_LINK_LOCAL, 102 | NETWORK_TYPE_MULTICAST, 103 | NETWORK_TYPE_LOOPBACK, 104 | NETWORK_TYPE_ANY, 105 | NETWORK_TYPE_DOCUMENTATION, 106 | NETWORK_TYPE_UNKNOWN, 107 | NETWORK_TYPE_PUBLIC = NETWORK_TYPE_UNKNOWN // we currently do not distinguish public and unknown 108 | }; 109 | 110 | 111 | typedef std::uint32_t string_ip_t; 112 | 113 | // address 114 | // 115 | constexpr string_ip_t STRING_IP_ADDRESS = 0x0001; // include the address 116 | constexpr string_ip_t STRING_IP_BRACKET_ADDRESS = 0x0002; // address with the brackets in IPv6 117 | 118 | // port 119 | // 120 | constexpr string_ip_t STRING_IP_PORT = 0x0004; // include the port 121 | constexpr string_ip_t STRING_IP_PORT_NAME = 0x0008; // use the port name if available (in /etc/services) 122 | 123 | // mask 124 | // 125 | constexpr string_ip_t STRING_IP_MASK = 0x0010; // include the mask 126 | constexpr string_ip_t STRING_IP_BRACKET_MASK = 0x0020; // put brackets around IPv6 mask 127 | constexpr string_ip_t STRING_IP_MASK_AS_ADDRESS = 0x0040; // output the mask as n.n.n.n or x:x:x:x:x:x:x:x 128 | constexpr string_ip_t STRING_IP_MASK_IF_NEEDED = 0x0080; // output mask only if not equal to 128 129 | 130 | // default IP 131 | // 132 | constexpr string_ip_t STRING_IP_DEFAULT_AS_ASTERISK = 0x0100; // use "*" instead of "::" 133 | constexpr string_ip_t STRING_IP_DEFAULT_AS_IPV4 = 0x0200; // use "0.0.0.0" instead of "::" (useful in to_ipv4or6_string() and to_ipv6_string() 134 | 135 | // combo 136 | // 137 | constexpr string_ip_t STRING_IP_ADDRESS_PORT = STRING_IP_BRACKET_ADDRESS 138 | | STRING_IP_PORT; 139 | constexpr string_ip_t STRING_IP_NO_BRACKETS = STRING_IP_ADDRESS 140 | | STRING_IP_PORT 141 | | STRING_IP_MASK; 142 | constexpr string_ip_t STRING_IP_ALL = STRING_IP_BRACKET_ADDRESS 143 | | STRING_IP_PORT 144 | | STRING_IP_BRACKET_MASK; 145 | 146 | 147 | class addr 148 | { 149 | public: 150 | typedef std::shared_ptr pointer_t; 151 | typedef std::set set_t; 152 | typedef std::vector vector_t; 153 | typedef int socket_flag_t; 154 | 155 | static socket_flag_t const SOCKET_FLAG_CLOEXEC = 0x01; 156 | static socket_flag_t const SOCKET_FLAG_NONBLOCK = 0x02; 157 | static socket_flag_t const SOCKET_FLAG_REUSE = 0x04; 158 | 159 | addr(); 160 | addr(sockaddr_in const & in); 161 | addr(sockaddr_in6 const & in6); 162 | 163 | void set_interface(std::string const & interface); 164 | void set_hostname(std::string const & hostname); 165 | void set_from_socket(int s, bool peer); 166 | void set_ipv4(sockaddr_in const & in); 167 | void set_ipv4_loopback(); 168 | void set_ipv6(sockaddr_in6 const & in6); 169 | void set_ipv6_loopback(); 170 | void set_port_defined(bool defined = true); 171 | bool set_port(char const * port); 172 | void set_port(int port); 173 | void set_protocol_defined(bool defined = true); 174 | void set_protocol(char const * protocol); 175 | void set_protocol(int protocol); 176 | void set_mask_defined(bool defined = true); 177 | void set_mask(std::uint8_t const * mask); 178 | void set_mask_count(int mask_size); 179 | void apply_mask(bool inversed = false); 180 | 181 | std::string get_interface() const; 182 | std::string get_hostname() const; 183 | bool is_hostname_an_ip() const; 184 | int get_family() const; 185 | bool is_default() const; 186 | bool is_valid() const; 187 | bool is_lan(bool include_all = false) const; 188 | bool is_wan(bool include_default = true) const; 189 | bool is_ipv4() const; 190 | void get_ipv4(sockaddr_in & in) const; 191 | void get_ipv6(sockaddr_in6 & in6) const; 192 | std::string to_ipv4_string(string_ip_t const mode) const; 193 | std::string to_ipv6_string(string_ip_t const mode) const; 194 | std::string to_ipv4or6_string(string_ip_t const mode = STRING_IP_ALL) const; 195 | #pragma GCC diagnostic push 196 | #pragma GCC diagnostic ignored "-Wpedantic" 197 | unsigned __int128 ip_to_uint128() const; 198 | void ip_from_uint128(unsigned __int128 u); 199 | #pragma GCC diagnostic pop 200 | 201 | network_type_t get_network_type() const; 202 | char const * get_network_type_string() const; 203 | 204 | int create_socket(socket_flag_t flags) const; 205 | int connect(int s) const; 206 | int bind(int s); 207 | int bind(int s) const; 208 | ssize_t sendto(int s, char const * buffer, std::size_t size) const; 209 | ssize_t recvfrom(int s, char * buffer, std::size_t size); 210 | std::string get_name() const; 211 | std::string get_service() const; 212 | bool is_port_defined() const; 213 | int get_port() const; 214 | std::string get_port_name() const; 215 | std::string get_str_port() const; 216 | bool is_protocol_defined() const; 217 | int get_protocol() const; 218 | std::string get_protocol_name() const; 219 | void get_mask(std::uint8_t * mask) const; 220 | int get_mask_size() const; 221 | bool is_mask_ipv4_compatible() const; 222 | bool is_mask_defined() const; 223 | 224 | bool match(addr const & ip, bool any = false) const; 225 | bool is_next(addr const & a) const; 226 | bool is_previous(addr const & a) const; 227 | bool operator == (addr const & rhs) const; 228 | bool operator != (addr const & rhs) const; 229 | bool operator < (addr const & rhs) const; 230 | bool operator <= (addr const & rhs) const; 231 | bool operator > (addr const & rhs) const; 232 | bool operator >= (addr const & rhs) const; 233 | addr & operator ++ (); 234 | addr operator ++ (int); 235 | addr & operator -- (); 236 | addr operator -- (int); 237 | addr operator + (int offset) const; 238 | addr operator - (int offset) const; 239 | #pragma GCC diagnostic push 240 | #pragma GCC diagnostic ignored "-Wpedantic" 241 | __int128 operator - (addr const & rhs) const; 242 | #pragma GCC diagnostic push 243 | addr & operator += (int offset); 244 | addr & operator -= (int offset); 245 | 246 | private: 247 | void address_changed(); 248 | 249 | // always keep address in an IPv6 structure 250 | // 251 | sockaddr_in6 f_address = init_in6(); 252 | std::uint8_t f_mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; 253 | bool f_port_defined = false; 254 | bool f_protocol_defined = false; 255 | bool f_mask_defined = false; 256 | int f_protocol = IPPROTO_TCP; 257 | mutable network_type_t f_private_network = network_type_t::NETWORK_TYPE_UNDEFINED; 258 | std::string f_interface = std::string(); 259 | std::string f_hostname = std::string(); 260 | }; 261 | 262 | 263 | 264 | /** \brief Set of flags attached to an ostream for an addr object. 265 | * 266 | * This structure holds data used to output an addr object in an ostream. 267 | * 268 | * The mode defines how each address is output (see addr::to_ipv4or6_string()). 269 | * 270 | * The separator is used whenever a vector or set of addresses is printed 271 | * out. 272 | */ 273 | struct _ostream_info 274 | { 275 | string_ip_t f_mode = STRING_IP_ALL; 276 | std::string f_sep = std::string(","); 277 | }; 278 | 279 | /** \brief Retrieve the addr ostream index. 280 | * 281 | * Each class (or at least each project) can allocate a unique index that 282 | * it later references when sending data to an ostream (or istream). 283 | * 284 | * At the moment, the index is allocated for the addr class specifically. 285 | * If we extend the addr_range::vector_t to printing in an ostream as well, 286 | * we can add support for the separator between each range. 287 | */ 288 | int get_ostream_index(); 289 | 290 | 291 | /** \brief An intermediate structure to pass a new mode to ostream. 292 | * 293 | * This structure is used by the setaddrmode() function to update the 294 | * address mode in this specific ostream. 295 | * 296 | * \sa setaddrmode() 297 | */ 298 | struct _setaddrmode 299 | { 300 | string_ip_t f_mode; 301 | }; 302 | 303 | 304 | /** \brief Change the address ostream mode to \p mode. 305 | * 306 | * The conversion of an address to a string uses the to_ipv4or6_string() 307 | * function. That function accepts a mode parameter. By default, it is 308 | * set to "all" (addr::STRING_IP_ALL). You can change 309 | * the mode using this setaddrmode() function in your ostream: 310 | * 311 | * \code 312 | * std::cout << setaddrmode(addr::STRING_IP_ADDRESS | addr::STRING_IP_PORT) 313 | * << my_address 314 | * << std::endl; 315 | * \endcode 316 | * 317 | * The most common is to use the addr::STRING_IP_ADDRESS and the 318 | * addr::STRING_IP_PORT although any other value works as expected (i.e. if 319 | * you do not want to include the port number and do not care about brackets 320 | * around an IPv6, then the most basic addr::STRING_IP_ADDRESS can be used). 321 | */ 322 | inline _setaddrmode setaddrmode(string_ip_t mode) 323 | { 324 | return { mode }; 325 | } 326 | 327 | 328 | /** \brief An intermediate structure to pass a new separator to ostream. 329 | * 330 | * This structure is used by the setaddrsep() function to update the 331 | * address separator in this specific ostream. 332 | * 333 | * \sa setaddrsep() 334 | */ 335 | struct _setaddrsep 336 | { 337 | std::string f_sep; 338 | }; 339 | 340 | 341 | /** \brief Change the address separator to \p sep. 342 | * 343 | * This function initializes a _setsep structure which can then be passed 344 | * to an ostream in order to change the separator used to print between 345 | * each address when writing a container of addresses to an ostream. 346 | * 347 | * The default separator is the comma (","). 348 | * 349 | * \code 350 | * std::cout << setaddrsep("\n") << addr_set << std::endl; 351 | * \endcode 352 | * 353 | * \param[in] sep The new separator to use to print a set of addresses. 354 | */ 355 | inline _setaddrsep setaddrsep(std::string const & sep) 356 | { 357 | return { sep }; 358 | } 359 | 360 | 361 | inline void basic_stream_event_callback(std::ios_base::event e, std::ios_base & out, int index) 362 | { 363 | switch(e) 364 | { 365 | case std::ios_base::erase_event: 366 | delete static_cast<_ostream_info *>(out.pword(index)); 367 | out.pword(index) = nullptr; 368 | break; 369 | 370 | case std::ios_base::copyfmt_event: 371 | { 372 | _ostream_info * info(static_cast<_ostream_info *>(out.pword(index))); 373 | if(info != nullptr) 374 | { 375 | _ostream_info * new_info(new _ostream_info(*info)); 376 | out.pword(index) = new_info; 377 | } 378 | } 379 | break; 380 | 381 | default: 382 | // ignore imbue; we have nothing to do with the locale 383 | break; 384 | 385 | } 386 | } 387 | 388 | 389 | /** \brief Change the current address mode. 390 | * 391 | * This ostream extension function allows you to change the address mode 392 | * using the setaddrmode() function. 393 | * 394 | * \sa setaddrmode() 395 | */ 396 | template 397 | inline std::basic_ostream<_CharT, _Traits> & 398 | operator << (std::basic_ostream<_CharT, _Traits> & out, _setaddrmode mode) 399 | { 400 | int const index(get_ostream_index()); 401 | _ostream_info * info(static_cast<_ostream_info *>(out.pword(index))); 402 | if(info == nullptr) 403 | { 404 | info = new _ostream_info; 405 | out.pword(index) = info; 406 | out.register_callback(basic_stream_event_callback, index); 407 | } 408 | info->f_mode = mode.f_mode; 409 | return out; 410 | } 411 | 412 | 413 | /** \brief Change the current address separator. 414 | * 415 | * The address containers (vector/set) can be printed with an ostream. This 416 | * parameter defines which separator to use between each address. 417 | * 418 | * The addresses are separated by commas by default. 419 | * 420 | * \sa setaddrsep() 421 | */ 422 | template 423 | inline std::basic_ostream<_CharT, _Traits> & 424 | operator << (std::basic_ostream<_CharT, _Traits> & out, _setaddrsep sep) 425 | { 426 | int const index(get_ostream_index()); 427 | _ostream_info * info(static_cast<_ostream_info *>(out.pword(index))); 428 | if(info == nullptr) 429 | { 430 | info = new _ostream_info; 431 | out.pword(index) = info; 432 | out.register_callback(basic_stream_event_callback, index); 433 | } 434 | info->f_sep = sep.f_sep; 435 | return out; 436 | } 437 | 438 | 439 | /** \brief Output an address in your stream. 440 | * 441 | * This function outputs the specified address in your output stream. 442 | * 443 | * \param[in,out] out The output stream where the address is written. 444 | * \param[in] address The address to output in the stream. 445 | * 446 | * \return The reference to out for chaining. 447 | */ 448 | template 449 | inline std::basic_ostream<_CharT, _Traits> & 450 | operator << (std::basic_ostream<_CharT, _Traits> & out, addr const & address) 451 | { 452 | _ostream_info * info(static_cast<_ostream_info *>(out.pword(get_ostream_index()))); 453 | if(info == nullptr) 454 | { 455 | out << address.to_ipv4or6_string(STRING_IP_ALL); 456 | } 457 | else 458 | { 459 | out << address.to_ipv4or6_string(info->f_mode); 460 | } 461 | return out; 462 | } 463 | 464 | 465 | template 466 | inline typename std::enable_if< 467 | std::is_same<_ContainerT, addr::vector_t>::value 468 | || std::is_same<_ContainerT, addr::set_t>::value 469 | , std::basic_ostream<_CharT, _Traits>>::type & 470 | operator << (std::basic_ostream<_CharT, _Traits> & out, _ContainerT const & addresses) 471 | { 472 | std::string sep(","); 473 | _ostream_info * info(static_cast<_ostream_info *>(out.pword(get_ostream_index()))); 474 | if(info != nullptr) 475 | { 476 | sep = info->f_sep; 477 | } 478 | 479 | bool first(true); 480 | for(auto const & a : addresses) 481 | { 482 | if(first) 483 | { 484 | first = false; 485 | } 486 | else 487 | { 488 | out << sep; 489 | } 490 | out << a; 491 | } 492 | return out; 493 | } 494 | 495 | 496 | 497 | } 498 | // namespace addr 499 | 500 | 501 | inline bool operator == (sockaddr_in6 const & a, sockaddr_in6 const & b) 502 | { 503 | return memcmp(&a, &b, sizeof(sockaddr_in6)) == 0; 504 | } 505 | 506 | 507 | inline bool operator != (sockaddr_in6 const & a, sockaddr_in6 const & b) 508 | { 509 | return memcmp(&a, &b, sizeof(sockaddr_in6)) != 0; 510 | } 511 | 512 | 513 | inline bool operator < (sockaddr_in6 const & a, sockaddr_in6 const & b) 514 | { 515 | return memcmp(&a, &b, sizeof(sockaddr_in6)) < 0; 516 | } 517 | 518 | 519 | inline bool operator <= (sockaddr_in6 const & a, sockaddr_in6 const & b) 520 | { 521 | return memcmp(&a, &b, sizeof(sockaddr_in6)) <= 0; 522 | } 523 | 524 | 525 | inline bool operator > (sockaddr_in6 const & a, sockaddr_in6 const & b) 526 | { 527 | return memcmp(&a, &b, sizeof(sockaddr_in6)) > 0; 528 | } 529 | 530 | 531 | inline bool operator >= (sockaddr_in6 const & a, sockaddr_in6 const & b) 532 | { 533 | return memcmp(&a, &b, sizeof(sockaddr_in6)) >= 0; 534 | } 535 | 536 | 537 | inline bool operator == (in6_addr const & a, in6_addr const & b) 538 | { 539 | return memcmp(&a, &b, sizeof(in6_addr)) == 0; 540 | } 541 | 542 | 543 | inline bool operator != (in6_addr const & a, in6_addr const & b) 544 | { 545 | return memcmp(&a, &b, sizeof(in6_addr)) != 0; 546 | } 547 | 548 | 549 | inline bool operator < (in6_addr const & a, in6_addr const & b) 550 | { 551 | return memcmp(&a, &b, sizeof(in6_addr)) < 0; 552 | } 553 | 554 | 555 | inline bool operator <= (in6_addr const & a, in6_addr const & b) 556 | { 557 | return memcmp(&a, &b, sizeof(in6_addr)) <= 0; 558 | } 559 | 560 | 561 | inline bool operator > (in6_addr const & a, in6_addr const & b) 562 | { 563 | return memcmp(&a, &b, sizeof(in6_addr)) > 0; 564 | } 565 | 566 | 567 | inline bool operator >= (in6_addr const & a, in6_addr const & b) 568 | { 569 | return memcmp(&a, &b, sizeof(in6_addr)) >= 0; 570 | } 571 | 572 | 573 | 574 | // vim: ts=4 sw=4 et 575 | -------------------------------------------------------------------------------- /libaddr/addr_parser.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief The declaration of the parser of the libaddr classes. 27 | * 28 | * This header includes the addr_parser class used to parse user input 29 | * string and convert them to binary IP addresses. 30 | */ 31 | 32 | // self 33 | // 34 | #include 35 | 36 | 37 | 38 | namespace addr 39 | { 40 | 41 | 42 | enum class allow_t 43 | { 44 | ALLOW_ADDRESS, // address (IP) 45 | ALLOW_REQUIRED_ADDRESS, // address cannot be empty 46 | ALLOW_MULTI_ADDRESSES_COMMAS, // IP:port/mask,IP:port/mask,... 47 | ALLOW_MULTI_ADDRESSES_SPACES, // IP:port/mask IP:port/mask ... 48 | ALLOW_MULTI_ADDRESSES_NEWLINES, // IP:port/mask\nIP:port/mask\n... 49 | ALLOW_ADDRESS_LOOKUP, // whether DNS lookup is allowed 50 | ALLOW_ADDRESS_RANGE, // IP-IP:port/mask 51 | 52 | ALLOW_PORT, // port 53 | ALLOW_REQUIRED_PORT, // port must be defined 54 | 55 | ALLOW_MASK, // mask 56 | ALLOW_ADDRESS_MASK, // mask like an address (opposed to just a number, which is the only new valid version) 57 | 58 | ALLOW_COMMENT_HASH, // if address starts with '#', it's a comment, ignore; useful with ALLOW_MULTI_ADDRESSES_NEWLINES 59 | ALLOW_COMMENT_SEMICOLON, // if address starts with ':', it's a comment, ignore; useful with ALLOW_MULTI_ADDRESSES_NEWLINES 60 | 61 | // TODO: the following are not yet implemented 62 | ALLOW_MULTI_PORTS_SEMICOLONS, // port1;port2;... 63 | ALLOW_MULTI_PORTS_COMMAS, // port1,port2,... 64 | ALLOW_PORT_RANGE, // port1-port2 65 | 66 | ALLOW_max 67 | }; 68 | 69 | 70 | typedef std::uint_fast16_t sort_t; 71 | 72 | constexpr sort_t const SORT_NO = 0x0000; // keep IPs as found 73 | constexpr sort_t const SORT_IPV6_FIRST = 0x0001; // put IPv6 first (IPv6, IPv4, empty) 74 | constexpr sort_t const SORT_IPV4_FIRST = 0x0002; // put IPv4 first (IPv4, IPv6, empty) 75 | constexpr sort_t const SORT_FULL = 0x0004; // sort IPs between each others (default keep in order found) 76 | constexpr sort_t const SORT_MERGE = 0x0008; // merge ranges which support a union (implies SORT_FULL) 77 | constexpr sort_t const SORT_NO_EMPTY = 0x0010; // remove empty entries 78 | 79 | 80 | class addr_parser 81 | { 82 | public: 83 | addr_parser(); 84 | 85 | void set_default_address(std::string const & address); 86 | std::string const & get_default_address4() const; 87 | std::string const & get_default_address6() const; 88 | 89 | void set_default_port(std::string const & port); 90 | void set_default_port(int const port); 91 | int get_default_port() const; 92 | 93 | void set_default_mask(std::string const & mask); 94 | std::string const & get_default_mask4() const; 95 | std::string const & get_default_mask6() const; 96 | 97 | void set_protocol(std::string const & protocol); 98 | void set_protocol(int const protocol); 99 | void clear_protocol(); 100 | int get_protocol() const; 101 | 102 | void set_sort_order(sort_t const sort); 103 | sort_t get_sort_order() const; 104 | 105 | void set_allow(allow_t const flag, bool const allow); 106 | bool get_allow(allow_t const flag) const; 107 | 108 | bool has_errors() const; 109 | void emit_error(std::string const & msg); 110 | std::string const & error_messages() const; 111 | int error_count() const; 112 | void clear_errors(); 113 | 114 | addr_range::vector_t parse(std::string const & in); 115 | 116 | private: 117 | void parse_address_range(std::string const & in, addr_range::vector_t & result); 118 | void parse_cidr(std::string const & in, addr_range::vector_t & result); 119 | bool parse_address(std::string const & in, std::string const & mask, addr_range::vector_t & result); 120 | void parse_address4(std::string const & in, addr_range::vector_t & result); 121 | void parse_address6(std::string const & in, std::size_t const colons, addr_range::vector_t & result); 122 | void parse_address_range_port(std::string const & addresses, std::string const & port_str, addr_range::vector_t & result, bool ipv6); 123 | void parse_address_port(std::string address, std::string port_str, addr_range::vector_t & result, bool ipv6); 124 | void parse_address_port_ignore_duplicates(std::string address, std::string port_str, addr_range::vector_t & result, bool ipv6); 125 | void parse_mask(std::string const & mask, addr & cidr, bool is_ipv4); 126 | 127 | bool f_flags[static_cast(allow_t::ALLOW_max)] = {}; 128 | sort_t f_sort = SORT_NO; 129 | std::string f_default_address4 = std::string(); 130 | std::string f_default_address6 = std::string(); 131 | std::string f_default_mask4 = std::string(); 132 | std::string f_default_mask6 = std::string(); 133 | int f_protocol = -1; 134 | int f_default_port = -1; 135 | std::string f_error = std::string(); 136 | int f_error_count = 0; 137 | }; 138 | 139 | addr string_to_addr( 140 | std::string const & a 141 | , std::string const & default_address = std::string() 142 | , int default_port = -1 143 | , std::string const & protocol = std::string() 144 | , bool mask = false); 145 | 146 | 147 | 148 | } 149 | // namespace addr 150 | // vim: ts=4 sw=4 et 151 | -------------------------------------------------------------------------------- /libaddr/addr_range.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief The addr_range class. 27 | * 28 | * This header defines the addr_range class used to handle one range of 29 | * addresses (with a 'from' and a 'to' pair of addresses.) 30 | * 31 | * Also we support CIDR, a CIDR is not a range. A range can define anything 32 | * that is not a perfect CIDR match. For example, you could have a start 33 | * address of 192.168.10.5 and an end address of 192.168.10.10. 34 | */ 35 | 36 | // self 37 | // 38 | #include 39 | 40 | 41 | 42 | namespace addr 43 | { 44 | 45 | 46 | class addr_range 47 | { 48 | public: 49 | typedef std::shared_ptr pointer_t; 50 | typedef std::vector vector_t; 51 | 52 | bool has_from() const; 53 | bool has_to() const; 54 | bool is_defined() const; 55 | bool is_range() const; 56 | bool is_empty() const; 57 | bool is_in(addr const & rhs) const; 58 | bool is_ipv4() const; 59 | 60 | void set_from(addr const & from); 61 | addr & get_from(); 62 | addr const & get_from() const; 63 | void set_to(addr const & to); 64 | addr & get_to(); 65 | addr const & get_to() const; 66 | void swap_from_to(); 67 | void from_cidr(addr const & a); 68 | bool to_cidr(addr & a) const; 69 | addr::vector_t to_addresses(std::size_t limit = 1000) const; 70 | std::string to_string(string_ip_t const mode = STRING_IP_ALL) const; 71 | static std::string to_string( 72 | vector_t const & ranges 73 | , string_ip_t const mode = STRING_IP_ALL 74 | , std::string const & separator = std::string(",")); 75 | 76 | std::size_t size() const; 77 | addr_range intersection(addr_range const & rhs) const; 78 | addr_range union_if_possible(addr_range const & rhs) const; 79 | bool match(addr const & address) const; 80 | compare_t compare(addr_range const & rhs, bool mixed = false) const; 81 | bool operator < (addr_range const & rhs) const; 82 | 83 | static addr::vector_t to_addresses(vector_t ranges, std::size_t limit = 1000); 84 | 85 | private: 86 | bool f_has_from = false; 87 | bool f_has_to = false; 88 | addr f_from = addr(); 89 | addr f_to = addr(); 90 | }; 91 | 92 | 93 | bool address_match_ranges(addr_range::vector_t ranges, addr const & address); 94 | bool optimize_vector(addr::vector_t & v); 95 | 96 | 97 | template 98 | inline std::basic_ostream<_CharT, _Traits> & 99 | operator << (std::basic_ostream<_CharT, _Traits> & out, addr_range const & range) 100 | { 101 | _ostream_info * info(static_cast<_ostream_info *>(out.pword(get_ostream_index()))); 102 | if(info == nullptr) 103 | { 104 | out << range.to_string(STRING_IP_ALL); 105 | } 106 | else 107 | { 108 | out << range.to_string(info->f_mode); 109 | } 110 | return out; 111 | } 112 | 113 | 114 | template 115 | inline std::basic_ostream<_CharT, _Traits> & 116 | operator << (std::basic_ostream<_CharT, _Traits> & out, addr_range::vector_t const & ranges) 117 | { 118 | _ostream_info * info(static_cast<_ostream_info *>(out.pword(get_ostream_index()))); 119 | if(info == nullptr) 120 | { 121 | out << addr_range::to_string(ranges); 122 | } 123 | else 124 | { 125 | out << addr_range::to_string( 126 | ranges 127 | , info->f_mode 128 | , info->f_sep); 129 | } 130 | return out; 131 | } 132 | 133 | 134 | 135 | 136 | 137 | 138 | } 139 | // namespace addr 140 | // vim: ts=4 sw=4 et 141 | -------------------------------------------------------------------------------- /libaddr/addr_unix.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief The Unix libaddr class. 27 | * 28 | * This header defines the Unix address class. This is used to connect to 29 | * Unix sockets. 30 | * 31 | * The library supports all three types of Unix addresses supported by 32 | * Linux: 33 | * 34 | * * File based: a path to a file on disk. 35 | * * Abstract: a abstract path. 36 | * * Unnamed: a completely unnamed socket. 37 | * 38 | * The first one (File) is what most users are expected to use. 39 | * 40 | * The second one (Abstract) is what many X11 tools use to communicate. 41 | * Especially, it is called the "bus" in Gnome. 42 | * 43 | * The third one (Unnamed) is only useful for parent/child communication. 44 | * The child can be a process created by fork() and fork() + exec(). 45 | */ 46 | 47 | // C++ 48 | // 49 | #include 50 | #include 51 | #include 52 | 53 | 54 | // C 55 | // 56 | #include 57 | #include 58 | 59 | 60 | 61 | namespace addr 62 | { 63 | 64 | 65 | 66 | 67 | /** \brief Initialize a Unix address as such. 68 | * 69 | * This function initializes a sockaddr_un with all zeroes except 70 | * for the sun_family which is set to AF_UNIX. 71 | * 72 | * return The initialized Unix address. 73 | */ 74 | constexpr struct sockaddr_un init_un() 75 | { 76 | struct sockaddr_un un = sockaddr_un(); 77 | un.sun_family = AF_UNIX; 78 | return un; 79 | } 80 | 81 | 82 | constexpr int const DEFAULT_MODE = 0600; 83 | 84 | 85 | class addr_unix 86 | { 87 | public: 88 | typedef std::shared_ptr pointer_t; 89 | typedef std::vector vector_t; 90 | typedef int socket_flag_t; 91 | 92 | addr_unix(); 93 | addr_unix(sockaddr_un const & un); 94 | addr_unix(std::string const & address, bool abstract = false); 95 | 96 | void set_scheme(std::string const & scheme); 97 | void set_un(sockaddr_un const & un); 98 | void make_unnamed(); 99 | void set_file(std::string const & address); 100 | void set_mode(int mode); 101 | void set_group(std::string const & group); 102 | void set_abstract(std::string const & address); 103 | void set_uri(std::string const & address); 104 | bool set_from_socket(int s); 105 | 106 | bool is_file() const; 107 | bool is_abstract() const; 108 | bool is_unnamed() const; 109 | std::string get_scheme() const; 110 | void get_un(sockaddr_un & un) const; 111 | int get_mode() const; 112 | std::string get_group() const; 113 | std::string to_string() const; 114 | std::string to_uri() const; 115 | int unlink(); 116 | 117 | bool operator == (addr_unix const & rhs) const; 118 | bool operator != (addr_unix const & rhs) const; 119 | bool operator < (addr_unix const & rhs) const; 120 | bool operator <= (addr_unix const & rhs) const; 121 | bool operator > (addr_unix const & rhs) const; 122 | bool operator >= (addr_unix const & rhs) const; 123 | 124 | private: 125 | std::string verify_path(std::string const & path, bool abstract); 126 | 127 | std::string f_scheme = std::string(); 128 | sockaddr_un f_address = init_un(); 129 | int f_mode = DEFAULT_MODE; 130 | std::string f_group = std::string(); 131 | }; 132 | 133 | 134 | 135 | 136 | 137 | } 138 | // namespace addr 139 | 140 | 141 | inline bool operator == (sockaddr_un const & a, sockaddr_un const & b) 142 | { 143 | return memcmp(&a, &b, sizeof(sockaddr_un)) == 0; 144 | } 145 | 146 | 147 | inline bool operator != (sockaddr_un const & a, sockaddr_un const & b) 148 | { 149 | return memcmp(&a, &b, sizeof(sockaddr_un)) != 0; 150 | } 151 | 152 | 153 | inline bool operator < (sockaddr_un const & a, sockaddr_un const & b) 154 | { 155 | return memcmp(&a, &b, sizeof(sockaddr_un)) < 0; 156 | } 157 | 158 | 159 | inline bool operator <= (sockaddr_un const & a, sockaddr_un const & b) 160 | { 161 | return memcmp(&a, &b, sizeof(sockaddr_un)) <= 0; 162 | } 163 | 164 | 165 | inline bool operator > (sockaddr_un const & a, sockaddr_un const & b) 166 | { 167 | return memcmp(&a, &b, sizeof(sockaddr_un)) > 0; 168 | } 169 | 170 | 171 | inline bool operator >= (sockaddr_un const & a, sockaddr_un const & b) 172 | { 173 | return memcmp(&a, &b, sizeof(sockaddr_un)) >= 0; 174 | } 175 | 176 | 177 | 178 | // vim: ts=4 sw=4 et 179 | -------------------------------------------------------------------------------- /libaddr/exception.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief The list of libaddr exceptions. 27 | * 28 | * This header defines various exceptions used throughout the addr library. 29 | */ 30 | 31 | // libexcept 32 | // 33 | #include 34 | 35 | 36 | namespace addr 37 | { 38 | 39 | 40 | 41 | DECLARE_LOGIC_ERROR(logic_error); // LCOV_EXCL_LINE 42 | DECLARE_OUT_OF_RANGE(out_of_range); 43 | 44 | DECLARE_MAIN_EXCEPTION(addr_error); 45 | 46 | DECLARE_EXCEPTION(addr_error, addr_io_error); 47 | DECLARE_EXCEPTION(addr_error, addr_invalid_argument); 48 | DECLARE_EXCEPTION(addr_error, addr_invalid_state); 49 | DECLARE_EXCEPTION(addr_error, addr_invalid_structure); 50 | DECLARE_EXCEPTION(addr_error, addr_unexpected_error); // LCOV_EXCL_LINE 51 | DECLARE_EXCEPTION(addr_error, addr_unexpected_mask); 52 | DECLARE_EXCEPTION(addr_error, addr_unsupported_as_range); 53 | 54 | 55 | 56 | } 57 | // namespace addr 58 | // vim: ts=4 sw=4 et 59 | -------------------------------------------------------------------------------- /libaddr/iface.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | /** \file 26 | * \brief The implementation of the addr class. 27 | * 28 | * This file includes the implementation of the addr class. The one that 29 | * deals with low level classes. 30 | */ 31 | 32 | 33 | // self 34 | // 35 | #include "libaddr/iface.h" 36 | #include "libaddr/route.h" 37 | 38 | 39 | 40 | // cppthread 41 | // 42 | #include 43 | #include 44 | 45 | 46 | // snapdev 47 | // 48 | #include 49 | 50 | 51 | // C++ 52 | // 53 | #include 54 | #include 55 | 56 | 57 | // C 58 | // 59 | #include 60 | #include 61 | 62 | 63 | // last include 64 | // 65 | #include 66 | 67 | 68 | 69 | namespace addr 70 | { 71 | 72 | 73 | /** \brief Details used by the addr class implementation. 74 | * 75 | * We have a function to check whether an address is part of 76 | * the interfaces of your computer. This check requires the 77 | * use of a `struct ifaddrs` and as such it requires to 78 | * delete that structure. We define a deleter for that 79 | * strucure here. 80 | */ 81 | namespace 82 | { 83 | 84 | 85 | 86 | /** \brief Cache TTL. 87 | * 88 | * The time the cache survies another call to iface::get_local_addresses(). 89 | * 90 | * After the TTL is elapsed, the next call ignores the cache and re-reads 91 | * the list of interfaces from the kernel. 92 | */ 93 | std::uint32_t g_cache_ttl = 5 * 60; 94 | 95 | 96 | /** \brief Cache lifetime. 97 | * 98 | * This parameter is set to time(nullptr) + TTL whenever a new set of 99 | * interfaces is gathered from the OS. 100 | */ 101 | time_t g_cache_timeout = 0; 102 | 103 | 104 | /** \brief Array of interfaces. 105 | * 106 | * This vector keeps the interfaces in our cache for a few minutes. This 107 | * way, functions that make heavy use of interfaces will still go fast. 108 | * 109 | * You can call the reset_cache() function if you want to reset the 110 | * cache and make sure what you load is fresh. This is not necessary if 111 | * you just started your process. 112 | */ 113 | iface::pointer_vector_t g_cache_iface = iface::pointer_vector_t(); 114 | 115 | 116 | /** \brief Delete an ifaddrs structure. 117 | * 118 | * This deleter is used to make sure all the ifaddrs get released when 119 | * an exception occurs or the function using such exists. 120 | * 121 | * \param[in] ia The ifaddrs structure to free. 122 | */ 123 | void ifaddrs_deleter(struct ifaddrs * ia) 124 | { 125 | freeifaddrs(ia); 126 | } 127 | 128 | 129 | 130 | } 131 | // no name namespace 132 | 133 | 134 | 135 | 136 | 137 | /** \brief Initializes an interface name/index pair. 138 | * 139 | * This function creates an interface name/index object. 140 | * 141 | * In some circumstances (NETLINK) you need to specify the index of an 142 | * interface. The kernel keeps a list of interface by index starting at 1 143 | * and each have a name such as "eth0". This function initializes 144 | * one of those pairs. 145 | * 146 | * \param[in] index The index of the interface. 147 | * \param[in] name The name of the interface. 148 | */ 149 | iface_index_name::iface_index_name(unsigned int index, std::string const & name) 150 | : f_index(index) 151 | , f_name(name) 152 | { 153 | } 154 | 155 | 156 | /** \brief Get the index of this interface. 157 | * 158 | * This function is used to retrieve the index of a name/index pair. 159 | * 160 | * \return The index of the name/index pair. 161 | */ 162 | unsigned int iface_index_name::get_index() const 163 | { 164 | return f_index; 165 | } 166 | 167 | 168 | /** \brief Get the name of this interface. 169 | * 170 | * This function is used to retrieve the name of a name/index pair. 171 | * 172 | * \return The name of the name/index pair. 173 | */ 174 | std::string const & iface_index_name::get_name() const 175 | { 176 | return f_name; 177 | } 178 | 179 | 180 | 181 | /** \brief Get the list of existing interfaces. 182 | * 183 | * This function gathers the complete list of interfaces by index and 184 | * name pairs. The result is a vector of iface_index_name objects. 185 | * 186 | * Note that over time the index of an interface can change since interfaces 187 | * can be added and removed from your network configuration. It is a good 188 | * idea to not cache that information. 189 | * 190 | * \return A vector of index/name pair objects. 191 | */ 192 | iface_index_name::vector_t get_interface_name_index() 193 | { 194 | iface_index_name::vector_t result; 195 | 196 | // the index starts at 1 197 | // 198 | for(unsigned int index(1);; ++index) 199 | { 200 | // get the next interface name by index 201 | // 202 | char name[IF_NAMESIZE + 1]; 203 | if(if_indextoname(index, name) == nullptr) 204 | { 205 | return result; 206 | } 207 | 208 | // make sure the name is null terminated 209 | // 210 | name[IF_NAMESIZE] = '\0'; 211 | 212 | iface_index_name const in(index, name); 213 | result.push_back(in); 214 | } 215 | snapdev::NOT_REACHED(); 216 | } // LCOV_EXCL_LINE 217 | 218 | 219 | /** \brief Get the index of an interface from its name. 220 | * 221 | * If you are given the name of an interface, you can retrieve its index 222 | * by calling this function. The resulting value is the index from 1 to n. 223 | * 224 | * If the named interface is not found, then the function returns 0. 225 | * 226 | * \return The interface index or 0 on error. 227 | */ 228 | unsigned int get_interface_index_by_name(std::string const & name) 229 | { 230 | return if_nametoindex(name.c_str()); 231 | } 232 | 233 | 234 | 235 | 236 | 237 | 238 | /** \brief Return a list of local addresses on this machine. 239 | * 240 | * Peruse the list of available interfaces, and return any detected 241 | * ip addresses in a vector. 242 | * 243 | * These addresses include: 244 | * 245 | * \li A mask whenever available (very likely if the interface is up). 246 | * \li A name you can retrieve with get_iface_name() 247 | * \li A set of flags defining the current status of the network interface 248 | * (i.e. IFF_UP, IFF_BROADCAST, IFF_NOARP, etc.) 249 | * 250 | * \note 251 | * The function caches the list of interfaces. On a second call, and if 252 | * the cache did not yet time out (see set_local_addresses_cache_ttl() 253 | * for details), then the same list is returned. You can prevent the 254 | * behavior by first clearing the cache (see reset_local_addresses_cache() 255 | * for details). 256 | * \note 257 | * The cache is managed in a thread safe manner. 258 | * 259 | * \return A vector of all the local interface IP addresses. 260 | * 261 | * \sa set_local_addresses_cache_ttl() 262 | * \sa reset_local_addresses_cache() 263 | */ 264 | iface::pointer_vector_t iface::get_local_addresses() 265 | { 266 | // check whether we have that vector in our cache, if so use that 267 | { 268 | cppthread::guard lock(*cppthread::g_system_mutex); 269 | 270 | if(g_cache_timeout >= time(nullptr) 271 | && g_cache_iface != nullptr) 272 | { 273 | return g_cache_iface; 274 | } 275 | g_cache_iface = std::make_shared(); 276 | } 277 | 278 | // get the list of interface addresses 279 | // 280 | struct ifaddrs * ifa_start(nullptr); 281 | if(getifaddrs(&ifa_start) != 0) 282 | { 283 | // TODO: Should this throw, or just return an empty list quietly? 284 | // 285 | return iface::pointer_vector_t(); // LCOV_EXCL_LINE 286 | } 287 | 288 | std::shared_ptr auto_free(ifa_start, ifaddrs_deleter); 289 | 290 | std::uint8_t mask[16]; 291 | iface::pointer_vector_t iface_list(std::make_shared()); 292 | for(struct ifaddrs * ifa(ifa_start); ifa != nullptr; ifa = ifa->ifa_next) 293 | { 294 | // the documentation says there may be no addresses at all 295 | // skip such entries at the moment 296 | // 297 | if(ifa->ifa_addr == nullptr) 298 | { 299 | continue; // LCOV_EXCL_LINE 300 | } 301 | 302 | // initialize an interface 303 | // 304 | iface::pointer_t the_interface(std::make_shared()); 305 | 306 | // copy the name and flags as is 307 | // 308 | // TBD: can the ifa_name ever be a null pointer? 309 | // 310 | the_interface->f_name = ifa->ifa_name; 311 | the_interface->f_flags = ifa->ifa_flags; // IFF_... flags (see `man 7 netdevice` search for SIOCGIFFLAGS) 312 | 313 | // get the family to know how to treat the address 314 | // 315 | // when an interface has an IPv4 and an IPv6, there are two entries in 316 | // the list, both with the same name 317 | // 318 | std::uint16_t const family(ifa->ifa_addr->sa_family); 319 | 320 | switch(family) 321 | { 322 | case AF_INET: 323 | the_interface->f_address.set_ipv4(*(reinterpret_cast(ifa->ifa_addr))); 324 | 325 | if((ifa->ifa_flags & IFF_BROADCAST) != 0 326 | && ifa->ifa_broadaddr != nullptr) 327 | { 328 | the_interface->f_broadcast_address.set_ipv4(*(reinterpret_cast(ifa->ifa_broadaddr))); 329 | } 330 | if((ifa->ifa_flags & IFF_POINTOPOINT) != 0 331 | && ifa->ifa_dstaddr != nullptr) // LCOV_EXCL_LINE 332 | { 333 | the_interface->f_destination_address.set_ipv4(*(reinterpret_cast(ifa->ifa_dstaddr))); // LCOV_EXCL_LINE 334 | } 335 | 336 | // if present, add the mask as well 337 | // 338 | if(ifa->ifa_netmask != nullptr) 339 | { 340 | // for the IPv4 mask, we have to break it down in such a 341 | // way as to make it IPv6 compatible 342 | // 343 | memset(mask, 255, 12); 344 | mask[12] = reinterpret_cast(ifa->ifa_netmask)->sin_addr.s_addr >> 0; 345 | mask[13] = reinterpret_cast(ifa->ifa_netmask)->sin_addr.s_addr >> 8; 346 | mask[14] = reinterpret_cast(ifa->ifa_netmask)->sin_addr.s_addr >> 16; 347 | mask[15] = reinterpret_cast(ifa->ifa_netmask)->sin_addr.s_addr >> 24; 348 | the_interface->f_address.set_mask(mask); 349 | } 350 | break; 351 | 352 | case AF_INET6: 353 | the_interface->f_address.set_ipv6(*(reinterpret_cast(ifa->ifa_addr))); 354 | 355 | // this should never happen since IPv6 does not support broadcast addresses 356 | // 357 | if((ifa->ifa_flags & IFF_BROADCAST) != 0 358 | && ifa->ifa_broadaddr != nullptr) 359 | { 360 | the_interface->f_broadcast_address.set_ipv6(*(reinterpret_cast(ifa->ifa_broadaddr))); // LCOV_EXCL_LINE 361 | } 362 | if((ifa->ifa_flags & IFF_POINTOPOINT) != 0 363 | && ifa->ifa_dstaddr != nullptr) // LCOV_EXCL_LINE 364 | { 365 | the_interface->f_destination_address.set_ipv6(*(reinterpret_cast(ifa->ifa_dstaddr))); // LCOV_EXCL_LINE 366 | } 367 | 368 | // if present, add the mask as well 369 | // 370 | if(ifa->ifa_netmask != nullptr) 371 | { 372 | the_interface->f_address.set_mask(reinterpret_cast(&reinterpret_cast(ifa->ifa_netmask)->sin6_addr)); 373 | } 374 | break; 375 | 376 | default: // AF_PACKET happens on Linux (Raw Packet) 377 | // TODO: can we just ignore unexpected address families? 378 | //throw addr_invalid_structure("Unknown address family."); 379 | continue; 380 | 381 | } 382 | 383 | iface_list->push_back(the_interface); 384 | } 385 | 386 | { 387 | cppthread::guard lock(*cppthread::g_system_mutex); 388 | 389 | g_cache_timeout = time(nullptr) + g_cache_ttl; 390 | g_cache_iface.swap(iface_list); 391 | return g_cache_iface; 392 | } 393 | } 394 | 395 | 396 | /** \brief Explicitly reset the interface cache. 397 | * 398 | * This function resets the cache timeout to 0 and resets the vector of 399 | * interfaces. If you use the list of interfaces just once and then will 400 | * never call the function again, it is a good idea to reset the cache. 401 | */ 402 | void iface::reset_local_addresses_cache() 403 | { 404 | cppthread::guard lock(*cppthread::g_system_mutex); 405 | 406 | g_cache_timeout = 0; 407 | g_cache_iface.reset(); 408 | } 409 | 410 | 411 | /** \brief Change the TTL of the interface cache. 412 | * 413 | * By default the TTL of the interface cache is set to 5 minutes. If you do 414 | * not expect any changes, you could grow this number quite a bit. If you 415 | * do expect a lot of changes all the time, then a much smaller number 416 | * should be used. 417 | * 418 | * 0 does not cancel the use of the cache entirely. Instead, it will be 419 | * used for up to one second. 420 | * 421 | * \note 422 | * This function is thread safe. 423 | * 424 | * \param[in] duration_seconds The duration of the interface cache. 425 | */ 426 | void iface::set_local_addresses_cache_ttl(std::uint32_t duration_seconds) 427 | { 428 | g_cache_ttl = duration_seconds; 429 | } 430 | 431 | 432 | /** \brief Get the interface name. 433 | * 434 | * This function returns the name of the interface such as 'eth0' or 'p4p1'. 435 | * 436 | * The name is used in a few places such as the ioctl() function with the 437 | * SIOCGIFMTU command. Otherwise, it's mainly for display and easing use 438 | * (i.e. to let users select which interface to connect to.) 439 | * 440 | * \return The interface name. 441 | */ 442 | std::string iface::get_name() const 443 | { 444 | return f_name; 445 | } 446 | 447 | 448 | /** \brief Get the interface setup flags. 449 | * 450 | * This function returns a set of flags defined on that interface. The flags 451 | * are defined in the `man 7 netdevice` as the IFF_... flags. The flags are 452 | * defined under the SIOCGIFFLAGS and SIOCSIFFLAGS entries. 453 | * 454 | * One flag of interest is the IFF_UP flag. This means the interface is 455 | * active (even if not actually in use.) 456 | * 457 | * \return The interface flags. 458 | */ 459 | unsigned int iface::get_flags() const 460 | { 461 | return f_flags; 462 | } 463 | 464 | 465 | /** \brief Get this interface address. 466 | * 467 | * This function returns the address of the interface. This address is very 468 | * likely to have a mask (i.e. 192.168.0.0/255.255.0.0). 469 | * 470 | * The address may be an IPv4 or an IPv6 address. 471 | * 472 | * \return The address of the interface. 473 | */ 474 | addr const & iface::get_address() const 475 | { 476 | return f_address; 477 | } 478 | 479 | 480 | /** \brief Get the broadcast address. 481 | * 482 | * This function returns a constant reference to the broadcast address 483 | * of this interface. The address is always available in this class. It 484 | * will be set to the ANY address if it was not defined. Note, however, 485 | * that even though the ANY address is not a valid broadcast address, 486 | * you should call the has_broadcast_address() function to know whether 487 | * this address is indeed defined. 488 | * 489 | * \note 490 | * An interface with only IPv6 addresses has no broadcast addresses. 491 | * 492 | * \return The broadcast address of this interface or the ANY address if not 493 | * available. 494 | */ 495 | addr const & iface::get_broadcast_address() const 496 | { 497 | return f_broadcast_address; 498 | } 499 | 500 | 501 | /** \brief Get the destination address. 502 | * 503 | * This function returns a constant reference to the destination address 504 | * of this interface. The address is always available in this class. It 505 | * will be set to the ANY address if it was not defined. Note, however, 506 | * that the ANY address is a valid destination address (i.e. default 507 | * route). 508 | * 509 | * To know whether the destination address is defined in that interface, 510 | * make sure to call the has_destination_address() function first. 511 | * 512 | * \return The destination address of this interface. 513 | */ 514 | addr const & iface::get_destination_address() const 515 | { 516 | return f_destination_address; 517 | } 518 | 519 | 520 | /** \brief Check whether a broadcast address. 521 | * 522 | * The broadcast address is not present on all interfaces. When it is, this 523 | * function returns true. 524 | * 525 | * Note that you can always call the get_broadcast_address(), but if 526 | * undefined it will appear as a default address (NETWORK_TYPE_ANY) 527 | * which you can't distinguish from a valid address although 528 | * the NETWORK_TYPE_ANY is not a valid address for a broadcast 529 | * address. 530 | * 531 | * \note 532 | * When a broadcast address is defined on an interface, then there can't 533 | * be a destination address. 534 | * 535 | * \note 536 | * An interface with only an IPv6 address has no broadcast address. 537 | * 538 | * \return true if a broadcast address is defined. 539 | */ 540 | bool iface::has_broadcast_address() const 541 | { 542 | return (f_flags & IFF_BROADCAST) != 0; 543 | } 544 | 545 | 546 | /** \brief Check whether this interface defines a destination address. 547 | * 548 | * This function returns true if this interface defined a destination 549 | * address. Either way you can call the get_destination_address() 550 | * function, however, the address will be of type NETWORK_TYPE_ANY 551 | * which does not tell you whether it was defined or not. 552 | * 553 | * Ethernet and the local interfaces all define a destination address. 554 | * 555 | * \note 556 | * The destination address is not assigned any specific mask (all 557 | * are ff or 255). 558 | * 559 | * \note 560 | * When there is a destination address defined on an interface, then 561 | * there can't be a broadcast address. 562 | * 563 | * \return true when that interface defined a destination address. 564 | */ 565 | bool iface::has_destination_address() const 566 | { 567 | return (f_flags & IFF_POINTOPOINT) != 0; 568 | } 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | /** \brief Search for the interface corresponding to this address. 587 | * 588 | * Peruse the list of available interfaces and return the one that matches 589 | * the \p a address if any, otherwise return a null pointer. 590 | * 591 | * Say you create an addr object with the IP address "127.0.0.1" and then 592 | * call this function. You will get a pointer to the "lo" interface and 593 | * can check the validity of the flags (i.e. is the interface UP, can it 594 | * BROADCAST or MULTICAST your UDP packets, etc.) 595 | * 596 | * If the address is a remote address, then this function returns a null 597 | * pointer. 598 | * 599 | * \warning 600 | * If you allow for the default destination, this function calls the 601 | * route::get_ipv4_routes() function which can be costly. Try to avoid 602 | * doing that in a loop. 603 | * 604 | * \param[in] a The address used to search for an interface. 605 | * \param[in] allow_default_destination If true and \p a doesn't match 606 | * any of the interfaces, use the one interface with its 607 | * destination set to 0.0.0.0 or equivalent. 608 | * 609 | * \return A pointer to an interface IP address. 610 | */ 611 | iface::pointer_t find_addr_interface(addr const & a, bool allow_default_destination) 612 | { 613 | iface::pointer_vector_t interfaces(iface::get_local_addresses()); 614 | 615 | for(auto i : *interfaces) 616 | { 617 | if(i->get_address().match(a)) 618 | { 619 | return i; 620 | } 621 | } 622 | 623 | // if there is a default, keep a copy in case we do not find a 624 | // local address while looking (and only if the user requested 625 | // such, which is the default) 626 | // 627 | if(!allow_default_destination) 628 | { 629 | return iface::pointer_t(); 630 | } 631 | 632 | // to determine the default interface, we need the list of routes 633 | // so we first gather that information and then search for the 634 | // interface that has that name 635 | // 636 | route::vector_t routes(route::get_ipv4_routes()); 637 | route::pointer_t default_route(find_default_route(routes)); 638 | if(default_route == nullptr) 639 | { 640 | return iface::pointer_t(); // LCOV_EXCL_LINE 641 | } 642 | 643 | std::string const & default_iface(default_route->get_interface_name()); 644 | auto it(std::find_if( 645 | interfaces->cbegin() 646 | , interfaces->cend() 647 | , [default_iface](auto const & i) 648 | { 649 | return i->get_name() == default_iface; 650 | })); 651 | if(it == interfaces->cend()) 652 | { 653 | return iface::pointer_t(); // LCOV_EXCL_LINE 654 | } 655 | 656 | return *it; 657 | } 658 | 659 | 660 | /** \brief Check whether \p a represents an interface's broadcast address. 661 | * 662 | * The function first searches for the address among the interfaces 663 | * available on this computer. If found, it then verifies that \p a 664 | * represents the broadcasting address of that interface. 665 | * 666 | * \note 667 | * IPv6 addresses do not support broadcast addresses. This function always 668 | * return false for an IPv6 address. 669 | * 670 | * \warning 671 | * This test does not return true if the address is a multicast address 672 | * (the 224.0.0.0/4 address range in IPv4) for two reasons: (1) you can 673 | * always check that using the addr::get_network_type() function and 674 | * (2) that address range is deprecated and should not really be used 675 | * (although many service discovery on intranets still make heavy use 676 | * of those IPs). 677 | * 678 | * \warning 679 | * Some protected environment, such as Docker and SELinux, may prevent 680 | * access to SO_BROADCAST. Often, though, Docker does not set the 681 | * Broadcast address on their interface but it is still accessible. Either 682 | * way, our applications will not detect a broadcast IP address if not 683 | * properly set in the interface. 684 | * 685 | * \todo 686 | * The current version does not cache anything so each call requires 687 | * us to list the interfaces and search through the vector. We may want 688 | * to look into a way to cache the data. The current version is that way 689 | * for two reasons: (1) in most cases the list is checked only once, and 690 | * (2) this way we can make sure to always test with the current set 691 | * of IPs in the system. Long term services need that ability. 692 | * 693 | * \param[in] a The address to check as a broadcast address. 694 | * 695 | * \return true if the address represents the broadcast address. 696 | */ 697 | bool is_broadcast_address(addr const & a) 698 | { 699 | if(!a.is_ipv4()) 700 | { 701 | return false; 702 | } 703 | 704 | iface::pointer_t ptr(find_addr_interface(a, false)); 705 | if(ptr == nullptr) 706 | { 707 | return false; // LCOV_EXCL_LINE 708 | } 709 | 710 | return ptr->get_broadcast_address() == a; 711 | } 712 | 713 | 714 | 715 | } 716 | // namespace addr 717 | // vim: ts=4 sw=4 et 718 | -------------------------------------------------------------------------------- /libaddr/iface.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief The various libaddr classes. 27 | * 28 | * This header includes the base addr class used to handle one binary 29 | * address. 30 | */ 31 | 32 | // addr 33 | // 34 | #include 35 | 36 | 37 | 38 | namespace addr 39 | { 40 | 41 | 42 | class iface_index_name 43 | { 44 | public: 45 | typedef std::vector vector_t; 46 | 47 | iface_index_name(unsigned int index, std::string const & name); 48 | 49 | unsigned int get_index() const; 50 | std::string const & get_name() const; 51 | 52 | private: 53 | unsigned int f_index = 0; 54 | std::string f_name = std::string(); 55 | }; 56 | 57 | iface_index_name::vector_t get_interface_name_index(); 58 | unsigned int get_interface_index_by_name(std::string const & name); 59 | 60 | 61 | class iface 62 | { 63 | public: 64 | typedef std::shared_ptr pointer_t; 65 | typedef std::vector vector_t; 66 | typedef std::shared_ptr pointer_vector_t; 67 | 68 | static iface::pointer_vector_t get_local_addresses(); 69 | static void reset_local_addresses_cache(); 70 | static void set_local_addresses_cache_ttl(std::uint32_t duration_seconds); 71 | 72 | std::string get_name() const; 73 | unsigned int get_flags() const; 74 | addr const & get_address() const; 75 | addr const & get_broadcast_address() const; 76 | addr const & get_destination_address() const; 77 | 78 | bool has_broadcast_address() const; 79 | bool has_destination_address() const; 80 | 81 | private: 82 | std::string f_name = std::string(); 83 | unsigned int f_flags = 0; 84 | addr f_address = addr(); 85 | addr f_broadcast_address = addr(); 86 | addr f_destination_address = addr(); 87 | }; 88 | 89 | 90 | 91 | iface::pointer_t find_addr_interface(addr const & a, bool allow_default_destination = true); 92 | bool is_broadcast_address(addr const & a); 93 | 94 | 95 | 96 | } 97 | // namespace addr 98 | // vim: ts=4 sw=4 et 99 | -------------------------------------------------------------------------------- /libaddr/route.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | /** \file 26 | * \brief The implementation of the route class. 27 | * 28 | * This file includes the implementation of the route class. 29 | * 30 | * The route class registers information about a route. It is created 31 | * by using the get_routes() function. 32 | */ 33 | 34 | // self 35 | // 36 | #include "libaddr/exception.h" 37 | #include "libaddr/route.h" 38 | 39 | 40 | // C++ 41 | // 42 | #include 43 | #include 44 | #include 45 | 46 | 47 | // C 48 | // 49 | #include 50 | 51 | 52 | // last include 53 | // 54 | #include 55 | 56 | 57 | 58 | namespace addr 59 | { 60 | 61 | 62 | typedef std::vector words_t; 63 | 64 | 65 | /** \brief Details used by the route class implementation. 66 | * 67 | * The following handles the route class and gathering of the routes. 68 | */ 69 | namespace 70 | { 71 | 72 | 73 | /** \brief Read one line of content from a file. 74 | * 75 | * This function reads one line of content up to the next '\n'. 76 | * 77 | * \param[in,out] in The input stream. 78 | * \param[out] line The line just read. 79 | * 80 | * \return 0 on success, -1 on error (generally EOF) 81 | */ 82 | int readwords(std::ifstream & in, words_t & words) 83 | { 84 | words.clear(); 85 | std::string w; 86 | for(;;) 87 | { 88 | int const c(in.get()); 89 | if(c < 0) 90 | { 91 | return -1; 92 | } 93 | if(c == '\n') 94 | { 95 | return 0; 96 | } 97 | if(c == '\t' || c == ' ') 98 | { 99 | // there should always be a first word, however, there can 100 | // be multiple '\t' or ' ' after one another 101 | if(!w.empty()) 102 | { 103 | words.push_back(w); 104 | w.clear(); 105 | } 106 | } 107 | else 108 | { 109 | w += c; 110 | } 111 | } 112 | } 113 | 114 | 115 | int get_position(words_t const & headers, std::string const & column_name) 116 | { 117 | auto it(std::find( 118 | headers.cbegin() 119 | , headers.cend() 120 | , column_name)); 121 | 122 | if(it == headers.end()) 123 | { 124 | return -1; // LCOV_EXCL_LINE 125 | } 126 | 127 | return it - headers.begin(); 128 | } 129 | 130 | 131 | std::string const & get_value(words_t const & entries, int pos) 132 | { 133 | static std::string const not_found; 134 | 135 | if(pos < static_cast(entries.size())) 136 | { 137 | return entries[pos]; 138 | } 139 | 140 | return not_found; // LCOV_EXCL_LINE 141 | } 142 | 143 | 144 | int hex_to_number(char c) 145 | { 146 | if(c >= '0' && c <= '9') 147 | { 148 | return c - '0'; 149 | } 150 | if(c >= 'a' && c <= 'f') 151 | { 152 | return c - 'a' + 10; // LCOV_EXCL_LINE 153 | } 154 | if(c >= 'A' && c <= 'F') 155 | { 156 | return c - 'A' + 10; 157 | } 158 | throw addr_invalid_argument("invalid hexadecimal digit"); // LCOV_EXCL_LINE 159 | } 160 | 161 | 162 | addr hex_to_addr(std::string const & address) 163 | { 164 | if(address.length() != 8) 165 | { 166 | throw addr_invalid_argument("invalid length for a hex address"); // LCOV_EXCL_LINE 167 | } 168 | 169 | struct sockaddr_in in = sockaddr_in(); 170 | in.sin_family = AF_INET; 171 | in.sin_port = 0; 172 | in.sin_addr.s_addr = 173 | (hex_to_number(address[7]) << 0) 174 | | (hex_to_number(address[6]) << 4) 175 | | (hex_to_number(address[5]) << 8) 176 | | (hex_to_number(address[4]) << 12) 177 | | (hex_to_number(address[3]) << 16) 178 | | (hex_to_number(address[2]) << 20) 179 | | (hex_to_number(address[1]) << 24) 180 | | (hex_to_number(address[0]) << 28) 181 | ; 182 | 183 | return addr(in); 184 | } 185 | 186 | 187 | struct flag_name_t 188 | { 189 | uint32_t const f_flag; 190 | char const f_name; 191 | }; 192 | 193 | /** \brief Flags used by route tables. 194 | * 195 | * \note 196 | * The list of flags presented here includes IPv4 and IPv6 flags. 197 | * 198 | * \note 199 | * Some of the flags are not defined in Ubuntu 16.04. 200 | */ 201 | flag_name_t const g_rtf_flag_names[] = 202 | { 203 | { RTF_UP, 'U' }, 204 | { RTF_GATEWAY, 'G' }, 205 | { RTF_REJECT, '!' }, // may not be defined 206 | { RTF_HOST, 'H' }, 207 | { RTF_REINSTATE, 'R' }, 208 | { RTF_DYNAMIC, 'D' }, 209 | { RTF_MODIFIED, 'M' }, 210 | { RTF_DEFAULT, 'd' }, 211 | { RTF_ALLONLINK, 'a' }, 212 | { RTF_ADDRCONF, 'c' }, 213 | { RTF_NONEXTHOP, 'o' }, 214 | //{ RTF_EXPIRES, 'e' }, 215 | { RTF_CACHE, 'C' }, 216 | { RTF_FLOW, 'f' }, 217 | { RTF_POLICY, 'p' }, 218 | { RTF_LOCAL, 'l' }, 219 | { RTF_MTU, 'u' }, 220 | { RTF_WINDOW, 'w' }, 221 | { RTF_IRTT, 'i' }, 222 | //{ RTF_NOTCACHED, 'n' }, 223 | }; 224 | 225 | 226 | 227 | } 228 | // no name namespace 229 | 230 | 231 | 232 | /** \brief Read the list of routes. 233 | * 234 | * This function reads the list of routes using the /proc/net/routes 235 | * file. It returns a vector of easy to use route objects. 236 | * 237 | * The content of the route table is scanned using the column names 238 | * so it makes sure that it does not use the wrong column (i.e. 239 | * expect that the columns never change over time.) 240 | * 241 | * \note 242 | * If an error occurs, the reurned vector is empty and errno is 243 | * set to the error that happened. The ENODATA error is used 244 | * if some mandatory columns are missing and thus this function 245 | * cannot properly load the columns. 246 | * 247 | * \todo 248 | * Write the IPv6 function. It's similar only there are no headers 249 | * and (obviously?!) the IPs are IPv6 instead of IPv4. 250 | * 251 | * \return A vector of the routes found in the file. 252 | */ 253 | route::vector_t route::get_ipv4_routes() 254 | { 255 | // the 'route' tool uses '/proc/net/route' so we do that too here 256 | // 257 | route::vector_t routes; 258 | 259 | std::ifstream in("/proc/net/route"); 260 | 261 | // the first line is a set of headers, we use that to make sure that 262 | // we know what each column is 263 | // 264 | words_t headers; 265 | int e(readwords(in, headers)); 266 | if(e < 0) 267 | { 268 | return routes; // LCOV_EXCL_LINE 269 | } 270 | 271 | // TODO: we may want to remove case although I don't think it will 272 | // change over time, it could be one more thing that could... 273 | 274 | int const pos_iface (get_position(headers, "Iface")); 275 | int const pos_destination(get_position(headers, "Destination")); 276 | int const pos_gateway (get_position(headers, "Gateway")); 277 | int const pos_flags (get_position(headers, "Flags")); 278 | int const pos_refcnt (get_position(headers, "RefCnt")); 279 | int const pos_use (get_position(headers, "Use")); 280 | int const pos_metric (get_position(headers, "Metric")); 281 | int const pos_mask (get_position(headers, "Mask")); 282 | int const pos_mtu (get_position(headers, "MTU")); 283 | int const pos_window (get_position(headers, "Window")); 284 | int const pos_irtt (get_position(headers, "IRTT")); 285 | 286 | if(pos_iface == -1 287 | || pos_destination == -1 288 | || pos_gateway == -1) 289 | { 290 | errno = ENODATA; // LCOV_EXCL_LINE 291 | return routes; // LCOV_EXCL_LINE 292 | } 293 | 294 | for(;;) 295 | { 296 | // read one entry 297 | // 298 | words_t entries; 299 | e = readwords(in, entries); 300 | if(e < 0) 301 | { 302 | break; 303 | } 304 | 305 | // convert each column to data in a 'route' object 306 | // 307 | route r; 308 | 309 | r.f_interface_name = get_value(entries, pos_iface); 310 | r.f_destination_address = hex_to_addr(get_value(entries, pos_destination)); 311 | r.f_gateway_address = hex_to_addr(get_value(entries, pos_gateway)); 312 | r.f_flags = std::stol(get_value(entries, pos_flags)); 313 | r.f_reference_count = std::stol(get_value(entries, pos_refcnt)); 314 | r.f_use = std::stol(get_value(entries, pos_use)); 315 | r.f_metric = std::stol(get_value(entries, pos_metric)); 316 | r.f_mtu = std::stol(get_value(entries, pos_mtu)); 317 | r.f_window = std::stol(get_value(entries, pos_window)); 318 | r.f_irtt = std::stol(get_value(entries, pos_irtt)); 319 | 320 | // the mask is handled specially 321 | // 322 | std::string mask_str(get_value(entries, pos_mask)); 323 | if(!mask_str.empty()) 324 | { 325 | addr mask = hex_to_addr(mask_str); 326 | struct sockaddr_in ipv4 = sockaddr_in(); 327 | mask.get_ipv4(ipv4); 328 | uint8_t m[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; 329 | m[12] = ipv4.sin_addr.s_addr >> 0; 330 | m[13] = ipv4.sin_addr.s_addr >> 8; 331 | m[14] = ipv4.sin_addr.s_addr >> 16; 332 | m[15] = ipv4.sin_addr.s_addr >> 24; 333 | r.f_destination_address.set_mask(m); 334 | } 335 | 336 | routes.push_back(pointer_t(new route(r))); 337 | } 338 | 339 | return routes; 340 | } 341 | 342 | 343 | std::string const & route::get_interface_name() const 344 | { 345 | return f_interface_name; 346 | } 347 | 348 | 349 | addr const & route::get_destination_address() const 350 | { 351 | return f_destination_address; 352 | } 353 | 354 | 355 | addr const & route::get_gateway_address() const 356 | { 357 | return f_gateway_address; 358 | } 359 | 360 | 361 | int route::get_flags() const 362 | { 363 | return f_flags; 364 | } 365 | 366 | 367 | std::string route::flags_to_string() const 368 | { 369 | std::string result; 370 | 371 | std::for_each( 372 | g_rtf_flag_names 373 | , g_rtf_flag_names + sizeof(g_rtf_flag_names) / sizeof(g_rtf_flag_names[0]) 374 | , [&result, this](auto const & fn) 375 | { 376 | if((f_flags & fn.f_flag) != 0) 377 | { 378 | result += fn.f_name; 379 | } 380 | }); 381 | 382 | return result; 383 | } // LCOV_EXCL_LINE 384 | 385 | 386 | int route::get_reference_count() const 387 | { 388 | return f_reference_count; 389 | } 390 | 391 | 392 | int route::get_use() const 393 | { 394 | return f_use; 395 | } 396 | 397 | 398 | int route::get_metric() const 399 | { 400 | return f_metric; 401 | } 402 | 403 | 404 | int route::get_mtu() const 405 | { 406 | return f_mtu; 407 | } 408 | 409 | 410 | int route::get_window() const 411 | { 412 | return f_window; 413 | } 414 | 415 | 416 | int route::get_irtt() const 417 | { 418 | return f_irtt; 419 | } 420 | 421 | 422 | route::pointer_t find_default_route(route::vector_t const & routes) 423 | { 424 | auto it(std::find_if( 425 | routes.cbegin() 426 | , routes.cend() 427 | , [](auto const & r) 428 | { 429 | return r->get_destination_address().is_default(); 430 | })); 431 | 432 | if(it == routes.cend()) 433 | { 434 | return nullptr; 435 | } 436 | 437 | return *it; 438 | } 439 | 440 | 441 | 442 | } 443 | // namespace addr 444 | // vim: ts=4 sw=4 et 445 | -------------------------------------------------------------------------------- /libaddr/route.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief The various route class. 27 | * 28 | * This header includes the route class used to handle routes as found 29 | * in the routing tables of the kernel. 30 | */ 31 | 32 | // addr 33 | // 34 | #include 35 | 36 | 37 | 38 | namespace addr 39 | { 40 | 41 | 42 | 43 | class route 44 | { 45 | public: 46 | typedef std::shared_ptr pointer_t; 47 | typedef std::vector vector_t; 48 | 49 | static vector_t get_ipv4_routes(); 50 | 51 | std::string const & get_interface_name() const; 52 | addr const & get_destination_address() const; 53 | addr const & get_gateway_address() const; 54 | int get_flags() const; 55 | std::string flags_to_string() const; 56 | int get_reference_count() const; 57 | int get_use() const; 58 | int get_metric() const; 59 | int get_mtu() const; 60 | int get_window() const; 61 | int get_irtt() const; 62 | 63 | private: 64 | std::string f_interface_name = std::string(); 65 | addr f_destination_address = addr(); // Destination + Mask 66 | addr f_gateway_address = addr(); 67 | int f_flags = 0; 68 | int f_reference_count = 0; 69 | int f_use = 0; 70 | int f_metric = 0; 71 | int f_mtu = 0; 72 | int f_window = 0; 73 | int f_irtt = 0; 74 | }; 75 | 76 | 77 | route::pointer_t find_default_route(route::vector_t const & routes); 78 | 79 | 80 | } 81 | // namespace addr 82 | // vim: ts=4 sw=4 et 83 | -------------------------------------------------------------------------------- /libaddr/validator_address.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // This program is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 2 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along 17 | // with this program; if not, write to the Free Software Foundation, Inc., 18 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | 20 | /** \file 21 | * \brief Implementation of the address validator. 22 | * 23 | * The address validator allows us to verify that a parameter represents 24 | * an address as supported by the addr_parser class. 25 | * 26 | * The input parameters understood by the address validator are: 27 | * 28 | * * `address=[yes|no|required] [commas] [spaces] [newlines] [range] [lookup]` 29 | * 30 | * If `yes`, then an address is allowed. This is the default if none of 31 | * `yes`, `no`, and `required` were specified. 32 | * 33 | * If `no`, an address is not allowed. 34 | * 35 | * If `required`, an address must be specified (it may still come from 36 | * the default address). This option is mutually exclusive with the `yes` 37 | * and the `no`. Only one of the three can be specified. 38 | * 39 | * The `commas`, `spaces`, `newlines` allow for multiple addresses 40 | * separated by commas (,), spaces ( ), and newlines (\\n). None, 41 | * one, or a mix can be specified. The newlines should probably not 42 | * be used with the command line validators since in all likelihood 43 | * users won't pass a parameter with newlines in it. 44 | * 45 | * The `range` allows address ranges (addresses separated by a dash (-)). 46 | * 47 | * The `lookup` -- if a hostname is specified, a lookup is allowed 48 | * 49 | * * `default=\
:\/\ ...` 50 | * 51 | * Specify a default address, port, and mask. 52 | * 53 | * You can specify two of these: one for IPv4 and one for IPv6. To make 54 | * sure that an address is viewed as an IPv6 address, make sure to use 55 | * brackets around the address and the mask. 56 | * 57 | * * `comment=yes|all|hash|semicolon|no` 58 | * 59 | * Whether comments are allowed or not. In most likelihood, it should not 60 | * be used with the validator since parameters passed on the command line 61 | * cannot be separated by newlines. 62 | * 63 | * The "yes" and "all" mean the same thing. All the different types of 64 | * comments will be allowed. 65 | * 66 | * The "hash" means the '#' character starts a comment. 67 | * 68 | * The "semicolon" means the ';' character starts a comment. 69 | * 70 | * * `port=yes|no|required` 71 | * 72 | * Whether the port is allowed (`yes`), not allowed (`no`), or must be 73 | * specified (`required`). 74 | * 75 | * * `mask=yes|no|address` 76 | * 77 | * If `yes` then a mask is allowed. 78 | * 79 | * If `no` then no mask is allowed. 80 | * 81 | * If `address` then a mask is allowed and it can be written as an IP 82 | * address (opposed to just a CIDR number). 83 | * 84 | * \todo 85 | * Once support for multi-ports and ranges is available, add such to the 86 | * validator. 87 | */ 88 | 89 | // self 90 | // 91 | #include "libaddr/validator_address.h" 92 | 93 | 94 | // cppthread 95 | // 96 | #include 97 | 98 | 99 | // snapdev 100 | // 101 | #include 102 | 103 | 104 | // C++ 105 | // 106 | #include 107 | 108 | 109 | // last include 110 | // 111 | #include 112 | 113 | 114 | 115 | 116 | namespace addr 117 | { 118 | 119 | 120 | 121 | namespace 122 | { 123 | 124 | 125 | 126 | class validator_address_factory 127 | : public advgetopt::validator_factory 128 | { 129 | public: 130 | validator_address_factory() 131 | { 132 | advgetopt::validator::register_validator(*this); 133 | } 134 | 135 | virtual std::string get_name() const override 136 | { 137 | return std::string("address"); 138 | } 139 | 140 | virtual std::shared_ptr create(advgetopt::string_list_t const & data) const override 141 | { 142 | return std::make_shared(data); 143 | } 144 | }; 145 | 146 | validator_address_factory g_validator_address_factory; 147 | 148 | 149 | 150 | } // no name namespace 151 | 152 | 153 | 154 | 155 | 156 | /** \brief Initialize a validator_address object. 157 | * 158 | * This function parses the specified \p address as a default set of 159 | * parameters to the addr_parser class. Note that the function accepts 160 | * a list but the list is expected to be empty or have exactly one 161 | * parameter. 162 | * 163 | * \param[in] data The address defining defaults. 164 | */ 165 | validator_address::validator_address(advgetopt::string_list_t const & data) 166 | { 167 | for(auto const & p : data) 168 | { 169 | // this should not happen in the regular advgetopt since the empty 170 | // string does not get added to the string_list_t vector; but a 171 | // user could do that 172 | // 173 | if(p.empty()) 174 | { 175 | continue; 176 | } 177 | 178 | std::string name; 179 | advgetopt::string_list_t values; 180 | std::string::size_type const equal(p.find('=')); 181 | if(equal == std::string::npos) 182 | { 183 | name = p; 184 | values.push_back("yes"); 185 | } 186 | else 187 | { 188 | name = p.substr(0, equal); 189 | advgetopt::split_string(p.substr(equal + 1), values, {" "}); 190 | if(values.empty()) 191 | { 192 | values.push_back("yes"); 193 | } 194 | } 195 | 196 | assert(!values.empty()); 197 | 198 | switch(name[0]) 199 | { 200 | case 'a': 201 | if(name == "address") 202 | { 203 | // first reset it all 204 | // 205 | f_parser.set_allow(allow_t::ALLOW_ADDRESS, false); 206 | f_parser.set_allow(allow_t::ALLOW_REQUIRED_ADDRESS, false); 207 | f_parser.set_allow(allow_t::ALLOW_MULTI_ADDRESSES_COMMAS, false); 208 | f_parser.set_allow(allow_t::ALLOW_MULTI_ADDRESSES_SPACES, false); 209 | f_parser.set_allow(allow_t::ALLOW_MULTI_ADDRESSES_NEWLINES, false); 210 | f_parser.set_allow(allow_t::ALLOW_ADDRESS_RANGE, false); 211 | f_parser.set_allow(allow_t::ALLOW_ADDRESS_LOOKUP, false); 212 | 213 | if(std::find(values.begin(), values.end(), std::string("no")) != values.end()) 214 | { 215 | if(values.size() != 1) 216 | { 217 | cppthread::log 218 | << cppthread::log_level_t::error 219 | << "the \"no\" option in the address=... option must be used by itself." 220 | << cppthread::end; 221 | } 222 | } 223 | else 224 | { 225 | f_parser.set_allow(allow_t::ALLOW_ADDRESS, true); 226 | for(auto const & v : values) 227 | { 228 | switch(v[0]) 229 | { 230 | case 'c': 231 | if(v == "commas") 232 | { 233 | f_parser.set_allow(allow_t::ALLOW_MULTI_ADDRESSES_COMMAS, true); 234 | continue; 235 | } 236 | break; 237 | 238 | case 'l': 239 | if(v == "lookup") 240 | { 241 | f_parser.set_allow(allow_t::ALLOW_ADDRESS_LOOKUP, true); 242 | continue; 243 | } 244 | break; 245 | 246 | case 'n': 247 | if(v == "newlines") 248 | { 249 | f_parser.set_allow(allow_t::ALLOW_MULTI_ADDRESSES_NEWLINES, true); 250 | continue; 251 | } 252 | break; 253 | 254 | case 'r': 255 | if(v == "range") 256 | { 257 | f_parser.set_allow(allow_t::ALLOW_ADDRESS_RANGE, true); 258 | continue; 259 | } 260 | if(v == "required") 261 | { 262 | f_parser.set_allow(allow_t::ALLOW_REQUIRED_ADDRESS, true); 263 | continue; 264 | } 265 | break; 266 | 267 | case 's': 268 | if(v == "spaces") 269 | { 270 | f_parser.set_allow(allow_t::ALLOW_MULTI_ADDRESSES_SPACES, true); 271 | continue; 272 | } 273 | break; 274 | 275 | case 'y': 276 | if(v == "yes") 277 | { 278 | if(std::find(values.begin(), values.end(), std::string("required")) != values.end()) 279 | { 280 | cppthread::log 281 | << cppthread::log_level_t::error 282 | << "the \"yes\" and \"required\" options are mutually exclusive, use one or the other (or none, which defaults to \"yes\")." 283 | << cppthread::end; 284 | } 285 | continue; 286 | } 287 | break; 288 | 289 | } 290 | 291 | cppthread::log 292 | << cppthread::log_level_t::error 293 | << "the \"" 294 | << v 295 | << "\" parameter is not understood by the \"address\" options." 296 | << cppthread::end; 297 | } 298 | } 299 | continue; 300 | } 301 | break; 302 | 303 | case 'c': 304 | if(name == "comment") 305 | { 306 | f_parser.set_allow(allow_t::ALLOW_COMMENT_HASH, false); 307 | f_parser.set_allow(allow_t::ALLOW_COMMENT_SEMICOLON, false); 308 | 309 | if(values.size() != 1) 310 | { 311 | cppthread::log 312 | << cppthread::log_level_t::error 313 | << "the \"comment\" option expects one of \"yes\", \"all\", \"hash\", \"semicolon\" or \"no\"." 314 | << cppthread::end; 315 | } 316 | else if(values[0] == "yes" 317 | || values[0] == "all") 318 | { 319 | f_parser.set_allow(allow_t::ALLOW_COMMENT_HASH, true); 320 | f_parser.set_allow(allow_t::ALLOW_COMMENT_SEMICOLON, true); 321 | } 322 | else if(values[0] == "hash") 323 | { 324 | f_parser.set_allow(allow_t::ALLOW_COMMENT_HASH, true); 325 | } 326 | else if(values[0] == "semicolon") 327 | { 328 | f_parser.set_allow(allow_t::ALLOW_COMMENT_SEMICOLON, true); 329 | } 330 | else if(values[0] != "no") 331 | { 332 | cppthread::log 333 | << cppthread::log_level_t::error 334 | << "value \"" 335 | << values[0] 336 | << "\" is unexpected for the \"comment\" option which expects one of \"yes\", \"all\", \"hash\", \"semicolon\" or \"no\"." 337 | << cppthread::end; 338 | } 339 | continue; 340 | } 341 | break; 342 | 343 | case 'd': 344 | if(name == "default" 345 | || name == "defaults") 346 | { 347 | // `values` cannot be empty, instead it gets set to "yes" 348 | // and in case of the defaults, it means clear the defaults 349 | // 350 | if(values.size() == 1 351 | && values[0] == "yes") 352 | { 353 | // remove all defaults 354 | // 355 | f_parser.set_default_address(std::string()); 356 | f_parser.set_default_port(std::string()); 357 | f_parser.set_default_mask(std::string()); 358 | } 359 | else 360 | { 361 | // TODO we need to properly distinguish between 362 | // IPv4 and IPv6 363 | // 364 | for(auto const & param : values) 365 | { 366 | addr_parser parser; 367 | parser.set_allow(allow_t::ALLOW_MASK, true); 368 | parser.set_protocol(IPPROTO_TCP); 369 | addr_range::vector_t v(parser.parse(param)); 370 | if(v.size() == 1 371 | && v[0].has_from() 372 | && !v[0].has_to()) 373 | { 374 | // TODO: try to find a way to avoid getting multiple 375 | // IP addresses; by default the system gives 376 | // us one IP per Proto (TCP, UDP, IP) 377 | // 378 | addr const a(v[0].get_from()); 379 | 380 | if(a.get_network_type() != network_type_t::NETWORK_TYPE_ANY) 381 | { 382 | f_parser.set_default_address(a.to_ipv4or6_string(STRING_IP_BRACKET_ADDRESS)); 383 | } 384 | 385 | if(a.get_port() != 0) 386 | { 387 | f_parser.set_default_port(a.get_str_port()); 388 | } 389 | 390 | int const mask(a.get_mask_size()); 391 | if(mask != -1 392 | && mask != 128) 393 | { 394 | if(a.is_ipv4()) 395 | { 396 | f_parser.set_default_mask(std::to_string(mask)); 397 | } 398 | else 399 | { 400 | // add the '[...]' to make it an IPv6 mask 401 | // 402 | #pragma GCC diagnostic push 403 | #pragma GCC diagnostic ignored "-Wrestrict" 404 | f_parser.set_default_mask("[" + std::to_string(mask) + "]"); 405 | #pragma GCC diagnostic pop 406 | } 407 | } 408 | } 409 | else 410 | { 411 | cppthread::log 412 | << cppthread::log_level_t::error 413 | << "the default address \"" 414 | << param 415 | << "\" could not be parsed properly. Error: " 416 | << parser.error_messages() 417 | << cppthread::end; 418 | } 419 | } 420 | } 421 | continue; 422 | } 423 | break; 424 | 425 | case 'm': 426 | if(name == "mask") 427 | { 428 | f_parser.set_allow(allow_t::ALLOW_MASK, false); 429 | f_parser.set_allow(allow_t::ALLOW_ADDRESS_MASK, false); 430 | 431 | if(values.size() != 1) 432 | { 433 | cppthread::log 434 | << cppthread::log_level_t::error 435 | << "the \"mask\" option expects one of \"yes\", \"no\", or \"address\"." 436 | << cppthread::end; 437 | } 438 | else if(values[0] != "no") 439 | { 440 | f_parser.set_allow(allow_t::ALLOW_MASK, true); 441 | 442 | if(values[0] == "address") 443 | { 444 | f_parser.set_allow(allow_t::ALLOW_ADDRESS_MASK, true); 445 | } 446 | else if(values[0] != "yes") 447 | { 448 | cppthread::log 449 | << cppthread::log_level_t::error 450 | << "value \"" 451 | << values[0] 452 | << "\" is unexpected for the \"mask\" option which expects one of \"yes\", \"no\", or \"address\"." 453 | << cppthread::end; 454 | } 455 | } 456 | continue; 457 | } 458 | break; 459 | 460 | case 'p': 461 | if(name == "port") 462 | { 463 | f_parser.set_allow(allow_t::ALLOW_PORT, false); 464 | f_parser.set_allow(allow_t::ALLOW_REQUIRED_PORT, false); 465 | 466 | if(values.size() != 1) 467 | { 468 | cppthread::log 469 | << cppthread::log_level_t::error 470 | << "the port=... option expects one of \"yes\", \"no\", or \"required\"." 471 | << cppthread::end; 472 | } 473 | else if(values[0] != "no") 474 | { 475 | f_parser.set_allow(allow_t::ALLOW_PORT, true); 476 | 477 | if(values[0] != "yes") 478 | { 479 | if(values[0] == "required") 480 | { 481 | f_parser.set_allow(allow_t::ALLOW_REQUIRED_PORT, true); 482 | } 483 | else 484 | { 485 | cppthread::log 486 | << cppthread::log_level_t::error 487 | << "unexpected value \"" 488 | << values[0] 489 | << "\" for the port=... option which expects one of \"yes\", \"no\", or \"required\"." 490 | << cppthread::end; 491 | } 492 | } 493 | } 494 | continue; 495 | } 496 | break; 497 | 498 | } 499 | 500 | cppthread::log 501 | << cppthread::log_level_t::error 502 | << "\"" 503 | << p 504 | << "\" is not a known option for the address validator." 505 | << cppthread::end; 506 | } 507 | } 508 | 509 | 510 | /** \brief Return the name of this validator. 511 | * 512 | * This function returns "address". 513 | * 514 | * \return "address". 515 | */ 516 | std::string validator_address::name() const 517 | { 518 | return std::string("address"); 519 | } 520 | 521 | 522 | /** \brief Check the value against a regular expression. 523 | * 524 | * This function is used to match the value of an argument against a 525 | * regular expression. It returns true when it does match. 526 | * 527 | * \param[in] value The value to be validated. 528 | * 529 | * \return true on a match. 530 | */ 531 | bool validator_address::validate(std::string const & value) const 532 | { 533 | f_parser.clear_errors(); 534 | snapdev::NOT_USED(f_parser.parse(value)); 535 | 536 | #ifdef _DEBUG 537 | if(f_parser.has_errors()) 538 | { 539 | std::cerr << "--- parser errors: [" << f_parser.error_messages() << "]\n"; 540 | } 541 | #endif 542 | 543 | return !f_parser.has_errors(); 544 | } 545 | 546 | 547 | 548 | } // namespace advgetopt 549 | // vim: ts=4 sw=4 et 550 | -------------------------------------------------------------------------------- /libaddr/validator_address.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // This program is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 2 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along 17 | // with this program; if not, write to the Free Software Foundation, Inc., 18 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | #pragma once 20 | 21 | /** \file 22 | * \brief Declaration of a validator to verify that a parameter is an address. 23 | * 24 | * The advgetopt library offers a way to validate command line and 25 | * configuration parameters through the use of validators. This validator 26 | * is an extension which verifies that the parameter is considered to be 27 | * a valid address or hostname. 28 | */ 29 | 30 | // self 31 | // 32 | #include "libaddr/addr_parser.h" 33 | 34 | 35 | // advgetopt 36 | // 37 | #include "advgetopt/validator.h" 38 | 39 | 40 | // C++ 41 | // 42 | #include 43 | 44 | 45 | 46 | namespace addr 47 | { 48 | 49 | 50 | 51 | class validator_address 52 | : public advgetopt::validator 53 | { 54 | public: 55 | validator_address(advgetopt::string_list_t const & data); 56 | 57 | // validator implementation 58 | // 59 | virtual std::string name() const override; 60 | virtual bool validate(std::string const & value) const override; 61 | 62 | static bool convert_string(std::string const & address 63 | , addr_range::vector_t & result); 64 | 65 | private: 66 | mutable addr_parser f_parser = addr_parser(); 67 | }; 68 | 69 | 70 | 71 | } // namespace advgetopt 72 | // vim: ts=4 sw=4 et 73 | -------------------------------------------------------------------------------- /libaddr/version.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | /** \file 26 | * \brief Implementation of the few global functions used to define the version. 27 | * 28 | * This file includes the few functions one can use to dynamically check 29 | * the version of the libaddr library. If you compiled with a different 30 | * version, then you very certainly could have an incompatible version 31 | * of the interface (i.e. C++ classes cannot always work right when 32 | * created through modified versions of such.) 33 | */ 34 | 35 | // self 36 | // 37 | #include "libaddr/addr.h" 38 | #include "libaddr/version.h" 39 | 40 | 41 | // last include 42 | // 43 | #include 44 | 45 | 46 | 47 | namespace addr 48 | { 49 | 50 | /** \brief Major version of the libaddr library. 51 | * 52 | * This function returns the major version of the library at the 53 | * time it was compiled. 54 | * 55 | * The C++ classes are very likely different when compiled against 56 | * a different major version of the library. This means it is likely 57 | * to crash if used. 58 | * 59 | * \return The major version of the libaddr library. 60 | */ 61 | int get_version_major() 62 | { 63 | return LIBADDR_VERSION_MAJOR; 64 | } 65 | 66 | 67 | /** \brief Minor version of the libaddr library. 68 | * 69 | * This function returns the minor version of the library at the 70 | * time it was compiled. 71 | * 72 | * The C++ classes are likely different when compiled against 73 | * a different minor version of the library. This means it is likely 74 | * to crash if used. 75 | * 76 | * \return The minor version of the libaddr library. 77 | */ 78 | int get_version_minor() 79 | { 80 | return LIBADDR_VERSION_MINOR; 81 | } 82 | 83 | 84 | /** \brief Patch version of the libaddr library. 85 | * 86 | * This function returns the patch version of the library at the 87 | * time it was compiled. 88 | * 89 | * The C++ classes should not have changed in such a way that it 90 | * will crash your application when compiled against a version 91 | * that has a different patching version. 92 | * 93 | * \return The patch version of the libaddr library. 94 | */ 95 | int get_version_patch() 96 | { 97 | return LIBADDR_VERSION_PATCH; 98 | } 99 | 100 | 101 | /** \brief The full version of the libaddr library as a string. 102 | * 103 | * This function returns a string with the major, minor, and 104 | * path versions of the library. The build number is not included. 105 | * 106 | * If you want to compare the version, we suggest that you use 107 | * the other functions: get_version_major(), get_version_minor(), 108 | * and get_version_patch(). This function should be used for 109 | * display only. 110 | * 111 | * \return The full version of the libaddr library as a string. 112 | */ 113 | char const * get_version_string() 114 | { 115 | return LIBADDR_VERSION_STRING; 116 | } 117 | 118 | 119 | 120 | } 121 | // namespace addr 122 | // vim: ts=4 sw=4 et 123 | -------------------------------------------------------------------------------- /libaddr/version.h.in: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | #pragma once 24 | 25 | /** \file 26 | * \brief Version header. 27 | * 28 | * This header file defines the libaddr library version information. 29 | */ 30 | 31 | #define LIBADDR_VERSION_MAJOR @LIBADDR_VERSION_MAJOR@ 32 | #define LIBADDR_VERSION_MINOR @LIBADDR_VERSION_MINOR@ 33 | #define LIBADDR_VERSION_PATCH @LIBADDR_VERSION_PATCH@ 34 | #define LIBADDR_VERSION_STRING "@LIBADDR_VERSION_MAJOR@.@LIBADDR_VERSION_MINOR@.@LIBADDR_VERSION_PATCH@" 35 | 36 | namespace addr 37 | { 38 | 39 | int get_version_major(); 40 | int get_version_minor(); 41 | int get_version_patch(); 42 | char const * get_version_string(); 43 | 44 | } 45 | // namespace addr 46 | // vim: ts=4 sw=4 et 47 | -------------------------------------------------------------------------------- /mk: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # See the snapcmakemodules project for details about this script 4 | # https://github.com/m2osw/snapcmakemodules 5 | 6 | if test -x ../../cmake/scripts/mk 7 | then 8 | # We assume we have an Apache2 running on our server 9 | # 10 | export PROJECT_TEST_ARGS='--tcp-port 80' 11 | 12 | ../../cmake/scripts/mk $* 13 | else 14 | echo "error: could not locate the cmake mk script" 15 | exit 1 16 | fi 17 | 18 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | # 3 | # https://snapwebsites.org/project/libaddr 4 | # contact@m2osw.com 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in 14 | # all copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | # THE SOFTWARE. 23 | 24 | 25 | ## 26 | ## libaddr tests 27 | ## 28 | project(unittest) 29 | 30 | find_package(SnapCatch2) 31 | if(SnapCatch2_FOUND) 32 | 33 | add_executable(${PROJECT_NAME} 34 | catch_main.cpp 35 | 36 | catch_global.cpp 37 | catch_interfaces.cpp 38 | catch_ipv4.cpp 39 | catch_ipv6.cpp 40 | catch_log_for_test.cpp 41 | catch_range.cpp 42 | catch_routes.cpp 43 | catch_unix.cpp 44 | catch_validator.cpp 45 | ) 46 | 47 | # The reference to the src folder is required by the internal test 48 | target_include_directories(${PROJECT_NAME} 49 | PUBLIC 50 | ${SNAPCATCH2_INCLUDE_DIRS} 51 | ${LIBEXCEPT_INCLUDE_DIRS} 52 | ) 53 | 54 | target_link_libraries(${PROJECT_NAME} 55 | addr 56 | ${SNAPCATCH2_LIBRARIES} 57 | ) 58 | 59 | else(SnapCatch2_FOUND) 60 | 61 | message("snapcatch2 not found... no test will be built.") 62 | 63 | endif(SnapCatch2_FOUND) 64 | 65 | if(SnapCatch2_FOUND) 66 | 67 | find_package(SnapTestRunner) 68 | AddUnitTestsTarget( 69 | PROJECT_NAME 70 | rununittests 71 | ) 72 | 73 | endif(SnapCatch2_FOUND) 74 | 75 | # vim: ts=4 sw=4 et 76 | -------------------------------------------------------------------------------- /tests/catch_global.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // Permission is hereby granted, free of charge, to any 7 | // person obtaining a copy of this software and 8 | // associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, 11 | // merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom 13 | // the Software is furnished to do so, subject to the 14 | // following conditions: 15 | // 16 | // The above copyright notice and this permission notice 17 | // shall be included in all copies or substantial 18 | // portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 21 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 22 | // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 24 | // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | // SOFTWARE. 30 | 31 | 32 | /** \file 33 | * \brief Check the global functions. 34 | * 35 | * This test file includes test that checks the global functions. 36 | * 37 | * At this time, the only global functions we check here are the 38 | * version functions. 39 | * 40 | * The address_match_ranges() function is checked in the IPv4 41 | * and IPv6 tests along with other address tests. 42 | */ 43 | 44 | // addr 45 | // 46 | #include 47 | #include 48 | 49 | 50 | // self 51 | // 52 | #include "catch_main.h" 53 | 54 | 55 | // last include 56 | // 57 | #include 58 | 59 | 60 | 61 | 62 | 63 | CATCH_TEST_CASE( "version", "[global]" ) 64 | { 65 | CATCH_START_SECTION("version: verify runtime vs compile time versions") 66 | { 67 | CATCH_REQUIRE(addr::get_version_major() == LIBADDR_VERSION_MAJOR); 68 | CATCH_REQUIRE(addr::get_version_minor() == LIBADDR_VERSION_MINOR); 69 | CATCH_REQUIRE(addr::get_version_patch() == LIBADDR_VERSION_PATCH); 70 | CATCH_REQUIRE(std::string(addr::get_version_string()) == std::string(LIBADDR_VERSION_STRING)); 71 | } 72 | CATCH_END_SECTION() 73 | } 74 | 75 | 76 | // vim: ts=4 sw=4 et 77 | -------------------------------------------------------------------------------- /tests/catch_interfaces.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // Permission is hereby granted, free of charge, to any 7 | // person obtaining a copy of this software and 8 | // associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, 11 | // merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom 13 | // the Software is furnished to do so, subject to the 14 | // following conditions: 15 | // 16 | // The above copyright notice and this permission notice 17 | // shall be included in all copies or substantial 18 | // portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 21 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 22 | // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 24 | // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | // SOFTWARE. 30 | 31 | 32 | /** \file 33 | * \brief Verify the interfaces function. 34 | * 35 | * This file implements a test that verifies the function that 36 | * reads the list of IP addresses as defined in your local 37 | * interfaces. 38 | */ 39 | 40 | // addr 41 | // 42 | #include 43 | 44 | 45 | // self 46 | // 47 | #include "catch_main.h" 48 | 49 | 50 | // C 51 | // 52 | #include 53 | 54 | 55 | // last include 56 | // 57 | #include 58 | 59 | 60 | 61 | CATCH_TEST_CASE( "iface::interfaces", "[iface]" ) 62 | { 63 | CATCH_GIVEN("iface::get_local_addresses()") 64 | { 65 | addr::iface::set_local_addresses_cache_ttl(1500); 66 | 67 | addr::iface::pointer_vector_t list(addr::iface::get_local_addresses()); 68 | addr::iface_index_name::vector_t name_index(addr::get_interface_name_index()); 69 | 70 | CATCH_START_SECTION("iface::interfaces: verify list") 71 | { 72 | CATCH_REQUIRE_FALSE(list->empty()); // at least "lo" 73 | 74 | // add stuff like verify there is an "lo" entry? 75 | for(auto i : *list) 76 | { 77 | CATCH_REQUIRE_FALSE(i->get_name().empty()); 78 | CATCH_REQUIRE(i->get_flags() != 0); 79 | 80 | switch(i->get_address().get_network_type()) 81 | { 82 | case addr::network_type_t::NETWORK_TYPE_PRIVATE: 83 | case addr::network_type_t::NETWORK_TYPE_PUBLIC: 84 | case addr::network_type_t::NETWORK_TYPE_LOOPBACK: 85 | case addr::network_type_t::NETWORK_TYPE_LINK_LOCAL: 86 | break; 87 | 88 | default: 89 | //std::cerr << "unexpected interface type " << static_cast(i->get_address().get_network_type()) << "\n"; 90 | CATCH_REQUIRE(i->get_address().get_network_type() == addr::network_type_t::NETWORK_TYPE_PUBLIC); 91 | break; 92 | 93 | } 94 | 95 | CATCH_REQUIRE(i->has_broadcast_address() == ((i->get_flags() & IFF_BROADCAST) != 0)); 96 | CATCH_REQUIRE(i->has_destination_address() == ((i->get_flags() & IFF_POINTOPOINT) != 0)); 97 | 98 | addr::addr const & b(i->get_broadcast_address()); 99 | if(i->has_broadcast_address()) 100 | { 101 | if(b.is_ipv4()) 102 | { 103 | CATCH_REQUIRE(addr::is_broadcast_address(b)); 104 | } 105 | else 106 | { 107 | // IPv6 is not offering broadcast IPs so we always 108 | // get the default IP here 109 | // 110 | CATCH_REQUIRE(b.is_default()); 111 | CATCH_REQUIRE_FALSE(addr::is_broadcast_address(b)); 112 | } 113 | } 114 | else 115 | { 116 | CATCH_REQUIRE(b.is_default()); 117 | } 118 | 119 | addr::addr const & d(i->get_destination_address()); 120 | if(!i->has_destination_address()) 121 | { 122 | CATCH_REQUIRE(d.is_default()); 123 | } 124 | 125 | unsigned int const index(addr::get_interface_index_by_name(i->get_name())); 126 | for(auto & ni : name_index) 127 | { 128 | if(ni.get_name() == i->get_name()) 129 | { 130 | CATCH_REQUIRE(ni.get_index() == index); 131 | } 132 | } 133 | } 134 | 135 | addr::iface::reset_local_addresses_cache(); 136 | } 137 | CATCH_END_SECTION() 138 | } 139 | } 140 | 141 | 142 | // vim: ts=4 sw=4 et 143 | -------------------------------------------------------------------------------- /tests/catch_log_for_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // This program is free software; you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation; either version 2 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along 17 | // with this program; if not, write to the Free Software Foundation, Inc., 18 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | 20 | // self 21 | // 22 | #include "catch_main.h" 23 | 24 | 25 | // cppthread 26 | // 27 | #include 28 | 29 | 30 | // libexcept 31 | // 32 | #include 33 | 34 | 35 | // last include 36 | // 37 | #include 38 | 39 | 40 | 41 | 42 | namespace SNAP_CATCH2_NAMESPACE 43 | { 44 | 45 | 46 | 47 | namespace 48 | { 49 | 50 | std::vector g_expected_logs = std::vector(); 51 | 52 | } 53 | // no name namespace 54 | 55 | 56 | 57 | void push_expected_log(std::string const & message) 58 | { 59 | g_expected_logs.push_back(message); 60 | } 61 | 62 | 63 | void log_for_test(cppthread::log_level_t level, std::string const & message) 64 | { 65 | if(SNAP_CATCH2_NAMESPACE::g_verbose() 66 | || g_expected_logs.empty()) 67 | { 68 | std::cerr << "logger sent:\n" 69 | << cppthread::to_string(level) 70 | << ": " 71 | << message 72 | << std::endl; 73 | } 74 | 75 | // at this time it's impossible to debug the location of the empty 76 | // problem without a proper stack trace... 77 | // 78 | if(g_expected_logs.empty()) 79 | { 80 | libexcept::stack_trace_t trace(libexcept::collect_stack_trace_with_line_numbers()); 81 | std::cerr << "*** STACK TRACE ***" << std::endl; 82 | for(auto const & l : trace) 83 | { 84 | std::cerr << l << std::endl; 85 | } 86 | std::cerr << "***" << std::endl; 87 | } 88 | 89 | CATCH_REQUIRE_FALSE(g_expected_logs.empty()); 90 | 91 | std::stringstream ss; 92 | ss << cppthread::to_string(level) << ": " << message; 93 | 94 | // again, the REQUIRE() is not going to be useful in terms of line number 95 | // 96 | if(g_expected_logs[0] != ss.str()) 97 | { 98 | libexcept::stack_trace_t trace(libexcept::collect_stack_trace_with_line_numbers()); 99 | std::cerr << "*** STACK TRACE ***" << std::endl; 100 | for(auto const & l : trace) 101 | { 102 | std::cerr << l << std::endl; 103 | } 104 | std::cerr << "***" << std::endl; 105 | } 106 | 107 | std::string expected_msg(g_expected_logs[0]); 108 | g_expected_logs.erase(g_expected_logs.begin()); 109 | 110 | CATCH_REQUIRE(expected_msg == ss.str()); 111 | } 112 | 113 | 114 | void expected_logs_stack_is_empty() 115 | { 116 | if(!g_expected_logs.empty()) 117 | { 118 | std::cerr << "List of expected error logs which did not occur:" << std::endl; 119 | for(auto l : g_expected_logs) 120 | { 121 | std::cerr << " " << l << std::endl; 122 | } 123 | g_expected_logs.clear(); 124 | throw std::logic_error("a test left an unexpected error message in the g_expected_logs vector."); 125 | } 126 | 127 | cppthread::log.reset_counters(); 128 | } 129 | 130 | 131 | } // SNAP_CATCH2_NAMESPACE namespace 132 | // vim: ts=4 sw=4 et 133 | -------------------------------------------------------------------------------- /tests/catch_main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // Permission is hereby granted, free of charge, to any 7 | // person obtaining a copy of this software and 8 | // associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, 11 | // merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom 13 | // the Software is furnished to do so, subject to the 14 | // following conditions: 15 | // 16 | // The above copyright notice and this permission notice 17 | // shall be included in all copies or substantial 18 | // portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 21 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 22 | // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 24 | // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | // SOFTWARE. 30 | 31 | 32 | /** \file 33 | * \brief The main() function of the addr library tests. 34 | * 35 | * This file implements the main() function of the unit tests used to 36 | * verify the addr library. 37 | * 38 | * It defines any globals (none at this point) and a few basic command 39 | * line options such as --help and --version. 40 | */ 41 | 42 | // Tell catch we want it to add the runner code in this file. 43 | #define CATCH_CONFIG_RUNNER 44 | 45 | // self 46 | // 47 | #include "catch_main.h" 48 | 49 | 50 | // snapdev 51 | // 52 | #include 53 | 54 | 55 | // last include 56 | // 57 | #include 58 | 59 | 60 | 61 | namespace SNAP_CATCH2_NAMESPACE 62 | { 63 | 64 | int g_tcp_port = -1; 65 | 66 | } 67 | 68 | 69 | namespace 70 | { 71 | 72 | 73 | void add_command_line_options(Catch::Clara::Parser & cli) 74 | { 75 | cli |= Catch::Clara::Opt(SNAP_CATCH2_NAMESPACE::g_tcp_port, "port") 76 | ["--tcp-port"] 77 | ("define a TCP port we can connect to in order to test the get_from_socket() function"); 78 | } 79 | 80 | 81 | int finish_init(Catch::Session & session) 82 | { 83 | snapdev::NOT_USED(session); 84 | 85 | cppthread::set_log_callback(SNAP_CATCH2_NAMESPACE::log_for_test); 86 | 87 | return 0; 88 | } 89 | 90 | 91 | void cleanup() 92 | { 93 | SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty(); 94 | 95 | if(system("rm -rf socket-test*") != 0) 96 | { 97 | std::cerr << "error: test could not properly clean up socket files." << std::endl; 98 | } 99 | } 100 | 101 | 102 | } 103 | // namespace 104 | 105 | 106 | int main(int argc, char * argv[]) 107 | { 108 | return SNAP_CATCH2_NAMESPACE::snap_catch2_main( 109 | "libaddr" 110 | , LIBADDR_VERSION_STRING 111 | , argc 112 | , argv 113 | , nullptr 114 | , &add_command_line_options 115 | , &finish_init 116 | , &cleanup 117 | ); 118 | } 119 | 120 | // vim: ts=4 sw=4 et 121 | -------------------------------------------------------------------------------- /tests/catch_main.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // Permission is hereby granted, free of charge, to any 7 | // person obtaining a copy of this software and 8 | // associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, 11 | // merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom 13 | // the Software is furnished to do so, subject to the 14 | // following conditions: 15 | // 16 | // The above copyright notice and this permission notice 17 | // shall be included in all copies or substantial 18 | // portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 21 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 22 | // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 24 | // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | // SOFTWARE. 30 | #pragma once 31 | 32 | 33 | /** \file 34 | * \brief Basic definitions for all of our libaddr unit tests. 35 | * 36 | * This files includes and declares basics that are to be used 37 | * by all our unit tests. 38 | */ 39 | 40 | 41 | // libaddr 42 | // 43 | #include 44 | #include 45 | #include 46 | 47 | 48 | // catch 49 | // 50 | #include 51 | 52 | 53 | // C++ 54 | // 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | 62 | // C 63 | // 64 | #include 65 | #include 66 | #include 67 | 68 | 69 | // cppthread 70 | // 71 | #include 72 | 73 | 74 | // last include 75 | // 76 | #include 77 | 78 | 79 | 80 | namespace SNAP_CATCH2_NAMESPACE 81 | { 82 | 83 | // Place globals defined by main() from the command line and used 84 | // by various tests in here 85 | // 86 | 87 | extern int g_tcp_port; 88 | 89 | 90 | void push_expected_log(std::string const & message); 91 | void log_for_test(cppthread::log_level_t level, std::string const & message); 92 | void expected_logs_stack_is_empty(); 93 | 94 | 95 | } 96 | // namespace SNAP_CATCH2_NAMESPACE 97 | // vim: ts=4 sw=4 et 98 | -------------------------------------------------------------------------------- /tests/catch_routes.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // contact@m2osw.com 5 | // 6 | // Permission is hereby granted, free of charge, to any 7 | // person obtaining a copy of this software and 8 | // associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, 11 | // merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom 13 | // the Software is furnished to do so, subject to the 14 | // following conditions: 15 | // 16 | // The above copyright notice and this permission notice 17 | // shall be included in all copies or substantial 18 | // portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 21 | // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 22 | // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 23 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 24 | // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 26 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | // SOFTWARE. 30 | 31 | /** \file 32 | * \brief Verify the route class a little further. 33 | * 34 | * This file implements a test that verifies a few additional things 35 | * in the route table. 36 | */ 37 | 38 | // libaddr 39 | // 40 | #include 41 | 42 | 43 | // self 44 | // 45 | #include "catch_main.h" 46 | 47 | 48 | 49 | // C 50 | // 51 | #include 52 | #include 53 | 54 | 55 | // last include 56 | // 57 | #include 58 | 59 | 60 | 61 | CATCH_TEST_CASE("ipv4::routes", "[ipv4]") 62 | { 63 | CATCH_GIVEN("route::get_ipv4_routes()") 64 | { 65 | addr::route::vector_t routes(addr::route::get_ipv4_routes()); 66 | addr::route::vector_t routes_without_default; 67 | 68 | CATCH_START_SECTION("routes: verify list") 69 | { 70 | CATCH_REQUIRE_FALSE(routes.empty()); // at least the default route 71 | 72 | // check a few things 73 | // 74 | bool found_default(false); 75 | bool found_gateway(false); 76 | //std::map found; 77 | for(auto r : routes) 78 | { 79 | CATCH_REQUIRE_FALSE(r->get_interface_name().empty()); 80 | CATCH_REQUIRE(r->get_interface_name().length() < IFNAMSIZ); // IFNAMSIZ includes the '\0' so '<' and not '<=' 81 | 82 | //if(found[r->get_interface_name()]) 83 | //{ 84 | // std::cerr 85 | // << "WARNING: found interface \"" 86 | // << r->get_interface_name() 87 | // << "\" twice.\n"; 88 | // continue; 89 | //} 90 | //found[r->get_interface_name()] = true; 91 | 92 | // at least one flag is not zero 93 | int const f(r->get_flags()); 94 | std::string const flags(r->flags_to_string()); 95 | 96 | CATCH_REQUIRE(f != 0); 97 | CATCH_REQUIRE(!flags.empty()); 98 | 99 | #if 0 100 | // output similar to `route` 101 | std::cout << "Route: Dest: " << r->get_destination_address().to_ipv4or6_string(addr::STRING_IP_ADDRESS) 102 | << " Gateway: " << r->get_gateway_address().to_ipv4or6_string(addr::STRING_IP_ADDRESS) 103 | << " Flags: " << r->get_flags() 104 | << " Metric: " << r->get_metric() 105 | << " Iface: " << r->get_interface_name() 106 | << "\n"; 107 | #endif 108 | if(r->get_destination_address().is_default()) 109 | { 110 | CATCH_REQUIRE_FALSE(found_default); 111 | found_default = true; 112 | 113 | CATCH_REQUIRE((f & RTF_UP) != 0); 114 | 115 | if(!r->get_gateway_address().is_default()) 116 | { 117 | CATCH_REQUIRE_FALSE(found_gateway); 118 | found_gateway = true; 119 | } 120 | } 121 | else 122 | { 123 | routes_without_default.push_back(r); 124 | } 125 | 126 | if(!r->get_gateway_address().is_default()) 127 | { 128 | CATCH_REQUIRE((f & RTF_GATEWAY) != 0); 129 | } 130 | 131 | // Not much I can test on the following? 132 | //r->get_flags() 133 | CATCH_REQUIRE(r->get_reference_count() >= 0); 134 | CATCH_REQUIRE(r->get_use() >= 0); 135 | CATCH_REQUIRE(r->get_metric() >= 0); 136 | CATCH_REQUIRE(r->get_mtu() >= 0); 137 | CATCH_REQUIRE(r->get_window() >= 0); 138 | CATCH_REQUIRE(r->get_irtt() >= 0); 139 | } 140 | CATCH_REQUIRE(found_default); 141 | CATCH_REQUIRE(found_gateway); 142 | } 143 | CATCH_END_SECTION() 144 | 145 | CATCH_START_SECTION("routes: verify a search without a default route") 146 | { 147 | CATCH_REQUIRE(find_default_route(routes_without_default) == nullptr); 148 | } 149 | CATCH_END_SECTION() 150 | } 151 | } 152 | 153 | 154 | // vim: ts=4 sw=4 et 155 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved 2 | # 3 | # https://snapwebsites.org/project/libaddr 4 | # contact@m2osw.com 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a 7 | # copy of this software and associated documentation files (the 8 | # "Software"), to deal in the Software without restriction, including 9 | # without limitation the rights to use, copy, modify, merge, publish, 10 | # distribute, sublicense, and/or sell copies of the Software, and to 11 | # permit persons to whom the Software is furnished to do so, subject to 12 | # the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included 15 | # in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | 26 | ## 27 | ## Addr command line tool 28 | ## 29 | project(validate-ip) 30 | 31 | add_executable(${PROJECT_NAME} 32 | validate_ip.cpp 33 | ) 34 | 35 | target_include_directories(${PROJECT_NAME} 36 | PUBLIC 37 | ${LIBEXCEPT_INCLUDE_DIRS} 38 | ) 39 | 40 | target_link_libraries(${PROJECT_NAME} 41 | addr 42 | ${ADVGETOPT_LIBRARIES} 43 | ${LIBEXCEPT_LIBRARIES} 44 | ${LIBUTF8_LIBRARIES} 45 | ) 46 | 47 | install( 48 | TARGETS 49 | ${PROJECT_NAME} 50 | 51 | RUNTIME DESTINATION 52 | bin 53 | ) 54 | 55 | 56 | ## 57 | ## Route command line tool 58 | ## 59 | project(ipv4-routes) 60 | 61 | include_directories( 62 | ${LIBEXCEPT_INCLUDE_DIRS} 63 | ) 64 | 65 | add_executable(${PROJECT_NAME} 66 | ipv4_routes.cpp 67 | ) 68 | 69 | target_link_libraries(${PROJECT_NAME} 70 | addr 71 | ) 72 | 73 | install( 74 | TARGETS 75 | ${PROJECT_NAME} 76 | 77 | RUNTIME DESTINATION 78 | bin 79 | ) 80 | 81 | 82 | ## 83 | ## Route command line tool 84 | ## 85 | project(ifaces) 86 | 87 | include_directories( 88 | ${LIBEXCEPT_INCLUDE_DIRS} 89 | ) 90 | 91 | add_executable(${PROJECT_NAME} 92 | ifaces.cpp 93 | ) 94 | 95 | target_link_libraries(${PROJECT_NAME} 96 | addr 97 | ) 98 | 99 | install( 100 | TARGETS 101 | ${PROJECT_NAME} 102 | 103 | RUNTIME DESTINATION 104 | bin 105 | ) 106 | 107 | 108 | # vim: ts=4 sw=4 et 109 | -------------------------------------------------------------------------------- /tools/ifaces.cpp: -------------------------------------------------------------------------------- 1 | // Network Address -- get routes and print them, similar to system `route` 2 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 3 | // 4 | // https://snapwebsites.org/project/libaddr 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the 8 | // "Software"), to deal in the Software without restriction, including 9 | // without limitation the rights to use, copy, modify, merge, publish, 10 | // distribute, sublicense, and/or sell copies of the Software, and to 11 | // permit persons to whom the Software is furnished to do so, subject to 12 | // the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included 15 | // in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | /** \file 27 | * \brief A tool to check the system interfaces. 28 | * 29 | * This tool is used to verify that our iface class works as expected. 30 | */ 31 | 32 | // libaddr 33 | // 34 | #include 35 | #include 36 | #include 37 | 38 | 39 | // C++ 40 | // 41 | #include 42 | #include 43 | #include 44 | 45 | 46 | // last include 47 | // 48 | #include 49 | 50 | 51 | 52 | namespace 53 | { 54 | 55 | enum filter_t 56 | { 57 | FILTER_ALL, // no filtering 58 | FILTER_PUBLIC, // only display interfaces with public IP addresses 59 | FILTER_PRIVATE, // only display interfaces with private IP addresses 60 | FILTER_LOOPBACK, // only display interfaces with the "lo" interface 61 | FILTER_DEFAULT, // only display interfaces with the default route 62 | }; 63 | 64 | filter_t g_filter = FILTER_ALL; 65 | bool g_hide_headers = false; 66 | bool g_asterisk = false; 67 | bool g_name_only = false; 68 | 69 | } 70 | 71 | int main(int argc, char * argv[]) 72 | { 73 | for(int idx(1); idx < argc; ++idx) 74 | { 75 | if(strcmp(argv[idx], "-h") == 0 76 | || strcmp(argv[idx], "--help") == 0) 77 | { 78 | std::cout 79 | << "Usage: " << argv[0] << " [-opts]\n" 80 | "where -opts is one or more of:\n" 81 | " --help | -h print out this help screen.\n" 82 | " --default | -d only print name of default interface.\n" 83 | " --hide-headers do not print the headers.\n" 84 | " --public only print name of public interfaces.\n" 85 | " --private only print name of private interfaces.\n" 86 | " --loopback only print name of loopback interface.\n" 87 | " --asterisk print an asterisk for default addresses (instead of 0.0.0.0 or ::).\n" 88 | " --name-only only print the name of the interface.\n" 89 | " --version | -V print out the version of ifaces.\n" 90 | ; 91 | return 1; 92 | } 93 | else if(strcmp(argv[idx], "--hide-headers") == 0) 94 | { 95 | g_hide_headers = true; 96 | } 97 | else if(strcmp(argv[idx], "-d") == 0 98 | || strcmp(argv[idx], "--default") == 0) 99 | { 100 | g_filter = FILTER_DEFAULT; 101 | } 102 | else if(strcmp(argv[idx], "--public") == 0) 103 | { 104 | g_filter = FILTER_PUBLIC; 105 | } 106 | else if(strcmp(argv[idx], "--private") == 0) 107 | { 108 | g_filter = FILTER_PRIVATE; 109 | } 110 | else if(strcmp(argv[idx], "--loopback") == 0) 111 | { 112 | g_filter = FILTER_LOOPBACK; 113 | } 114 | else if(strcmp(argv[idx], "--asterisk") == 0) 115 | { 116 | g_asterisk = true; 117 | } 118 | else if(strcmp(argv[idx], "--name-only") == 0) 119 | { 120 | g_name_only = true; 121 | } 122 | else if(strcmp(argv[idx], "-V") == 0 123 | || strcmp(argv[idx], "--version") == 0) 124 | { 125 | std::cout << LIBADDR_VERSION_STRING << '\n'; 126 | return 0; 127 | } 128 | else 129 | { 130 | std::cerr 131 | << "error: unknown command line option \"" 132 | << argv[idx] 133 | << "\". Try --help for additional info.\n"; 134 | return 1; 135 | } 136 | } 137 | 138 | addr::iface::pointer_vector_t interfaces(addr::iface::get_local_addresses()); 139 | if(interfaces->empty()) 140 | { 141 | std::cerr << "error: no interfaces found, is your network up?" << std::endl; 142 | return 1; 143 | } 144 | 145 | // headers 146 | // 147 | if(!g_hide_headers && !g_name_only) 148 | { 149 | std::cout << "Iface " 150 | "Flags " 151 | "Address " 152 | "Broadcast " 153 | "Destination " 154 | "\n"; 155 | } 156 | 157 | std::string default_interface; 158 | if(g_filter == FILTER_DEFAULT) 159 | { 160 | addr::route::vector_t routes(addr::route::get_ipv4_routes()); 161 | if(routes.empty()) 162 | { 163 | std::cerr << "error: unknown default route.\n"; 164 | return 1; 165 | } 166 | for(auto const & r : routes) 167 | { 168 | if(r->get_destination_address().is_default()) 169 | { 170 | default_interface = r->get_interface_name(); 171 | } 172 | } 173 | } 174 | 175 | std::set found; 176 | for(auto const & i : *interfaces) 177 | { 178 | addr::addr const & a(i->get_address()); 179 | switch(g_filter) 180 | { 181 | case FILTER_ALL: 182 | // no filtering 183 | break; 184 | 185 | case FILTER_PUBLIC: 186 | if(a.get_network_type() != addr::network_type_t::NETWORK_TYPE_PUBLIC) 187 | { 188 | continue; 189 | } 190 | break; 191 | 192 | case FILTER_PRIVATE: 193 | if(a.get_network_type() != addr::network_type_t::NETWORK_TYPE_PRIVATE) 194 | { 195 | continue; 196 | } 197 | break; 198 | 199 | case FILTER_LOOPBACK: 200 | if(a.get_network_type() != addr::network_type_t::NETWORK_TYPE_LOOPBACK) 201 | { 202 | continue; 203 | } 204 | break; 205 | 206 | case FILTER_DEFAULT: 207 | if(a.get_name() != default_interface) 208 | { 209 | continue; 210 | } 211 | break; 212 | 213 | } 214 | 215 | if(g_name_only) 216 | { 217 | // prevent printing the same name twice 218 | // 219 | std::pair inserted(found.insert(i->get_name())); 220 | if(inserted.second) 221 | { 222 | std::cout 223 | << i->get_name() 224 | << '\n'; 225 | } 226 | } 227 | else 228 | { 229 | addr::addr const & b(i->get_broadcast_address()); 230 | addr::addr const & d(i->get_destination_address()); 231 | bool const a_is_ipv4(a.is_ipv4()); 232 | 233 | addr::string_ip_t const mode(addr::STRING_IP_ADDRESS 234 | | (g_asterisk ? addr::STRING_IP_DEFAULT_AS_ASTERISK : 0) 235 | | (a_is_ipv4 ? addr::STRING_IP_DEFAULT_AS_IPV4 : 0)); 236 | 237 | std::cout 238 | << std::left << std::setw(17) << i->get_name() 239 | << std::left << std::setw( 6) << i->get_flags() // TODO: add conversion to letters 240 | << std::left << std::setw(41) << a.to_ipv4or6_string(addr::STRING_IP_ADDRESS) 241 | << std::left << std::setw(41) << b.to_ipv4or6_string(mode) 242 | << std::left << std::setw(41) << d.to_ipv4or6_string(mode) 243 | << '\n'; 244 | } 245 | } 246 | 247 | return 0; 248 | } 249 | 250 | // vim: ts=4 sw=4 et 251 | 252 | -------------------------------------------------------------------------------- /tools/ipv4_routes.cpp: -------------------------------------------------------------------------------- 1 | // Network Address -- get routes and print them, similar to system `route` 2 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 3 | // 4 | // https://snapwebsites.org/project/libaddr 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the 8 | // "Software"), to deal in the Software without restriction, including 9 | // without limitation the rights to use, copy, modify, merge, publish, 10 | // distribute, sublicense, and/or sell copies of the Software, and to 11 | // permit persons to whom the Software is furnished to do so, subject to 12 | // the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included 15 | // in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | // 25 | 26 | /** \file 27 | * \brief A tool to check the system routes. 28 | * 29 | * This tool is used to verify that our route class works as expected. 30 | */ 31 | 32 | // libaddr 33 | // 34 | #include 35 | 36 | 37 | // C++ 38 | // 39 | #include 40 | #include 41 | #include 42 | 43 | 44 | // last include 45 | // 46 | #include 47 | 48 | 49 | namespace 50 | { 51 | 52 | bool g_show_default = false; 53 | bool g_hide_headers = false; 54 | 55 | } 56 | 57 | int main(int argc, char * argv[]) 58 | { 59 | for(int idx(1); idx < argc; ++idx) 60 | { 61 | if(strcmp(argv[idx], "-h") == 0 62 | || strcmp(argv[idx], "--help") == 0) 63 | { 64 | std::cout 65 | << "Usage: " << argv[0] << " [-opts]\n" 66 | "where -opts is one or more of:\n" 67 | " --help | -h print out this help screen.\n" 68 | " --default | -d only print the default route.\n" 69 | " --hide-headers do not print the headers.\n"; 70 | return 1; 71 | } 72 | else if(strcmp(argv[idx], "-d") == 0 73 | || strcmp(argv[idx], "--default") == 0) 74 | { 75 | g_show_default = true; 76 | } 77 | else if(strcmp(argv[idx], "--hide-headers") == 0) 78 | { 79 | g_hide_headers = true; 80 | } 81 | else 82 | { 83 | std::cerr 84 | << "error: unknown command line option \"" 85 | << argv[idx] 86 | << "\". Try --help for additional info.\n"; 87 | return 1; 88 | } 89 | } 90 | 91 | addr::route::vector_t routes(addr::route::get_ipv4_routes()); 92 | if(routes.empty()) 93 | { 94 | std::cerr << "error: no routes found, is your network up?\n"; 95 | return 1; 96 | } 97 | 98 | // headers 99 | // 100 | if(!g_hide_headers) 101 | { 102 | std::cout << "Iface " 103 | "Destination " 104 | "Gateway " 105 | "Flags " 106 | "RefCnt " 107 | "Use " 108 | "Metric " 109 | "Mask " 110 | "MTU " 111 | "Window " 112 | "IRTT " 113 | "\n"; 114 | } 115 | 116 | for(auto r : routes) 117 | { 118 | if(!g_show_default 119 | || r->get_destination_address().is_default()) 120 | { 121 | uint8_t mask[16]; 122 | r->get_destination_address().get_mask(mask); 123 | std::stringstream m; 124 | m << static_cast(mask[12]) << "." 125 | << static_cast(mask[13]) << "." 126 | << static_cast(mask[14]) << "." 127 | << static_cast(mask[15]); 128 | std::cout << std::left << std::setw( 8) << r->get_interface_name() 129 | << std::left << std::setw(16) << r->get_destination_address().to_ipv4or6_string(addr::STRING_IP_ADDRESS) 130 | << std::left << std::setw(16) << r->get_gateway_address().to_ipv4or6_string(addr::STRING_IP_ADDRESS) 131 | << std::left << std::setw( 8) << r->flags_to_string() 132 | << std::left << std::setw( 8) << r->get_reference_count() 133 | << std::left << std::setw( 8) << r->get_use() 134 | << std::left << std::setw( 8) << r->get_metric() 135 | << std::left << std::setw(16) << m.str() 136 | << std::left << std::setw( 8) << r->get_mtu() 137 | << std::left << std::setw( 8) << r->get_window() 138 | << std::left << std::setw( 8) << r->get_irtt() 139 | << '\n'; 140 | } 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | // vim: ts=4 sw=4 et 147 | 148 | -------------------------------------------------------------------------------- /tools/validate_ip.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2025 Made to Order Software Corp. All Rights Reserved 2 | // 3 | // https://snapwebsites.org/project/libaddr 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included 14 | // in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | // 24 | 25 | /** \file 26 | * \brief A tool to check the validity of an IP address. 27 | * 28 | * This tool is used to verify or canonicalize an IP address or a list of 29 | * IP addresses. 30 | * 31 | * The default is to verify (`--verify`). In this case, the tool generates 32 | * no output. It exits with 0 when no error were found. It prints out 33 | * errors to stderr and exit with 1 when errors there are. 34 | * 35 | * The `--canonicalize` command line option requires the tool to verify 36 | * each address and then print them, canonicalized, to stdout. At this 37 | * time, the CIDR are printed in full (i.e. `255.255.255.255`). 38 | * 39 | * The tool supports a few options as follow: 40 | * 41 | * \li `--address` -- require that an address be specified otherwise we 42 | * generate an error. 43 | * \li `--port` -- require that a port be specified otherwise we generate 44 | * an error. 45 | * \li `--list` -- allow list of IP address (command & space separated). 46 | * \li `--mask` -- allow a mask. 47 | * \li `--protocol \` -- specify the protocol (default "tcp"). 48 | * \li `--default-address` -- define the default address, used when not 49 | * specified in an input string (i.e. `:123`). 50 | * \li `--default-port` -- define the default port, used when not 51 | * specified in an input string (i.e. `[::]`). 52 | * 53 | * To avoid receiving the error messages in stderr, use the `--quiet` flag. 54 | */ 55 | 56 | 57 | // libaddr 58 | // 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | 65 | // advgetopt 66 | // 67 | #include 68 | #include 69 | #include 70 | #include 71 | 72 | 73 | // snapdev 74 | // 75 | #include 76 | #include 77 | 78 | 79 | // C++ 80 | // 81 | #include 82 | 83 | 84 | // last include 85 | // 86 | #include 87 | 88 | 89 | 90 | namespace 91 | { 92 | 93 | 94 | advgetopt::option const g_options[] = 95 | { 96 | // COMMANDS 97 | // 98 | advgetopt::define_option( 99 | advgetopt::Name("canonicalize") 100 | , advgetopt::ShortName('c') 101 | , advgetopt::Flags(advgetopt::standalone_command_flags< 102 | advgetopt::GETOPT_FLAG_GROUP_COMMANDS>()) 103 | , advgetopt::Help("canonicalize the addresses and print the result in stdout.") 104 | ), 105 | advgetopt::define_option( 106 | advgetopt::Name("verify") 107 | , advgetopt::Flags(advgetopt::standalone_command_flags< 108 | advgetopt::GETOPT_FLAG_GROUP_COMMANDS>()) 109 | , advgetopt::Help("verify the specify addresses.") 110 | ), 111 | 112 | // OPTIONS 113 | // 114 | advgetopt::define_option( 115 | advgetopt::Name("address") 116 | , advgetopt::ShortName('a') 117 | , advgetopt::Flags(advgetopt::standalone_command_flags< 118 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS>()) 119 | , advgetopt::Help("address is required.") 120 | ), 121 | advgetopt::define_option( 122 | advgetopt::Name("default-address") 123 | , advgetopt::Flags(advgetopt::command_flags< 124 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS 125 | , advgetopt::GETOPT_FLAG_REQUIRED>()) 126 | , advgetopt::DefaultValue("127.0.0.1,::") 127 | , advgetopt::Help("default IPv4 and IPv6 addresses.") 128 | ), 129 | advgetopt::define_option( 130 | advgetopt::Name("default-port") 131 | , advgetopt::Flags(advgetopt::command_flags< 132 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS 133 | , advgetopt::GETOPT_FLAG_REQUIRED>()) 134 | , advgetopt::DefaultValue("60000") 135 | , advgetopt::Help("default port.") 136 | ), 137 | advgetopt::define_option( 138 | advgetopt::Name("list") 139 | , advgetopt::ShortName('l') 140 | , advgetopt::Flags(advgetopt::standalone_command_flags< 141 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS>()) 142 | , advgetopt::Help("allow list of addresses separated by spaces and/or commas.") 143 | ), 144 | advgetopt::define_option( 145 | advgetopt::Name("mask") 146 | , advgetopt::ShortName('m') 147 | , advgetopt::Flags(advgetopt::standalone_command_flags< 148 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS>()) 149 | , advgetopt::Help("mask is allowed.") 150 | ), 151 | advgetopt::define_option( 152 | advgetopt::Name("port") 153 | , advgetopt::ShortName('p') 154 | , advgetopt::Flags(advgetopt::standalone_command_flags< 155 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS>()) 156 | , advgetopt::Help("port is required.") 157 | ), 158 | advgetopt::define_option( 159 | advgetopt::Name("protocol") 160 | , advgetopt::Flags(advgetopt::command_flags< 161 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS 162 | , advgetopt::GETOPT_FLAG_REQUIRED>()) 163 | , advgetopt::DefaultValue("tcp") 164 | , advgetopt::Help("specify protocol.") 165 | ), 166 | advgetopt::define_option( 167 | advgetopt::Name("quiet") 168 | , advgetopt::ShortName('q') 169 | , advgetopt::Flags(advgetopt::standalone_command_flags< 170 | advgetopt::GETOPT_FLAG_GROUP_OPTIONS>()) 171 | , advgetopt::Help("do not show error messages.") 172 | ), 173 | 174 | // FILENAMES/PATHS 175 | // 176 | advgetopt::define_option( 177 | advgetopt::Name("--") 178 | , advgetopt::Flags(advgetopt::command_flags< 179 | advgetopt::GETOPT_FLAG_GROUP_NONE 180 | , advgetopt::GETOPT_FLAG_MULTIPLE 181 | , advgetopt::GETOPT_FLAG_DEFAULT_OPTION>()) 182 | ), 183 | 184 | // END 185 | // 186 | advgetopt::end_options() 187 | }; 188 | 189 | 190 | advgetopt::group_description const g_group_descriptions[] = 191 | { 192 | advgetopt::define_group( 193 | advgetopt::GroupNumber(advgetopt::GETOPT_FLAG_GROUP_COMMANDS) 194 | , advgetopt::GroupName("command") 195 | , advgetopt::GroupDescription("Commands:") 196 | ), 197 | advgetopt::define_group( 198 | advgetopt::GroupNumber(advgetopt::GETOPT_FLAG_GROUP_OPTIONS) 199 | , advgetopt::GroupName("option") 200 | , advgetopt::GroupDescription("Options:") 201 | ), 202 | advgetopt::end_groups() 203 | }; 204 | 205 | 206 | // until we have C++20, remove warnings this way 207 | #pragma GCC diagnostic push 208 | #pragma GCC diagnostic ignored "-Wpedantic" 209 | advgetopt::options_environment const g_options_environment = 210 | { 211 | .f_project_name = "libaddr", 212 | .f_group_name = nullptr, 213 | .f_options = g_options, 214 | .f_options_files_directory = nullptr, 215 | .f_environment_variable_name = nullptr, 216 | .f_environment_variable_intro = nullptr, 217 | .f_section_variables_name = nullptr, 218 | .f_configuration_files = nullptr, 219 | .f_configuration_filename = nullptr, 220 | .f_configuration_directories = nullptr, 221 | .f_environment_flags = advgetopt::GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS, 222 | .f_help_header = "Usage: %p [--] ...\n" 223 | "where -- is one or more of:", 224 | .f_help_footer = "%c", 225 | .f_version = LIBADDR_VERSION_STRING, 226 | .f_license = "GNU GPL v2", 227 | .f_copyright = "Copyright (c) 2013-" 228 | SNAPDEV_STRINGIZE(UTC_BUILD_YEAR) 229 | " by Made to Order Software Corporation -- All Rights Reserved", 230 | .f_build_date = UTC_BUILD_DATE, 231 | .f_build_time = UTC_BUILD_TIME, 232 | .f_groups = g_group_descriptions 233 | }; 234 | #pragma GCC diagnostic pop 235 | 236 | 237 | 238 | class validate_ip 239 | { 240 | public: 241 | validate_ip(int argc, char * argv[]); 242 | 243 | void run(); 244 | int error_count() const; 245 | 246 | private: 247 | advgetopt::getopt f_opts; 248 | int f_error_count = 0; 249 | }; 250 | 251 | 252 | 253 | validate_ip::validate_ip(int argc, char * argv[]) 254 | : f_opts(g_options_environment, argc, argv) 255 | { 256 | } 257 | 258 | 259 | void validate_ip::run() 260 | { 261 | size_t const max(f_opts.size("--")); 262 | for(size_t idx(0); idx < max; ++idx) 263 | { 264 | std::string addr(f_opts.get_string("--", idx)); 265 | 266 | addr::addr_parser p; 267 | 268 | p.set_default_address("127.0.0.1"); 269 | p.set_default_address("::"); 270 | std::string const default_address(f_opts.get_string("default-address")); 271 | std::string::size_type const pos(default_address.find(',')); 272 | if(pos == std::string::npos) 273 | { 274 | p.set_default_address(default_address); 275 | } 276 | else 277 | { 278 | p.set_default_address(default_address.substr(0, pos)); 279 | p.set_default_address(default_address.substr(pos + 1)); 280 | } 281 | 282 | p.set_default_port(f_opts.get_long("default-port")); 283 | 284 | p.set_default_mask("255.255.255.255"); 285 | p.set_default_mask("FF:FF:FF:FF:FF:FF:FF:FF"); 286 | 287 | p.set_protocol(f_opts.get_string("protocol")); 288 | 289 | p.set_allow(addr::allow_t::ALLOW_ADDRESS, true); 290 | p.set_allow(addr::allow_t::ALLOW_PORT, true); 291 | 292 | if(f_opts.is_defined("address")) 293 | { 294 | p.set_allow(addr::allow_t::ALLOW_REQUIRED_ADDRESS, true); 295 | } 296 | if(f_opts.is_defined("port")) 297 | { 298 | p.set_allow(addr::allow_t::ALLOW_REQUIRED_PORT, true); 299 | } 300 | if(f_opts.is_defined("mask")) 301 | { 302 | p.set_allow(addr::allow_t::ALLOW_MASK, true); 303 | } 304 | if(f_opts.is_defined("list")) 305 | { 306 | p.set_allow(addr::allow_t::ALLOW_MULTI_ADDRESSES_COMMAS, true); 307 | p.set_allow(addr::allow_t::ALLOW_MULTI_ADDRESSES_SPACES, true); 308 | } 309 | 310 | addr::addr_range::vector_t const range(p.parse(addr)); 311 | 312 | if(p.has_errors()) 313 | { 314 | f_error_count += p.error_count(); 315 | if(!f_opts.is_defined("quiet")) 316 | { 317 | std::cerr << "address \"" 318 | << addr 319 | << "\" generated " 320 | << p.error_count() 321 | << " error" 322 | << (p.error_count() == 1 ? "" : "s") 323 | << ": " 324 | << p.error_messages() 325 | << std::endl; 326 | } 327 | } 328 | else if(f_opts.is_defined("canonicalize")) 329 | { 330 | for(auto r : range) 331 | { 332 | if(r.is_range()) 333 | { 334 | std::cout << r.get_from().to_ipv4or6_string(addr::STRING_IP_ALL) 335 | << " .. " 336 | << r.get_to().to_ipv4or6_string(addr::STRING_IP_ALL) 337 | << std::endl; 338 | } 339 | else if(r.has_from()) 340 | { 341 | std::cout << r.get_from().to_ipv4or6_string(addr::STRING_IP_ALL) 342 | << std::endl; 343 | } 344 | else if(r.has_to()) 345 | { 346 | std::cout << r.get_to().to_ipv4or6_string(addr::STRING_IP_ALL) 347 | << std::endl; 348 | } 349 | else 350 | { 351 | throw addr::addr_invalid_structure("unexpected range, no from and no to defined."); 352 | } 353 | } 354 | } 355 | } 356 | } 357 | 358 | 359 | 360 | int validate_ip::error_count() const 361 | { 362 | return f_error_count; 363 | } 364 | 365 | 366 | 367 | 368 | } 369 | // no name namespace 370 | 371 | 372 | int main(int argc, char * argv[]) 373 | { 374 | try 375 | { 376 | validate_ip v(argc, argv); 377 | v.run(); 378 | return v.error_count() != 0 ? 1 : 0; 379 | } 380 | catch(advgetopt::getopt_exit const & e) 381 | { 382 | snapdev::NOT_USED(e); 383 | return 0; 384 | } 385 | catch(std::exception const & e) 386 | { 387 | std::cerr << "error: an error occurred: " << e.what() << std::endl; 388 | return 1; 389 | } 390 | } 391 | 392 | // vim: ts=4 sw=4 et 393 | --------------------------------------------------------------------------------