summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:15:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:15:13 +0000
commit5fb98df7b32417914e9b282e91987199416d0a97 (patch)
treed674271dc3d99faa1a75fa689888ee3d3aec4e10
parentInitial commit. (diff)
downloadipcalc-ng-upstream.tar.xz
ipcalc-ng-upstream.zip
Adding upstream version 1.0.3.upstream/1.0.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.editorconfig8
-rw-r--r--.gitignore10
-rw-r--r--.gitlab-ci.yml100
-rw-r--r--COPYING339
-rw-r--r--Makefile40
-rw-r--r--NEWS131
-rw-r--r--README.md186
-rw-r--r--deaggregate.c233
-rw-r--r--ipcalc-geoip.c266
-rw-r--r--ipcalc-maxmind.c201
-rw-r--r--ipcalc-reverse.c127
-rw-r--r--ipcalc-utils.c83
-rw-r--r--ipcalc.1.md237
-rw-r--r--ipcalc.c1990
-rw-r--r--ipcalc.h156
-rw-r--r--ipv6.c81
-rw-r--r--ipv6.h29
-rw-r--r--meson.build88
-rw-r--r--meson_options.txt15
-rw-r--r--netsplit.c253
-rw-r--r--tests/12.15.1.55
-rw-r--r--tests/129.15.31.55
-rw-r--r--tests/192.168.1.5-165
-rw-r--r--tests/192.168.1.5-245
-rw-r--r--tests/192.168.1.5-305
-rw-r--r--tests/192.168.1.5-315
-rw-r--r--tests/192.168.1.5-85
-rw-r--r--tests/192.168.2.68
-rw-r--r--tests/192.168.2.78
-rw-r--r--tests/193.92.150.3-246
-rw-r--r--tests/193.92.31.05
-rw-r--r--tests/all-info-192.168.2.711
-rw-r--r--tests/deaggregate-192.168.2.0-192.168.3.2552
-rw-r--r--tests/deaggregate-192.168.2.33-192.168.3.212
-rw-r--r--tests/deaggregate-192.168.2.7-192.168.2.133
-rw-r--r--tests/deaggregate-2a03:2880:20:4f06:face::0-2a03:2880:20:4f06:face::fffe16
-rw-r--r--tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:0-fcd3:57d1:733:c18f:b498:25e1:788:ffff2
-rw-r--r--tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:f-fcd3:57d1:733:c18f:b498:25e1:789:ffa928
-rw-r--r--tests/fd0b:a336:4e7d::-485
-rw-r--r--tests/fd95:6be5:0ae0:84a5::-645
-rw-r--r--tests/hostname-localhost-ipv41
-rw-r--r--tests/hostname-localhost-ipv4-json11
-rw-r--r--tests/hostname-localhost-ipv61
-rw-r--r--tests/i-0.0.0.12
-rw-r--r--tests/i-10.0.0.12
-rw-r--r--tests/i-100.64.0.12
-rw-r--r--tests/i-127.0.0.12
-rw-r--r--tests/i-127.0.1.12
-rw-r--r--tests/i-169.254.0.12
-rw-r--r--tests/i-172.16.0.12
-rw-r--r--tests/i-172.31.255.2542
-rw-r--r--tests/i-192.0.0.12
-rw-r--r--tests/i-192.0.0.102
-rw-r--r--tests/i-192.0.0.1702
-rw-r--r--tests/i-192.0.0.1712
-rw-r--r--tests/i-192.0.0.2542
-rw-r--r--tests/i-192.0.0.62
-rw-r--r--tests/i-192.0.0.82
-rw-r--r--tests/i-192.0.0.92
-rw-r--r--tests/i-192.0.2.12
-rw-r--r--tests/i-192.168.0.12
-rw-r--r--tests/i-192.175.48.122
-rw-r--r--tests/i-192.31.196.12
-rw-r--r--tests/i-192.52.193.52
-rw-r--r--tests/i-192.88.99.12
-rw-r--r--tests/i-198.18.0.12
-rw-r--r--tests/i-198.19.201.712
-rw-r--r--tests/i-198.19.255.2542
-rw-r--r--tests/i-198.51.100.12
-rw-r--r--tests/i-2001:0:50::d78a:0:c3
-rw-r--r--tests/i-2001:190:70::e86a:0:b3
-rw-r--r--tests/i-2001:1::13
-rw-r--r--tests/i-2001:1::23
-rw-r--r--tests/i-2001:1e:ab:7::3
-rw-r--r--tests/i-2001:2:0:a::5:b7f3
-rw-r--r--tests/i-2001:2c:ab:7::3
-rw-r--r--tests/i-2001:3:89:71::ab:13
-rw-r--r--tests/i-2001:4:112::6483:bd12:90103
-rw-r--r--tests/i-2001:db8:329::4a3
-rw-r--r--tests/i-2002::343
-rw-r--r--tests/i-203.0.113.12
-rw-r--r--tests/i-224.0.0.12
-rw-r--r--tests/i-240.0.0.12
-rw-r--r--tests/i-250.7.93.12
-rw-r--r--tests/i-255.255.255.2542
-rw-r--r--tests/i-255.255.255.2552
-rw-r--r--tests/i-2620:4f:8000::7372:ad13
-rw-r--r--tests/i-2a03:2880:20:4f06:face:b00c:0:13
-rw-r--r--tests/i-3.130.45.152
-rw-r--r--tests/i-64:ff9b:1:ea21:4316:55::13
-rw-r--r--tests/i-64:ff9b::2100:951a3
-rw-r--r--tests/i-fc00:0:a001::bcdf:43
-rw-r--r--tests/i-fd0b:a336:4e7d::-488
-rw-r--r--tests/i-fe80::b:0:7acd:0:53
-rw-r--r--tests/info-192.168.2.79
-rw-r--r--tests/ip-localhost-ipv41
-rw-r--r--tests/ip-localhost-ipv4-json12
-rw-r--r--tests/ip-localhost-ipv61
-rwxr-xr-xtests/ipcalc-delegate-ipv6-random.sh33
-rwxr-xr-xtests/ipcalc-delegate-split-ipv4.sh42
-rwxr-xr-xtests/ipcalc-delegate-split-ipv6.sh42
-rwxr-xr-xtests/ipcalc-testrunner.sh86
-rw-r--r--tests/json-i-2a03:2880:20:4f06:face:b00c:0:1-5612
-rw-r--r--tests/json-nsplit-10.10.10.0-16-24261
-rw-r--r--tests/json-nsplit-192.168.5.45-24-269
-rw-r--r--tests/json-nsplit-2a03:2880:20:4f06:face::-56-64261
-rw-r--r--tests/json-split-10.10.10.0-16-24261
-rw-r--r--tests/json-split-192.168.5.45-24-269
-rw-r--r--tests/json-split-2a03:2880:20:4f06:face::-56-64261
-rw-r--r--tests/meson.build1330
-rw-r--r--tests/no-decorate-192.168.2.0-248
-rw-r--r--tests/no-decorate-all-info-192.168.2.0-2410
-rw-r--r--tests/nsplit-10.10.10.0-16-184
-rw-r--r--tests/nsplit-10.10.10.0-16-24256
-rw-r--r--tests/nsplit-192.168.5.0-24-2932
-rw-r--r--tests/nsplit-192.168.5.0-24-31128
-rw-r--r--tests/nsplit-192.168.5.0-24-32256
-rw-r--r--tests/nsplit-192.168.5.0-31-322
-rw-r--r--tests/nsplit-192.168.5.45-24-264
-rw-r--r--tests/nsplit-2a03:2880:20:4f06:face::-56-64256
-rw-r--r--tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-112-120256
-rw-r--r--tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-127-1282
-rwxr-xr-xtests/run-coverage.sh4
-rw-r--r--tests/split-10.10.10.0-16-188
-rw-r--r--tests/split-10.10.10.0-16-24260
-rw-r--r--tests/split-192.168.5.0-24-2936
-rw-r--r--tests/split-192.168.5.0-24-31132
-rw-r--r--tests/split-192.168.5.0-24-32260
-rw-r--r--tests/split-192.168.5.0-31-326
-rw-r--r--tests/split-192.168.5.45-24-268
-rw-r--r--tests/split-2a03:2880:20:4f06:face::-56-64260
-rw-r--r--tests/split-fcfa:b4ca:f1d8:125b:dc00::-112-120260
-rw-r--r--tests/split-fcfa:b4ca:f1d8:125b:dc00::-127-1286
-rw-r--r--tests/standard-192.168.2.0-248
134 files changed, 9949 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..e88230b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,8 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+
+[*.{c,h,sh}]
+indent_style = tab
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..364044f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+# Ignore swap and backup files used by some editors.
+*~
+*.swp
+
+# Ignore final build artifacts (for the legacy Makefile).
+ipcalc
+out.tmp
+
+# Ignore the default out-of-tree build directory (for Meson).
+/build
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..7ee01e4
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,100 @@
+stages:
+ - generate
+ - deploy
+
+.fedora.latest.template: &fedora_template
+ image: fedora:latest
+ before_script:
+#in F34 rubygem-ronn got replaced by rubygem-ronn-ng
+ - dnf install -y GeoIP-devel libmaxminddb-devel make meson ninja-build gcc libasan geolite2-{city,country} rubygem-ronn
+
+fedora.nogeo:
+ stage: generate
+ <<: *fedora_template
+ script:
+ - meson setup build -Duse_maxminddb=disabled -Duse_geoip=disabled --buildtype=plain -Dc_args="-O2 -g -Werror"
+ - ninja -C build
+ - ninja -C build test
+ - USE_MAXMIND=no USE_GEOIP=no USE_RUNTIME_LINKING=no CFLAGS="-O2 -g -Werror" make
+
+fedora.geoip:
+ stage: generate
+ <<: *fedora_template
+ script:
+ - meson setup build -Duse_maxminddb=disabled -Duse_geoip=enabled -Duse_runtime_linking=disabled --buildtype=plain -Dc_args="-O2 -g -Werror"
+ - ninja -C build
+ - ninja -C build test
+ - USE_GEOIP=yes USE_RUNTIME_LINKING=no USE_MAXMIND=no CFLAGS="-O2 -g -Werror" make
+
+fedora.dyn_geoip:
+ stage: generate
+ <<: *fedora_template
+ script:
+ - meson setup build -Duse_maxminddb=disabled -Duse_geoip=enabled -Duse_runtime_linking=enabled --buildtype=plain -Dc_args="-O2 -g -Werror"
+ - ninja -C build
+ - ninja -C build test
+ - USE_GEOIP=yes USE_RUNTIME_LINKING=yes USE_MAXMIND=no CFLAGS="-O2 -g -Werror" make
+
+fedora.maxmind:
+ stage: generate
+ <<: *fedora_template
+ script:
+ - meson setup build -Duse_maxminddb=enabled -Duse_geoip=disabled -Duse_runtime_linking=disabled --buildtype=plain -Dc_args="-O2 -g -Werror"
+ - ninja -C build
+ - ninja -C build test
+ - USE_GEOIP=no USE_RUNTIME_LINKING=no USE_MAXMIND=yes CFLAGS="-O2 -g -Werror" make
+
+fedora.dyn_maxmind:
+ stage: generate
+ <<: *fedora_template
+ script:
+ - meson setup build -Duse_maxminddb=enabled -Duse_geoip=disabled -Duse_runtime_linking=enabled --buildtype=plain -Dc_args="-O2 -g -Werror"
+ - ninja -C build
+ - ninja -C build test
+ - USE_GEOIP=no USE_RUNTIME_LINKING=yes USE_MAXMIND=yes CFLAGS="-O2 -g -Werror" make
+
+fedora.dyn_maxmind_with_asan:
+ stage: generate
+ <<: *fedora_template
+ script:
+ - export ASAN_OPTIONS="detect_leaks=0"
+ - meson setup build -Db_sanitize=address -Dwerror=true
+ - ninja -C build test
+ - ./build/ipcalc -g 217.31.205.50
+
+# Generates coverage report
+pages-test:
+ stage: deploy
+ <<: *fedora_template
+ script:
+ - dnf install -y lcov
+ - meson setup build -Db_coverage=true -Duse_maxminddb=enabled -Duse_geoip=disabled -Duse_runtime_linking=enabled --buildtype=plain -Dc_args="-Og -g -Werror"
+ - ninja -C build
+ - ninja -C build test
+ - ninja -C build coverage-html && mv build/meson-logs/coveragereport public
+
+
+ tags:
+ - shared
+ except:
+ - master
+
+pages:
+ stage: deploy
+ <<: *fedora_template
+ script:
+ - dnf install -y lcov
+ - meson setup build -Db_coverage=true -Duse_maxminddb=enabled -Duse_geoip=disabled -Duse_runtime_linking=enabled --buildtype=plain -Dc_args="-Og -g -Werror"
+ - ninja -C build
+ - ninja -C build test
+ - ninja -C build coverage-html && mv build/meson-logs/coveragereport public
+ - tests/run-coverage.sh
+ tags:
+ - shared
+ coverage: '/coverage lines: \d+\.\d+/'
+ artifacts:
+ when: on_success
+ paths:
+ - public
+ only:
+ - master
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a1766c3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,40 @@
+USE_GEOIP?=no
+USE_MAXMIND?=yes
+USE_RUNTIME_LINKING?=yes
+
+LIBPATH?=/usr/lib64
+#LIBPATH=/usr/lib/x86_64-linux-gnu
+
+LIBS?=
+VERSION=$(shell cat meson.build|grep 'version :'|cut -d ':' -f 2|tr -d " \'")
+CC?=gcc
+CFLAGS?=-O2 -g -Wall
+LDFLAGS=$(LIBS)
+
+ifeq ($(USE_GEOIP),yes)
+ifeq ($(USE_RUNTIME_LINKING),yes)
+LDFLAGS+=-ldl
+CFLAGS+=-DUSE_GEOIP -DUSE_RUNTIME_LINKING -DLIBPATH="\"$(LIBPATH)\""
+else
+LDFLAGS+=-lGeoIP
+CFLAGS+=-DUSE_GEOIP
+endif # DYN GEOIP
+else # GEOIP
+ifeq ($(USE_MAXMIND),yes)
+ifeq ($(USE_RUNTIME_LINKING),yes)
+LDFLAGS+=-ldl
+CFLAGS+=-DUSE_MAXMIND -DUSE_RUNTIME_LINKING -DLIBPATH="\"$(LIBPATH)\""
+else
+LDFLAGS+=-lmaxminddb
+CFLAGS+=-DUSE_MAXMIND
+endif # DYN MAXMIND
+endif # MAXMIND
+endif # not GEOIP
+
+all: ipcalc
+
+ipcalc: ipcalc.c ipv6.c deaggregate.c ipcalc-geoip.c ipcalc-maxmind.c ipcalc-reverse.c ipcalc-utils.c netsplit.c
+ $(CC) $(CFLAGS) -DVERSION="\"$(VERSION)\"" $^ -o $@ $(LDFLAGS)
+
+clean:
+ rm -f ipcalc
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..8b49202
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,131 @@
+* Version 1.0.3 (released 2023-06-07)
+- When --no-decorate is given the default output will
+ include no colors (#28)
+- Correctly split networks with /31 (#25)
+
+
+* Version 1.0.2 (released 2022-11-26)
+- Fix ULA prefix generator to use only defined ULA range
+- Corrected manpage generation
+
+
+* Version 1.0.1 (released 2021-06-06)
+- The application will now build even without ronn
+- Improved JSON output on single host input
+
+
+* Version 1.0.0 (released 2020-10-03)
+- Manpage was converted to markdown
+
+
+* Version 0.4.1 (released 2020-04-24)
+- Fix identification of TEST-NET-1 and TEST-NET-2.
+- Updated IANA IPv4 special purpose address registry to the
+ 2020-04-06 version.
+
+
+* Version 0.4.0 (released 2019-12-28)
+- Set the broadcast address according to RFC3021
+- Added the --deaggregate (-d) option. This allows identifying the networks
+ that cover a given IP range.
+
+
+* Version 0.3.0 (released 2019-11-23)
+- Added Meson build system; to build use:
+ $ meson setup build
+ $ ninja -C build
+ $ ninja -C build test
+- Extend --no-decorate support to work with the specific info output options.
+- Added the -a/--address info output option to explicitly print the address.
+- Do not display the address class information unless --all-info is given
+ on command line.
+- Fixed detection of IPv6 IETF Protocol Assignments address block
+- Fixed detection of IPv6 6to4 address block
+- Updated the IANA IPv6 Special-Purpose Address Registry support to
+ 2019-09-13, which adds a few new IPv6 address blocks that can now be
+ detected by ipcalc.
+- Added the -j/--json output mode to print the info using the JSON format.
+
+
+* Version 0.2.5 (released 2019-02-18)
+- Fixed compilation with no geoinformation
+- Fixed segmentation fault when compiled with, but run without libmaxminddb.
+
+
+* Version 0.2.4 (released 2018-07-23)
+- Added support for libmaxmind DB API as an alternative to libgeoip.
+
+
+* Version 0.2.3 (released 2018-05-26)
+- Fixed --no-decorate option with --split and IPv6 addresses.
+- Fixed build with USE_GEOIP=yes and USE_DYN_GEOIP=no (David Guglielmi)
+- Fixed build with libgeoip < 1.6.3
+
+
+* Version 0.2.2 (released 2017-12-27)
+- Added a more silent version of --split when combined with
+ --no-decorate option.
+
+
+* Version 0.2.0 (released 2017-05-15)
+- Added the --split (-S) option. This allows splitting networks
+ into smaller chunks.
+
+
+* Version 0.1.8 (released 2016-06-14)
+- Do not print the reverse DNS information by default. Only
+ when --all-info is specified.
+
+
+* Version 0.1.7 (released 2016-04-01)
+- Assume a classless IPv4 range by default. This breaks compatibility
+ with previous versions since, unless --class-prefix is specified,
+ the default IPv4 prefix is now /32.
+- Added support for printing reverse DNS addresses.
+
+
+* Version 0.1.6 (released 2015-12-08)
+- Introduced color printing.
+
+
+* Version 0.1.5 (released 2015-11-05)
+- Auto-detect IPv6 addresses when generating random networks.
+- Removed libpopt dependency by using getopt_long().
+
+
+* Version 0.1.4 (released 2015-10-14)
+- Added the --all-info option to enable the printing of all
+ available information.
+
+
+* Version 0.1.3 (released 2015-10-05)
+- Print the country code in informational mode.
+
+
+* Version 0.1.2 (released 2015-06-09)
+- Print the country code when --geoinfo is requested.
+- Only quote the strings if there are spaces in them.
+
+
+* Version 0.1.1 (released 2015-05-19)
+- Allow a prefix of 0, or 0.0.0.0 to be compatible with previous
+ tool.
+
+
+* Version 0.1.0 (released 2015-05-18)
+- Added --random-private parameter to generate private networks.
+- IPv4 and IPv6 addresses are now automatically being detected,
+ and the --ipv4 or --ipv6 options are not mandatory to specify.
+- Added the --minaddr and --maxaddr options to print the minimum
+ and maximum addresses in the provided network.
+- Added the --addresses option to print the number of addresses
+ in the provided network.
+- Added the --addrspace option to print the type of the network
+ the address resides on.
+- Added the --geoinfo option to print geographic information about
+ the given IP address. That will work if libGeoIP is found on
+ the system.
+- By default, when no parameters are given, general information
+ about the provided network/address are printed (also as --info
+ option).
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..db83a4e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,186 @@
+# Information about ipcalc
+
+This is a modern tool to assist in network address calculations for IPv4 and IPv6.
+It acts both as a tool to output human readable information about a network or address,
+as well as a tool suitable to be used by scripts or other programs.
+
+It supports printing a summary about the provided network address, multiple
+command line options per information to be printed, transparent IPv6 support,
+and in addition it will use libGeoIP if available to provide geographic information.
+
+The project started as a fork of the ipcalc tool in the Fedora distribution
+but it has since then replaced the original tool.
+
+
+# How to build
+
+This project is built using Meson and Ninja. To build it simply type:
+```
+$ meson setup build
+$ ninja -C build
+```
+
+## Build options
+
+There are a few build-time options supported by ipcalc. You can learn about
+them, and optionally reconfigure the project before building it, by running the
+following command after `meson setup build`:
+```
+$ meson configure build
+```
+
+In order to access geo-information, ipcalc depends on the maxmind
+database (libmaxminddb). Alternatively it can be built using the older
+libgeoip (libgeoip), or with no geo-information whatsoever. Meson will
+detect which supported geo-information libraries are available on your system,
+if any, and automatically choose the best one. You can override this choice by
+providing `-Duse_maxminddb=enabled` to `meson setup` or `meson configure` to
+require libmaxminddb or `-Duse_maxminddb=disabled -Duse_geoip=enabled` to
+require libgeoip. See `meson configure build` for more options.
+
+For example, the following command will compile with no support for
+geo-information.
+```
+$ meson setup build `-Duse_maxminddb=disabled -Duse_geoip=disabled`
+$ ninja -C build
+```
+
+To generate the manpage the ronn application is necessary.
+
+## Optimizing the build
+
+By default Meson optimizes for the most common type of build: those done by
+developers. Consequently default builds of ipcalc with Meson are without
+optimization and with debug information. If you want an optimized build,
+pass `--buildtype=release` to `meson setup` or `meson configure`. See
+[the Meson documentation](https://mesonbuild.com/Running-Meson.html#configuring-the-build-directory)
+for more build options.
+```
+$ meson setup build --buildtype=release
+$ ninja -C build
+```
+
+
+# Running unit tests
+
+After the application has been configured and built for the host platform
+(default), you may run the unit test suite against the ipcalc binary as
+follows:
+```
+$ ninja -C build test
+```
+
+
+# Legacy build method
+
+Although the Meson Build System, described above, is the recommended way to
+build this application, the legacy GNU Makefile is still supported for older
+systems that do not have the requisite versions of Meson and Ninja readily
+available. The primary limitations of using the Makefile are that it does not
+do automatic detection of libmaxminddb or libgeoip - you may have to specify
+support for one or neither of those libraries manually - and there is no easy
+way to run the test suite.
+
+To build using the legacy GNU Makefile simply type:
+```
+$ make
+```
+
+In order to access geo-information the application depends on the maxmind
+database (libmaxminddb). Alternatively it can be built using the older
+libgeoip (libgeoip) or with no geo-information whatsoever. The options
+can be provided on the makefile via the variables USE_GEOIP (yes/no),
+USE_MAXMIND (yes/no). For example the following command will compile
+with no support for geo-information.
+
+```
+$ make USE_GEOIP=no USE_MAXMIND=no
+```
+
+
+# Examples
+
+## IPv4
+
+```
+$ ipcalc --all-info 193.92.150.2/24
+Address: 193.92.150.2
+Network: 193.92.150.0/24
+Netmask: 255.255.255.0 = 24
+Broadcast: 193.92.150.255
+Reverse DNS: 150.92.193.in-addr.arpa.
+
+Address space: Internet
+Address class: Class C
+HostMin: 193.92.150.1
+HostMax: 193.92.150.254
+Hosts/Net: 254
+
+Country code: GR
+Country: Greece
+```
+
+```
+$ ipcalc -pnmb --minaddr --maxaddr --geoinfo --addrspace 193.92.150.2/255.255.255.224
+NETMASK=255.255.255.224
+PREFIX=27
+BROADCAST=193.92.150.31
+NETWORK=193.92.150.0
+MINADDR=193.92.150.1
+MAXADDR=193.92.150.30
+ADDRSPACE="Internet"
+COUNTRY="Greece"
+```
+
+## IPv6
+
+```
+$ ipcalc --all-info 2a03:2880:20:4f06:face:b00c:0:14/64
+Full Address: 2a03:2880:0020:4f06:face:b00c:0000:0014
+Address: 2a03:2880:20:4f06:face:b00c:0:14
+Full Network: 2a03:2880:0020:4f06:0000:0000:0000:0000/64
+Network: 2a03:2880:20:4f06::/64
+Netmask: ffff:ffff:ffff:ffff:: = 64
+Reverse DNS: 6.0.f.4.0.2.0.0.0.8.8.2.3.0.a.2.ip6.arpa.
+
+Address space: Global Unicast
+HostMin: 2a03:2880:20:4f06::
+HostMax: 2a03:2880:20:4f06:ffff:ffff:ffff:ffff
+Hosts/Net: 2^(64) = 18446744073709551616
+
+Country code: IE
+Country: Ireland
+```
+
+```
+$ ipcalc -pnmb --minaddr --maxaddr --addrspace --geoinfo 2a03:2880:20:4f06:face:b00c:0:14/64
+NETMASK=ffff:ffff:ffff:ffff::
+PREFIX=64
+NETWORK=2a03:2880:20:4f06::
+MINADDR=2a03:2880:20:4f06::
+MAXADDR=2a03:2880:20:4f06:ffff:ffff:ffff:ffff
+ADDRSPACE="Global Unicast"
+COUNTRY="Ireland"
+```
+
+## JSON output
+
+```
+$ ipcalc --all-info -j 2a03:2880:20:4f06:face:b00c:0:14/64
+{
+ "FULLADDRESS":"2a03:2880:0020:4f06:face:b00c:0000:0014",
+ "ADDRESS":"2a03:2880:20:4f06:face:b00c:0:14",
+ "FULLNETWORK":"2a03:2880:0020:4f06:0000:0000:0000:0000",
+ "NETWORK":"2a03:2880:20:4f06::",
+ "NETMASK":"ffff:ffff:ffff:ffff::",
+ "PREFIX":"64",
+ "REVERSEDNS":"6.0.f.4.0.2.0.0.0.8.8.2.3.0.a.2.ip6.arpa.",
+ "ADDRSPACE":"Global Unicast",
+ "MINADDR":"2a03:2880:20:4f06::",
+ "MAXADDR":"2a03:2880:20:4f06:ffff:ffff:ffff:ffff",
+ "ADDRESSES":"18446744073709551616",
+ "COUNTRYCODE":"IE",
+ "COUNTRY":"Ireland",
+ "COORDINATES":"53.000000,-8.000000"
+}
+```
diff --git a/deaggregate.c b/deaggregate.c
new file mode 100644
index 0000000..c6174f6
--- /dev/null
+++ b/deaggregate.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2019 Nikos Mavrogiannopoulos
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+
+#include "ipcalc.h"
+#include "ipv6.h"
+
+static void deaggregate_v4(const char *ip1s, const char *ip2s, unsigned flags);
+static void deaggregate_v6(const char *ip1s, const char *ip2s, unsigned flags);
+
+static char *trim(char *str)
+{
+ int len, i;
+ char *out;
+
+ len = strlen(str);
+ for (i=len-1;i>=0;i--) {
+ if (isspace(str[i]))
+ str[i] = 0;
+ else
+ break;
+ }
+
+ out = str;
+ for (i=0;i<len;i++) {
+ if (isspace(str[i]))
+ out++;
+ else
+ break;
+ }
+
+ return out;
+}
+
+void deaggregate(char *str, unsigned flags)
+{
+ char *d1Str = NULL, *d2Str = NULL;
+
+ d1Str = strtok(str, "-");
+ if (d1Str == NULL) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: bad deaggregation string: %s\n", str);
+ exit(1);
+ }
+ d1Str = trim(d1Str);
+
+
+ d2Str = strtok(NULL, "-");
+ if (d2Str == NULL) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: bad deaggregation string: %s\n", str);
+ exit(1);
+ }
+ d2Str = trim(d2Str);
+
+ if (flags & FLAG_IPV6)
+ deaggregate_v6(d1Str, d2Str, flags);
+ else
+ deaggregate_v4(d1Str, d2Str, flags);
+}
+
+static void print_ipv4_net(unsigned *jsonchain, uint32_t ip, unsigned prefix, unsigned flags)
+{
+ char namebuf[INET_ADDRSTRLEN + 1] = {0};
+ struct in_addr s;
+
+ s.s_addr = htonl(ip);
+
+ if (inet_ntop(AF_INET, &s, namebuf, INET_ADDRSTRLEN) == NULL) {
+ fprintf(stderr, "inet_ntop failure at line %d\n",
+ __LINE__);
+ exit(1);
+ }
+
+ default_printf(jsonchain, "Network:\t", NULL, "%s/%u", namebuf, prefix);
+}
+
+void deaggregate_v4(const char *ip1s, const char *ip2s, unsigned flags)
+{
+ struct in_addr ip1, ip2;
+ unsigned step;
+ uint32_t base, end;
+ unsigned jsonchain;
+
+ if (inet_pton(AF_INET, ip1s, &ip1) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv4 address: %s\n",
+ ip1s);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET, ip2s, &ip2) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv4 address: %s\n",
+ ip2s);
+ exit(1);
+ }
+
+ base = ntohl(ip1.s_addr);
+ end = ntohl(ip2.s_addr);
+
+ if (base > end) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad range\n");
+ exit(1);
+ }
+
+ output_start(&jsonchain);
+ array_start(&jsonchain, "Deaggregated networks", "DEAGGREGATEDNETWORK");
+
+ while (base <= end) {
+ step = 0;
+ while ((base | (1 << step)) != base) {
+ if ((base | (UINT32_MAX >> (31-step))) > end)
+ break;
+ step++;
+ }
+
+ print_ipv4_net(&jsonchain, base, 32-step, flags);
+ base += (1 << step);
+ }
+
+ array_stop(&jsonchain);
+ output_stop(&jsonchain);
+
+ return;
+}
+
+static void print_ipv6_net(unsigned *jsonchain, struct in6_addr *ip, unsigned prefix, unsigned flags)
+{
+ char namebuf[INET6_ADDRSTRLEN + 1] = {0};
+
+ if (inet_ntop(AF_INET6, ip, namebuf, sizeof(namebuf)) == NULL) {
+ fprintf(stderr, "inet_ntop failure at line %d\n",
+ __LINE__);
+ exit(1);
+ }
+
+ default_printf(jsonchain, "Network:\t", NULL, "%s/%u", namebuf, prefix);
+}
+
+static unsigned ipv6_base_ok(struct in6_addr *base, unsigned step)
+{
+ struct in6_addr b2;
+ memcpy(&b2, base, sizeof(b2));
+
+ ipv6_or1(&b2, step);
+
+ return memcmp(base->s6_addr, &b2.s6_addr, 16);
+}
+
+void deaggregate_v6(const char *ip1s, const char *ip2s, unsigned flags)
+{
+ struct in6_addr ip1, ip2;
+ unsigned step;
+ struct in6_addr base, end;
+ struct in6_addr tmp;
+ unsigned jsonchain;
+
+ if (inet_pton(AF_INET6, ip1s, &ip1) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 address: %s\n",
+ ip1s);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET6, ip2s, &ip2) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 address: %s\n",
+ ip2s);
+ exit(1);
+ }
+
+ memcpy(&base, &ip1, sizeof(base));
+ memcpy(&end, &ip2, sizeof(end));
+
+ if (ipv6_cmp(&base, &end) > 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 range\n");
+ exit(1);
+ }
+
+ output_start(&jsonchain);
+ array_start(&jsonchain, "Deaggregated networks", "DEAGGREGATEDNETWORK");
+
+
+ while (ipv6_cmp(&base, &end) <= 0) {
+ step = 0;
+ while (ipv6_base_ok(&base, step)) {
+ memcpy(&tmp, &base, sizeof(tmp));
+ ipv6_orm(&tmp, step+1);
+ if (ipv6_cmp(&tmp, &end) > 0)
+ break;
+ step++;
+ }
+
+ print_ipv6_net(&jsonchain, &base, 128-step, flags);
+ memset(&tmp, 0, sizeof(tmp));
+ ipv6_or1(&tmp, step);
+
+ /* v6add */
+ ipv6_add(&base, &tmp);
+ }
+
+ array_stop(&jsonchain);
+ output_stop(&jsonchain);
+
+ return;
+}
diff --git a/ipcalc-geoip.c b/ipcalc-geoip.c
new file mode 100644
index 0000000..6f2b513
--- /dev/null
+++ b/ipcalc-geoip.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Nikos Mavrogiannopoulos <nmav@redhat.com>
+ */
+
+#define _GNU_SOURCE /* asprintf */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include "ipcalc.h"
+
+#ifdef USE_GEOIP
+
+# include <GeoIP.h>
+# include <GeoIPCity.h>
+
+#define GEOIP_SILENCE 16 /* fix libgeoip < 1.6.3 */
+
+# ifdef USE_RUNTIME_LINKING
+# include <dlfcn.h>
+
+typedef void (*_GeoIP_setup_dbfilename_func)(void);
+typedef GeoIP * (*GeoIP_open_type_func)(int type, int flags);
+typedef const char * (*GeoIP_country_name_by_id_func)(GeoIP * gi, int id);
+typedef void (*GeoIP_delete_func)(GeoIP * gi);
+typedef GeoIPRecord * (*GeoIP_record_by_ipnum_func)(GeoIP * gi, unsigned long ipnum);
+typedef int (*GeoIP_id_by_ipnum_func)(GeoIP * gi, unsigned long ipnum);
+typedef int (*GeoIP_id_by_ipnum_v6_func)(GeoIP * gi, geoipv6_t ipnum);
+typedef GeoIPRecord *(*GeoIP_record_by_ipnum_v6_func)(GeoIP * gi, geoipv6_t ipnum);
+typedef const char *(*GeoIP_code_by_id_func)(int id);
+
+static _GeoIP_setup_dbfilename_func p_GeoIP_setup_dbfilename;
+static GeoIP_open_type_func pGeoIP_open_type;
+static GeoIP_country_name_by_id_func pGeoIP_country_name_by_id;
+static GeoIP_code_by_id_func pGeoIP_code_by_id;
+static GeoIP_delete_func pGeoIP_delete;
+static GeoIP_record_by_ipnum_func pGeoIP_record_by_ipnum;
+static GeoIP_id_by_ipnum_func pGeoIP_id_by_ipnum;
+static GeoIP_id_by_ipnum_v6_func pGeoIP_id_by_ipnum_v6;
+static GeoIP_record_by_ipnum_v6_func pGeoIP_record_by_ipnum_v6;
+
+#define LIBNAME LIBPATH"/libGeoIP.so.1"
+
+int geo_setup(void)
+{
+ static void *ld = NULL;
+ static int ret = 0;
+ static char err[256] = {0};
+
+ if (ld != NULL || ret != 0) {
+ if (!beSilent && err[0] != 0) {
+ fprintf(stderr, "%s", err);
+ }
+ return ret;
+ }
+
+ ld = dlopen(LIBNAME, RTLD_LAZY);
+ if (ld == NULL) {
+ snprintf(err, sizeof(err), "ipcalc: could not open %s\n", LIBNAME);
+ ret = -1;
+ goto exit;
+ }
+
+ p_GeoIP_setup_dbfilename = dlsym(ld, "_GeoIP_setup_dbfilename");
+
+ pGeoIP_open_type = dlsym(ld, "GeoIP_open_type");
+ pGeoIP_country_name_by_id = dlsym(ld, "GeoIP_country_name_by_id");
+ pGeoIP_delete = dlsym(ld, "GeoIP_delete");
+ pGeoIP_record_by_ipnum = dlsym(ld, "GeoIP_record_by_ipnum");
+ pGeoIP_id_by_ipnum = dlsym(ld, "GeoIP_id_by_ipnum");
+ pGeoIP_id_by_ipnum_v6 = dlsym(ld, "GeoIP_id_by_ipnum_v6");
+ pGeoIP_record_by_ipnum_v6 = dlsym(ld, "GeoIP_record_by_ipnum_v6");
+ pGeoIP_code_by_id = dlsym(ld, "GeoIP_code_by_id");
+
+ if (pGeoIP_open_type == NULL || pGeoIP_country_name_by_id == NULL ||
+ pGeoIP_delete == NULL || pGeoIP_record_by_ipnum == NULL ||
+ pGeoIP_id_by_ipnum == NULL || pGeoIP_id_by_ipnum_v6 == NULL ||
+ pGeoIP_record_by_ipnum_v6 == NULL) {
+ snprintf(err, sizeof(err), "ipcalc: could not find symbols in libGeoIP\n");
+ ret = -1;
+ goto exit;
+ }
+
+ ret = 0;
+ exit:
+ return ret;
+}
+
+# else
+
+extern void _GeoIP_setup_dbfilename(void);
+# define p_GeoIP_setup_dbfilename _GeoIP_setup_dbfilename
+# define pGeoIP_open_type GeoIP_open_type
+# define pGeoIP_country_name_by_id GeoIP_country_name_by_id
+# define pGeoIP_delete GeoIP_delete
+# define pGeoIP_record_by_ipnum GeoIP_record_by_ipnum
+# define pGeoIP_id_by_ipnum GeoIP_id_by_ipnum
+# define pGeoIP_id_by_ipnum_v6 GeoIP_id_by_ipnum_v6
+# define pGeoIP_record_by_ipnum_v6 GeoIP_record_by_ipnum_v6
+# define pGeoIP_code_by_id GeoIP_code_by_id
+# endif
+
+static void geo_ipv4_lookup(struct in_addr ip, char **country, char **ccode, char **city, char **coord)
+{
+ GeoIP *gi;
+ GeoIPRecord *gir;
+ int country_id;
+ const char *p;
+
+ if (geo_setup() != 0)
+ return;
+
+ ip.s_addr = ntohl(ip.s_addr);
+
+ p_GeoIP_setup_dbfilename();
+
+ gi = pGeoIP_open_type(GEOIP_COUNTRY_EDITION, GEOIP_STANDARD | GEOIP_SILENCE);
+ if (gi != NULL) {
+ gi->charset = GEOIP_CHARSET_UTF8;
+
+ country_id = pGeoIP_id_by_ipnum(gi, ip.s_addr);
+ if (country_id < 0) {
+ return;
+ }
+ p = pGeoIP_country_name_by_id(gi, country_id);
+ if (p)
+ *country = safe_strdup(p);
+
+ p = pGeoIP_code_by_id(country_id);
+ if (p)
+ *ccode = safe_strdup(p);
+
+ pGeoIP_delete(gi);
+ }
+
+ gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV1, GEOIP_STANDARD | GEOIP_SILENCE);
+ if (gi != NULL) {
+ gi->charset = GEOIP_CHARSET_UTF8;
+
+ gir = pGeoIP_record_by_ipnum(gi, ip.s_addr);
+
+ if (gir && gir->city)
+ *city = safe_strdup(gir->city);
+
+ if (gir && gir->longitude != 0 && gir->longitude != 0)
+ safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
+
+ pGeoIP_delete(gi);
+ } else {
+ gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV0, GEOIP_STANDARD | GEOIP_SILENCE);
+ if (gi != NULL) {
+ gi->charset = GEOIP_CHARSET_UTF8;
+
+ gir = pGeoIP_record_by_ipnum(gi, ip.s_addr);
+
+ if (gir && gir->city)
+ *city = safe_strdup(gir->city);
+
+ if (gir && gir->longitude != 0 && gir->longitude != 0)
+ safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
+
+ pGeoIP_delete(gi);
+ }
+ }
+
+ return;
+}
+
+static void geo_ipv6_lookup(struct in6_addr *ip, char **country, char **ccode, char **city, char **coord)
+{
+ GeoIP *gi;
+ GeoIPRecord *gir;
+ int country_id;
+ const char *p;
+
+ if (geo_setup() != 0)
+ return;
+
+ p_GeoIP_setup_dbfilename();
+
+ gi = pGeoIP_open_type(GEOIP_COUNTRY_EDITION_V6, GEOIP_STANDARD | GEOIP_SILENCE);
+ if (gi != NULL) {
+ gi->charset = GEOIP_CHARSET_UTF8;
+
+ country_id = pGeoIP_id_by_ipnum_v6(gi, (geoipv6_t)*ip);
+ if (country_id < 0) {
+ return;
+ }
+ p = pGeoIP_country_name_by_id(gi, country_id);
+ if (p)
+ *country = safe_strdup(p);
+
+ p = pGeoIP_code_by_id(country_id);
+ if (p)
+ *ccode = safe_strdup(p);
+
+ pGeoIP_delete(gi);
+ }
+
+ gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV1_V6, GEOIP_STANDARD | GEOIP_SILENCE);
+ if (gi != NULL) {
+ gi->charset = GEOIP_CHARSET_UTF8;
+
+ gir = pGeoIP_record_by_ipnum_v6(gi, (geoipv6_t)*ip);
+
+ if (gir && gir->city)
+ *city = safe_strdup(gir->city);
+
+ if (gir && gir->longitude != 0 && gir->longitude != 0)
+ safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
+
+ pGeoIP_delete(gi);
+ } else {
+ gi = pGeoIP_open_type(GEOIP_CITY_EDITION_REV0_V6, GEOIP_STANDARD | GEOIP_SILENCE);
+ if (gi != NULL) {
+ gi->charset = GEOIP_CHARSET_UTF8;
+
+ gir = pGeoIP_record_by_ipnum_v6(gi, (geoipv6_t)*ip);
+
+ if (gir && gir->city)
+ *city = safe_strdup(gir->city);
+
+ if (gir && gir->longitude != 0 && gir->longitude != 0)
+ safe_asprintf(coord, "%f,%f", gir->latitude, gir->longitude);
+
+ pGeoIP_delete(gi);
+ }
+ }
+
+ return;
+}
+
+void geo_ip_lookup(const char *ip, char **country, char **ccode, char **city, char **coord)
+{
+ struct in_addr ipv4;
+ struct in6_addr ipv6;
+ if (inet_pton(AF_INET, ip, &ipv4) == 1) {
+ geo_ipv4_lookup(ipv4, country, ccode, city, coord);
+ } else if (inet_pton(AF_INET6, ip, &ipv6) == 1) {
+ geo_ipv6_lookup(&ipv6, country, ccode, city, coord);
+ }
+ return;
+}
+
+#endif
diff --git a/ipcalc-maxmind.c b/ipcalc-maxmind.c
new file mode 100644
index 0000000..a2f8654
--- /dev/null
+++ b/ipcalc-maxmind.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Martin Sehnoutka <msehnout@redhat.com>
+ */
+
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include "ipcalc.h"
+
+#ifdef USE_MAXMIND
+#include <maxminddb.h>
+
+#ifndef MAXMINDDB_LOCATION_COUNTRY
+#define MAXMINDDB_LOCATION_COUNTRY "/usr/share/GeoIP/GeoLite2-Country.mmdb"
+#endif
+
+#ifndef MAXMINDDB_LOCATION_CITY
+#define MAXMINDDB_LOCATION_CITY "/usr/share/GeoIP/GeoLite2-City.mmdb"
+#endif
+
+#ifdef USE_RUNTIME_LINKING
+# include <dlfcn.h>
+# define LIBNAME LIBPATH"/libmaxminddb.so.0"
+
+typedef int (*MMDB_open_fn)
+ (const char *const filename,
+ uint32_t flags,
+ MMDB_s *const mmdb);
+typedef void (*MMDB_close_fn)
+ (MMDB_s *const mmdb);
+typedef MMDB_lookup_result_s (*MMDB_lookup_string_fn)
+ (MMDB_s *const mmdb,
+ const char *const ipstr,
+ int *const gai_error,
+ int *const mmdb_error);
+typedef int (*MMDB_get_value_fn)
+ (MMDB_entry_s *const start,
+ MMDB_entry_data_s *const entry_data,
+ ...);
+
+static MMDB_close_fn pMMDB_close;
+static MMDB_get_value_fn pMMDB_get_value;
+static MMDB_lookup_string_fn pMMDB_lookup_string;
+static MMDB_open_fn pMMDB_open;
+
+int geo_setup(void)
+{
+ static void *ld = NULL;
+ static int ret = 0;
+ static char err[256] = {0};
+
+ if (ld != NULL || ret != 0) {
+ if (!beSilent && err[0] != 0) {
+ fprintf(stderr, "%s", err);
+ }
+ return ret;
+ }
+
+ ld = dlopen(LIBNAME, RTLD_LAZY);
+ if (ld == NULL) {
+ snprintf(err, sizeof(err), "ipcalc: could not open %s\n", LIBNAME);
+ ret = -1;
+ goto exit;
+ }
+
+ pMMDB_close = dlsym(ld, "MMDB_close");
+ pMMDB_get_value = dlsym(ld, "MMDB_get_value");
+ pMMDB_lookup_string = dlsym(ld, "MMDB_lookup_string");
+ pMMDB_open = dlsym(ld, "MMDB_open");
+
+ if(pMMDB_close == NULL ||
+ pMMDB_get_value == NULL ||
+ pMMDB_lookup_string == NULL ||
+ pMMDB_open == NULL) {
+ snprintf(err, sizeof(err), "ipcalc: could not find symbols in libmaxmind\n");
+ ret = -1;
+ goto exit;
+ }
+
+ ret = 0;
+ exit:
+ return ret;
+}
+
+#else
+#define pMMDB_close MMDB_close
+#define pMMDB_get_value MMDB_get_value
+#define pMMDB_lookup_string MMDB_lookup_string
+#define pMMDB_open MMDB_open
+#endif
+
+void process_result_from_mmdb_lookup(MMDB_entry_data_s *entry_data, int status, char **output)
+{
+ if (MMDB_SUCCESS == status) {
+ if (entry_data->has_data) {
+ if (entry_data->type == MMDB_DATA_TYPE_UTF8_STRING) {
+ *output = (char *) calloc(entry_data->data_size + 1, sizeof(char));
+ if (NULL != *output) {
+ memcpy(*output, entry_data->utf8_string, entry_data->data_size);
+ } else {
+ fprintf(stderr, "Memory allocation failure line %d\n", __LINE__);
+ }
+ }
+ }
+ }
+ /* Else fail silently */
+}
+
+void geo_ip_lookup(const char *ip, char **country, char **ccode, char **city, char **coord)
+{
+ MMDB_s mmdb;
+ MMDB_entry_data_s entry_data;
+ int gai_error, mmdb_error, status, coordinates=0;
+ double latitude = 0, longitude = 0;
+
+ if (geo_setup() != 0)
+ return;
+
+ /* Open the system maxmind database with countries */
+ status = pMMDB_open(MAXMINDDB_LOCATION_COUNTRY, MMDB_MODE_MMAP, &mmdb);
+ if (MMDB_SUCCESS == status) {
+ /* Lookup IP address in the database */
+ MMDB_lookup_result_s result = pMMDB_lookup_string(&mmdb, ip, &gai_error, &mmdb_error);
+ if (MMDB_SUCCESS == mmdb_error) {
+ /* If the lookup was successfull and an entry was found */
+ if (result.found_entry) {
+ memset(&entry_data, 0, sizeof(MMDB_entry_data_s));
+ /* Travel the path in the tree like structure of the MMDB and store the value if found */
+ status = pMMDB_get_value(&result.entry, &entry_data, "country", "names", "en", NULL);
+ process_result_from_mmdb_lookup(&entry_data, status, country);
+ memset(&entry_data, 0, sizeof(MMDB_entry_data_s));
+ status = pMMDB_get_value(&result.entry, &entry_data, "country", "iso_code", NULL);
+ process_result_from_mmdb_lookup(&entry_data, status, ccode);
+ }
+ }
+ /* Else fail silently */
+ pMMDB_close(&mmdb);
+ }
+ /* Else fail silently */
+
+ /* Open the system maxmind database with cities - which actually does not contain names of the cities */
+ status = pMMDB_open(MAXMINDDB_LOCATION_CITY, MMDB_MODE_MMAP, &mmdb);
+ if (MMDB_SUCCESS == status) {
+ /* Lookup IP address in the database */
+ MMDB_lookup_result_s result = pMMDB_lookup_string(&mmdb, ip, &gai_error, &mmdb_error);
+ if (MMDB_SUCCESS == mmdb_error) {
+ /* If the lookup was successfull and an entry was found */
+ if (result.found_entry) {
+ memset(&entry_data, 0, sizeof(MMDB_entry_data_s));
+ // NOTE: Information about the city is not available in the free database, so there is not way
+ // for me to implement this functionality right now, but it should be easy to add for anyone with
+ // access to the paid databases.
+ status = pMMDB_get_value(&result.entry, &entry_data, "location", "latitude", NULL);
+ if (MMDB_SUCCESS == status) {
+ if (entry_data.has_data) {
+ if (entry_data.type == MMDB_DATA_TYPE_DOUBLE) {
+ latitude = entry_data.double_value;
+ ++coordinates;
+ }
+ }
+ }
+ status = pMMDB_get_value(&result.entry, &entry_data, "location", "longitude", NULL);
+ if (MMDB_SUCCESS == status) {
+ if (entry_data.has_data) {
+ if (entry_data.type == MMDB_DATA_TYPE_DOUBLE) {
+ longitude = entry_data.double_value;
+ ++coordinates;
+ }
+ }
+ }
+ if (coordinates == 2) {
+ safe_asprintf(coord, "%f,%f", latitude, longitude);
+ }
+ }
+ }
+ /* Else fail silently */
+ pMMDB_close(&mmdb);
+ }
+ /* Else fail silently */
+}
+
+#endif
diff --git a/ipcalc-reverse.c b/ipcalc-reverse.c
new file mode 100644
index 0000000..3863ef6
--- /dev/null
+++ b/ipcalc-reverse.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Nikos Mavrogiannopoulos <nmav@redhat.com>
+ */
+
+#define _GNU_SOURCE /* asprintf */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include "ipcalc.h"
+
+/* draft-ietf-dnsop-rfc2317bis-00 replaces that legacy style
+ */
+#undef USE_RFC2317_STYLE
+
+char *calc_reverse_dns4(struct in_addr ip, unsigned prefix, struct in_addr network, struct in_addr broadcast)
+{
+ char *str = NULL;
+ int ret = -1;
+
+ unsigned byte1 = (ntohl(ip.s_addr) >> 24) & 0xff;
+ unsigned byte2 = (ntohl(ip.s_addr) >> 16) & 0xff;
+ unsigned byte3 = (ntohl(ip.s_addr) >> 8) & 0xff;
+ unsigned byte4 = (ntohl(ip.s_addr)) & 0xff;
+
+#ifdef USE_RFC2317_STYLE
+ if (prefix == 32) {
+ ret = asprintf(&str, "%u.%u.%u.%u.in-addr.arpa.", byte4, byte3, byte2, byte1);
+ } else if (prefix == 24) {
+ ret = asprintf(&str, "%u.%u.%u.in-addr.arpa.", byte3, byte2, byte1);
+ } else if (prefix == 16) {
+ ret = asprintf(&str, "%u.%u.in-addr.arpa.", byte2, byte1);
+ } else if (prefix == 8) {
+ ret = asprintf(&str, "%u.in-addr.arpa.", byte1);
+ } else if (prefix > 24) {
+ ret = asprintf(&str, "%u/%u.%u.%u.%u.in-addr.arpa.", byte4, prefix, byte3, byte2, byte1);
+ } else if (prefix > 16) {
+ ret = asprintf(&str, "%u/%u.%u.%u.in-addr.arpa.", byte3, prefix, byte2, byte1);
+ } else if (prefix > 8) {
+ ret = asprintf(&str, "%u/%u.%u.in-addr.arpa.", byte2, prefix, byte1);
+ }
+#else
+ if (prefix == 32) {
+ ret = asprintf(&str, "%u.%u.%u.%u.in-addr.arpa.", byte4, byte3, byte2, byte1);
+ } else if (prefix == 24) {
+ ret = asprintf(&str, "%u.%u.%u.in-addr.arpa.", byte3, byte2, byte1);
+ } else if (prefix == 16) {
+ ret = asprintf(&str, "%u.%u.in-addr.arpa.", byte2, byte1);
+ } else if (prefix == 8) {
+ ret = asprintf(&str, "%u.in-addr.arpa.", byte1);
+ } else if (prefix > 24) {
+ unsigned min = (ntohl(network.s_addr)) & 0xff;
+ unsigned max = (ntohl(broadcast.s_addr)) & 0xff;
+ ret = asprintf(&str, "%u-%u.%u.%u.%u.in-addr.arpa.", min, max, byte3, byte2, byte1);
+ } else if (prefix > 16) {
+ unsigned min = (ntohl(network.s_addr) >> 8) & 0xff;
+ unsigned max = (ntohl(broadcast.s_addr) >> 8) & 0xff;
+ ret = asprintf(&str, "%u-%u.%u.%u.in-addr.arpa.", min, max, byte2, byte1);
+ } else if (prefix > 8) {
+ unsigned min = (ntohl(network.s_addr) >> 16) & 0xff;
+ unsigned max = (ntohl(broadcast.s_addr) >> 16) & 0xff;
+ ret = asprintf(&str, "%u-%u.%u.in-addr.arpa.", min, max, byte1);
+ }
+#endif
+
+ if (ret == -1)
+ return NULL;
+ return str;
+}
+
+static char hexchar(unsigned int val)
+{
+ if (val < 10)
+ return '0' + val;
+ if (val < 16)
+ return 'a' + val - 10;
+ abort();
+}
+
+char *calc_reverse_dns6(struct in6_addr *ip, unsigned prefix)
+{
+ unsigned i, j = 0;
+ char str[256];
+ unsigned max = prefix/8;
+
+ if (prefix % 4 != 0)
+ return NULL;
+
+ if (prefix % 8 == 4) {
+ str[j++] = hexchar(ip->s6_addr[(prefix+4)/8-1] >> 4);
+ str[j++] = '.';
+ }
+
+ for (i=0;i<max;i++) {
+ str[j++] = hexchar(ip->s6_addr[max-1-i] & 0xf);
+ str[j++] = '.';
+
+ str[j++] = hexchar(ip->s6_addr[max-1-i] >> 4);
+ str[j++] = '.';
+
+ }
+
+ strcpy(&str[j], "ip6.arpa.");
+
+ return strdup(str);
+}
diff --git a/ipcalc-utils.c b/ipcalc-utils.c
new file mode 100644
index 0000000..026e069
--- /dev/null
+++ b/ipcalc-utils.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Martin Sehnoutka <msehnout@redhat.com>
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+int __attribute__((__format__(printf, 2, 3))) safe_asprintf(char **strp, const char *fmt, ...)
+{
+ int ret;
+ va_list args;
+
+ va_start(args, fmt);
+ ret = vasprintf(&(*strp), fmt, args);
+ va_end(args);
+ if (ret < 0) {
+ fprintf(stderr, "Memory allocation failure\n");
+ exit(1);
+ }
+ return ret;
+}
+
+int safe_atoi(const char *s, int *ret_i)
+{
+ char *x = NULL;
+ long l;
+
+ errno = 0;
+ l = strtol(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno > 0 ? -errno : -EINVAL;
+
+ if ((long)(int)l != l)
+ return -ERANGE;
+
+ *ret_i = (int)l;
+ return 0;
+}
+
+/*!
+ \fn char safe_strdup(const char *s)
+ \brief strdup(3) that checks memory allocation or fail
+
+ This function does the same as strdup(3) with additional memory allocation
+ check. When check fails the function will cause program to exit.
+
+ \param string to be duplicated
+ \return allocated duplicate
+*/
+extern char __attribute__((warn_unused_result)) *safe_strdup(const char *str)
+{
+ char *ret;
+
+ if (!str)
+ return NULL;
+
+ ret = strdup(str);
+ if (!ret) {
+ fprintf(stderr, "Memory allocation failure\n");
+ exit(1);
+ }
+ return ret;
+}
diff --git a/ipcalc.1.md b/ipcalc.1.md
new file mode 100644
index 0000000..481c317
--- /dev/null
+++ b/ipcalc.1.md
@@ -0,0 +1,237 @@
+# ipcalc(1) - Perform simple operations on IP addresses and networks
+
+## SYNOPSIS
+**ipcalc** [OPTION]... <IP address>[/prefix] [netmask]
+
+
+## Description
+
+**ipcalc** provides a simple way to calculate IP information for a host
+or network. Depending on the options specified, it may be used to provide
+IP network information in human readable format, in a format suitable for
+parsing in scripts, generate random private addresses, resolve an IP address,
+or check the validity of an address.
+
+By default or when the **--info** or **--all-info** parameters
+are specified the information provided is free form and human readable.
+Otherwise the output is JSON formatted when **-j** is specified,
+or when specific options are given (e.g., **--prefix**) the output is
+in the **VAR=VALUE** format.
+
+The various options specify what information **ipcalc** should display
+on standard output. Multiple options may be specified. It is required
+to specify an IP address; several operations require
+a netmask or a CIDR prefix as well.
+
+
+## Options
+
+* **-c**, **--check**
+ Validate the IP address under the specified family.
+
+* **-i**, **--info**
+ Display generic information on the provided network in human readable format.
+ This is the default option if no other options are provided.
+
+* **--all-info**
+ Display verbose information on the provided network and addresses in human
+ readable format. That includes GeoIP information.
+
+* **-S**, **--split**
+ Split the provided network using the specified prefix or netmask. That is,
+ split up the network into smaller chunks of a specified prefix. When
+ combined with no-decorate mode (**--no-decorate**), the split networks
+ will be printed in raw form. Example "ipcalc -S 26 192.168.1.0/24".
+
+* **-d**, **--deaggregate**
+ Deaggregates the provided address range. That is, print the networks that
+ cover the range. The range is given using the '-' separator, e.g.,
+ "192.168.1.3-192.168.1.23". When combined with no-decorate mode
+ (**--no-decorate**), the networks are printed in raw form.
+
+* **-r**, **--random-private**
+ Generate a random private address using the supplied prefix or mask. By default
+ it displays output in human readable format, but may be combined with
+ other options (e.g., **--network**) to display specific information in
+ **VAR=VALUE** format.
+
+* **-h**, **--hostname**
+ Display the hostname for the given IP address.
+ The variable exposed is HOSTNAME.
+
+* **-o**, **--lookup-host**
+ Display the IP address for the given hostname.
+ The variable exposed is ADDRESS.
+
+* **-4**, **--ipv4**
+ Explicitly specify the IPv4 address family.
+
+* **-6**, **--ipv6**
+ Explicitly specify the IPv6 address family.
+
+* **-b**, **--broadcast**
+ Display the broadcast address for the given IP address and netmask.
+ The variable exposed is BROADCAST (if available).
+
+* **-a**, **--address**
+ Display the IP address for the given input.
+ The variable exposed is ADDRESS (if available).
+
+* **-g**, **--geoinfo**
+ Display geographic information for the given IP address. This option
+ requires libGeoIP/libmaxminddb to be available. The variables exposed are
+ COUNTRYCODE, COUNTRY, CITY and COORDINATES (when available).
+
+* **-m**, **--netmask**
+ Calculate the netmask for the given IP address. If no mask or prefix
+ is provided, in IPv6 a 128-bit mask is assumed, while in IPv4 it assumes
+ that the IP address is in a complete class A, B, or C network. Note,
+ however, that many networks no longer use the default netmasks in IPv4.
+ The variable exposed is NETMASK.
+
+* **-p**, **--prefix**
+ Show the prefix for the given mask/IP address.
+ The variable exposed is PREFIX.
+
+* **--class-prefix**
+ Assign the netmask of the provided IPv4 address based on the address
+ class. This was the default in previous versions of this software.
+
+* **-n**, **--network**
+ Display the network address for the given IP address and netmask.
+ The variable exposed is NETWORK.
+
+* **--reverse-dns**
+ Display the reverse DNS for the given IP address and netmask.
+ The variable exposed is REVERSEDNS.
+
+* **--minaddr**
+ Display the minimum host address in the provided network.
+ The variable exposed is MINADDR.
+
+* **--maxaddr**
+ Display the maximum host address in the provided network.
+ The variable exposed is MAXADDR.
+
+* **--addresses**
+ Display the number of host addresses in the provided network.
+ The variable exposed is ADDRESSES.
+
+* **--addrspace**
+ Display address space allocation information for the provided network.
+ The variable exposed is ADDRSPACE.
+
+* **--no-decorate**
+ Print only the requested information. That when combined with
+ split networks option, will only print the networks without any
+ additions for readability.
+
+* **-j**, **--json**
+ When used with -i or -S, print the info as a JSON object
+ instead of the usual output format.
+
+* **-s**, **--silent**
+ Don't ever display error messages.
+
+
+## Examples
+
+### Display all information of an IPv4
+
+ $ ipcalc --all-info 193.92.150.2/24
+ Address: 193.92.150.2
+ Network: 193.92.150.0/24
+ Netmask: 255.255.255.0 = 24
+ Broadcast: 193.92.150.255
+ Reverse DNS: 150.92.193.in-addr.arpa.
+
+ Address space: Internet
+ Address class: Class C
+ HostMin: 193.92.150.1
+ HostMax: 193.92.150.254
+ Hosts/Net: 254
+
+ Country code: GR
+ Country: Greece
+
+### Display information in key-value format
+
+ $ ipcalc -pnmb --minaddr --maxaddr --geoinfo --addrspace 193.92.150.2/255.255.255.224
+ NETMASK=255.255.255.224
+ PREFIX=27
+ BROADCAST=193.92.150.31
+ NETWORK=193.92.150.0
+ MINADDR=193.92.150.1
+ MAXADDR=193.92.150.30
+ ADDRSPACE="Internet"
+ COUNTRY="Greece"
+
+### Display all information of an IPv6
+
+ $ ipcalc --all-info 2a03:2880:20:4f06:face:b00c:0:14/64
+ Full Address: 2a03:2880:0020:4f06:face:b00c:0000:0014
+ Address: 2a03:2880:20:4f06:face:b00c:0:14
+ Full Network: 2a03:2880:0020:4f06:0000:0000:0000:0000/64
+ Network: 2a03:2880:20:4f06::/64
+ Netmask: ffff:ffff:ffff:ffff:: = 64
+ Reverse DNS: 6.0.f.4.0.2.0.0.0.8.8.2.3.0.a.2.ip6.arpa.
+
+ Address space: Global Unicast
+ HostMin: 2a03:2880:20:4f06::
+ HostMax: 2a03:2880:20:4f06:ffff:ffff:ffff:ffff
+ Hosts/Net: 2^(64) = 18446744073709551616
+
+ Country code: IE
+ Country: Ireland
+
+### Display JSON output
+
+ $ ipcalc --all-info -j 2a03:2880:20:4f06:face:b00c:0:14/64
+ {
+ "FULLADDRESS":"2a03:2880:0020:4f06:face:b00c:0000:0014",
+ "ADDRESS":"2a03:2880:20:4f06:face:b00c:0:14",
+ "FULLNETWORK":"2a03:2880:0020:4f06:0000:0000:0000:0000",
+ "NETWORK":"2a03:2880:20:4f06::",
+ "NETMASK":"ffff:ffff:ffff:ffff::",
+ "PREFIX":"64",
+ "REVERSEDNS":"6.0.f.4.0.2.0.0.0.8.8.2.3.0.a.2.ip6.arpa.",
+ "ADDRSPACE":"Global Unicast",
+ "MINADDR":"2a03:2880:20:4f06::",
+ "MAXADDR":"2a03:2880:20:4f06:ffff:ffff:ffff:ffff",
+ "ADDRESSES":"18446744073709551616",
+ "COUNTRYCODE":"IE",
+ "COUNTRY":"Ireland",
+ "COORDINATES":"53.000000,-8.000000"
+ }
+
+### Lookup of a hostname
+
+ $ ipcalc --lookup-host localhost --no-decorate
+ ::1
+
+### IPv4 lookup of a hostname
+
+ $ ipcalc --lookup-host localhost --no-decorate -4
+ 127.0.0.1
+
+### Reverse lookup of a hostname
+
+ $ ipcalc -h 127.0.0.1 --no-decorate
+ localhost
+
+## Authors
+* Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
+* Erik Troan <ewt@redhat.com>
+* Preston Brown <pbrown@redhat.com>
+* David Cantrell <dcantrell@redhat.com>
+
+## Reporting Bugs
+
+Report bugs at https://gitlab.com/ipcalc/ipcalc/issues
+
+## Copyright
+
+Copyright © 1997-2020 Red Hat, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.
diff --git a/ipcalc.c b/ipcalc.c
new file mode 100644
index 0000000..b3d2c60
--- /dev/null
+++ b/ipcalc.c
@@ -0,0 +1,1990 @@
+/*
+ * Copyright (c) 1997-2015 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Nikos Mavrogiannopoulos <nmav@redhat.com>
+ * Erik Troan <ewt@redhat.com>
+ * Preston Brown <pbrown@redhat.com>
+ * David Cantrell <dcantrell@redhat.com>
+ */
+
+#define _GNU_SOURCE /* asprintf */
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h> /* open */
+#include <fcntl.h> /* open */
+#include <unistd.h> /* read */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <time.h> /* clock_gettime */
+#include "ipcalc.h"
+
+int beSilent = 0;
+static unsigned colors = 0;
+static unsigned flags = 0;
+
+/*!
+ \file ipcalc.c
+ \brief provides utilities for manipulating IP addresses.
+
+ ipcalc provides utilities and a front-end command line interface for
+ manipulating IP addresses, and calculating various aspects of an ip
+ address/netmask/network address/prefix/etc.
+
+ Functionality can be accessed from other languages from the library
+ interface, documented here. To use ipcalc from the shell, read the
+ ipcalc(1) manual page.
+
+ When passing parameters to the various functions, take note of whether they
+ take host byte order or network byte order. Most take host byte order, and
+ return host byte order, but there are some exceptions.
+*/
+
+/*!
+ \fn uint32_t prefix2mask(int bits)
+ \brief creates a netmask from a specified number of bits
+
+ This function converts a prefix length to a netmask. As CIDR (classless
+ internet domain internet domain routing) has taken off, more an more IP
+ addresses are being specified in the format address/prefix
+ (i.e. 192.168.2.3/24, with a corresponding netmask 255.255.255.0). If you
+ need to see what netmask corresponds to the prefix part of the address, this
+ is the function. See also \ref mask2prefix.
+
+ \param prefix is the number of bits to create a mask for.
+ \return a network mask, in network byte order.
+*/
+uint32_t prefix2mask(int prefix)
+{
+ struct in_addr mask;
+ memset(&mask, 0, sizeof(mask));
+ if (prefix) {
+ return htonl(~((1 << (32 - prefix)) - 1));
+ } else {
+ return htonl(0);
+ }
+}
+
+/*!
+ \fn struct in_addr calc_broadcast(struct in_addr addr, int prefix)
+
+ \brief calculate broadcast address given an IP address and a prefix length.
+
+ \param addr an IP address in network byte order.
+ \param prefix a prefix length.
+
+ \return the calculated broadcast address for the network, in network byte
+ order.
+*/
+static struct in_addr calc_broadcast(struct in_addr addr, int prefix)
+{
+ struct in_addr mask;
+ struct in_addr broadcast;
+
+ mask.s_addr = prefix2mask(prefix);
+
+ memset(&broadcast, 0, sizeof(broadcast));
+
+ /* Follow RFC3021 and set the limited broadcast address on /31 */
+ if (prefix == 31)
+ broadcast.s_addr = htonl(0xFFFFFFFF);
+ else
+ broadcast.s_addr = (addr.s_addr & mask.s_addr) | ~mask.s_addr;
+
+ return broadcast;
+}
+
+/*!
+ \fn struct in_addr calc_network(struct in_addr addr, int prefix)
+ \brief calculates the network address for a specified address and prefix.
+
+ \param addr an IP address, in network byte order
+ \param prefix the network prefix
+ \return the base address of the network that addr is associated with, in
+ network byte order.
+*/
+struct in_addr calc_network(struct in_addr addr, int prefix)
+{
+ struct in_addr mask;
+ struct in_addr network;
+
+ mask.s_addr = prefix2mask(prefix);
+
+ memset(&network, 0, sizeof(network));
+ network.s_addr = addr.s_addr & mask.s_addr;
+ return network;
+}
+
+/*!
+ \fn const char *get_hostname(int family, void *addr)
+ \brief returns the hostname associated with the specified IP address
+
+ \param family the address family, either AF_INET or AF_INET6.
+ \param addr an IP address to find a hostname for, in network byte order,
+ should either be a pointer to a struct in_addr or a struct in6_addr.
+
+ \return a hostname, or NULL if one cannot be determined. Hostname is stored
+ in an allocated buffer.
+*/
+static char *get_hostname(int family, void *addr)
+{
+ static char hostname[NI_MAXHOST];
+ int ret = -1;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (family == AF_INET) {
+ memset(&addr4, 0, sizeof(addr4));
+ addr4.sin_family = AF_INET;
+ memcpy(&addr4.sin_addr, addr, sizeof(struct in_addr));
+ ret = getnameinfo((struct sockaddr*)&addr4, sizeof(addr4), hostname, sizeof(hostname), NULL, 0, 0);
+ } else if (family == AF_INET6) {
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ memcpy(&addr6.sin6_addr, addr, sizeof(struct in6_addr));
+ ret = getnameinfo((struct sockaddr*)&addr6, sizeof(addr6), hostname, sizeof(hostname), NULL, 0, 0);
+ }
+
+ if (ret != 0)
+ return NULL;
+
+ return safe_strdup(hostname);
+}
+
+/*!
+ \fn const char *get_ip_address(int family, void *addr)
+ \brief returns the IP address associated with the specified hostname
+
+ \param family the requested address family or AF_UNSPEC for any
+ \param host a hostname
+
+ \return an IP address, or NULL if one cannot be determined. The IP is stored
+ in an allocated buffer.
+*/
+static char *get_ip_address(int family, const char *host)
+{
+ struct addrinfo *res, *rp;
+ struct addrinfo hints;
+ int err;
+ static char ipname[64];
+ void *addr;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+
+ err = getaddrinfo(host, NULL, &hints, &res);
+ if (err != 0)
+ return NULL;
+
+ for (rp=res;rp!=NULL;rp=rp->ai_next) {
+ if (rp->ai_family == AF_INET)
+ addr = (&((struct sockaddr_in *)(rp->ai_addr))->sin_addr);
+ else
+ addr = (&((struct sockaddr_in6 *)(rp->ai_addr))->sin6_addr);
+
+ if (inet_ntop(rp->ai_family, addr, ipname, sizeof(ipname)) != NULL) {
+ freeaddrinfo(res);
+ return safe_strdup(ipname);
+ }
+ }
+
+ freeaddrinfo(res);
+ return NULL;
+}
+
+static int bit_count(uint32_t i)
+{
+ int c = 0;
+
+ while (i > 0) {
+ if (i & 1)
+ c++;
+ i >>= 1;
+ }
+
+ return c;
+}
+
+/*!
+ \fn int mask2prefix(struct in_addr mask)
+ \brief calculates the number of bits masked off by a netmask.
+
+ This function calculates the significant bits in an IP address as specified by
+ a netmask. See also \ref prefix2mask.
+
+ \param mask is the netmask, specified as an struct in_addr in network byte order.
+ \return the number of significant bits. */
+static int mask2prefix(struct in_addr mask)
+{
+ int c = 0;
+ unsigned int seen_one = 0;
+ uint32_t i = ntohl(mask.s_addr);
+
+ while (i > 0) {
+ if (i & 1) {
+ seen_one = 1;
+ c++;
+ } else {
+ if (seen_one) {
+ return -1;
+ }
+ }
+ i >>= 1;
+ }
+
+ return c;
+}
+
+static
+int ipv4_mask_to_int(const char *prefix)
+{
+ int ret;
+ struct in_addr in;
+
+ ret = inet_pton(AF_INET, prefix, &in);
+ if (ret == 0)
+ return -1;
+
+ return mask2prefix(in);
+}
+
+/* Returns powers of two in textual format */
+static const char *p2_table(unsigned pow)
+{
+ static const char *pow2[] = {
+ "1",
+ "2",
+ "4",
+ "8",
+ "16",
+ "32",
+ "64",
+ "128",
+ "256",
+ "512",
+ "1024",
+ "2048",
+ "4096",
+ "8192",
+ "16384",
+ "32768",
+ "65536",
+ "131072",
+ "262144",
+ "524288",
+ "1048576",
+ "2097152",
+ "4194304",
+ "8388608",
+ "16777216",
+ "33554432",
+ "67108864",
+ "134217728",
+ "268435456",
+ "536870912",
+ "1073741824",
+ "2147483648",
+ "4294967296",
+ "8589934592",
+ "17179869184",
+ "34359738368",
+ "68719476736",
+ "137438953472",
+ "274877906944",
+ "549755813888",
+ "1099511627776",
+ "2199023255552",
+ "4398046511104",
+ "8796093022208",
+ "17592186044416",
+ "35184372088832",
+ "70368744177664",
+ "140737488355328",
+ "281474976710656",
+ "562949953421312",
+ "1125899906842624",
+ "2251799813685248",
+ "4503599627370496",
+ "9007199254740992",
+ "18014398509481984",
+ "36028797018963968",
+ "72057594037927936",
+ "144115188075855872",
+ "288230376151711744",
+ "576460752303423488",
+ "1152921504606846976",
+ "2305843009213693952",
+ "4611686018427387904",
+ "9223372036854775808",
+ "18446744073709551616",
+ "36893488147419103232",
+ "73786976294838206464",
+ "147573952589676412928",
+ "295147905179352825856",
+ "590295810358705651712",
+ "1180591620717411303424",
+ "2361183241434822606848",
+ "4722366482869645213696",
+ "9444732965739290427392",
+ "18889465931478580854784",
+ "37778931862957161709568",
+ "75557863725914323419136",
+ "151115727451828646838272",
+ "302231454903657293676544",
+ "604462909807314587353088",
+ "1208925819614629174706176",
+ "2417851639229258349412352",
+ "4835703278458516698824704",
+ "9671406556917033397649408",
+ "19342813113834066795298816",
+ "38685626227668133590597632",
+ "77371252455336267181195264",
+ "154742504910672534362390528",
+ "309485009821345068724781056",
+ "618970019642690137449562112",
+ "1237940039285380274899124224",
+ "2475880078570760549798248448",
+ "4951760157141521099596496896",
+ "9903520314283042199192993792",
+ "19807040628566084398385987584",
+ "39614081257132168796771975168",
+ "79228162514264337593543950336",
+ "158456325028528675187087900672",
+ "316912650057057350374175801344",
+ "633825300114114700748351602688",
+ "1267650600228229401496703205376",
+ "2535301200456458802993406410752",
+ "5070602400912917605986812821504",
+ "10141204801825835211973625643008",
+ "20282409603651670423947251286016",
+ "40564819207303340847894502572032",
+ "81129638414606681695789005144064",
+ "162259276829213363391578010288128",
+ "324518553658426726783156020576256",
+ "649037107316853453566312041152512",
+ "1298074214633706907132624082305024",
+ "2596148429267413814265248164610048",
+ "5192296858534827628530496329220096",
+ "10384593717069655257060992658440192",
+ "20769187434139310514121985316880384",
+ "41538374868278621028243970633760768",
+ "83076749736557242056487941267521536",
+ "166153499473114484112975882535043072",
+ "332306998946228968225951765070086144",
+ "664613997892457936451903530140172288",
+ "1329227995784915872903807060280344576",
+ "2658455991569831745807614120560689152",
+ "5316911983139663491615228241121378304",
+ "10633823966279326983230456482242756608",
+ "21267647932558653966460912964485513216",
+ "42535295865117307932921825928971026432",
+ "85070591730234615865843651857942052864",
+ "170141183460469231731687303715884105728",
+ };
+ if (pow <= 127)
+ return pow2[pow];
+ return "";
+}
+
+static const char *ipv4_net_to_type(struct in_addr net)
+{
+ unsigned byte1 = (ntohl(net.s_addr) >> 24) & 0xff;
+ unsigned byte2 = (ntohl(net.s_addr) >> 16) & 0xff;
+ unsigned byte3 = (ntohl(net.s_addr) >> 8) & 0xff;
+ unsigned byte4 = (ntohl(net.s_addr)) & 0xff;
+
+ /* based on IANA's iana-ipv4-special-registry and ipv4-address-space
+ * Updated: 2020-04-06
+ */
+ if (byte1 == 0) {
+ return "This host on this network";
+ }
+
+ if (byte1 == 10) {
+ return "Private Use";
+ }
+
+ if (byte1 == 100 && (byte2 & 0xc0) == 64) {
+ return "Shared Address Space";
+ }
+
+ if (byte1 == 127) {
+ return "Loopback";
+ }
+
+ if (byte1 == 169 && byte2 == 254) {
+ return "Link Local";
+ }
+
+ if (byte1 == 172 && (byte2 & 0xf0) == 16) {
+ return "Private Use";
+ }
+
+ if (byte1 == 192 && byte2 == 0 && byte3 == 0 && byte4 <= 7) {
+ return "IPv4 Service Continuity Prefix";
+ }
+
+ if (byte1 == 192 && byte2 == 0 && byte3 == 0 && byte4 == 8) {
+ return "IPv4 dummy address";
+ }
+
+ if (byte1 == 192 && byte2 == 0 && byte3 == 0 && byte4 == 9) {
+ return "Port Control Protocol Anycast";
+ }
+
+ if (byte1 == 192 && byte2 == 0 && byte3 == 0 && byte4 == 10) {
+ return "Traversal Using Relays around NAT Anycast";
+ }
+
+ if (byte1 == 192 && byte2 == 0 && byte3 == 0 && (byte4 == 170 || byte4 == 171)) {
+ return "NAT64/DNS64 Discovery";
+ }
+
+ if (byte1 == 192 && byte2 == 0 && byte3 == 0) {
+ return "IETF Protocol Assignments";
+ }
+
+ if (byte1 == 192 && byte2 == 0 && byte3 == 2) {
+ return "Documentation (TEST-NET-1)";
+ }
+
+ if (byte1 == 198 && byte2 == 51 && byte3 == 100) {
+ return "Documentation (TEST-NET-2)";
+ }
+
+ if (byte1 == 203 && byte2 == 0 && byte3 == 113) {
+ return "Documentation (TEST-NET-3)";
+ }
+
+ if (byte1 == 192 && byte2 == 88 && byte3 == 99) {
+ return "6 to 4 Relay Anycast (Deprecated)";
+ }
+
+ if (byte1 == 192 && byte2 == 31 && byte3 == 196) {
+ return "AS112-v4";
+ }
+
+ if (byte1 == 192 && byte2 == 52 && byte3 == 193) {
+ return "AMT";
+ }
+
+ if (byte1 == 192 && byte2 == 168) {
+ return "Private Use";
+ }
+
+ if (byte1 == 192 && byte2 == 175 && byte3 == 48) {
+ return "Direct Delegation AS112 Service";
+ }
+
+ if (byte1 == 255 && byte2 == 255 && byte3 == 255 && byte4 == 255) {
+ return "Limited Broadcast";
+ }
+
+ if (byte1 == 198 && (byte2 & 0xfe) == 18) {
+ return "Benchmarking";
+ }
+
+ if (byte1 >= 224 && byte1 <= 239) {
+ return "Multicast";
+ }
+
+ if ((byte1 & 0xf0) == 240) {
+ return "Reserved";
+ }
+
+ return "Internet";
+}
+
+static
+const char *ipv4_net_to_class(struct in_addr net)
+{
+ unsigned byte1 = (ntohl(net.s_addr) >> 24) & 0xff;
+
+ if (byte1 < 128) {
+ return "Class A";
+ }
+
+ if (byte1 >= 128 && byte1 < 192) {
+ return "Class B";
+ }
+
+ if (byte1 >= 192 && byte1 < 224) {
+ return "Class C";
+ }
+
+ if (byte1 >= 224 && byte1 < 239) {
+ return "Class D";
+ }
+
+ return "Class E";
+}
+
+static
+unsigned default_ipv4_prefix(struct in_addr net)
+{
+ unsigned byte1 = (ntohl(net.s_addr) >> 24) & 0xff;
+
+ if (byte1 < 128) {
+ return 8;
+ }
+
+ if (byte1 >= 128 && byte1 < 192) {
+ return 16;
+ }
+
+ if (byte1 >= 192 && byte1 < 224) {
+ return 24;
+ }
+
+ return 24;
+}
+
+char *ipv4_prefix_to_hosts(char *hosts, unsigned hosts_size, unsigned prefix)
+{
+ if (prefix >= 31) {
+ snprintf(hosts, hosts_size, "%s", p2_table(32 - prefix));
+ } else {
+ unsigned tmp = (1 << (32 - prefix)) - 2;
+ snprintf(hosts, hosts_size, "%u", tmp);
+ }
+ return hosts;
+}
+
+char *ipv6_prefix_to_hosts(char *hosts, unsigned hosts_size, unsigned prefix)
+{
+ snprintf(hosts, hosts_size, "%s", p2_table(128 - prefix));
+ return hosts;
+}
+
+
+static
+int get_ipv4_info(const char *ipStr, int prefix, ip_info_st * info,
+ unsigned flags)
+{
+ struct in_addr ip, netmask, network, broadcast, minhost, maxhost;
+ char namebuf[INET_ADDRSTRLEN + 1];
+ char errBuf[250];
+
+ memset(info, 0, sizeof(*info));
+
+ if (inet_pton(AF_INET, ipStr, &ip) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv4 address: %s\n",
+ ipStr);
+ return -1;
+ }
+
+ /* Handle CIDR entries such as 172/8 */
+ if (prefix >= 0) {
+ char *tmp = (char *)ipStr;
+ int i;
+
+ for (i = 3; i > 0; i--) {
+ tmp = strchr(tmp, '.');
+ if (!tmp)
+ break;
+ else
+ tmp++;
+ }
+
+ tmp = NULL;
+ for (; i > 0; i--) {
+ if (asprintf(&tmp, "%s.0", ipStr) == -1) {
+ fprintf(stderr,
+ "Memory allocation failure line %d\n",
+ __LINE__);
+ abort();
+ }
+ ipStr = tmp;
+ }
+ } else { /* assume good old days classful Internet */
+ if (flags & FLAG_ASSUME_CLASS_PREFIX)
+ prefix = default_ipv4_prefix(ip);
+ else
+ prefix = 32;
+ }
+
+ if (prefix > 32) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv4 prefix %d\n", prefix);
+ return -1;
+ }
+
+ if (inet_ntop(AF_INET, &ip, namebuf, sizeof(namebuf)) == 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: error calculating the IPv4 network\n");
+ return -1;
+ }
+ info->ip = safe_strdup(namebuf);
+
+ netmask.s_addr = prefix2mask(prefix);
+ memset(namebuf, '\0', sizeof(namebuf));
+
+ if (inet_ntop(AF_INET, &netmask, namebuf, INET_ADDRSTRLEN) == NULL) {
+ fprintf(stderr, "inet_ntop failure at line %d\n",
+ __LINE__);
+ exit(1);
+ }
+ info->netmask = safe_strdup(namebuf);
+ info->prefix = prefix;
+
+ broadcast = calc_broadcast(ip, prefix);
+
+ memset(namebuf, '\0', sizeof(namebuf));
+ if (inet_ntop(AF_INET, &broadcast, namebuf, INET_ADDRSTRLEN) == NULL) {
+ fprintf(stderr, "inet_ntop failure at line %d\n",
+ __LINE__);
+ exit(1);
+ }
+ info->broadcast = safe_strdup(namebuf);
+
+ network = calc_network(ip, prefix);
+
+ info->reverse_dns = calc_reverse_dns4(network, prefix, network, broadcast);
+
+ memset(namebuf, '\0', sizeof(namebuf));
+ if (inet_ntop(AF_INET, &network, namebuf, INET_ADDRSTRLEN) == NULL) {
+ fprintf(stderr, "inet_ntop failure at line %d\n",
+ __LINE__);
+ exit(1);
+ }
+
+ info->network = safe_strdup(namebuf);
+
+ info->type = ipv4_net_to_type(network);
+ info->class = ipv4_net_to_class(network);
+
+ if (prefix < 32) {
+ memcpy(&minhost, &network, sizeof(minhost));
+
+ if (prefix <= 30)
+ minhost.s_addr = htonl(ntohl(minhost.s_addr) | 1);
+ if (inet_ntop(AF_INET, &minhost, namebuf, INET_ADDRSTRLEN) ==
+ NULL) {
+ fprintf(stderr, "inet_ntop failure at line %d\n",
+ __LINE__);
+ exit(1);
+ }
+ info->hostmin = safe_strdup(namebuf);
+
+ memcpy(&maxhost, &network, sizeof(minhost));
+ maxhost.s_addr |= ~netmask.s_addr;
+ if (prefix <= 30) {
+ maxhost.s_addr = htonl(ntohl(maxhost.s_addr) - 1);
+ }
+ if (inet_ntop(AF_INET, &maxhost, namebuf, sizeof(namebuf)) == 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: error calculating the IPv4 network\n");
+ return -1;
+ }
+
+ info->hostmax = safe_strdup(namebuf);
+ } else {
+ info->hostmin = info->network;
+ info->hostmax = info->network;
+ }
+
+ ipv4_prefix_to_hosts(info->hosts, sizeof(info->hosts), prefix);
+
+#if defined(USE_GEOIP) || defined(USE_MAXMIND)
+ if (flags & FLAG_GET_GEOIP) {
+ geo_ip_lookup(ipStr, &info->geoip_country, &info->geoip_ccode, &info->geoip_city, &info->geoip_coord);
+ }
+#endif
+
+ if (flags & FLAG_RESOLVE_HOST) {
+ info->hostname = get_hostname(AF_INET, &ip);
+ if (info->hostname == NULL) {
+ if (!beSilent) {
+ sprintf(errBuf,
+ "ipcalc: cannot find hostname for %s",
+ ipStr);
+ herror(errBuf);
+ }
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int ipv6_prefix_to_mask(unsigned prefix, struct in6_addr *mask)
+{
+ struct in6_addr in6;
+ int i, j;
+
+ if (prefix > 128)
+ return -1;
+
+ memset(&in6, 0x0, sizeof(in6));
+ for (i = prefix, j = 0; i > 0; i -= 8, j++) {
+ if (i >= 8) {
+ in6.s6_addr[j] = 0xff;
+ } else {
+ in6.s6_addr[j] = (unsigned long)(0xffU << (8 - i));
+ }
+ }
+
+ memcpy(mask, &in6, sizeof(*mask));
+ return 0;
+}
+
+static char *ipv6_mask_to_str(const struct in6_addr *mask)
+{
+ char buf[128];
+
+ if (inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == NULL)
+ return NULL;
+
+ return safe_strdup(buf);
+}
+
+static const char *ipv6_net_to_type(struct in6_addr *net, int prefix)
+{
+ uint16_t word1 = net->s6_addr[0] << 8 | net->s6_addr[1];
+ uint16_t word2 = net->s6_addr[2] << 8 | net->s6_addr[3];
+
+ /* based on IANA's iana-ipv6-special-registry and ipv6-address-space
+ * Updated: 2019-09-13
+ */
+ if (prefix == 128 && memcmp
+ (net->s6_addr,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ 16) == 0)
+ return "Loopback Address";
+
+ if (prefix == 128 && memcmp
+ (net->s6_addr,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 16) == 0)
+ return "Unspecified Address";
+
+ if (prefix >= 96 && memcmp
+ (net->s6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff",
+ 12) == 0)
+ return "IPv4-mapped Address";
+
+ if (prefix >= 96 && memcmp
+ (net->s6_addr, "\x00\x64\xff\x9b\x00\x00\x00\x00\x00\x00\x00\x00",
+ 12) == 0)
+ return "IPv4-IPv6 Translat.";
+
+ if (prefix >= 48 && memcmp
+ (net->s6_addr, "\x00\x64\xff\x9b\x00\x01",
+ 6) == 0)
+ return "IPv4-IPv6 Translat.";
+
+ if (prefix >= 96 && memcmp
+ (net->s6_addr, "\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ 12) == 0)
+ return "Discard-Only Address Block";
+
+ if (prefix >= 32 && word1 == 0x2001 && word2 == 0)
+ return "TEREDO";
+
+ if (prefix == 128 && memcmp
+ (net->s6_addr, "\x20\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ 16) == 0)
+ return "Port Control Protocol Anycast";
+
+ if (prefix == 128 && memcmp
+ (net->s6_addr, "\x20\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ 16) == 0)
+ return "Traversal Using Relays around NAT Anycast";
+
+ if (prefix >= 48 && memcmp
+ (net->s6_addr, "\x20\x01\x00\x02\x00\x00",
+ 6) == 0)
+ return "Benchmarking";
+
+ if (prefix >= 32 && word1 == 0x2001 && word2 == 0x3)
+ return "AMT";
+
+ if (prefix >= 48 && memcmp
+ (net->s6_addr, "\x20\x01\x00\x04\x01\x12",
+ 6) == 0)
+ return "AS112-v6";
+
+ if (prefix >= 28 && word1 == 0x2001 && (word2 & 0xfff0) == 0x10)
+ return "Deprecated (previously ORCHID)";
+
+ if (prefix >= 28 && word1 == 0x2001 && (word2 & 0xfff0) == 0x20)
+ return "ORCHIDv2";
+
+ if (prefix >= 23 && word1 == 0x2001 && (word2 & 0xff00) <= 0x100)
+ return "IETF Protocol Assignments";
+
+ if (prefix >= 32 && word1 == 0x2001 && word2 == 0xdb8)
+ return "Documentation";
+
+ if (word1 == 0x2002)
+ return "6to4";
+
+ if (prefix >= 48 && memcmp
+ (net->s6_addr, "\x26\x20\x00\x4f\x80\x00",
+ 6) == 0)
+ return "Direct Delegation AS112 Service";
+
+ if ((word1 & 0xe000) == 0x2000) {
+ return "Global Unicast";
+ }
+
+ if (((net->s6_addr[0] & 0xfe) == 0xfc)) {
+ return "Unique Local Unicast";
+ }
+
+ if ((word1 & 0xffc0) == 0xfe80) {
+ return "Link-Scoped Unicast";
+ }
+
+ if ((net->s6_addr[0] & 0xff) == 0xff) {
+ return "Multicast";
+ }
+
+ return "Reserved";
+}
+
+static
+char *expand_ipv6(struct in6_addr *ip6)
+{
+ char buf[128];
+ char *p;
+ unsigned i;
+
+ p = buf;
+ for (i = 0; i < 16; i++) {
+ sprintf(p, "%.2x", (unsigned)ip6->s6_addr[i]);
+ p += 2;
+ if (i % 2 != 0 && i != 15) {
+ *p = ':';
+ p++;
+ }
+ }
+ *p = 0;
+
+ return safe_strdup(buf);
+}
+
+static
+int get_ipv6_info(const char *ipStr, int prefix, ip_info_st * info,
+ unsigned flags)
+{
+ struct in6_addr ip6, mask, network;
+ char errBuf[250];
+ unsigned i;
+
+ memset(info, 0, sizeof(*info));
+
+ if (inet_pton(AF_INET6, ipStr, &ip6) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 address: %s\n",
+ ipStr);
+ return -1;
+ }
+
+ /* expand */
+ info->expanded_ip = expand_ipv6(&ip6);
+
+ if (inet_ntop(AF_INET6, &ip6, errBuf, sizeof(errBuf)) == 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: error calculating the IPv6 network\n");
+ return -1;
+ }
+
+ info->ip = safe_strdup(errBuf);
+
+ if (prefix > 128) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 prefix: %d\n",
+ prefix);
+ return -1;
+ } else if (prefix < 0) {
+ prefix = 128;
+ }
+
+ info->prefix = prefix;
+
+ if (ipv6_prefix_to_mask(prefix, &mask) == -1) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: error converting IPv6 prefix: %d\n",
+ prefix);
+ return -1;
+ }
+
+ info->netmask = ipv6_mask_to_str(&mask);
+
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ network.s6_addr[i] = ip6.s6_addr[i] & mask.s6_addr[i];
+
+ if (inet_ntop(AF_INET6, &network, errBuf, sizeof(errBuf)) == 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: error calculating the IPv6 network\n");
+ return -1;
+ }
+
+ info->network = safe_strdup(errBuf);
+
+ info->expanded_network = expand_ipv6(&network);
+ info->type = ipv6_net_to_type(&network, prefix);
+
+ info->reverse_dns = calc_reverse_dns6(&network, prefix);
+
+ if (prefix < 128) {
+ info->hostmin = safe_strdup(errBuf);
+
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ network.s6_addr[i] |= ~mask.s6_addr[i];
+ if (inet_ntop(AF_INET6, &network, errBuf, sizeof(errBuf)) == 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: error calculating the IPv6 network\n");
+ return -1;
+ }
+
+ info->hostmax = safe_strdup(errBuf);
+ } else {
+ info->hostmin = info->network;
+ info->hostmax = info->network;
+ }
+
+ ipv6_prefix_to_hosts(info->hosts, sizeof(info->hosts), prefix);
+
+#if defined(USE_GEOIP) || defined(USE_MAXMIND)
+ if (flags & FLAG_GET_GEOIP) {
+ geo_ip_lookup(ipStr, &info->geoip_country, &info->geoip_ccode, &info->geoip_city, &info->geoip_coord);
+ }
+#endif
+
+ if (flags & FLAG_RESOLVE_HOST) {
+ info->hostname = get_hostname(AF_INET6, &ip6);
+ if (info->hostname == NULL) {
+ if (!beSilent) {
+ sprintf(errBuf,
+ "ipcalc: cannot find hostname for %s",
+ ipStr);
+ herror(errBuf);
+ }
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int randomize(void *ptr, unsigned size)
+{
+ int fd, ret;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ ret = read(fd, ptr, size);
+ close(fd);
+
+ if (ret != size) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static char *generate_ip_network(unsigned prefix, unsigned flags)
+{
+ struct timespec ts;
+ char ipbuf[64];
+ char *p = NULL;
+
+ if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) < 0)
+ return NULL;
+
+ if (flags & FLAG_IPV6) {
+ struct in6_addr net;
+
+ net.s6_addr[0] = 0xfd;
+ if (randomize(&net.s6_addr[1], 15) < 0)
+ return NULL;
+
+ if (inet_ntop(AF_INET6, &net, ipbuf, sizeof(ipbuf)) == NULL)
+ return NULL;
+ } else {
+ struct in_addr net;
+ unsigned c = ts.tv_nsec % 4;
+ uint8_t bytes[4];
+
+ if (randomize(bytes, 4) < 0)
+ return NULL;
+
+ if (prefix >= 16 && c < 2) {
+ if (c == 1) {
+ bytes[0] = 192;
+ bytes[1] = 168;
+ } else {
+ bytes[0] = 172;
+ bytes[1] = 16 | ((ts.tv_nsec >> 4) & 0x0f);
+ }
+ } else {
+ bytes[0] = 10;
+ }
+
+ memcpy(&net.s_addr, bytes, 4);
+
+ if (inet_ntop(AF_INET, &net, ipbuf, sizeof(ipbuf)) == NULL)
+ return NULL;
+ }
+
+ if (asprintf(&p, "%s/%u", ipbuf, prefix) == -1)
+ return NULL;
+
+ return p;
+}
+
+static
+int str_to_prefix(unsigned *flags, const char *prefixStr, unsigned fix)
+{
+ int prefix = -1;
+ if (!((*flags) & FLAG_IPV6) && strchr(prefixStr, '.')) { /* prefix is 255.x.x.x */
+ prefix = ipv4_mask_to_int(prefixStr);
+ } else {
+ int r = safe_atoi(prefixStr, &prefix);
+ if (r != 0) {
+ return -1;
+ }
+ }
+
+ if (fix && (prefix > 32 && !((*flags) & FLAG_IPV6)))
+ *flags |= FLAG_IPV6;
+
+ if (prefix < 0 || ((((*flags) & FLAG_IPV6) && prefix > 128) || (!((*flags) & FLAG_IPV6) && prefix > 32))) {
+ return -1;
+ }
+ return prefix;
+}
+
+#define OPT_ALLINFO 1
+#define OPT_MINADDR 2
+#define OPT_MAXADDR 3
+#define OPT_ADDRESSES 4
+#define OPT_ADDRSPACE 5
+#define OPT_USAGE 6
+#define OPT_REVERSE 7
+#define OPT_CLASS_PREFIX 8
+#define OPT_NO_DECORATE 9
+
+static const struct option long_options[] = {
+ {"check", 0, 0, 'c'},
+ {"random-private", 1, 0, 'r'},
+ {"split", 1, 0, 'S'},
+ {"deaggregate", 1, 0, 'd'},
+ {"info", 0, 0, 'i'},
+ {"all-info", 0, 0, OPT_ALLINFO},
+ {"ipv4", 0, 0, '4'},
+ {"ipv6", 0, 0, '6'},
+ {"address", 0, 0, 'a'},
+ {"broadcast", 0, 0, 'b'},
+ {"hostname", 0, 0, 'h'},
+ {"lookup-host", 1, 0, 'o'},
+ {"reverse-dns", 0, 0, OPT_REVERSE},
+#if defined(USE_GEOIP) || defined(USE_MAXMIND)
+ {"geoinfo", 0, 0, 'g'},
+#endif
+ {"netmask", 0, 0, 'm'},
+ {"network", 0, 0, 'n'},
+ {"prefix", 0, 0, 'p'},
+ {"class-prefix", 0, 0, OPT_CLASS_PREFIX},
+ {"minaddr", 0, 0, OPT_MINADDR},
+ {"maxaddr", 0, 0, OPT_MAXADDR},
+ {"addresses", 0, 0, OPT_ADDRESSES},
+ {"addrspace", 0, 0, OPT_ADDRSPACE},
+ {"silent", 0, 0, 's'},
+ {"no-decorate", 0, 0, OPT_NO_DECORATE},
+ {"json", 0, 0, 'j'},
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, '?'},
+ {"usage", 0, 0, OPT_USAGE},
+ {NULL, 0, 0, 0}
+};
+
+static
+void usage(unsigned verbose)
+{
+ if (verbose) {
+ fprintf(stderr, "Usage: ipcalc [OPTION...]\n");
+ fprintf(stderr, " -c, --check Validate IP address\n");
+ fprintf(stderr, " -r, --random-private=PREFIX Generate a random private IP network using\n");
+ fprintf(stderr, " the supplied prefix or mask.\n");
+ fprintf(stderr, " -S, --split=PREFIX Split the provided network using the\n");
+ fprintf(stderr, " provided prefix/netmask\n");
+ fprintf(stderr, " -d, --deaggregate=IP1-IP2 Deaggregate the provided address range\n");
+ fprintf(stderr, " -i, --info Print information on the provided IP address\n");
+ fprintf(stderr, " (default)\n");
+ fprintf(stderr, " --all-info Print verbose information on the provided IP\n");
+ fprintf(stderr, " address\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Specific info options:\n");
+ fprintf(stderr, " --reverse-dns Print network in a the reverse DNS format\n");
+ fprintf(stderr, " -a, --address Display IP address\n");
+ fprintf(stderr, " -b, --broadcast Display calculated broadcast address\n");
+ fprintf(stderr, " -m, --netmask Display netmask for IP\n");
+ fprintf(stderr, " -n, --network Display network address\n");
+ fprintf(stderr, " -p, --prefix Display network prefix\n");
+ fprintf(stderr, " --minaddr Display the minimum address in the network\n");
+ fprintf(stderr, " --maxaddr Display the maximum address in the network\n");
+ fprintf(stderr, " --addresses Display the maximum number of addresses in\n");
+ fprintf(stderr, " the network\n");
+ fprintf(stderr, " --addrspace Display the address space the network\n");
+ fprintf(stderr, " resides on\n");
+ fprintf(stderr, " -h, --hostname Show hostname determined via DNS\n");
+ fprintf(stderr, " -o, --lookup-host=STRING Show IP as determined via DNS\n");
+#if defined(USE_GEOIP) || defined(USE_MAXMIND)
+ fprintf(stderr, " -g, --geoinfo Show Geographic information about the\n");
+ fprintf(stderr, " provided IP\n");
+#endif
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Other options:\n");
+ fprintf(stderr, " -4, --ipv4 Explicitly specify the IPv4 address family\n");
+ fprintf(stderr, " -6, --ipv6 Explicitly specify the IPv6 address family\n");
+ fprintf(stderr, " --class-prefix When specified the default prefix will be determined\n");
+ fprintf(stderr, " by the IPv4 address class\n");
+ fprintf(stderr, " --no-decorate Print only the requested information\n");
+ fprintf(stderr, " -j, --json JSON output\n");
+ fprintf(stderr, " -s, --silent Don't ever display error messages\n");
+ fprintf(stderr, " -v, --version Display program version\n");
+ fprintf(stderr, " -?, --help Show this help message\n");
+ fprintf(stderr, " --usage Display brief usage message\n");
+ } else {
+ fprintf(stderr, "Usage: ipcalc [-46sv?] [-c|--check] [-r|--random-private=STRING] [-i|--info]\n");
+ fprintf(stderr, " [--all-info] [-4|--ipv4] [-6|--ipv6] [-a|--address] [-b|--broadcast]\n");
+ fprintf(stderr, " [-h|--hostname] [-o|--lookup-host=STRING] [-g|--geoinfo]\n");
+ fprintf(stderr, " [-m|--netmask] [-n|--network] [-p|--prefix] [--minaddr] [--maxaddr]\n");
+ fprintf(stderr, " [--addresses] [--addrspace] [-j|--json] [-s|--silent] [-v|--version]\n");
+ fprintf(stderr, " [--reverse-dns] [--class-prefix]\n");
+ fprintf(stderr, " [-?|--help] [--usage]\n");
+ }
+}
+
+void output_start(unsigned * const jsonfirst)
+{
+ if (flags & FLAG_JSON) {
+ printf("{\n");
+ }
+
+ *jsonfirst = JSON_FIRST;
+}
+
+void output_separate(unsigned * const jsonfirst)
+{
+ if (!(flags & FLAG_JSON)) {
+ printf("\n");
+ }
+}
+
+void output_stop(unsigned * const jsonfirst)
+{
+ if (flags & FLAG_JSON) {
+ printf("\n}\n");
+ }
+}
+
+void array_start(unsigned * const jsonfirst, const char *head, const char *json_head)
+{
+ if (flags & FLAG_JSON) {
+ if (*jsonfirst == JSON_NEXT) {
+ printf(",\n ");
+ }
+
+ printf(" \"%s\":[\n ", json_head);
+ } else {
+ if (!(flags & FLAG_NO_DECORATE))
+ printf("[%s]\n", head);
+ }
+
+ *jsonfirst = JSON_ARRAY_FIRST;
+}
+
+void array_stop(unsigned * const jsonfirst)
+{
+ if (flags & FLAG_JSON) {
+ printf("]");
+ *jsonfirst = JSON_NEXT;
+ }
+}
+
+void
+__attribute__ ((format(printf, 3, 4)))
+color_printf(const char *color, const char *title, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ va_color_printf(color, title, fmt, args);
+ va_end(args);
+
+ return;
+}
+
+void va_color_printf(const char *color, const char *title, const char *fmt, va_list varglist)
+{
+ int ret;
+ char *str = NULL;
+
+ ret = vasprintf(&str, fmt, varglist);
+
+ if (ret < 0) {
+ return;
+ }
+
+ fputs(title, stdout);
+ if (colors) {
+ fputs(color, stdout);
+ }
+ fputs(str, stdout);
+ fputs("\n", stdout);
+ if (colors) {
+ fputs(KRESET, stdout);
+ }
+ free(str);
+ return;
+}
+
+void
+__attribute__ ((format(printf, 3, 4)))
+json_printf(unsigned * const jsonfirst, const char *jsontitle, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ va_json_printf(jsonfirst, jsontitle, fmt, args);
+ va_end(args);
+
+ return;
+}
+void va_json_printf(unsigned * const jsonfirst, const char *jsontitle, const char *fmt, va_list varglist)
+{
+ int ret;
+ char *str = NULL;
+
+ ret = vasprintf(&str, fmt, varglist);
+ if (ret < 0)
+ return;
+
+ if (*jsonfirst == JSON_ARRAY_NEXT) {
+ fprintf(stdout, ",\n ");
+ } else if (*jsonfirst == JSON_NEXT) {
+ fprintf(stdout, ",\n");
+ }
+
+ fprintf(stdout, " ");
+ if (jsontitle)
+ fprintf(stdout, "\"%s\":\"%s\"", jsontitle, str);
+ else
+ fprintf(stdout, "\"%s\"", str);
+ if (*jsonfirst == JSON_FIRST)
+ *jsonfirst = JSON_NEXT;
+ else if (*jsonfirst == JSON_ARRAY_FIRST)
+ *jsonfirst = JSON_ARRAY_NEXT;
+
+ free(str);
+ return;
+}
+
+/* Always prints "title: value", will not color if --no-decorate is given
+ */
+static void
+__attribute__ ((format(printf, 4, 5)))
+pretty_printf(unsigned * const jsonfirst, const char *title, const char *jsontitle, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (flags & FLAG_JSON) {
+ va_json_printf(jsonfirst, jsontitle, fmt, args);
+ } else if (flags & FLAG_NO_DECORATE) {
+ fputs(title, stdout);
+ vprintf(fmt, args);
+ fputs("\n", stdout);
+ } else {
+ va_color_printf(KBLUE, title, fmt, args);
+ }
+ va_end(args);
+
+ return;
+}
+
+/* Always prints "title: value", will not color if --no-decorate is given
+ * To be used for distinct values (e.g., a summary).
+ */
+static void
+__attribute__ ((format(printf, 4, 5)))
+pretty_dist_printf(unsigned * const jsonfirst, const char *title, const char *jsontitle, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (flags & FLAG_JSON) {
+ va_json_printf(jsonfirst, jsontitle, fmt, args);
+ } else if (flags & FLAG_NO_DECORATE) {
+ fputs(title, stdout);
+ vprintf(fmt, args);
+ fputs("\n", stdout);
+ } else {
+ va_color_printf(KMAG, title, fmt, args);
+ }
+ va_end(args);
+
+ return;
+}
+
+/* Prints "title: value", will only print value if --no-decorate is given
+ */
+void
+__attribute__ ((format(printf, 4, 5)))
+default_printf(unsigned * const jsonfirst, const char *title, const char *jsontitle, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (flags & FLAG_JSON) {
+ va_json_printf(jsonfirst, jsontitle, fmt, args);
+ } else if (flags & FLAG_NO_DECORATE) {
+ vprintf(fmt, args);
+ printf("\n");
+ } else {
+ va_color_printf(KBLUE, title, fmt, args);
+ }
+ va_end(args);
+
+ return;
+}
+
+/* Prints "title: value", will only print value if --no-decorate is given. It
+ * prints a distinct value (e.g., to be used for a summary).
+ */
+void
+__attribute__ ((format(printf, 4, 5)))
+dist_printf(unsigned * const jsonfirst, const char *title, const char *jsontitle, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (flags & FLAG_JSON) {
+ va_json_printf(jsonfirst, jsontitle, fmt, args);
+ }
+ else if (flags & FLAG_NO_DECORATE) {
+ vprintf(fmt, args);
+ printf("\n");
+ } else {
+ va_color_printf(KMAG, title, fmt, args);
+ }
+ va_end(args);
+
+ return;
+}
+
+/* Printed variables names */
+#define HOSTNAME_NAME "HOSTNAME"
+#define FULL_ADDRESS_NAME "FULLADDRESS"
+#define ADDRESS_NAME "ADDRESS"
+#define FULL_NETWORK_NAME "FULLNETWORK"
+#define NETWORK_NAME "NETWORK"
+#define NETMASK_NAME "NETMASK"
+#define PREFIX_NAME "PREFIX"
+#define BROADCAST_NAME "BROADCAST"
+#define REVERSEDNS_NAME "REVERSEDNS"
+#define ADDRSPACE_NAME "ADDRSPACE"
+#define ADDRCLASS_NAME "ADDRCLASS"
+#define MINADDR_NAME "MINADDR"
+#define MAXADDR_NAME "MAXADDR"
+#define ADDRESSES_NAME "ADDRESSES"
+#define COUNTRYCODE_NAME "COUNTRYCODE"
+#define COUNTRY_NAME "COUNTRY"
+#define CITY_NAME "CITY"
+#define COORDINATES_NAME "COORDINATES"
+
+/*!
+ \fn main(int argc, const char **argv)
+ \brief wrapper program for ipcalc functions.
+
+ This is a wrapper program for the functions that the ipcalc library provides.
+ It can be used from shell scripts or directly from the command line.
+
+ For more information, please see the ipcalc(1) man page.
+*/
+int main(int argc, char **argv)
+{
+ char *randomStr = NULL;
+ char *hostname = NULL;
+ char *splitStr = NULL;
+ char *ipStr = NULL, *prefixStr = NULL, *netmaskStr = NULL, *chptr = NULL;
+ int prefix = -1, splitPrefix = -1;
+ ip_info_st info;
+ int r = 0;
+ unsigned jsonchain = JSON_FIRST;
+ enum app_t app = 0;
+
+ while (1) {
+ int c = getopt_long(argc, argv, "S:cr:i46abho:gmnpjsvd:", long_options, NULL);
+ if (c == -1)
+ break;
+
+ switch(c) {
+ case 'c':
+ app |= APP_CHECK_ADDRESS;
+ break;
+ case 'S':
+ app |= APP_SPLIT;
+ splitStr = safe_strdup(optarg);
+ if (splitStr == NULL) exit(1);
+ break;
+ case 'd':
+ app |= APP_DEAGGREGATE;
+ ipStr = safe_strdup(optarg);
+ if (ipStr == NULL) exit(1);
+ break;
+ case 'r':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_RANDOM;
+ randomStr = safe_strdup(optarg);
+ if (randomStr == NULL) exit(1);
+ break;
+ case 'i':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_MODERN_INFO;
+ break;
+ case OPT_ALLINFO:
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_ALL_INFO|FLAG_SHOW_MODERN_INFO;
+ break;
+ case OPT_CLASS_PREFIX:
+ flags |= FLAG_ASSUME_CLASS_PREFIX;
+ break;
+ case OPT_REVERSE:
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_REVERSE;
+ break;
+ case '4':
+ flags |= FLAG_IPV4;
+ break;
+ case '6':
+ flags |= FLAG_IPV6;
+ break;
+ case 'a':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_ADDRESS;
+ break;
+ case 'b':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_BROADCAST;
+ break;
+ case 'h':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_RESOLVE_HOST;
+ break;
+ case 'o':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_RESOLVE_IP;
+ hostname = safe_strdup(optarg);
+ if (hostname == NULL) exit(1);
+ break;
+ case 'g':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_GEOIP;
+ break;
+ case 'm':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_NETMASK;
+ break;
+ case 'n':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_NETWORK;
+ break;
+ case 'p':
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_PREFIX;
+ break;
+ case OPT_MINADDR:
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_MINADDR;
+ break;
+ case OPT_MAXADDR:
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_MAXADDR;
+ break;
+ case OPT_ADDRESSES:
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_ADDRESSES;
+ break;
+ case OPT_ADDRSPACE:
+ app |= APP_SHOW_INFO;
+ flags |= FLAG_SHOW_ADDRSPACE;
+ break;
+ case OPT_NO_DECORATE:
+ flags |= FLAG_NO_DECORATE;
+ break;
+ case 'j':
+ flags |= FLAG_JSON;
+ break;
+ case 's':
+ beSilent = 1;
+ break;
+ case 'v':
+ app |= APP_VERSION;
+ break;
+ case OPT_USAGE:
+ usage(0);
+ exit(0);
+ case '?':
+ usage(1);
+ exit(0);
+ }
+ }
+
+ if (optind < argc) {
+ if (ipStr != NULL) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: superfluous option given\n");
+ exit(1);
+ }
+
+ ipStr = argv[optind++];
+ if (optind < argc)
+ chptr = argv[optind++];
+ }
+
+ if ((flags & FLAG_JSON) && (flags & FLAG_NO_DECORATE)) {
+ flags &= ~FLAG_NO_DECORATE;
+ }
+
+ if (!(flags & FLAGS_TO_IGNORE_MASK))
+ flags |= FLAG_SHOW_MODERN_INFO;
+
+ /* Only the modern info flag results to JSON output */
+ if ((flags & ENV_INFO_MASK) && (flags & FLAG_JSON))
+ flags |= FLAG_SHOW_MODERN_INFO;
+
+ if (geo_setup() == 0 && (flags & FLAG_SHOW_ALL_INFO))
+ flags |= FLAG_GET_GEOIP;
+
+ if (bit_count(app) > 1) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: you cannot mix these options\n");
+ return 1;
+ }
+
+ if ((flags & FLAG_IPV6) && (flags & FLAG_IPV4)) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: you cannot specify both IPv4 and IPv6\n");
+ return 1;
+ }
+
+ /* if there is a : in the address, it is an IPv6 address.
+ * Note that we allow -4, and -6 to be given explicitly, so
+ * that the tool can be used to check for a valid IPv4 or IPv6
+ * address.
+ */
+ if ((flags & FLAG_IPV4) == 0 && ipStr && strchr(ipStr, ':') != NULL) {
+ flags |= FLAG_IPV6;
+ }
+
+ switch (app) {
+ case APP_VERSION:
+ printf("ipcalc %s\n", VERSION);
+ return 0;
+ case APP_DEAGGREGATE:
+ deaggregate(ipStr, flags);
+ return 0;
+ case APP_SPLIT:
+ case APP_CHECK_ADDRESS:
+ case APP_SHOW_INFO:
+ /* These are handled lower into the info app */
+ break;
+ }
+
+ /* The main application which displays information about an address or
+ * a network. */
+ if (flags & FLAG_RANDOM) {
+ if (ipStr) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: provided superfluous parameter '%s'\n", ipStr);
+ return 1;
+ }
+
+ prefix = str_to_prefix(&flags, randomStr, 1);
+ if (prefix < 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: bad %s prefix: %s\n", (flags&FLAG_IPV6)?"IPv6":"IPv4", randomStr);
+ return 1;
+ }
+
+ ipStr = generate_ip_network(prefix, flags);
+ if (ipStr == NULL) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: cannot generate network with prefix: %u\n",
+ prefix);
+ return 1;
+ }
+ }
+
+ if (hostname == NULL && ipStr == NULL) {
+ if (!beSilent) {
+ fprintf(stderr,
+ "ipcalc: ip address expected\n");
+ usage(1);
+ }
+ return 1;
+ }
+
+ /* resolve IP address if a hostname was given */
+ if (hostname) {
+ int family = AF_UNSPEC;
+ if (flags & FLAG_IPV6)
+ family = AF_INET6;
+ else if (flags & FLAG_IPV4)
+ family = AF_INET;
+
+ ipStr = get_ip_address(family, hostname);
+ if (ipStr == NULL) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: could not resolve %s\n", hostname);
+ return 1;
+ }
+
+ if ((flags & FLAG_IPV4) == 0 && strchr(ipStr, ':') != NULL) {
+ flags |= FLAG_IPV6;
+ }
+ }
+
+ if (chptr) {
+ if ((flags & FLAG_IPV6) == 0) {
+ prefixStr = chptr;
+ } else {
+ if (!beSilent) {
+ fprintf(stderr, "ipcalc: unexpected argument: %s\n",
+ chptr);
+ usage(1);
+ }
+ return 1;
+ }
+ }
+
+ if (prefixStr == NULL && strchr(ipStr, '/') != NULL) {
+ prefixStr = strchr(ipStr, '/');
+ *prefixStr = '\0'; /* fix up ipStr */
+ prefixStr++;
+ }
+
+ if (prefixStr != NULL) {
+ prefix = str_to_prefix(&flags, prefixStr, 0);
+ if (prefix < 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: bad %s prefix: %s\n", (flags & FLAG_IPV6)?"IPv6":"IPv4", prefixStr);
+ return 1;
+ }
+ }
+
+ if (flags & FLAG_IPV6) {
+ r = get_ipv6_info(ipStr, prefix, &info, flags);
+ } else {
+ if ((flags & FLAG_SHOW_BROADCAST) || (flags & FLAG_SHOW_NETWORK) || (flags & FLAG_SHOW_PREFIX)) {
+ if (netmaskStr && prefix >= 0) {
+ if (!beSilent) {
+ fprintf(stderr,
+ "ipcalc: both netmask and prefix specified\n");
+ usage(1);
+ }
+ return 1;
+ }
+ }
+
+ if (prefix == -1 && netmaskStr) {
+ prefix = ipv4_mask_to_int(netmaskStr);
+ if (prefix < 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: bad IPv4 prefix: %s\n", prefixStr);
+ return 1;
+ }
+ }
+ r = get_ipv4_info(ipStr, prefix, &info, flags);
+ }
+
+ if (r < 0) {
+ return 1;
+ }
+
+ switch (app) {
+ case APP_SPLIT:
+ splitPrefix = str_to_prefix(&flags, splitStr, 1);
+ if (splitPrefix < 0) {
+ if (!beSilent)
+ fprintf(stderr,
+ "ipcalc: bad %s prefix: %s\n", (flags & FLAG_IPV6)?"IPv6":"IPv4", splitStr);
+ return 1;
+ }
+
+ if (flags & FLAG_IPV6) {
+ show_split_networks_v6(splitPrefix, &info, flags);
+ } else {
+ show_split_networks_v4(splitPrefix, &info, flags);
+ }
+ return 0;
+ case APP_CHECK_ADDRESS:
+ return 0;
+ default:
+ break;
+ }
+
+ if (isatty(STDOUT_FILENO) != 0)
+ colors = 1;
+
+ /* we know what we want to display now, so display it. */
+ if (flags & FLAG_SHOW_MODERN_INFO) {
+ unsigned single_host = 0;
+
+ if (((flags & FLAG_IPV6) && info.prefix == 128) ||
+ (!(flags & FLAG_IPV6) && info.prefix == 32)) {
+ single_host = 1;
+ }
+
+ output_start(&jsonchain);
+
+ if ((!randomStr || single_host) &&
+ (single_host || strcmp(info.network, info.ip) != 0)) {
+ if (info.expanded_ip) {
+ pretty_printf(&jsonchain,"Full Address:\t", FULL_ADDRESS_NAME, "%s", info.expanded_ip);
+ }
+ pretty_printf(&jsonchain, "Address:\t", ADDRESS_NAME, "%s", info.ip);
+ }
+
+ if (single_host && info.hostname)
+ pretty_printf(&jsonchain, "Hostname:\t", HOSTNAME_NAME, "%s", info.hostname);
+
+ if (!single_host || (flags & FLAG_JSON)) {
+ if (! (flags & FLAG_JSON)) {
+ if (info.expanded_network) {
+ pretty_printf(&jsonchain, "Full Network:\t", FULL_NETWORK_NAME, "%s/%u", info.expanded_network, info.prefix);
+ }
+ pretty_printf(&jsonchain, "Network:\t", NETWORK_NAME, "%s/%u", info.network, info.prefix);
+ pretty_printf(&jsonchain, "Netmask:\t", NETMASK_NAME, "%s = %u", info.netmask, info.prefix);
+ }
+ else {
+ if (info.expanded_network) {
+ pretty_printf(&jsonchain, "Full Network:\t", FULL_NETWORK_NAME, "%s", info.expanded_network);
+ }
+ pretty_printf(&jsonchain, "Network:\t", NETWORK_NAME, "%s", info.network);
+ pretty_printf(&jsonchain, "Netmask:\t", NETMASK_NAME, "%s", info.netmask);
+ pretty_printf(&jsonchain, "Prefix:\t", PREFIX_NAME, "%u", info.prefix);
+ }
+
+
+ if (info.broadcast)
+ pretty_printf(&jsonchain, "Broadcast:\t", BROADCAST_NAME, "%s", info.broadcast);
+ }
+
+ if ((flags & FLAG_SHOW_ALL_INFO) && info.reverse_dns)
+ pretty_printf(&jsonchain, "Reverse DNS:\t", REVERSEDNS_NAME, "%s", info.reverse_dns);
+
+ if (!single_host || (flags & FLAG_JSON)) {
+ output_separate(&jsonchain);
+
+ if (info.type)
+ pretty_dist_printf(&jsonchain, "Address space:\t", ADDRSPACE_NAME, "%s", info.type);
+
+ if ((flags & FLAG_SHOW_ALL_INFO) && info.class)
+ pretty_dist_printf(&jsonchain, "Address class:\t", ADDRCLASS_NAME, "%s", info.class);
+
+ if (info.hostmin)
+ pretty_printf(&jsonchain, "HostMin:\t", MINADDR_NAME, "%s", info.hostmin);
+
+ if (info.hostmax)
+ pretty_printf(&jsonchain, "HostMax:\t", MAXADDR_NAME, "%s", info.hostmax);
+
+ if ((flags & FLAG_IPV6) && info.prefix < 112 && !(flags & FLAG_JSON))
+ pretty_printf(&jsonchain, "Hosts/Net:\t", ADDRESSES_NAME, "2^(%u) = %s", 128-info.prefix, info.hosts);
+ else
+ pretty_printf(&jsonchain, "Hosts/Net:\t", ADDRESSES_NAME, "%s", info.hosts);
+
+ } else {
+
+ if (info.type)
+ pretty_dist_printf(&jsonchain, "Address space:\t", ADDRSPACE_NAME, "%s", info.type);
+
+ if ((flags & FLAG_SHOW_ALL_INFO) && info.class)
+ pretty_dist_printf(&jsonchain, "Address class:\t", ADDRCLASS_NAME, "%s", info.class);
+ }
+
+ if (info.geoip_country || info.geoip_city || info.geoip_coord) {
+ output_separate(&jsonchain);
+
+ if (info.geoip_ccode)
+ pretty_dist_printf(&jsonchain, "Country code:\t", COUNTRYCODE_NAME, "%s", info.geoip_ccode);
+ if (info.geoip_country)
+ pretty_dist_printf(&jsonchain, "Country:\t", COUNTRY_NAME, "%s", info.geoip_country);
+ if (info.geoip_city)
+ pretty_dist_printf(&jsonchain, "City:\t\t", CITY_NAME, "%s", info.geoip_city);
+ if (info.geoip_coord)
+ pretty_dist_printf(&jsonchain, "Coordinates:\t", COORDINATES_NAME, "%s", info.geoip_coord);
+ }
+
+ output_stop(&jsonchain);
+
+ } else if (!(flags & FLAG_SHOW_MODERN_INFO)) {
+
+ if (flags & FLAG_SHOW_ADDRESS) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(ADDRESS_NAME"=");
+ }
+ printf("%s\n", info.ip);
+ }
+
+ if (flags & FLAG_SHOW_NETMASK) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(NETMASK_NAME"=");
+ }
+ printf("%s\n", info.netmask);
+ }
+
+ if (flags & FLAG_SHOW_PREFIX) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(PREFIX_NAME"=");
+ }
+ printf("%u\n", info.prefix);
+ }
+
+ if ((flags & FLAG_SHOW_BROADCAST) && !(flags & FLAG_IPV6)) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(BROADCAST_NAME"=");
+ }
+ printf("%s\n", info.broadcast);
+ }
+
+ if (flags & FLAG_SHOW_NETWORK) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(NETWORK_NAME"=");
+ }
+ printf("%s\n", info.network);
+ }
+
+ if (flags & FLAG_SHOW_REVERSE) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(REVERSEDNS_NAME"=");
+ }
+ printf("%s\n", info.reverse_dns);
+ }
+
+ if ((flags & FLAG_SHOW_MINADDR) && info.hostmin) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(MINADDR_NAME"=");
+ }
+ printf("%s\n", info.hostmin);
+ }
+
+ if ((flags & FLAG_SHOW_MAXADDR) && info.hostmax) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(MAXADDR_NAME"=");
+ }
+ printf("%s\n", info.hostmax);
+ }
+
+ if ((flags & FLAG_SHOW_ADDRSPACE) && info.type) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(ADDRSPACE_NAME"=");
+ }
+ if (strchr(info.type, ' ') != NULL)
+ printf("\"%s\"\n", info.type);
+ else
+ printf("%s\n", info.type);
+ }
+
+ if ((flags & FLAG_SHOW_ADDRESSES) && info.hosts[0]) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(ADDRESSES_NAME"=");
+ }
+ if (strchr(info.hosts, ' ') != NULL)
+ printf("\"%s\"\n", info.hosts);
+ else
+ printf("%s\n", info.hosts);
+ }
+
+ if ((flags & FLAG_RESOLVE_HOST) && info.hostname) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(HOSTNAME_NAME"=");
+ }
+ printf("%s\n", info.hostname);
+ }
+
+ if (flags & FLAG_RESOLVE_IP) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(ADDRESS_NAME"=");
+ }
+ printf("%s\n", ipStr);
+ }
+
+ if ((flags & FLAG_SHOW_GEOIP) == FLAG_SHOW_GEOIP) {
+ if (info.geoip_ccode) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(COUNTRYCODE_NAME"=");
+ }
+ printf("%s\n", info.geoip_ccode);
+ }
+ if (info.geoip_country) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(COUNTRY_NAME"=");
+ }
+ if (strchr(info.geoip_country, ' ') != NULL)
+ printf("\"%s\"\n", info.geoip_country);
+ else
+ printf("%s\n", info.geoip_country);
+ }
+ if (info.geoip_city) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(CITY_NAME"=");
+ }
+ if (strchr(info.geoip_city, ' ') != NULL) {
+ printf("\"%s\"\n", info.geoip_city);
+ } else {
+ printf("%s\n", info.geoip_city);
+ }
+ }
+ if (info.geoip_coord) {
+ if (! (flags & FLAG_NO_DECORATE)) {
+ printf(COORDINATES_NAME"=");
+ }
+ printf("\"%s\"\n", info.geoip_coord);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/ipcalc.h b/ipcalc.h
new file mode 100644
index 0000000..a220dc5
--- /dev/null
+++ b/ipcalc.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Nikos Mavrogiannopoulos <nmav@redhat.com>
+ */
+
+#ifndef _IPCALC_H
+#define _IPCALC_H
+
+#include <stdarg.h> /* for va_list */
+
+#if defined(USE_GEOIP)
+ void geo_ip_lookup(const char *ip, char **country, char **ccode, char **city, char **coord);
+ int geo_setup(void);
+# ifndef USE_RUNTIME_LINKING
+# define geo_setup() 0
+# endif
+#elif defined(USE_MAXMIND)
+ void geo_ip_lookup(const char *ip, char **country, char **ccode, char **city, char **coord);
+ int geo_setup(void);
+# ifndef USE_RUNTIME_LINKING
+# define geo_setup() 0
+# endif
+#else
+# define geo_ipv4_lookup(x,y,z,w,a)
+# define geo_ipv6_lookup(x,y,z,w,a)
+# define geo_setup() -1
+#endif
+
+int __attribute__((__format__(printf, 2, 3))) safe_asprintf(char **strp, const char *fmt, ...);
+char __attribute__((warn_unused_result)) *safe_strdup(const char *str);
+int safe_atoi(const char *s, int *ret_i);
+
+char *calc_reverse_dns4(struct in_addr ip, unsigned prefix, struct in_addr net, struct in_addr bcast);
+char *calc_reverse_dns6(struct in6_addr *ip, unsigned prefix);
+
+uint32_t prefix2mask(int prefix);
+int ipv6_prefix_to_mask(unsigned prefix, struct in6_addr *mask);
+
+struct in_addr calc_network(struct in_addr addr, int prefix);
+
+char *ipv4_prefix_to_hosts(char *hosts, unsigned hosts_size, unsigned prefix);
+char *ipv6_prefix_to_hosts(char *hosts, unsigned hosts_size, unsigned prefix);
+
+typedef struct ip_info_st {
+ char *ip;
+ char *expanded_ip;
+ char *expanded_network;
+ char *reverse_dns;
+
+ char *network;
+ char *broadcast; /* ipv4 only */
+ char *netmask;
+ char *hostname;
+ char *geoip_country;
+ char *geoip_ccode;
+ char *geoip_city;
+ char *geoip_coord;
+ char hosts[64]; /* number of hosts in text */
+ unsigned prefix;
+
+ char *hostmin;
+ char *hostmax;
+ const char *type;
+ const char *class;
+} ip_info_st;
+
+enum app_t {
+ APP_VERSION=1,
+ APP_CHECK_ADDRESS=1<<1,
+ APP_SHOW_INFO=1<<2,
+ APP_SPLIT=1<<3,
+ APP_DEAGGREGATE=1<<4
+};
+
+#define FLAG_IPV6 (1<<1)
+#define FLAG_IPV4 (1<<2)
+#define FLAG_SHOW_MODERN_INFO (1<<3)
+#define FLAG_RESOLVE_IP (1<<4)
+#define FLAG_RESOLVE_HOST (1<<5)
+#define FLAG_SHOW_BROADCAST (1<<6)
+#define FLAG_SHOW_NETMASK (1<<7)
+#define FLAG_SHOW_NETWORK (1<<8)
+#define FLAG_SHOW_PREFIX (1<<9)
+#define FLAG_SHOW_MINADDR (1<<10)
+#define FLAG_SHOW_MAXADDR (1<<11)
+#define FLAG_SHOW_ADDRESSES (1<<12)
+#define FLAG_SHOW_ADDRSPACE (1<<13)
+#define FLAG_GET_GEOIP (1<<14)
+#define FLAG_SHOW_GEOIP ((1<<15)|FLAG_GET_GEOIP)
+#define FLAG_SHOW_ALL_INFO (1<<16)
+#define FLAG_SHOW_REVERSE (1<<17)
+#define FLAG_ASSUME_CLASS_PREFIX (1<<18)
+#define FLAG_NO_DECORATE (1<<20)
+#define FLAG_SHOW_ADDRESS (1<<21)
+#define FLAG_JSON (1<<22)
+#define FLAG_RANDOM (1<<23)
+
+/* Flags that are modifying an existing option */
+#define FLAGS_TO_IGNORE (FLAG_IPV6|FLAG_IPV4|FLAG_GET_GEOIP|FLAG_NO_DECORATE|FLAG_JSON|FLAG_ASSUME_CLASS_PREFIX|(1<<16)|FLAG_RANDOM)
+#define FLAGS_TO_IGNORE_MASK (~FLAGS_TO_IGNORE)
+
+#define ENV_INFO_FLAGS (FLAG_SHOW_NETMASK|FLAG_SHOW_BROADCAST|FLAG_RESOLVE_IP|FLAG_RESOLVE_HOST|FLAG_SHOW_ADDRESS|FLAG_SHOW_REVERSE|FLAG_SHOW_GEOIP|FLAG_SHOW_ADDRSPACE|FLAG_SHOW_ADDRESSES|FLAG_SHOW_MAXADDR|FLAG_SHOW_MINADDR|FLAG_SHOW_PREFIX|FLAG_SHOW_NETWORK)
+#define ENV_INFO_MASK (~ENV_INFO_FLAGS)
+
+void show_split_networks_v4(unsigned split_prefix, const struct ip_info_st *info, unsigned flags);
+void show_split_networks_v6(unsigned split_prefix, const struct ip_info_st *info, unsigned flags);
+
+void deaggregate(char *str, unsigned flags);
+
+#define KBLUE "\x1B[34m"
+#define KMAG "\x1B[35m"
+#define KRESET "\033[0m"
+
+#define JSON_FIRST 0
+#define JSON_NEXT 1
+#define JSON_ARRAY_FIRST 2
+#define JSON_ARRAY_NEXT 3
+
+void
+__attribute__ ((format(printf, 3, 4)))
+color_printf(const char *color, const char *title, const char *fmt, ...);
+void
+__attribute__ ((format(printf, 3, 4)))
+json_printf(unsigned * const jsonfirst, const char *jsontitle, const char *fmt, ...);
+void va_color_printf(const char *color, const char *title, const char *fmt, va_list varglist);
+void va_json_printf(unsigned * const jsonfirst, const char *jsontitle, const char *fmt, va_list varglist);
+
+void
+__attribute__ ((format(printf, 4, 5)))
+default_printf(unsigned * const jsonfirst, const char *title, const char *jsontitle, const char *fmt, ...);
+void
+__attribute__ ((format(printf, 4, 5)))
+dist_printf(unsigned * const jsonfirst, const char *title, const char *jsontitle, const char *fmt, ...);
+
+void array_start(unsigned * const jsonfirst, const char *head, const char *json_head);
+void array_stop(unsigned * const jsonfirst);
+void output_start(unsigned * const jsonfirst);
+void output_stop(unsigned * const jsonfirst);
+
+extern int beSilent;
+
+#endif
diff --git a/ipv6.c b/ipv6.c
new file mode 100644
index 0000000..6fc5861
--- /dev/null
+++ b/ipv6.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Nikos Mavrogiannopoulos
+ * Copyright 1991-1997, 1999-2014 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+/* Adds the two IP addresses and places the output in ap. This is based
+ * on Niels Moeller's mini-gmp. */
+void ipv6_add(struct in6_addr *ap, const struct in6_addr *bp)
+{
+ int i;
+ uint8_t cy;
+
+ for (i = 15, cy = 0; i >= 0; i--) {
+ uint8_t a, b, r;
+ a = ap->s6_addr[i];
+ b = bp->s6_addr[i];
+ r = a + cy;
+ cy = (r < cy);
+ r += b;
+ cy += (r < b);
+ ap->s6_addr[i] = r;
+ }
+ return;
+}
+
+/* Sets the "bit" of the IPv6 address to one */
+void ipv6_or1(struct in6_addr *a, unsigned bit)
+{
+ unsigned byte = bit / 8;
+ unsigned shift = bit % 8;
+
+ assert(bit < 128);
+
+ a->s6_addr[15 - byte] |= 1 << shift;
+}
+
+/* Sets all bits below "bits" to one */
+void ipv6_orm(struct in6_addr *a, unsigned bits)
+{
+ int i;
+ unsigned bytes = bits / 8;
+
+ assert(bits < 128);
+
+ for (i = 0; i < bytes; i++)
+ a->s6_addr[15 - i] |= 0xff;
+
+ for (i = bytes * 8; i < bits; i++)
+ ipv6_or1(a, i);
+}
+
+/* Returns 1 if IP a is greater than IP b, 0 if equal, -1 if less */
+int ipv6_cmp(struct in6_addr *a, struct in6_addr *b)
+{
+ unsigned i;
+ for (i = 0; i < 16; i++) {
+ if (a->s6_addr[i] != b->s6_addr[i])
+ return a->s6_addr[i] > b->s6_addr[i] ? 1 : -1;
+ }
+ return 0;
+}
diff --git a/ipv6.h b/ipv6.h
new file mode 100644
index 0000000..b1ce884
--- /dev/null
+++ b/ipv6.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 Nikos Mavrogiannopoulos
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef IPV6_H
+#define IPV6_H
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void ipv6_add(struct in6_addr *a, const struct in6_addr *b);
+void ipv6_or1(struct in6_addr *a, unsigned bit);
+void ipv6_orm(struct in6_addr *a, unsigned bit);
+int ipv6_cmp(struct in6_addr *a, struct in6_addr *b);
+
+#endif
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..2a1d057
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,88 @@
+project('ipcalc', 'c',
+ license : 'GPLv2',
+ version : '1.0.3'
+)
+
+src = [
+ 'ipcalc.h',
+ 'ipcalc.c',
+ 'ipcalc-reverse.c',
+ 'ipcalc-utils.c',
+ 'netsplit.c',
+ 'ipv6.h',
+ 'ipv6.c',
+ 'deaggregate.c'
+]
+
+args = [
+ '-DVERSION="' + meson.project_version() + '"'
+]
+
+deps = []
+
+use_maxminddb = get_option('use_maxminddb')
+use_geoip = get_option('use_geoip')
+use_runtime_linking = get_option('use_runtime_linking')
+
+cc = meson.get_compiler('c')
+dl = cc.find_library('dl', required : use_runtime_linking)
+
+maxminddb = dependency('libmaxminddb',
+ method : 'pkg-config',
+ required : use_maxminddb
+)
+if maxminddb.found()
+ src += ['ipcalc-maxmind.c']
+ args += ['-DUSE_MAXMIND']
+ if dl.found()
+ message('linking maxminddb dynamically at runtime if it is available')
+ args += [
+ '-DUSE_RUNTIME_LINKING',
+ '-DLIBPATH="' + maxminddb.get_pkgconfig_variable('libdir') + '"'
+ ]
+ deps += [dl]
+ else
+ deps += [maxminddb]
+ endif
+else
+ geoip = dependency('geoip',
+ method : 'pkg-config',
+ required : use_geoip
+ )
+ if geoip.found()
+ src += ['ipcalc-geoip.c']
+ args += ['-DUSE_GEOIP']
+ if dl.found()
+ message('linking geoip dynamically at runtime if it is available')
+ args += [
+ '-DUSE_RUNTIME_LINKING',
+ '-DLIBPATH="' + geoip.get_pkgconfig_variable('libdir') + '"'
+ ]
+ deps += [dl]
+ else
+ deps += [geoip]
+ endif
+ endif
+endif
+
+ipcalc = executable('ipcalc',
+ sources : src,
+ c_args : args,
+ dependencies : deps,
+ install : true
+)
+
+ronn = find_program('ronn', required: false)
+if ronn.found()
+ ipcalc_1 = custom_target(
+ 'ipcalc.1',
+ output : 'ipcalc.1',
+ input : 'ipcalc.1.md',
+ command : [ronn, '--pipe', '-r', '@INPUT@'],
+ capture: true,
+ install_dir: join_paths(get_option('mandir'), 'man1'),
+ install: true
+ )
+endif
+
+subdir('tests')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..cd79386
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,15 @@
+option('use_geoip',
+ type : 'feature',
+ value : 'auto',
+ description : 'Use the GeoIP library to retrieve geo-information'
+)
+option('use_maxminddb',
+ type : 'feature',
+ value : 'auto',
+ description : 'Use the maxminddb library to retrieve geo-information'
+)
+option('use_runtime_linking',
+ type : 'feature',
+ value : 'auto',
+ description : 'Load the GeoIP or maxminddb library at runtime if available'
+)
diff --git a/netsplit.c b/netsplit.c
new file mode 100644
index 0000000..05fb1fb
--- /dev/null
+++ b/netsplit.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2003-2016 Simon Ekstrand
+ * Copyright (c) 2010-2016 Joachim Nilsson
+ * Copyright (c) 2016 Nikos Mavrogiannopoulos
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+
+#include "ipv6.h"
+#include "ipcalc.h"
+
+static const char *numtoquad(uint32_t num)
+{
+ static char quad[64];
+
+ num = htonl(num);
+ return inet_ntop(AF_INET, &num, quad, sizeof(quad));
+}
+
+void show_split_networks_v4(unsigned split_prefix, const struct ip_info_st *info, unsigned flags)
+{
+ char buf[64];
+ uint32_t diff, start, end;
+ size_t maxlen = 0;
+ unsigned count;
+ uint32_t splitmask = ntohl(prefix2mask(split_prefix));
+ uint32_t nmask = ntohl(prefix2mask(info->prefix));
+ struct in_addr net, broadcast;
+ unsigned jsonchain = JSON_FIRST;
+
+ if (splitmask < nmask) {
+ if (!beSilent)
+ fprintf(stderr, "Cannot subnet to /%d with this base network, use a prefix > /%d\n",
+ split_prefix, info->prefix);
+ exit(1);
+ }
+
+ output_start(&jsonchain);
+ array_start(&jsonchain, "Split networks", "SPLITNETWORK");
+
+ if (inet_pton(AF_INET, info->network, &net) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv4 address: %s\n", info->network);
+ exit(1);
+ }
+ net.s_addr = ntohl(net.s_addr);
+
+ if (inet_pton(AF_INET, info->broadcast, &broadcast) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad broadcast address: %s\n", info->broadcast);
+ exit(1);
+ }
+ broadcast.s_addr = ntohl(broadcast.s_addr);
+
+ diff = 0xffffffff - splitmask + 1;
+ start = net.s_addr;
+ end = net.s_addr + diff - 1;
+
+ /* broadcast here is used to get maximum hosts in network. Set it to start + 1 for /31. */
+ if (info->prefix == 31)
+ broadcast.s_addr = start + 1;
+
+ /* Figure out max width of a network string. */
+ while (1) {
+ size_t len;
+
+ len = snprintf(buf, sizeof(buf), "%s", numtoquad(start));
+ if (len > maxlen)
+ maxlen = len;
+
+ start += diff;
+ if (end == 0xffffffff || end >= broadcast.s_addr)
+ break;
+ end += diff;
+ }
+
+ start = net.s_addr;
+ end = net.s_addr + diff - 1;
+ count = 0;
+ while (1) {
+ if (!(flags & FLAG_NO_DECORATE) || (flags & FLAG_JSON)) {
+ default_printf(&jsonchain, "Network:\t", NULL, "%s/%u", numtoquad(start), split_prefix);
+ } else {
+ printf("%s/%u\n", numtoquad(start), split_prefix);
+ }
+
+ count++;
+ start += diff;
+ if (end == 0xffffffff || end >= broadcast.s_addr)
+ break;
+ end += diff;
+ }
+
+ array_stop(&jsonchain);
+
+ if ((!(flags & FLAG_NO_DECORATE)) || (flags & FLAG_JSON)) {
+ dist_printf(&jsonchain, "\nTotal: \t", "NETS", "%u", count);
+ dist_printf(&jsonchain, "Hosts/Net:\t", "ADDRESSES", "%s", ipv4_prefix_to_hosts(buf, sizeof(buf), split_prefix));
+ }
+
+ output_stop(&jsonchain);
+}
+
+static const char *ipv6tostr(struct in6_addr *ip)
+{
+ static char str[64];
+
+ return inet_ntop(AF_INET6, ip, str, sizeof(str));
+}
+
+void show_split_networks_v6(unsigned split_prefix, const struct ip_info_st *info, unsigned flags)
+{
+ int i, j, k;
+ unsigned count;
+ struct in6_addr splitmask, net, netmask, sdiff, ediff, start, end, tmpaddr, netlast;
+ char buf[32];
+ unsigned jsonchain = JSON_FIRST;
+
+ if (inet_pton(AF_INET6, info->network, &net) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 address: %s\n", info->network);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET6, info->hostmax, &netlast) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 address: %s\n", info->hostmax);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET6, info->netmask, &netmask) <= 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: bad IPv6 mask: %s\n", info->netmask);
+ exit(1);
+ }
+
+ if (ipv6_prefix_to_mask(split_prefix, &splitmask) < 0) {
+ if (!beSilent)
+ fprintf(stderr, "ipcalc: IPv6 prefix: %d\n", split_prefix);
+ exit(1);
+ }
+
+ i = 0;
+ j = 0;
+ do {
+ if (splitmask.s6_addr[i] > netmask.s6_addr[i])
+ j = 1;
+ if (netmask.s6_addr[i] > splitmask.s6_addr[i])
+ j = 2;
+ i++;
+ } while (i < 16 && !j);
+
+ if (j == 2) {
+ if (!beSilent)
+ fprintf(stderr, "Cannot subnet to /%d with this base network, use a prefix > /%d\n",
+ split_prefix, info->prefix);
+ exit(1);
+ }
+
+ memset(&sdiff, 0, sizeof(sdiff));
+ memset(&ediff, 0, sizeof(ediff));
+
+ for (i = 0; i < 16; i++) {
+ sdiff.s6_addr[i] = 0xff - splitmask.s6_addr[i];
+ end.s6_addr[i] = net.s6_addr[i] + sdiff.s6_addr[i];
+ }
+
+ memcpy(&start, &net, sizeof(net));
+ memcpy(&ediff, &sdiff, sizeof(sdiff));
+
+ memset(&tmpaddr, 0, sizeof(tmpaddr));
+ tmpaddr.s6_addr[15] = 1;
+ ipv6_add(&sdiff, &tmpaddr);
+
+ output_start(&jsonchain);
+
+ array_start(&jsonchain, "Split networks", "SPLITNETWORK");
+
+ i = count = 0;
+ while (!i) {
+ if (!(flags & FLAG_NO_DECORATE) || (flags & FLAG_JSON)) {
+ default_printf(&jsonchain, "Network:\t", NULL, "%s/%u", ipv6tostr(&start), split_prefix);
+ } else {
+ printf("%s/%u\n", ipv6tostr(&start), split_prefix);
+ }
+
+ ipv6_add(&start, &sdiff);
+
+ j = 0;
+ for (k = 0; k < 16; k+=2)
+ if (end.s6_addr[k] != 0xff && end.s6_addr[k+1] != 0xff)
+ j = 1;
+ if (!j)
+ i = 1;
+
+ j = 0;
+ k = 0;
+ do {
+ if (end.s6_addr[k] > netlast.s6_addr[k])
+ j = 1;
+ if (netlast.s6_addr[k] > end.s6_addr[k])
+ j = 2;
+ k++;
+ } while (k < 16 && !j);
+
+ if (!j || j == 1)
+ i = 1;
+
+ memset(&end, 0, sizeof(end));
+
+ ipv6_add(&end, &start);
+ ipv6_add(&end, &ediff);
+ count++;
+ }
+
+ array_stop(&jsonchain);
+
+ if ((!(flags & FLAG_NO_DECORATE)) || (flags & FLAG_JSON)) {
+ dist_printf(&jsonchain, "\nTotal: \t", "NETS", "%u", count);
+ dist_printf(&jsonchain, "Hosts/Net:\t", "ADDRESSES", "%s", ipv6_prefix_to_hosts(buf, sizeof(buf), split_prefix));
+ }
+
+ output_stop(&jsonchain);
+
+}
+
diff --git a/tests/12.15.1.5 b/tests/12.15.1.5
new file mode 100644
index 0000000..8272f43
--- /dev/null
+++ b/tests/12.15.1.5
@@ -0,0 +1,5 @@
+ADDRESS=12.15.1.5
+NETMASK=255.0.0.0
+PREFIX=8
+BROADCAST=12.255.255.255
+NETWORK=12.0.0.0
diff --git a/tests/129.15.31.5 b/tests/129.15.31.5
new file mode 100644
index 0000000..fa4a2df
--- /dev/null
+++ b/tests/129.15.31.5
@@ -0,0 +1,5 @@
+ADDRESS=129.15.31.5
+NETMASK=255.255.0.0
+PREFIX=16
+BROADCAST=129.15.255.255
+NETWORK=129.15.0.0
diff --git a/tests/192.168.1.5-16 b/tests/192.168.1.5-16
new file mode 100644
index 0000000..3d85627
--- /dev/null
+++ b/tests/192.168.1.5-16
@@ -0,0 +1,5 @@
+ADDRESS=10.100.4.1
+NETMASK=255.255.0.0
+PREFIX=16
+BROADCAST=10.100.255.255
+NETWORK=10.100.0.0
diff --git a/tests/192.168.1.5-24 b/tests/192.168.1.5-24
new file mode 100644
index 0000000..498101e
--- /dev/null
+++ b/tests/192.168.1.5-24
@@ -0,0 +1,5 @@
+ADDRESS=10.10.10.5
+NETMASK=255.255.255.0
+PREFIX=24
+BROADCAST=10.10.10.255
+NETWORK=10.10.10.0
diff --git a/tests/192.168.1.5-30 b/tests/192.168.1.5-30
new file mode 100644
index 0000000..3fc77b6
--- /dev/null
+++ b/tests/192.168.1.5-30
@@ -0,0 +1,5 @@
+ADDRESS=10.100.4.1
+NETMASK=255.255.255.252
+PREFIX=30
+BROADCAST=10.100.4.3
+NETWORK=10.100.4.0
diff --git a/tests/192.168.1.5-31 b/tests/192.168.1.5-31
new file mode 100644
index 0000000..a56422c
--- /dev/null
+++ b/tests/192.168.1.5-31
@@ -0,0 +1,5 @@
+ADDRESS=192.168.1.5
+NETMASK=255.255.255.254
+PREFIX=31
+BROADCAST=255.255.255.255
+NETWORK=192.168.1.4
diff --git a/tests/192.168.1.5-8 b/tests/192.168.1.5-8
new file mode 100644
index 0000000..0fe1ef5
--- /dev/null
+++ b/tests/192.168.1.5-8
@@ -0,0 +1,5 @@
+ADDRESS=10.10.10.10
+NETMASK=255.0.0.0
+PREFIX=8
+BROADCAST=10.255.255.255
+NETWORK=10.0.0.0
diff --git a/tests/192.168.2.6 b/tests/192.168.2.6
new file mode 100644
index 0000000..9b642ff
--- /dev/null
+++ b/tests/192.168.2.6
@@ -0,0 +1,8 @@
+ADDRESS=192.168.2.6
+NETMASK=255.255.255.0
+PREFIX=24
+BROADCAST=192.168.2.255
+NETWORK=192.168.2.0
+MINADDR=192.168.2.1
+MAXADDR=192.168.2.254
+ADDRESSES=254
diff --git a/tests/192.168.2.7 b/tests/192.168.2.7
new file mode 100644
index 0000000..c3dc8a9
--- /dev/null
+++ b/tests/192.168.2.7
@@ -0,0 +1,8 @@
+192.168.2.7
+255.255.255.0
+24
+192.168.2.255
+192.168.2.0
+192.168.2.1
+192.168.2.254
+254
diff --git a/tests/193.92.150.3-24 b/tests/193.92.150.3-24
new file mode 100644
index 0000000..2906374
--- /dev/null
+++ b/tests/193.92.150.3-24
@@ -0,0 +1,6 @@
+ADDRESS=193.92.150.3
+NETMASK=255.255.255.0
+PREFIX=24
+BROADCAST=193.92.150.255
+NETWORK=193.92.150.0
+ADDRSPACE=Internet
diff --git a/tests/193.92.31.0 b/tests/193.92.31.0
new file mode 100644
index 0000000..a1b582e
--- /dev/null
+++ b/tests/193.92.31.0
@@ -0,0 +1,5 @@
+ADDRESS=193.92.31.0
+NETMASK=255.255.255.0
+PREFIX=24
+BROADCAST=193.92.31.255
+NETWORK=193.92.31.0
diff --git a/tests/all-info-192.168.2.7 b/tests/all-info-192.168.2.7
new file mode 100644
index 0000000..de80084
--- /dev/null
+++ b/tests/all-info-192.168.2.7
@@ -0,0 +1,11 @@
+Address: 192.168.2.7
+Network: 192.168.2.0/24
+Netmask: 255.255.255.0 = 24
+Broadcast: 192.168.2.255
+Reverse DNS: 2.168.192.in-addr.arpa.
+
+Address space: Private Use
+Address class: Class C
+HostMin: 192.168.2.1
+HostMax: 192.168.2.254
+Hosts/Net: 254
diff --git a/tests/deaggregate-192.168.2.0-192.168.3.255 b/tests/deaggregate-192.168.2.0-192.168.3.255
new file mode 100644
index 0000000..a4b77e0
--- /dev/null
+++ b/tests/deaggregate-192.168.2.0-192.168.3.255
@@ -0,0 +1,2 @@
+[Deaggregated networks]
+Network: 192.168.2.0/23
diff --git a/tests/deaggregate-192.168.2.33-192.168.3.2 b/tests/deaggregate-192.168.2.33-192.168.3.2
new file mode 100644
index 0000000..c95f330
--- /dev/null
+++ b/tests/deaggregate-192.168.2.33-192.168.3.2
@@ -0,0 +1,12 @@
+{
+ "DEAGGREGATEDNETWORK":[
+ "192.168.2.33/32",
+ "192.168.2.34/31",
+ "192.168.2.36/30",
+ "192.168.2.40/29",
+ "192.168.2.48/28",
+ "192.168.2.64/26",
+ "192.168.2.128/25",
+ "192.168.3.0/31",
+ "192.168.3.2/32"]
+}
diff --git a/tests/deaggregate-192.168.2.7-192.168.2.13 b/tests/deaggregate-192.168.2.7-192.168.2.13
new file mode 100644
index 0000000..ee382f7
--- /dev/null
+++ b/tests/deaggregate-192.168.2.7-192.168.2.13
@@ -0,0 +1,3 @@
+192.168.2.7/32
+192.168.2.8/30
+192.168.2.12/31
diff --git a/tests/deaggregate-2a03:2880:20:4f06:face::0-2a03:2880:20:4f06:face::fffe b/tests/deaggregate-2a03:2880:20:4f06:face::0-2a03:2880:20:4f06:face::fffe
new file mode 100644
index 0000000..ae5782b
--- /dev/null
+++ b/tests/deaggregate-2a03:2880:20:4f06:face::0-2a03:2880:20:4f06:face::fffe
@@ -0,0 +1,16 @@
+2a03:2880:20:4f06:face::/113
+2a03:2880:20:4f06:face::8000/114
+2a03:2880:20:4f06:face::c000/115
+2a03:2880:20:4f06:face::e000/116
+2a03:2880:20:4f06:face::f000/117
+2a03:2880:20:4f06:face::f800/118
+2a03:2880:20:4f06:face::fc00/119
+2a03:2880:20:4f06:face::fe00/120
+2a03:2880:20:4f06:face::ff00/121
+2a03:2880:20:4f06:face::ff80/122
+2a03:2880:20:4f06:face::ffc0/123
+2a03:2880:20:4f06:face::ffe0/124
+2a03:2880:20:4f06:face::fff0/125
+2a03:2880:20:4f06:face::fff8/126
+2a03:2880:20:4f06:face::fffc/127
+2a03:2880:20:4f06:face::fffe/128
diff --git a/tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:0-fcd3:57d1:733:c18f:b498:25e1:788:ffff b/tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:0-fcd3:57d1:733:c18f:b498:25e1:788:ffff
new file mode 100644
index 0000000..3731c48
--- /dev/null
+++ b/tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:0-fcd3:57d1:733:c18f:b498:25e1:788:ffff
@@ -0,0 +1,2 @@
+[Deaggregated networks]
+Network: fcd3:57d1:733:c18f:b498:25e1:788:0/112
diff --git a/tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:f-fcd3:57d1:733:c18f:b498:25e1:789:ffa9 b/tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:f-fcd3:57d1:733:c18f:b498:25e1:789:ffa9
new file mode 100644
index 0000000..d2bbed3
--- /dev/null
+++ b/tests/deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:f-fcd3:57d1:733:c18f:b498:25e1:789:ffa9
@@ -0,0 +1,28 @@
+{
+ "DEAGGREGATEDNETWORK":[
+ "fcd3:57d1:733:c18f:b498:25e1:788:f/128",
+ "fcd3:57d1:733:c18f:b498:25e1:788:10/124",
+ "fcd3:57d1:733:c18f:b498:25e1:788:20/123",
+ "fcd3:57d1:733:c18f:b498:25e1:788:40/122",
+ "fcd3:57d1:733:c18f:b498:25e1:788:80/121",
+ "fcd3:57d1:733:c18f:b498:25e1:788:100/120",
+ "fcd3:57d1:733:c18f:b498:25e1:788:200/119",
+ "fcd3:57d1:733:c18f:b498:25e1:788:400/118",
+ "fcd3:57d1:733:c18f:b498:25e1:788:800/117",
+ "fcd3:57d1:733:c18f:b498:25e1:788:1000/116",
+ "fcd3:57d1:733:c18f:b498:25e1:788:2000/115",
+ "fcd3:57d1:733:c18f:b498:25e1:788:4000/114",
+ "fcd3:57d1:733:c18f:b498:25e1:788:8000/113",
+ "fcd3:57d1:733:c18f:b498:25e1:789:0/113",
+ "fcd3:57d1:733:c18f:b498:25e1:789:8000/114",
+ "fcd3:57d1:733:c18f:b498:25e1:789:c000/115",
+ "fcd3:57d1:733:c18f:b498:25e1:789:e000/116",
+ "fcd3:57d1:733:c18f:b498:25e1:789:f000/117",
+ "fcd3:57d1:733:c18f:b498:25e1:789:f800/118",
+ "fcd3:57d1:733:c18f:b498:25e1:789:fc00/119",
+ "fcd3:57d1:733:c18f:b498:25e1:789:fe00/120",
+ "fcd3:57d1:733:c18f:b498:25e1:789:ff00/121",
+ "fcd3:57d1:733:c18f:b498:25e1:789:ff80/123",
+ "fcd3:57d1:733:c18f:b498:25e1:789:ffa0/125",
+ "fcd3:57d1:733:c18f:b498:25e1:789:ffa8/127"]
+}
diff --git a/tests/fd0b:a336:4e7d::-48 b/tests/fd0b:a336:4e7d::-48
new file mode 100644
index 0000000..8d644d7
--- /dev/null
+++ b/tests/fd0b:a336:4e7d::-48
@@ -0,0 +1,5 @@
+ADDRESS=fd0b:a336:4e7d::
+NETMASK=ffff:ffff:ffff::
+PREFIX=48
+NETWORK=fd0b:a336:4e7d::
+ADDRSPACE="Unique Local Unicast"
diff --git a/tests/fd95:6be5:0ae0:84a5::-64 b/tests/fd95:6be5:0ae0:84a5::-64
new file mode 100644
index 0000000..92de440
--- /dev/null
+++ b/tests/fd95:6be5:0ae0:84a5::-64
@@ -0,0 +1,5 @@
+ADDRESS=fd95:6be5:ae0:84a5::
+NETMASK=ffff:ffff:ffff:ffff::
+PREFIX=64
+NETWORK=fd95:6be5:ae0:84a5::
+ADDRSPACE="Unique Local Unicast"
diff --git a/tests/hostname-localhost-ipv4 b/tests/hostname-localhost-ipv4
new file mode 100644
index 0000000..bc5e5ff
--- /dev/null
+++ b/tests/hostname-localhost-ipv4
@@ -0,0 +1 @@
+ADDRESS=127.0.0.1
diff --git a/tests/hostname-localhost-ipv4-json b/tests/hostname-localhost-ipv4-json
new file mode 100644
index 0000000..563aa6c
--- /dev/null
+++ b/tests/hostname-localhost-ipv4-json
@@ -0,0 +1,11 @@
+{
+ "ADDRESS":"127.0.0.1",
+ "NETWORK":"127.0.0.1",
+ "NETMASK":"255.255.255.255",
+ "PREFIX":"32",
+ "BROADCAST":"127.0.0.1",
+ "ADDRSPACE":"Loopback",
+ "MINADDR":"127.0.0.1",
+ "MAXADDR":"127.0.0.1",
+ "ADDRESSES":"1"
+}
diff --git a/tests/hostname-localhost-ipv6 b/tests/hostname-localhost-ipv6
new file mode 100644
index 0000000..6eca333
--- /dev/null
+++ b/tests/hostname-localhost-ipv6
@@ -0,0 +1 @@
+ADDRESS=::1
diff --git a/tests/i-0.0.0.1 b/tests/i-0.0.0.1
new file mode 100644
index 0000000..2a0daf2
--- /dev/null
+++ b/tests/i-0.0.0.1
@@ -0,0 +1,2 @@
+Address: 0.0.0.1
+Address space: This host on this network
diff --git a/tests/i-10.0.0.1 b/tests/i-10.0.0.1
new file mode 100644
index 0000000..cc96eea
--- /dev/null
+++ b/tests/i-10.0.0.1
@@ -0,0 +1,2 @@
+Address: 10.0.0.1
+Address space: Private Use
diff --git a/tests/i-100.64.0.1 b/tests/i-100.64.0.1
new file mode 100644
index 0000000..81ccbce
--- /dev/null
+++ b/tests/i-100.64.0.1
@@ -0,0 +1,2 @@
+Address: 100.64.0.1
+Address space: Shared Address Space
diff --git a/tests/i-127.0.0.1 b/tests/i-127.0.0.1
new file mode 100644
index 0000000..02155c1
--- /dev/null
+++ b/tests/i-127.0.0.1
@@ -0,0 +1,2 @@
+Address: 127.0.0.1
+Address space: Loopback
diff --git a/tests/i-127.0.1.1 b/tests/i-127.0.1.1
new file mode 100644
index 0000000..7d6f871
--- /dev/null
+++ b/tests/i-127.0.1.1
@@ -0,0 +1,2 @@
+Address: 127.0.1.1
+Address space: Loopback
diff --git a/tests/i-169.254.0.1 b/tests/i-169.254.0.1
new file mode 100644
index 0000000..0f92b14
--- /dev/null
+++ b/tests/i-169.254.0.1
@@ -0,0 +1,2 @@
+Address: 169.254.0.1
+Address space: Link Local
diff --git a/tests/i-172.16.0.1 b/tests/i-172.16.0.1
new file mode 100644
index 0000000..508a71f
--- /dev/null
+++ b/tests/i-172.16.0.1
@@ -0,0 +1,2 @@
+Address: 172.16.0.1
+Address space: Private Use
diff --git a/tests/i-172.31.255.254 b/tests/i-172.31.255.254
new file mode 100644
index 0000000..db339ba
--- /dev/null
+++ b/tests/i-172.31.255.254
@@ -0,0 +1,2 @@
+Address: 172.31.255.254
+Address space: Private Use
diff --git a/tests/i-192.0.0.1 b/tests/i-192.0.0.1
new file mode 100644
index 0000000..14370ef
--- /dev/null
+++ b/tests/i-192.0.0.1
@@ -0,0 +1,2 @@
+Address: 192.0.0.1
+Address space: IETF Protocol Assignments
diff --git a/tests/i-192.0.0.10 b/tests/i-192.0.0.10
new file mode 100644
index 0000000..3e91ba5
--- /dev/null
+++ b/tests/i-192.0.0.10
@@ -0,0 +1,2 @@
+Address: 192.0.0.10
+Address space: Traversal Using Relays around NAT Anycast
diff --git a/tests/i-192.0.0.170 b/tests/i-192.0.0.170
new file mode 100644
index 0000000..ab8584c
--- /dev/null
+++ b/tests/i-192.0.0.170
@@ -0,0 +1,2 @@
+Address: 192.0.0.170
+Address space: NAT64/DNS64 Discovery
diff --git a/tests/i-192.0.0.171 b/tests/i-192.0.0.171
new file mode 100644
index 0000000..7cba65c
--- /dev/null
+++ b/tests/i-192.0.0.171
@@ -0,0 +1,2 @@
+Address: 192.0.0.171
+Address space: NAT64/DNS64 Discovery
diff --git a/tests/i-192.0.0.254 b/tests/i-192.0.0.254
new file mode 100644
index 0000000..03641c2
--- /dev/null
+++ b/tests/i-192.0.0.254
@@ -0,0 +1,2 @@
+Address: 192.0.0.254
+Address space: IETF Protocol Assignments
diff --git a/tests/i-192.0.0.6 b/tests/i-192.0.0.6
new file mode 100644
index 0000000..c30affd
--- /dev/null
+++ b/tests/i-192.0.0.6
@@ -0,0 +1,2 @@
+Address: 192.0.0.6
+Address space: IPv4 Service Continuity Prefix
diff --git a/tests/i-192.0.0.8 b/tests/i-192.0.0.8
new file mode 100644
index 0000000..cc3925b
--- /dev/null
+++ b/tests/i-192.0.0.8
@@ -0,0 +1,2 @@
+Address: 192.0.0.8
+Address space: IPv4 dummy address
diff --git a/tests/i-192.0.0.9 b/tests/i-192.0.0.9
new file mode 100644
index 0000000..52a2513
--- /dev/null
+++ b/tests/i-192.0.0.9
@@ -0,0 +1,2 @@
+Address: 192.0.0.9
+Address space: Port Control Protocol Anycast
diff --git a/tests/i-192.0.2.1 b/tests/i-192.0.2.1
new file mode 100644
index 0000000..9eadfed
--- /dev/null
+++ b/tests/i-192.0.2.1
@@ -0,0 +1,2 @@
+Address: 192.0.2.1
+Address space: Documentation (TEST-NET-1)
diff --git a/tests/i-192.168.0.1 b/tests/i-192.168.0.1
new file mode 100644
index 0000000..366f180
--- /dev/null
+++ b/tests/i-192.168.0.1
@@ -0,0 +1,2 @@
+Address: 192.168.0.1
+Address space: Private Use
diff --git a/tests/i-192.175.48.12 b/tests/i-192.175.48.12
new file mode 100644
index 0000000..a7c1d9f
--- /dev/null
+++ b/tests/i-192.175.48.12
@@ -0,0 +1,2 @@
+Address: 192.175.48.12
+Address space: Direct Delegation AS112 Service
diff --git a/tests/i-192.31.196.1 b/tests/i-192.31.196.1
new file mode 100644
index 0000000..1e817b5
--- /dev/null
+++ b/tests/i-192.31.196.1
@@ -0,0 +1,2 @@
+Address: 192.31.196.1
+Address space: AS112-v4
diff --git a/tests/i-192.52.193.5 b/tests/i-192.52.193.5
new file mode 100644
index 0000000..0eaeacd
--- /dev/null
+++ b/tests/i-192.52.193.5
@@ -0,0 +1,2 @@
+Address: 192.52.193.5
+Address space: AMT
diff --git a/tests/i-192.88.99.1 b/tests/i-192.88.99.1
new file mode 100644
index 0000000..5ddcf09
--- /dev/null
+++ b/tests/i-192.88.99.1
@@ -0,0 +1,2 @@
+Address: 192.88.99.1
+Address space: 6 to 4 Relay Anycast (Deprecated)
diff --git a/tests/i-198.18.0.1 b/tests/i-198.18.0.1
new file mode 100644
index 0000000..472945c
--- /dev/null
+++ b/tests/i-198.18.0.1
@@ -0,0 +1,2 @@
+Address: 198.18.0.1
+Address space: Benchmarking
diff --git a/tests/i-198.19.201.71 b/tests/i-198.19.201.71
new file mode 100644
index 0000000..d91bacc
--- /dev/null
+++ b/tests/i-198.19.201.71
@@ -0,0 +1,2 @@
+Address: 198.19.201.71
+Address space: Benchmarking
diff --git a/tests/i-198.19.255.254 b/tests/i-198.19.255.254
new file mode 100644
index 0000000..9151daf
--- /dev/null
+++ b/tests/i-198.19.255.254
@@ -0,0 +1,2 @@
+Address: 198.19.255.254
+Address space: Benchmarking
diff --git a/tests/i-198.51.100.1 b/tests/i-198.51.100.1
new file mode 100644
index 0000000..1a5ca38
--- /dev/null
+++ b/tests/i-198.51.100.1
@@ -0,0 +1,2 @@
+Address: 198.51.100.1
+Address space: Documentation (TEST-NET-2)
diff --git a/tests/i-2001:0:50::d78a:0:c b/tests/i-2001:0:50::d78a:0:c
new file mode 100644
index 0000000..d69118d
--- /dev/null
+++ b/tests/i-2001:0:50::d78a:0:c
@@ -0,0 +1,3 @@
+Full Address: 2001:0000:0050:0000:0000:d78a:0000:000c
+Address: 2001:0:50::d78a:0:c
+Address space: TEREDO
diff --git a/tests/i-2001:190:70::e86a:0:b b/tests/i-2001:190:70::e86a:0:b
new file mode 100644
index 0000000..d57aecc
--- /dev/null
+++ b/tests/i-2001:190:70::e86a:0:b
@@ -0,0 +1,3 @@
+Full Address: 2001:0190:0070:0000:0000:e86a:0000:000b
+Address: 2001:190:70::e86a:0:b
+Address space: IETF Protocol Assignments
diff --git a/tests/i-2001:1::1 b/tests/i-2001:1::1
new file mode 100644
index 0000000..0d162d0
--- /dev/null
+++ b/tests/i-2001:1::1
@@ -0,0 +1,3 @@
+Full Address: 2001:0001:0000:0000:0000:0000:0000:0001
+Address: 2001:1::1
+Address space: Port Control Protocol Anycast
diff --git a/tests/i-2001:1::2 b/tests/i-2001:1::2
new file mode 100644
index 0000000..2d17f28
--- /dev/null
+++ b/tests/i-2001:1::2
@@ -0,0 +1,3 @@
+Full Address: 2001:0001:0000:0000:0000:0000:0000:0002
+Address: 2001:1::2
+Address space: Traversal Using Relays around NAT Anycast
diff --git a/tests/i-2001:1e:ab:7:: b/tests/i-2001:1e:ab:7::
new file mode 100644
index 0000000..249cb97
--- /dev/null
+++ b/tests/i-2001:1e:ab:7::
@@ -0,0 +1,3 @@
+Full Address: 2001:001e:00ab:0007:0000:0000:0000:0000
+Address: 2001:1e:ab:7::
+Address space: Deprecated (previously ORCHID)
diff --git a/tests/i-2001:2:0:a::5:b7f b/tests/i-2001:2:0:a::5:b7f
new file mode 100644
index 0000000..8057a19
--- /dev/null
+++ b/tests/i-2001:2:0:a::5:b7f
@@ -0,0 +1,3 @@
+Full Address: 2001:0002:0000:000a:0000:0000:0005:0b7f
+Address: 2001:2:0:a::5:b7f
+Address space: Benchmarking
diff --git a/tests/i-2001:2c:ab:7:: b/tests/i-2001:2c:ab:7::
new file mode 100644
index 0000000..c84c2ab
--- /dev/null
+++ b/tests/i-2001:2c:ab:7::
@@ -0,0 +1,3 @@
+Full Address: 2001:002c:00ab:0007:0000:0000:0000:0000
+Address: 2001:2c:ab:7::
+Address space: ORCHIDv2
diff --git a/tests/i-2001:3:89:71::ab:1 b/tests/i-2001:3:89:71::ab:1
new file mode 100644
index 0000000..e7d5408
--- /dev/null
+++ b/tests/i-2001:3:89:71::ab:1
@@ -0,0 +1,3 @@
+Full Address: 2001:0003:0089:0071:0000:0000:00ab:0001
+Address: 2001:3:89:71::ab:1
+Address space: AMT
diff --git a/tests/i-2001:4:112::6483:bd12:9010 b/tests/i-2001:4:112::6483:bd12:9010
new file mode 100644
index 0000000..2f9a45c
--- /dev/null
+++ b/tests/i-2001:4:112::6483:bd12:9010
@@ -0,0 +1,3 @@
+Full Address: 2001:0004:0112:0000:0000:6483:bd12:9010
+Address: 2001:4:112::6483:bd12:9010
+Address space: AS112-v6
diff --git a/tests/i-2001:db8:329::4a b/tests/i-2001:db8:329::4a
new file mode 100644
index 0000000..b94f99d
--- /dev/null
+++ b/tests/i-2001:db8:329::4a
@@ -0,0 +1,3 @@
+Full Address: 2001:0db8:0329:0000:0000:0000:0000:004a
+Address: 2001:db8:329::4a
+Address space: Documentation
diff --git a/tests/i-2002::34 b/tests/i-2002::34
new file mode 100644
index 0000000..421801a
--- /dev/null
+++ b/tests/i-2002::34
@@ -0,0 +1,3 @@
+Full Address: 2002:0000:0000:0000:0000:0000:0000:0034
+Address: 2002::34
+Address space: 6to4
diff --git a/tests/i-203.0.113.1 b/tests/i-203.0.113.1
new file mode 100644
index 0000000..3945b60
--- /dev/null
+++ b/tests/i-203.0.113.1
@@ -0,0 +1,2 @@
+Address: 203.0.113.1
+Address space: Documentation (TEST-NET-3)
diff --git a/tests/i-224.0.0.1 b/tests/i-224.0.0.1
new file mode 100644
index 0000000..723ecf4
--- /dev/null
+++ b/tests/i-224.0.0.1
@@ -0,0 +1,2 @@
+Address: 224.0.0.1
+Address space: Multicast
diff --git a/tests/i-240.0.0.1 b/tests/i-240.0.0.1
new file mode 100644
index 0000000..4a93d4f
--- /dev/null
+++ b/tests/i-240.0.0.1
@@ -0,0 +1,2 @@
+Address: 240.0.0.1
+Address space: Reserved
diff --git a/tests/i-250.7.93.1 b/tests/i-250.7.93.1
new file mode 100644
index 0000000..e78e944
--- /dev/null
+++ b/tests/i-250.7.93.1
@@ -0,0 +1,2 @@
+Address: 250.7.93.1
+Address space: Reserved
diff --git a/tests/i-255.255.255.254 b/tests/i-255.255.255.254
new file mode 100644
index 0000000..61e1e90
--- /dev/null
+++ b/tests/i-255.255.255.254
@@ -0,0 +1,2 @@
+Address: 255.255.255.254
+Address space: Reserved
diff --git a/tests/i-255.255.255.255 b/tests/i-255.255.255.255
new file mode 100644
index 0000000..da812f4
--- /dev/null
+++ b/tests/i-255.255.255.255
@@ -0,0 +1,2 @@
+Address: 255.255.255.255
+Address space: Limited Broadcast
diff --git a/tests/i-2620:4f:8000::7372:ad1 b/tests/i-2620:4f:8000::7372:ad1
new file mode 100644
index 0000000..cd696b6
--- /dev/null
+++ b/tests/i-2620:4f:8000::7372:ad1
@@ -0,0 +1,3 @@
+Full Address: 2620:004f:8000:0000:0000:0000:7372:0ad1
+Address: 2620:4f:8000::7372:ad1
+Address space: Direct Delegation AS112 Service
diff --git a/tests/i-2a03:2880:20:4f06:face:b00c:0:1 b/tests/i-2a03:2880:20:4f06:face:b00c:0:1
new file mode 100644
index 0000000..0405afd
--- /dev/null
+++ b/tests/i-2a03:2880:20:4f06:face:b00c:0:1
@@ -0,0 +1,3 @@
+Full Address: 2a03:2880:0020:4f06:face:b00c:0000:0001
+Address: 2a03:2880:20:4f06:face:b00c:0:1
+Address space: Global Unicast
diff --git a/tests/i-3.130.45.15 b/tests/i-3.130.45.15
new file mode 100644
index 0000000..290d755
--- /dev/null
+++ b/tests/i-3.130.45.15
@@ -0,0 +1,2 @@
+Address: 3.130.45.15
+Address space: Internet
diff --git a/tests/i-64:ff9b:1:ea21:4316:55::1 b/tests/i-64:ff9b:1:ea21:4316:55::1
new file mode 100644
index 0000000..895d9bf
--- /dev/null
+++ b/tests/i-64:ff9b:1:ea21:4316:55::1
@@ -0,0 +1,3 @@
+Full Address: 0064:ff9b:0001:ea21:4316:0055:0000:0001
+Address: 64:ff9b:1:ea21:4316:55:0:1
+Address space: IPv4-IPv6 Translat.
diff --git a/tests/i-64:ff9b::2100:951a b/tests/i-64:ff9b::2100:951a
new file mode 100644
index 0000000..d10f3e7
--- /dev/null
+++ b/tests/i-64:ff9b::2100:951a
@@ -0,0 +1,3 @@
+Full Address: 0064:ff9b:0000:0000:0000:0000:2100:951a
+Address: 64:ff9b::2100:951a
+Address space: IPv4-IPv6 Translat.
diff --git a/tests/i-fc00:0:a001::bcdf:4 b/tests/i-fc00:0:a001::bcdf:4
new file mode 100644
index 0000000..b116df9
--- /dev/null
+++ b/tests/i-fc00:0:a001::bcdf:4
@@ -0,0 +1,3 @@
+Full Address: fc00:0000:a001:0000:0000:0000:bcdf:0004
+Address: fc00:0:a001::bcdf:4
+Address space: Unique Local Unicast
diff --git a/tests/i-fd0b:a336:4e7d::-48 b/tests/i-fd0b:a336:4e7d::-48
new file mode 100644
index 0000000..d2c2e71
--- /dev/null
+++ b/tests/i-fd0b:a336:4e7d::-48
@@ -0,0 +1,8 @@
+Full Network: fd0b:a336:4e7d:0000:0000:0000:0000:0000/48
+Network: fd0b:a336:4e7d::/48
+Netmask: ffff:ffff:ffff:: = 48
+
+Address space: Unique Local Unicast
+HostMin: fd0b:a336:4e7d::
+HostMax: fd0b:a336:4e7d:ffff:ffff:ffff:ffff:ffff
+Hosts/Net: 2^(80) = 1208925819614629174706176
diff --git a/tests/i-fe80::b:0:7acd:0:5 b/tests/i-fe80::b:0:7acd:0:5
new file mode 100644
index 0000000..fc0e55d
--- /dev/null
+++ b/tests/i-fe80::b:0:7acd:0:5
@@ -0,0 +1,3 @@
+Full Address: fe80:0000:0000:000b:0000:7acd:0000:0005
+Address: fe80::b:0:7acd:0:5
+Address space: Link-Scoped Unicast
diff --git a/tests/info-192.168.2.7 b/tests/info-192.168.2.7
new file mode 100644
index 0000000..4d0b0c2
--- /dev/null
+++ b/tests/info-192.168.2.7
@@ -0,0 +1,9 @@
+Address: 192.168.2.7
+Network: 192.168.2.0/24
+Netmask: 255.255.255.0 = 24
+Broadcast: 192.168.2.255
+
+Address space: Private Use
+HostMin: 192.168.2.1
+HostMax: 192.168.2.254
+Hosts/Net: 254
diff --git a/tests/ip-localhost-ipv4 b/tests/ip-localhost-ipv4
new file mode 100644
index 0000000..0b793e2
--- /dev/null
+++ b/tests/ip-localhost-ipv4
@@ -0,0 +1 @@
+HOSTNAME=localhost
diff --git a/tests/ip-localhost-ipv4-json b/tests/ip-localhost-ipv4-json
new file mode 100644
index 0000000..75cb285
--- /dev/null
+++ b/tests/ip-localhost-ipv4-json
@@ -0,0 +1,12 @@
+{
+ "ADDRESS":"127.0.0.1",
+ "HOSTNAME":"localhost",
+ "NETWORK":"127.0.0.1",
+ "NETMASK":"255.255.255.255",
+ "PREFIX":"32",
+ "BROADCAST":"127.0.0.1",
+ "ADDRSPACE":"Loopback",
+ "MINADDR":"127.0.0.1",
+ "MAXADDR":"127.0.0.1",
+ "ADDRESSES":"1"
+}
diff --git a/tests/ip-localhost-ipv6 b/tests/ip-localhost-ipv6
new file mode 100644
index 0000000..0b793e2
--- /dev/null
+++ b/tests/ip-localhost-ipv6
@@ -0,0 +1 @@
+HOSTNAME=localhost
diff --git a/tests/ipcalc-delegate-ipv6-random.sh b/tests/ipcalc-delegate-ipv6-random.sh
new file mode 100755
index 0000000..4083f3f
--- /dev/null
+++ b/tests/ipcalc-delegate-ipv6-random.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# Copyright (C) 2019 Nikos Mavrogiannopoulos
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>
+
+IPCALC="${IPCALC:-build/ipcalc}"
+
+set -e
+
+eval $(${IPCALC} -r 96 --prefix -n --minaddr --maxaddr)
+
+NEW=$(${IPCALC} -d "${MINADDR}-${MAXADDR}" --no-decorate)
+
+set +e
+
+if test "${NEW}" != "${NETWORK}/${PREFIX}";then
+ echo "Networks do not match"
+ exit 1
+fi
+
+exit 0
diff --git a/tests/ipcalc-delegate-split-ipv4.sh b/tests/ipcalc-delegate-split-ipv4.sh
new file mode 100755
index 0000000..1dbfcea
--- /dev/null
+++ b/tests/ipcalc-delegate-split-ipv4.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# Copyright (C) 2019 Nikos Mavrogiannopoulos
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>
+
+IPCALC="${IPCALC:-build/ipcalc}"
+
+set -e
+
+eval $(${IPCALC} -r 24 --prefix -n)
+HEAD=$(${IPCALC} -S 26 ${NETWORK}/${PREFIX} --no-decorate|head -1)
+TAIL=$(${IPCALC} -S 26 ${NETWORK}/${PREFIX} --no-decorate|tail -1)
+echo "Network: ${NETWORK}/${PREFIX}"
+
+export HEAD TAIL
+FIRST=$(${IPCALC} --no-decorate -n ${HEAD})
+LAST=$(${IPCALC} --no-decorate -b ${TAIL})
+
+export FIRST LAST
+NEW=$(${IPCALC} --no-decorate -d ${FIRST}-${LAST})
+echo "Calculated: ${NETWORK}/${PREFIX}"
+
+set +e
+
+if test "${NEW}" != "${NETWORK}/${PREFIX}";then
+ echo "Addresses do not match"
+ exit 1
+fi
+
+exit 0
diff --git a/tests/ipcalc-delegate-split-ipv6.sh b/tests/ipcalc-delegate-split-ipv6.sh
new file mode 100755
index 0000000..39d0a4e
--- /dev/null
+++ b/tests/ipcalc-delegate-split-ipv6.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# Copyright (C) 2019 Nikos Mavrogiannopoulos
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>
+
+IPCALC="${IPCALC:-build/ipcalc}"
+
+set -e
+
+eval $(${IPCALC} -r 56 --prefix -n)
+HEAD=$(${IPCALC} -S 64 ${NETWORK}/${PREFIX} --no-decorate|head -1)
+TAIL=$(${IPCALC} -S 64 ${NETWORK}/${PREFIX} --no-decorate|tail -1)
+echo "Network: ${NETWORK}/${PREFIX}"
+
+export HEAD TAIL
+FIRST=$(${IPCALC} --no-decorate --minaddr ${HEAD})
+LAST=$(${IPCALC} --no-decorate --maxaddr ${TAIL})
+
+export FIRST LAST
+NEW=$(${IPCALC} --no-decorate -d ${FIRST}-${LAST})
+echo "Calculated: ${NETWORK}/${PREFIX}"
+
+set +e
+
+if test "${NEW}" != "${NETWORK}/${PREFIX}";then
+ echo "Addresses do not match"
+ exit 1
+fi
+
+exit 0
diff --git a/tests/ipcalc-testrunner.sh b/tests/ipcalc-testrunner.sh
new file mode 100755
index 0000000..d5bc2fd
--- /dev/null
+++ b/tests/ipcalc-testrunner.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# This shell script is a simple test runner for ipcalc tests.
+#
+# Adapted from: Matej Susta <msusta@redhat.com>
+#
+# Copyright (c) 2009 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing
+# to use, modify, copy, or redistribute it subject to the terms
+# and conditions of the GNU General Public License version 2.
+#
+# This program is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+exitcode=0
+
+ok() {
+ echo "ok."
+}
+
+fail() {
+ echo "FAILED!"
+ exitcode=$((exitcode+1))
+ echo -e "Output was:\n$1"
+}
+
+TestSuccess() {
+ echo -n "Checking $@... "
+ output=$(sh -c "$1" 2>&1)
+ rc=$?
+ [ $rc -eq 0 ] && ok || fail $output
+}
+
+TestFailure() {
+ echo -n "Checking $@... "
+ output=$(sh -c "$1" 2>&1)
+ rc=$?
+ [ $rc -eq 0 ] && fail $output || ok
+}
+
+TestOutput() {
+ echo -n "Checking $1... "
+ output=$(sh -c "$1" 2>&1)
+ rc=$?
+ [ "$output" = "$2" ] && ok || fail $output
+}
+
+TestOutputFile() {
+ echo -n "Reading $2... "
+ [ -e "$2" ] || { fail "missing file $2"; return; }
+ contents="$(cat "$2" 2>/dev/null)"
+ [ -n "$contents" ] && ok || { fail "failed to read $2"; return; }
+ TestOutput "$1" "$contents"
+}
+
+TestEqual() {
+ TestSuccess "$1"
+ [ -n "$output" ] && output1="$output" || { fail "no output from $1"; return; }
+ TestSuccess "$2"
+ [ -n "$output" ] && output2="$output" || { fail "no output from $2"; return; }
+ echo -n "Comparing output... "
+ [ "$output1" = "$output2" ] && ok || fail "$output1 <> $output2"
+}
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ --test-success) TestSuccess "$2"; shift ;;
+ --test-failure) TestFailure "$2"; shift ;;
+ --test-output) TestOutput "$2" "$3"; shift; shift ;;
+ --test-outfile) TestOutputFile "$2" "$3"; shift; shift ;;
+ --test-equal) TestEqual "$2" "$3"; shift; shift ;;
+ *) fail "invalid argument: $1" ;;
+ esac
+ shift
+done
+
+echo "$exitcode test(s) failed."
+exit $exitcode
diff --git a/tests/json-i-2a03:2880:20:4f06:face:b00c:0:1-56 b/tests/json-i-2a03:2880:20:4f06:face:b00c:0:1-56
new file mode 100644
index 0000000..a00a5fa
--- /dev/null
+++ b/tests/json-i-2a03:2880:20:4f06:face:b00c:0:1-56
@@ -0,0 +1,12 @@
+{
+ "FULLADDRESS":"2a03:2880:0020:4f06:face:b00c:0000:0001",
+ "ADDRESS":"2a03:2880:20:4f06:face:b00c:0:1",
+ "FULLNETWORK":"2a03:2880:0020:4f00:0000:0000:0000:0000",
+ "NETWORK":"2a03:2880:20:4f00::",
+ "NETMASK":"ffff:ffff:ffff:ff00::",
+ "PREFIX":"56",
+ "ADDRSPACE":"Global Unicast",
+ "MINADDR":"2a03:2880:20:4f00::",
+ "MAXADDR":"2a03:2880:20:4fff:ffff:ffff:ffff:ffff",
+ "ADDRESSES":"4722366482869645213696"
+}
diff --git a/tests/json-nsplit-10.10.10.0-16-24 b/tests/json-nsplit-10.10.10.0-16-24
new file mode 100644
index 0000000..95b3db9
--- /dev/null
+++ b/tests/json-nsplit-10.10.10.0-16-24
@@ -0,0 +1,261 @@
+{
+ "SPLITNETWORK":[
+ "10.10.0.0/24",
+ "10.10.1.0/24",
+ "10.10.2.0/24",
+ "10.10.3.0/24",
+ "10.10.4.0/24",
+ "10.10.5.0/24",
+ "10.10.6.0/24",
+ "10.10.7.0/24",
+ "10.10.8.0/24",
+ "10.10.9.0/24",
+ "10.10.10.0/24",
+ "10.10.11.0/24",
+ "10.10.12.0/24",
+ "10.10.13.0/24",
+ "10.10.14.0/24",
+ "10.10.15.0/24",
+ "10.10.16.0/24",
+ "10.10.17.0/24",
+ "10.10.18.0/24",
+ "10.10.19.0/24",
+ "10.10.20.0/24",
+ "10.10.21.0/24",
+ "10.10.22.0/24",
+ "10.10.23.0/24",
+ "10.10.24.0/24",
+ "10.10.25.0/24",
+ "10.10.26.0/24",
+ "10.10.27.0/24",
+ "10.10.28.0/24",
+ "10.10.29.0/24",
+ "10.10.30.0/24",
+ "10.10.31.0/24",
+ "10.10.32.0/24",
+ "10.10.33.0/24",
+ "10.10.34.0/24",
+ "10.10.35.0/24",
+ "10.10.36.0/24",
+ "10.10.37.0/24",
+ "10.10.38.0/24",
+ "10.10.39.0/24",
+ "10.10.40.0/24",
+ "10.10.41.0/24",
+ "10.10.42.0/24",
+ "10.10.43.0/24",
+ "10.10.44.0/24",
+ "10.10.45.0/24",
+ "10.10.46.0/24",
+ "10.10.47.0/24",
+ "10.10.48.0/24",
+ "10.10.49.0/24",
+ "10.10.50.0/24",
+ "10.10.51.0/24",
+ "10.10.52.0/24",
+ "10.10.53.0/24",
+ "10.10.54.0/24",
+ "10.10.55.0/24",
+ "10.10.56.0/24",
+ "10.10.57.0/24",
+ "10.10.58.0/24",
+ "10.10.59.0/24",
+ "10.10.60.0/24",
+ "10.10.61.0/24",
+ "10.10.62.0/24",
+ "10.10.63.0/24",
+ "10.10.64.0/24",
+ "10.10.65.0/24",
+ "10.10.66.0/24",
+ "10.10.67.0/24",
+ "10.10.68.0/24",
+ "10.10.69.0/24",
+ "10.10.70.0/24",
+ "10.10.71.0/24",
+ "10.10.72.0/24",
+ "10.10.73.0/24",
+ "10.10.74.0/24",
+ "10.10.75.0/24",
+ "10.10.76.0/24",
+ "10.10.77.0/24",
+ "10.10.78.0/24",
+ "10.10.79.0/24",
+ "10.10.80.0/24",
+ "10.10.81.0/24",
+ "10.10.82.0/24",
+ "10.10.83.0/24",
+ "10.10.84.0/24",
+ "10.10.85.0/24",
+ "10.10.86.0/24",
+ "10.10.87.0/24",
+ "10.10.88.0/24",
+ "10.10.89.0/24",
+ "10.10.90.0/24",
+ "10.10.91.0/24",
+ "10.10.92.0/24",
+ "10.10.93.0/24",
+ "10.10.94.0/24",
+ "10.10.95.0/24",
+ "10.10.96.0/24",
+ "10.10.97.0/24",
+ "10.10.98.0/24",
+ "10.10.99.0/24",
+ "10.10.100.0/24",
+ "10.10.101.0/24",
+ "10.10.102.0/24",
+ "10.10.103.0/24",
+ "10.10.104.0/24",
+ "10.10.105.0/24",
+ "10.10.106.0/24",
+ "10.10.107.0/24",
+ "10.10.108.0/24",
+ "10.10.109.0/24",
+ "10.10.110.0/24",
+ "10.10.111.0/24",
+ "10.10.112.0/24",
+ "10.10.113.0/24",
+ "10.10.114.0/24",
+ "10.10.115.0/24",
+ "10.10.116.0/24",
+ "10.10.117.0/24",
+ "10.10.118.0/24",
+ "10.10.119.0/24",
+ "10.10.120.0/24",
+ "10.10.121.0/24",
+ "10.10.122.0/24",
+ "10.10.123.0/24",
+ "10.10.124.0/24",
+ "10.10.125.0/24",
+ "10.10.126.0/24",
+ "10.10.127.0/24",
+ "10.10.128.0/24",
+ "10.10.129.0/24",
+ "10.10.130.0/24",
+ "10.10.131.0/24",
+ "10.10.132.0/24",
+ "10.10.133.0/24",
+ "10.10.134.0/24",
+ "10.10.135.0/24",
+ "10.10.136.0/24",
+ "10.10.137.0/24",
+ "10.10.138.0/24",
+ "10.10.139.0/24",
+ "10.10.140.0/24",
+ "10.10.141.0/24",
+ "10.10.142.0/24",
+ "10.10.143.0/24",
+ "10.10.144.0/24",
+ "10.10.145.0/24",
+ "10.10.146.0/24",
+ "10.10.147.0/24",
+ "10.10.148.0/24",
+ "10.10.149.0/24",
+ "10.10.150.0/24",
+ "10.10.151.0/24",
+ "10.10.152.0/24",
+ "10.10.153.0/24",
+ "10.10.154.0/24",
+ "10.10.155.0/24",
+ "10.10.156.0/24",
+ "10.10.157.0/24",
+ "10.10.158.0/24",
+ "10.10.159.0/24",
+ "10.10.160.0/24",
+ "10.10.161.0/24",
+ "10.10.162.0/24",
+ "10.10.163.0/24",
+ "10.10.164.0/24",
+ "10.10.165.0/24",
+ "10.10.166.0/24",
+ "10.10.167.0/24",
+ "10.10.168.0/24",
+ "10.10.169.0/24",
+ "10.10.170.0/24",
+ "10.10.171.0/24",
+ "10.10.172.0/24",
+ "10.10.173.0/24",
+ "10.10.174.0/24",
+ "10.10.175.0/24",
+ "10.10.176.0/24",
+ "10.10.177.0/24",
+ "10.10.178.0/24",
+ "10.10.179.0/24",
+ "10.10.180.0/24",
+ "10.10.181.0/24",
+ "10.10.182.0/24",
+ "10.10.183.0/24",
+ "10.10.184.0/24",
+ "10.10.185.0/24",
+ "10.10.186.0/24",
+ "10.10.187.0/24",
+ "10.10.188.0/24",
+ "10.10.189.0/24",
+ "10.10.190.0/24",
+ "10.10.191.0/24",
+ "10.10.192.0/24",
+ "10.10.193.0/24",
+ "10.10.194.0/24",
+ "10.10.195.0/24",
+ "10.10.196.0/24",
+ "10.10.197.0/24",
+ "10.10.198.0/24",
+ "10.10.199.0/24",
+ "10.10.200.0/24",
+ "10.10.201.0/24",
+ "10.10.202.0/24",
+ "10.10.203.0/24",
+ "10.10.204.0/24",
+ "10.10.205.0/24",
+ "10.10.206.0/24",
+ "10.10.207.0/24",
+ "10.10.208.0/24",
+ "10.10.209.0/24",
+ "10.10.210.0/24",
+ "10.10.211.0/24",
+ "10.10.212.0/24",
+ "10.10.213.0/24",
+ "10.10.214.0/24",
+ "10.10.215.0/24",
+ "10.10.216.0/24",
+ "10.10.217.0/24",
+ "10.10.218.0/24",
+ "10.10.219.0/24",
+ "10.10.220.0/24",
+ "10.10.221.0/24",
+ "10.10.222.0/24",
+ "10.10.223.0/24",
+ "10.10.224.0/24",
+ "10.10.225.0/24",
+ "10.10.226.0/24",
+ "10.10.227.0/24",
+ "10.10.228.0/24",
+ "10.10.229.0/24",
+ "10.10.230.0/24",
+ "10.10.231.0/24",
+ "10.10.232.0/24",
+ "10.10.233.0/24",
+ "10.10.234.0/24",
+ "10.10.235.0/24",
+ "10.10.236.0/24",
+ "10.10.237.0/24",
+ "10.10.238.0/24",
+ "10.10.239.0/24",
+ "10.10.240.0/24",
+ "10.10.241.0/24",
+ "10.10.242.0/24",
+ "10.10.243.0/24",
+ "10.10.244.0/24",
+ "10.10.245.0/24",
+ "10.10.246.0/24",
+ "10.10.247.0/24",
+ "10.10.248.0/24",
+ "10.10.249.0/24",
+ "10.10.250.0/24",
+ "10.10.251.0/24",
+ "10.10.252.0/24",
+ "10.10.253.0/24",
+ "10.10.254.0/24",
+ "10.10.255.0/24"],
+ "NETS":"256",
+ "ADDRESSES":"254"
+}
diff --git a/tests/json-nsplit-192.168.5.45-24-26 b/tests/json-nsplit-192.168.5.45-24-26
new file mode 100644
index 0000000..1726822
--- /dev/null
+++ b/tests/json-nsplit-192.168.5.45-24-26
@@ -0,0 +1,9 @@
+{
+ "SPLITNETWORK":[
+ "192.168.5.0/26",
+ "192.168.5.64/26",
+ "192.168.5.128/26",
+ "192.168.5.192/26"],
+ "NETS":"4",
+ "ADDRESSES":"62"
+}
diff --git a/tests/json-nsplit-2a03:2880:20:4f06:face::-56-64 b/tests/json-nsplit-2a03:2880:20:4f06:face::-56-64
new file mode 100644
index 0000000..4aed1c7
--- /dev/null
+++ b/tests/json-nsplit-2a03:2880:20:4f06:face::-56-64
@@ -0,0 +1,261 @@
+{
+ "SPLITNETWORK":[
+ "2a03:2880:20:4f00::/64",
+ "2a03:2880:20:4f01::/64",
+ "2a03:2880:20:4f02::/64",
+ "2a03:2880:20:4f03::/64",
+ "2a03:2880:20:4f04::/64",
+ "2a03:2880:20:4f05::/64",
+ "2a03:2880:20:4f06::/64",
+ "2a03:2880:20:4f07::/64",
+ "2a03:2880:20:4f08::/64",
+ "2a03:2880:20:4f09::/64",
+ "2a03:2880:20:4f0a::/64",
+ "2a03:2880:20:4f0b::/64",
+ "2a03:2880:20:4f0c::/64",
+ "2a03:2880:20:4f0d::/64",
+ "2a03:2880:20:4f0e::/64",
+ "2a03:2880:20:4f0f::/64",
+ "2a03:2880:20:4f10::/64",
+ "2a03:2880:20:4f11::/64",
+ "2a03:2880:20:4f12::/64",
+ "2a03:2880:20:4f13::/64",
+ "2a03:2880:20:4f14::/64",
+ "2a03:2880:20:4f15::/64",
+ "2a03:2880:20:4f16::/64",
+ "2a03:2880:20:4f17::/64",
+ "2a03:2880:20:4f18::/64",
+ "2a03:2880:20:4f19::/64",
+ "2a03:2880:20:4f1a::/64",
+ "2a03:2880:20:4f1b::/64",
+ "2a03:2880:20:4f1c::/64",
+ "2a03:2880:20:4f1d::/64",
+ "2a03:2880:20:4f1e::/64",
+ "2a03:2880:20:4f1f::/64",
+ "2a03:2880:20:4f20::/64",
+ "2a03:2880:20:4f21::/64",
+ "2a03:2880:20:4f22::/64",
+ "2a03:2880:20:4f23::/64",
+ "2a03:2880:20:4f24::/64",
+ "2a03:2880:20:4f25::/64",
+ "2a03:2880:20:4f26::/64",
+ "2a03:2880:20:4f27::/64",
+ "2a03:2880:20:4f28::/64",
+ "2a03:2880:20:4f29::/64",
+ "2a03:2880:20:4f2a::/64",
+ "2a03:2880:20:4f2b::/64",
+ "2a03:2880:20:4f2c::/64",
+ "2a03:2880:20:4f2d::/64",
+ "2a03:2880:20:4f2e::/64",
+ "2a03:2880:20:4f2f::/64",
+ "2a03:2880:20:4f30::/64",
+ "2a03:2880:20:4f31::/64",
+ "2a03:2880:20:4f32::/64",
+ "2a03:2880:20:4f33::/64",
+ "2a03:2880:20:4f34::/64",
+ "2a03:2880:20:4f35::/64",
+ "2a03:2880:20:4f36::/64",
+ "2a03:2880:20:4f37::/64",
+ "2a03:2880:20:4f38::/64",
+ "2a03:2880:20:4f39::/64",
+ "2a03:2880:20:4f3a::/64",
+ "2a03:2880:20:4f3b::/64",
+ "2a03:2880:20:4f3c::/64",
+ "2a03:2880:20:4f3d::/64",
+ "2a03:2880:20:4f3e::/64",
+ "2a03:2880:20:4f3f::/64",
+ "2a03:2880:20:4f40::/64",
+ "2a03:2880:20:4f41::/64",
+ "2a03:2880:20:4f42::/64",
+ "2a03:2880:20:4f43::/64",
+ "2a03:2880:20:4f44::/64",
+ "2a03:2880:20:4f45::/64",
+ "2a03:2880:20:4f46::/64",
+ "2a03:2880:20:4f47::/64",
+ "2a03:2880:20:4f48::/64",
+ "2a03:2880:20:4f49::/64",
+ "2a03:2880:20:4f4a::/64",
+ "2a03:2880:20:4f4b::/64",
+ "2a03:2880:20:4f4c::/64",
+ "2a03:2880:20:4f4d::/64",
+ "2a03:2880:20:4f4e::/64",
+ "2a03:2880:20:4f4f::/64",
+ "2a03:2880:20:4f50::/64",
+ "2a03:2880:20:4f51::/64",
+ "2a03:2880:20:4f52::/64",
+ "2a03:2880:20:4f53::/64",
+ "2a03:2880:20:4f54::/64",
+ "2a03:2880:20:4f55::/64",
+ "2a03:2880:20:4f56::/64",
+ "2a03:2880:20:4f57::/64",
+ "2a03:2880:20:4f58::/64",
+ "2a03:2880:20:4f59::/64",
+ "2a03:2880:20:4f5a::/64",
+ "2a03:2880:20:4f5b::/64",
+ "2a03:2880:20:4f5c::/64",
+ "2a03:2880:20:4f5d::/64",
+ "2a03:2880:20:4f5e::/64",
+ "2a03:2880:20:4f5f::/64",
+ "2a03:2880:20:4f60::/64",
+ "2a03:2880:20:4f61::/64",
+ "2a03:2880:20:4f62::/64",
+ "2a03:2880:20:4f63::/64",
+ "2a03:2880:20:4f64::/64",
+ "2a03:2880:20:4f65::/64",
+ "2a03:2880:20:4f66::/64",
+ "2a03:2880:20:4f67::/64",
+ "2a03:2880:20:4f68::/64",
+ "2a03:2880:20:4f69::/64",
+ "2a03:2880:20:4f6a::/64",
+ "2a03:2880:20:4f6b::/64",
+ "2a03:2880:20:4f6c::/64",
+ "2a03:2880:20:4f6d::/64",
+ "2a03:2880:20:4f6e::/64",
+ "2a03:2880:20:4f6f::/64",
+ "2a03:2880:20:4f70::/64",
+ "2a03:2880:20:4f71::/64",
+ "2a03:2880:20:4f72::/64",
+ "2a03:2880:20:4f73::/64",
+ "2a03:2880:20:4f74::/64",
+ "2a03:2880:20:4f75::/64",
+ "2a03:2880:20:4f76::/64",
+ "2a03:2880:20:4f77::/64",
+ "2a03:2880:20:4f78::/64",
+ "2a03:2880:20:4f79::/64",
+ "2a03:2880:20:4f7a::/64",
+ "2a03:2880:20:4f7b::/64",
+ "2a03:2880:20:4f7c::/64",
+ "2a03:2880:20:4f7d::/64",
+ "2a03:2880:20:4f7e::/64",
+ "2a03:2880:20:4f7f::/64",
+ "2a03:2880:20:4f80::/64",
+ "2a03:2880:20:4f81::/64",
+ "2a03:2880:20:4f82::/64",
+ "2a03:2880:20:4f83::/64",
+ "2a03:2880:20:4f84::/64",
+ "2a03:2880:20:4f85::/64",
+ "2a03:2880:20:4f86::/64",
+ "2a03:2880:20:4f87::/64",
+ "2a03:2880:20:4f88::/64",
+ "2a03:2880:20:4f89::/64",
+ "2a03:2880:20:4f8a::/64",
+ "2a03:2880:20:4f8b::/64",
+ "2a03:2880:20:4f8c::/64",
+ "2a03:2880:20:4f8d::/64",
+ "2a03:2880:20:4f8e::/64",
+ "2a03:2880:20:4f8f::/64",
+ "2a03:2880:20:4f90::/64",
+ "2a03:2880:20:4f91::/64",
+ "2a03:2880:20:4f92::/64",
+ "2a03:2880:20:4f93::/64",
+ "2a03:2880:20:4f94::/64",
+ "2a03:2880:20:4f95::/64",
+ "2a03:2880:20:4f96::/64",
+ "2a03:2880:20:4f97::/64",
+ "2a03:2880:20:4f98::/64",
+ "2a03:2880:20:4f99::/64",
+ "2a03:2880:20:4f9a::/64",
+ "2a03:2880:20:4f9b::/64",
+ "2a03:2880:20:4f9c::/64",
+ "2a03:2880:20:4f9d::/64",
+ "2a03:2880:20:4f9e::/64",
+ "2a03:2880:20:4f9f::/64",
+ "2a03:2880:20:4fa0::/64",
+ "2a03:2880:20:4fa1::/64",
+ "2a03:2880:20:4fa2::/64",
+ "2a03:2880:20:4fa3::/64",
+ "2a03:2880:20:4fa4::/64",
+ "2a03:2880:20:4fa5::/64",
+ "2a03:2880:20:4fa6::/64",
+ "2a03:2880:20:4fa7::/64",
+ "2a03:2880:20:4fa8::/64",
+ "2a03:2880:20:4fa9::/64",
+ "2a03:2880:20:4faa::/64",
+ "2a03:2880:20:4fab::/64",
+ "2a03:2880:20:4fac::/64",
+ "2a03:2880:20:4fad::/64",
+ "2a03:2880:20:4fae::/64",
+ "2a03:2880:20:4faf::/64",
+ "2a03:2880:20:4fb0::/64",
+ "2a03:2880:20:4fb1::/64",
+ "2a03:2880:20:4fb2::/64",
+ "2a03:2880:20:4fb3::/64",
+ "2a03:2880:20:4fb4::/64",
+ "2a03:2880:20:4fb5::/64",
+ "2a03:2880:20:4fb6::/64",
+ "2a03:2880:20:4fb7::/64",
+ "2a03:2880:20:4fb8::/64",
+ "2a03:2880:20:4fb9::/64",
+ "2a03:2880:20:4fba::/64",
+ "2a03:2880:20:4fbb::/64",
+ "2a03:2880:20:4fbc::/64",
+ "2a03:2880:20:4fbd::/64",
+ "2a03:2880:20:4fbe::/64",
+ "2a03:2880:20:4fbf::/64",
+ "2a03:2880:20:4fc0::/64",
+ "2a03:2880:20:4fc1::/64",
+ "2a03:2880:20:4fc2::/64",
+ "2a03:2880:20:4fc3::/64",
+ "2a03:2880:20:4fc4::/64",
+ "2a03:2880:20:4fc5::/64",
+ "2a03:2880:20:4fc6::/64",
+ "2a03:2880:20:4fc7::/64",
+ "2a03:2880:20:4fc8::/64",
+ "2a03:2880:20:4fc9::/64",
+ "2a03:2880:20:4fca::/64",
+ "2a03:2880:20:4fcb::/64",
+ "2a03:2880:20:4fcc::/64",
+ "2a03:2880:20:4fcd::/64",
+ "2a03:2880:20:4fce::/64",
+ "2a03:2880:20:4fcf::/64",
+ "2a03:2880:20:4fd0::/64",
+ "2a03:2880:20:4fd1::/64",
+ "2a03:2880:20:4fd2::/64",
+ "2a03:2880:20:4fd3::/64",
+ "2a03:2880:20:4fd4::/64",
+ "2a03:2880:20:4fd5::/64",
+ "2a03:2880:20:4fd6::/64",
+ "2a03:2880:20:4fd7::/64",
+ "2a03:2880:20:4fd8::/64",
+ "2a03:2880:20:4fd9::/64",
+ "2a03:2880:20:4fda::/64",
+ "2a03:2880:20:4fdb::/64",
+ "2a03:2880:20:4fdc::/64",
+ "2a03:2880:20:4fdd::/64",
+ "2a03:2880:20:4fde::/64",
+ "2a03:2880:20:4fdf::/64",
+ "2a03:2880:20:4fe0::/64",
+ "2a03:2880:20:4fe1::/64",
+ "2a03:2880:20:4fe2::/64",
+ "2a03:2880:20:4fe3::/64",
+ "2a03:2880:20:4fe4::/64",
+ "2a03:2880:20:4fe5::/64",
+ "2a03:2880:20:4fe6::/64",
+ "2a03:2880:20:4fe7::/64",
+ "2a03:2880:20:4fe8::/64",
+ "2a03:2880:20:4fe9::/64",
+ "2a03:2880:20:4fea::/64",
+ "2a03:2880:20:4feb::/64",
+ "2a03:2880:20:4fec::/64",
+ "2a03:2880:20:4fed::/64",
+ "2a03:2880:20:4fee::/64",
+ "2a03:2880:20:4fef::/64",
+ "2a03:2880:20:4ff0::/64",
+ "2a03:2880:20:4ff1::/64",
+ "2a03:2880:20:4ff2::/64",
+ "2a03:2880:20:4ff3::/64",
+ "2a03:2880:20:4ff4::/64",
+ "2a03:2880:20:4ff5::/64",
+ "2a03:2880:20:4ff6::/64",
+ "2a03:2880:20:4ff7::/64",
+ "2a03:2880:20:4ff8::/64",
+ "2a03:2880:20:4ff9::/64",
+ "2a03:2880:20:4ffa::/64",
+ "2a03:2880:20:4ffb::/64",
+ "2a03:2880:20:4ffc::/64",
+ "2a03:2880:20:4ffd::/64",
+ "2a03:2880:20:4ffe::/64",
+ "2a03:2880:20:4fff::/64"],
+ "NETS":"256",
+ "ADDRESSES":"18446744073709551616"
+}
diff --git a/tests/json-split-10.10.10.0-16-24 b/tests/json-split-10.10.10.0-16-24
new file mode 100644
index 0000000..95b3db9
--- /dev/null
+++ b/tests/json-split-10.10.10.0-16-24
@@ -0,0 +1,261 @@
+{
+ "SPLITNETWORK":[
+ "10.10.0.0/24",
+ "10.10.1.0/24",
+ "10.10.2.0/24",
+ "10.10.3.0/24",
+ "10.10.4.0/24",
+ "10.10.5.0/24",
+ "10.10.6.0/24",
+ "10.10.7.0/24",
+ "10.10.8.0/24",
+ "10.10.9.0/24",
+ "10.10.10.0/24",
+ "10.10.11.0/24",
+ "10.10.12.0/24",
+ "10.10.13.0/24",
+ "10.10.14.0/24",
+ "10.10.15.0/24",
+ "10.10.16.0/24",
+ "10.10.17.0/24",
+ "10.10.18.0/24",
+ "10.10.19.0/24",
+ "10.10.20.0/24",
+ "10.10.21.0/24",
+ "10.10.22.0/24",
+ "10.10.23.0/24",
+ "10.10.24.0/24",
+ "10.10.25.0/24",
+ "10.10.26.0/24",
+ "10.10.27.0/24",
+ "10.10.28.0/24",
+ "10.10.29.0/24",
+ "10.10.30.0/24",
+ "10.10.31.0/24",
+ "10.10.32.0/24",
+ "10.10.33.0/24",
+ "10.10.34.0/24",
+ "10.10.35.0/24",
+ "10.10.36.0/24",
+ "10.10.37.0/24",
+ "10.10.38.0/24",
+ "10.10.39.0/24",
+ "10.10.40.0/24",
+ "10.10.41.0/24",
+ "10.10.42.0/24",
+ "10.10.43.0/24",
+ "10.10.44.0/24",
+ "10.10.45.0/24",
+ "10.10.46.0/24",
+ "10.10.47.0/24",
+ "10.10.48.0/24",
+ "10.10.49.0/24",
+ "10.10.50.0/24",
+ "10.10.51.0/24",
+ "10.10.52.0/24",
+ "10.10.53.0/24",
+ "10.10.54.0/24",
+ "10.10.55.0/24",
+ "10.10.56.0/24",
+ "10.10.57.0/24",
+ "10.10.58.0/24",
+ "10.10.59.0/24",
+ "10.10.60.0/24",
+ "10.10.61.0/24",
+ "10.10.62.0/24",
+ "10.10.63.0/24",
+ "10.10.64.0/24",
+ "10.10.65.0/24",
+ "10.10.66.0/24",
+ "10.10.67.0/24",
+ "10.10.68.0/24",
+ "10.10.69.0/24",
+ "10.10.70.0/24",
+ "10.10.71.0/24",
+ "10.10.72.0/24",
+ "10.10.73.0/24",
+ "10.10.74.0/24",
+ "10.10.75.0/24",
+ "10.10.76.0/24",
+ "10.10.77.0/24",
+ "10.10.78.0/24",
+ "10.10.79.0/24",
+ "10.10.80.0/24",
+ "10.10.81.0/24",
+ "10.10.82.0/24",
+ "10.10.83.0/24",
+ "10.10.84.0/24",
+ "10.10.85.0/24",
+ "10.10.86.0/24",
+ "10.10.87.0/24",
+ "10.10.88.0/24",
+ "10.10.89.0/24",
+ "10.10.90.0/24",
+ "10.10.91.0/24",
+ "10.10.92.0/24",
+ "10.10.93.0/24",
+ "10.10.94.0/24",
+ "10.10.95.0/24",
+ "10.10.96.0/24",
+ "10.10.97.0/24",
+ "10.10.98.0/24",
+ "10.10.99.0/24",
+ "10.10.100.0/24",
+ "10.10.101.0/24",
+ "10.10.102.0/24",
+ "10.10.103.0/24",
+ "10.10.104.0/24",
+ "10.10.105.0/24",
+ "10.10.106.0/24",
+ "10.10.107.0/24",
+ "10.10.108.0/24",
+ "10.10.109.0/24",
+ "10.10.110.0/24",
+ "10.10.111.0/24",
+ "10.10.112.0/24",
+ "10.10.113.0/24",
+ "10.10.114.0/24",
+ "10.10.115.0/24",
+ "10.10.116.0/24",
+ "10.10.117.0/24",
+ "10.10.118.0/24",
+ "10.10.119.0/24",
+ "10.10.120.0/24",
+ "10.10.121.0/24",
+ "10.10.122.0/24",
+ "10.10.123.0/24",
+ "10.10.124.0/24",
+ "10.10.125.0/24",
+ "10.10.126.0/24",
+ "10.10.127.0/24",
+ "10.10.128.0/24",
+ "10.10.129.0/24",
+ "10.10.130.0/24",
+ "10.10.131.0/24",
+ "10.10.132.0/24",
+ "10.10.133.0/24",
+ "10.10.134.0/24",
+ "10.10.135.0/24",
+ "10.10.136.0/24",
+ "10.10.137.0/24",
+ "10.10.138.0/24",
+ "10.10.139.0/24",
+ "10.10.140.0/24",
+ "10.10.141.0/24",
+ "10.10.142.0/24",
+ "10.10.143.0/24",
+ "10.10.144.0/24",
+ "10.10.145.0/24",
+ "10.10.146.0/24",
+ "10.10.147.0/24",
+ "10.10.148.0/24",
+ "10.10.149.0/24",
+ "10.10.150.0/24",
+ "10.10.151.0/24",
+ "10.10.152.0/24",
+ "10.10.153.0/24",
+ "10.10.154.0/24",
+ "10.10.155.0/24",
+ "10.10.156.0/24",
+ "10.10.157.0/24",
+ "10.10.158.0/24",
+ "10.10.159.0/24",
+ "10.10.160.0/24",
+ "10.10.161.0/24",
+ "10.10.162.0/24",
+ "10.10.163.0/24",
+ "10.10.164.0/24",
+ "10.10.165.0/24",
+ "10.10.166.0/24",
+ "10.10.167.0/24",
+ "10.10.168.0/24",
+ "10.10.169.0/24",
+ "10.10.170.0/24",
+ "10.10.171.0/24",
+ "10.10.172.0/24",
+ "10.10.173.0/24",
+ "10.10.174.0/24",
+ "10.10.175.0/24",
+ "10.10.176.0/24",
+ "10.10.177.0/24",
+ "10.10.178.0/24",
+ "10.10.179.0/24",
+ "10.10.180.0/24",
+ "10.10.181.0/24",
+ "10.10.182.0/24",
+ "10.10.183.0/24",
+ "10.10.184.0/24",
+ "10.10.185.0/24",
+ "10.10.186.0/24",
+ "10.10.187.0/24",
+ "10.10.188.0/24",
+ "10.10.189.0/24",
+ "10.10.190.0/24",
+ "10.10.191.0/24",
+ "10.10.192.0/24",
+ "10.10.193.0/24",
+ "10.10.194.0/24",
+ "10.10.195.0/24",
+ "10.10.196.0/24",
+ "10.10.197.0/24",
+ "10.10.198.0/24",
+ "10.10.199.0/24",
+ "10.10.200.0/24",
+ "10.10.201.0/24",
+ "10.10.202.0/24",
+ "10.10.203.0/24",
+ "10.10.204.0/24",
+ "10.10.205.0/24",
+ "10.10.206.0/24",
+ "10.10.207.0/24",
+ "10.10.208.0/24",
+ "10.10.209.0/24",
+ "10.10.210.0/24",
+ "10.10.211.0/24",
+ "10.10.212.0/24",
+ "10.10.213.0/24",
+ "10.10.214.0/24",
+ "10.10.215.0/24",
+ "10.10.216.0/24",
+ "10.10.217.0/24",
+ "10.10.218.0/24",
+ "10.10.219.0/24",
+ "10.10.220.0/24",
+ "10.10.221.0/24",
+ "10.10.222.0/24",
+ "10.10.223.0/24",
+ "10.10.224.0/24",
+ "10.10.225.0/24",
+ "10.10.226.0/24",
+ "10.10.227.0/24",
+ "10.10.228.0/24",
+ "10.10.229.0/24",
+ "10.10.230.0/24",
+ "10.10.231.0/24",
+ "10.10.232.0/24",
+ "10.10.233.0/24",
+ "10.10.234.0/24",
+ "10.10.235.0/24",
+ "10.10.236.0/24",
+ "10.10.237.0/24",
+ "10.10.238.0/24",
+ "10.10.239.0/24",
+ "10.10.240.0/24",
+ "10.10.241.0/24",
+ "10.10.242.0/24",
+ "10.10.243.0/24",
+ "10.10.244.0/24",
+ "10.10.245.0/24",
+ "10.10.246.0/24",
+ "10.10.247.0/24",
+ "10.10.248.0/24",
+ "10.10.249.0/24",
+ "10.10.250.0/24",
+ "10.10.251.0/24",
+ "10.10.252.0/24",
+ "10.10.253.0/24",
+ "10.10.254.0/24",
+ "10.10.255.0/24"],
+ "NETS":"256",
+ "ADDRESSES":"254"
+}
diff --git a/tests/json-split-192.168.5.45-24-26 b/tests/json-split-192.168.5.45-24-26
new file mode 100644
index 0000000..1726822
--- /dev/null
+++ b/tests/json-split-192.168.5.45-24-26
@@ -0,0 +1,9 @@
+{
+ "SPLITNETWORK":[
+ "192.168.5.0/26",
+ "192.168.5.64/26",
+ "192.168.5.128/26",
+ "192.168.5.192/26"],
+ "NETS":"4",
+ "ADDRESSES":"62"
+}
diff --git a/tests/json-split-2a03:2880:20:4f06:face::-56-64 b/tests/json-split-2a03:2880:20:4f06:face::-56-64
new file mode 100644
index 0000000..aeb294e
--- /dev/null
+++ b/tests/json-split-2a03:2880:20:4f06:face::-56-64
@@ -0,0 +1,261 @@
+{
+ "split_network":[
+ "2a03:2880:20:4f00::/64",
+ "2a03:2880:20:4f01::/64",
+ "2a03:2880:20:4f02::/64",
+ "2a03:2880:20:4f03::/64",
+ "2a03:2880:20:4f04::/64",
+ "2a03:2880:20:4f05::/64",
+ "2a03:2880:20:4f06::/64",
+ "2a03:2880:20:4f07::/64",
+ "2a03:2880:20:4f08::/64",
+ "2a03:2880:20:4f09::/64",
+ "2a03:2880:20:4f0a::/64",
+ "2a03:2880:20:4f0b::/64",
+ "2a03:2880:20:4f0c::/64",
+ "2a03:2880:20:4f0d::/64",
+ "2a03:2880:20:4f0e::/64",
+ "2a03:2880:20:4f0f::/64",
+ "2a03:2880:20:4f10::/64",
+ "2a03:2880:20:4f11::/64",
+ "2a03:2880:20:4f12::/64",
+ "2a03:2880:20:4f13::/64",
+ "2a03:2880:20:4f14::/64",
+ "2a03:2880:20:4f15::/64",
+ "2a03:2880:20:4f16::/64",
+ "2a03:2880:20:4f17::/64",
+ "2a03:2880:20:4f18::/64",
+ "2a03:2880:20:4f19::/64",
+ "2a03:2880:20:4f1a::/64",
+ "2a03:2880:20:4f1b::/64",
+ "2a03:2880:20:4f1c::/64",
+ "2a03:2880:20:4f1d::/64",
+ "2a03:2880:20:4f1e::/64",
+ "2a03:2880:20:4f1f::/64",
+ "2a03:2880:20:4f20::/64",
+ "2a03:2880:20:4f21::/64",
+ "2a03:2880:20:4f22::/64",
+ "2a03:2880:20:4f23::/64",
+ "2a03:2880:20:4f24::/64",
+ "2a03:2880:20:4f25::/64",
+ "2a03:2880:20:4f26::/64",
+ "2a03:2880:20:4f27::/64",
+ "2a03:2880:20:4f28::/64",
+ "2a03:2880:20:4f29::/64",
+ "2a03:2880:20:4f2a::/64",
+ "2a03:2880:20:4f2b::/64",
+ "2a03:2880:20:4f2c::/64",
+ "2a03:2880:20:4f2d::/64",
+ "2a03:2880:20:4f2e::/64",
+ "2a03:2880:20:4f2f::/64",
+ "2a03:2880:20:4f30::/64",
+ "2a03:2880:20:4f31::/64",
+ "2a03:2880:20:4f32::/64",
+ "2a03:2880:20:4f33::/64",
+ "2a03:2880:20:4f34::/64",
+ "2a03:2880:20:4f35::/64",
+ "2a03:2880:20:4f36::/64",
+ "2a03:2880:20:4f37::/64",
+ "2a03:2880:20:4f38::/64",
+ "2a03:2880:20:4f39::/64",
+ "2a03:2880:20:4f3a::/64",
+ "2a03:2880:20:4f3b::/64",
+ "2a03:2880:20:4f3c::/64",
+ "2a03:2880:20:4f3d::/64",
+ "2a03:2880:20:4f3e::/64",
+ "2a03:2880:20:4f3f::/64",
+ "2a03:2880:20:4f40::/64",
+ "2a03:2880:20:4f41::/64",
+ "2a03:2880:20:4f42::/64",
+ "2a03:2880:20:4f43::/64",
+ "2a03:2880:20:4f44::/64",
+ "2a03:2880:20:4f45::/64",
+ "2a03:2880:20:4f46::/64",
+ "2a03:2880:20:4f47::/64",
+ "2a03:2880:20:4f48::/64",
+ "2a03:2880:20:4f49::/64",
+ "2a03:2880:20:4f4a::/64",
+ "2a03:2880:20:4f4b::/64",
+ "2a03:2880:20:4f4c::/64",
+ "2a03:2880:20:4f4d::/64",
+ "2a03:2880:20:4f4e::/64",
+ "2a03:2880:20:4f4f::/64",
+ "2a03:2880:20:4f50::/64",
+ "2a03:2880:20:4f51::/64",
+ "2a03:2880:20:4f52::/64",
+ "2a03:2880:20:4f53::/64",
+ "2a03:2880:20:4f54::/64",
+ "2a03:2880:20:4f55::/64",
+ "2a03:2880:20:4f56::/64",
+ "2a03:2880:20:4f57::/64",
+ "2a03:2880:20:4f58::/64",
+ "2a03:2880:20:4f59::/64",
+ "2a03:2880:20:4f5a::/64",
+ "2a03:2880:20:4f5b::/64",
+ "2a03:2880:20:4f5c::/64",
+ "2a03:2880:20:4f5d::/64",
+ "2a03:2880:20:4f5e::/64",
+ "2a03:2880:20:4f5f::/64",
+ "2a03:2880:20:4f60::/64",
+ "2a03:2880:20:4f61::/64",
+ "2a03:2880:20:4f62::/64",
+ "2a03:2880:20:4f63::/64",
+ "2a03:2880:20:4f64::/64",
+ "2a03:2880:20:4f65::/64",
+ "2a03:2880:20:4f66::/64",
+ "2a03:2880:20:4f67::/64",
+ "2a03:2880:20:4f68::/64",
+ "2a03:2880:20:4f69::/64",
+ "2a03:2880:20:4f6a::/64",
+ "2a03:2880:20:4f6b::/64",
+ "2a03:2880:20:4f6c::/64",
+ "2a03:2880:20:4f6d::/64",
+ "2a03:2880:20:4f6e::/64",
+ "2a03:2880:20:4f6f::/64",
+ "2a03:2880:20:4f70::/64",
+ "2a03:2880:20:4f71::/64",
+ "2a03:2880:20:4f72::/64",
+ "2a03:2880:20:4f73::/64",
+ "2a03:2880:20:4f74::/64",
+ "2a03:2880:20:4f75::/64",
+ "2a03:2880:20:4f76::/64",
+ "2a03:2880:20:4f77::/64",
+ "2a03:2880:20:4f78::/64",
+ "2a03:2880:20:4f79::/64",
+ "2a03:2880:20:4f7a::/64",
+ "2a03:2880:20:4f7b::/64",
+ "2a03:2880:20:4f7c::/64",
+ "2a03:2880:20:4f7d::/64",
+ "2a03:2880:20:4f7e::/64",
+ "2a03:2880:20:4f7f::/64",
+ "2a03:2880:20:4f80::/64",
+ "2a03:2880:20:4f81::/64",
+ "2a03:2880:20:4f82::/64",
+ "2a03:2880:20:4f83::/64",
+ "2a03:2880:20:4f84::/64",
+ "2a03:2880:20:4f85::/64",
+ "2a03:2880:20:4f86::/64",
+ "2a03:2880:20:4f87::/64",
+ "2a03:2880:20:4f88::/64",
+ "2a03:2880:20:4f89::/64",
+ "2a03:2880:20:4f8a::/64",
+ "2a03:2880:20:4f8b::/64",
+ "2a03:2880:20:4f8c::/64",
+ "2a03:2880:20:4f8d::/64",
+ "2a03:2880:20:4f8e::/64",
+ "2a03:2880:20:4f8f::/64",
+ "2a03:2880:20:4f90::/64",
+ "2a03:2880:20:4f91::/64",
+ "2a03:2880:20:4f92::/64",
+ "2a03:2880:20:4f93::/64",
+ "2a03:2880:20:4f94::/64",
+ "2a03:2880:20:4f95::/64",
+ "2a03:2880:20:4f96::/64",
+ "2a03:2880:20:4f97::/64",
+ "2a03:2880:20:4f98::/64",
+ "2a03:2880:20:4f99::/64",
+ "2a03:2880:20:4f9a::/64",
+ "2a03:2880:20:4f9b::/64",
+ "2a03:2880:20:4f9c::/64",
+ "2a03:2880:20:4f9d::/64",
+ "2a03:2880:20:4f9e::/64",
+ "2a03:2880:20:4f9f::/64",
+ "2a03:2880:20:4fa0::/64",
+ "2a03:2880:20:4fa1::/64",
+ "2a03:2880:20:4fa2::/64",
+ "2a03:2880:20:4fa3::/64",
+ "2a03:2880:20:4fa4::/64",
+ "2a03:2880:20:4fa5::/64",
+ "2a03:2880:20:4fa6::/64",
+ "2a03:2880:20:4fa7::/64",
+ "2a03:2880:20:4fa8::/64",
+ "2a03:2880:20:4fa9::/64",
+ "2a03:2880:20:4faa::/64",
+ "2a03:2880:20:4fab::/64",
+ "2a03:2880:20:4fac::/64",
+ "2a03:2880:20:4fad::/64",
+ "2a03:2880:20:4fae::/64",
+ "2a03:2880:20:4faf::/64",
+ "2a03:2880:20:4fb0::/64",
+ "2a03:2880:20:4fb1::/64",
+ "2a03:2880:20:4fb2::/64",
+ "2a03:2880:20:4fb3::/64",
+ "2a03:2880:20:4fb4::/64",
+ "2a03:2880:20:4fb5::/64",
+ "2a03:2880:20:4fb6::/64",
+ "2a03:2880:20:4fb7::/64",
+ "2a03:2880:20:4fb8::/64",
+ "2a03:2880:20:4fb9::/64",
+ "2a03:2880:20:4fba::/64",
+ "2a03:2880:20:4fbb::/64",
+ "2a03:2880:20:4fbc::/64",
+ "2a03:2880:20:4fbd::/64",
+ "2a03:2880:20:4fbe::/64",
+ "2a03:2880:20:4fbf::/64",
+ "2a03:2880:20:4fc0::/64",
+ "2a03:2880:20:4fc1::/64",
+ "2a03:2880:20:4fc2::/64",
+ "2a03:2880:20:4fc3::/64",
+ "2a03:2880:20:4fc4::/64",
+ "2a03:2880:20:4fc5::/64",
+ "2a03:2880:20:4fc6::/64",
+ "2a03:2880:20:4fc7::/64",
+ "2a03:2880:20:4fc8::/64",
+ "2a03:2880:20:4fc9::/64",
+ "2a03:2880:20:4fca::/64",
+ "2a03:2880:20:4fcb::/64",
+ "2a03:2880:20:4fcc::/64",
+ "2a03:2880:20:4fcd::/64",
+ "2a03:2880:20:4fce::/64",
+ "2a03:2880:20:4fcf::/64",
+ "2a03:2880:20:4fd0::/64",
+ "2a03:2880:20:4fd1::/64",
+ "2a03:2880:20:4fd2::/64",
+ "2a03:2880:20:4fd3::/64",
+ "2a03:2880:20:4fd4::/64",
+ "2a03:2880:20:4fd5::/64",
+ "2a03:2880:20:4fd6::/64",
+ "2a03:2880:20:4fd7::/64",
+ "2a03:2880:20:4fd8::/64",
+ "2a03:2880:20:4fd9::/64",
+ "2a03:2880:20:4fda::/64",
+ "2a03:2880:20:4fdb::/64",
+ "2a03:2880:20:4fdc::/64",
+ "2a03:2880:20:4fdd::/64",
+ "2a03:2880:20:4fde::/64",
+ "2a03:2880:20:4fdf::/64",
+ "2a03:2880:20:4fe0::/64",
+ "2a03:2880:20:4fe1::/64",
+ "2a03:2880:20:4fe2::/64",
+ "2a03:2880:20:4fe3::/64",
+ "2a03:2880:20:4fe4::/64",
+ "2a03:2880:20:4fe5::/64",
+ "2a03:2880:20:4fe6::/64",
+ "2a03:2880:20:4fe7::/64",
+ "2a03:2880:20:4fe8::/64",
+ "2a03:2880:20:4fe9::/64",
+ "2a03:2880:20:4fea::/64",
+ "2a03:2880:20:4feb::/64",
+ "2a03:2880:20:4fec::/64",
+ "2a03:2880:20:4fed::/64",
+ "2a03:2880:20:4fee::/64",
+ "2a03:2880:20:4fef::/64",
+ "2a03:2880:20:4ff0::/64",
+ "2a03:2880:20:4ff1::/64",
+ "2a03:2880:20:4ff2::/64",
+ "2a03:2880:20:4ff3::/64",
+ "2a03:2880:20:4ff4::/64",
+ "2a03:2880:20:4ff5::/64",
+ "2a03:2880:20:4ff6::/64",
+ "2a03:2880:20:4ff7::/64",
+ "2a03:2880:20:4ff8::/64",
+ "2a03:2880:20:4ff9::/64",
+ "2a03:2880:20:4ffa::/64",
+ "2a03:2880:20:4ffb::/64",
+ "2a03:2880:20:4ffc::/64",
+ "2a03:2880:20:4ffd::/64",
+ "2a03:2880:20:4ffe::/64",
+ "2a03:2880:20:4fff::/64"],
+ "nets":"256",
+ "host_per_net":"18446744073709551616"
+}
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000..d3e6989
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,1330 @@
+testrunner = find_program('ipcalc-testrunner.sh')
+
+# Incompatible combinations test
+test('Split-Info',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -abmnp -S 26 10.100.1.0/24'
+ ]
+)
+test('Check-Info',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -c -abmnp 10.100.1.1'
+ ]
+)
+test('Check-Split',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -c -S 26 10.100.1.0/24'
+ ]
+)
+test('Check-Host',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -c -h 127.0.0.1'
+ ]
+)
+test('Random-Info',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -r 24 -i 127.0.0.1'
+ ]
+)
+test('Random',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -r 24' + '|grep Address'
+ ]
+)
+test('RandomAddress',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -r 24 -a' + '|grep ADDRESS'
+ ]
+)
+test('RandomIPv6Implicit',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -r 112' + '|grep Address'
+ ]
+)
+test('RandomIPv6PrefixIsValidULA',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -6 -r 48 -a' + '|grep ^ADDRESS=fd'
+ ]
+)
+test('RandomIPv6Explicit',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -6 -r 24' + '|grep Address'
+ ]
+)
+test('HostnameIPv6Localhost',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -6 -o localhost',
+ files('hostname-localhost-ipv6')
+ ]
+)
+test('HostnameIPv4Localhost',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -4 -o localhost',
+ files('hostname-localhost-ipv4')
+ ]
+)
+test('HostnameIPv4LocalhostJson',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -4 -o localhost',
+ files('hostname-localhost-ipv4-json')
+ ]
+)
+test('IPIPv6Localhost',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -h ::1',
+ files('ip-localhost-ipv6')
+ ]
+)
+test('IPIPv4Localhost',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -h 127.0.0.1',
+ files('ip-localhost-ipv4')
+ ]
+)
+test('IPIPv4LocalhostJson',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -h 127.0.0.1',
+ files('ip-localhost-ipv4-json')
+ ]
+)
+# --class-prefix tests
+test('AssignClassPrefix12',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 12.15.1.5 --class-prefix',
+ files('12.15.1.5')
+ ]
+)
+test('AssignClassPrefix129',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 129.15.31.5 --class-prefix',
+ files('129.15.31.5')
+ ]
+)
+test('AssignClassPrefix193',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 193.92.31.0 --class-prefix',
+ files('193.92.31.0')
+ ]
+)
+
+# prefix tests
+test('TestPrefix31',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 192.168.1.5/31',
+ files('192.168.1.5-31')
+ ]
+)
+test('TestPrefix24',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 10.10.10.5/24',
+ files('192.168.1.5-24')
+ ]
+)
+test('TestPrefix30',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 10.100.4.1/30',
+ files('192.168.1.5-30')
+ ]
+)
+test('TestPrefix16',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 10.100.4.1/16',
+ files('192.168.1.5-16')
+ ]
+)
+test('TestPrefix8',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp 10.10.10.10/8',
+ files('192.168.1.5-8')
+ ]
+)
+
+# --split tests
+test('SplitPrefix18',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 18 10.10.10.10/16',
+ files('split-10.10.10.0-16-18')
+ ]
+)
+test('SplitPrefix24',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 24 10.10.10.0/16',
+ files('split-10.10.10.0-16-24')
+ ]
+)
+test('SplitPrefix26',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 26 192.168.5.45/24',
+ files('split-192.168.5.45-24-26')
+ ]
+)
+test('SplitPrefix29',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 29 192.168.5.0/24',
+ files('split-192.168.5.0-24-29')
+ ]
+)
+test('SplitPrefix31',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 31 192.168.5.0/24',
+ files('split-192.168.5.0-24-31')
+ ]
+)
+test('SplitPrefix32',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 32 192.168.5.0/24',
+ files('split-192.168.5.0-24-32')
+ ]
+)
+test('SplitPrefix64',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 64 2a03:2880:20:4f06:face::/56',
+ files('split-2a03:2880:20:4f06:face::-56-64')
+ ]
+)
+test('SplitPrefix128',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 128 fcfa:b4ca:f1d8:125b:dc00::/127',
+ files('split-fcfa:b4ca:f1d8:125b:dc00::-127-128')
+ ]
+)
+test('SplitPrefix120',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -S 120 fcfa:b4ca:f1d8:125b:dc00::/112',
+ files('split-fcfa:b4ca:f1d8:125b:dc00::-112-120')
+ ]
+)
+
+# --no-decorate tests
+test('NoDecorateSplitPrefix18',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 18 10.10.10.10/16',
+ files('nsplit-10.10.10.0-16-18')
+ ]
+)
+test('NoDecorateSplitPrefix24',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 24 10.10.10.0/16',
+ files('nsplit-10.10.10.0-16-24')
+ ]
+)
+test('NoDecorateSplitPrefix26',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 26 192.168.5.45/24',
+ files('nsplit-192.168.5.45-24-26')
+ ]
+)
+test('NoDecorateSplitPrefix29',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 29 192.168.5.0/24',
+ files('nsplit-192.168.5.0-24-29')
+ ]
+)
+test('NoDecorateSplitPrefix31',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 31 192.168.5.0/24',
+ files('nsplit-192.168.5.0-24-31')
+ ]
+)
+test('NoDecorateSplitPrefix32',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 32 192.168.5.0/24',
+ files('nsplit-192.168.5.0-24-32')
+ ]
+)
+test('NoDecorateSplitPrefix64',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 64 2a03:2880:20:4f06:face::/56',
+ files('nsplit-2a03:2880:20:4f06:face::-56-64')
+ ]
+)
+test('NoDecorateSplitPrefix128',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 128 fcfa:b4ca:f1d8:125b:dc00::/127',
+ files('nsplit-fcfa:b4ca:f1d8:125b:dc00::-127-128')
+ ]
+)
+test('NoDecorateSplitPrefix120',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -S 120 fcfa:b4ca:f1d8:125b:dc00::/112',
+ files('nsplit-fcfa:b4ca:f1d8:125b:dc00::-112-120')
+ ]
+)
+
+# --addrspace tests
+test('AllocateAddressSpacePrefix24',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --addrspace -abmnp 193.92.150.3/24',
+ files('193.92.150.3-24')
+ ]
+)
+test('AllocateAddressSpacePrefix64',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --addrspace -abmnp fd95:6be5:0ae0:84a5::/64',
+ files('fd95:6be5:0ae0:84a5::-64')
+ ]
+)
+test('AllocateAddressSpacePrefix48',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --addrspace -abmnp fd0b:a336:4e7d::/48',
+ files('fd0b:a336:4e7d::-48')
+ ]
+)
+
+# --info tests
+test('TestHumanReadableGenericInfoNoPrefix',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2a03:2880:20:4f06:face:b00c:0:1',
+ files('i-2a03:2880:20:4f06:face:b00c:0:1')
+ ]
+)
+test('TestHumanReadableGenericInfoInternetIPv4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 3.130.45.15',
+ files('i-3.130.45.15')
+ ]
+)
+test('TestHumanReadableHostOnThisNetwork',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 0.0.0.1',
+ files('i-0.0.0.1')
+ ]
+)
+test('TestHumanReadablePrivateUse1',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 10.0.0.1',
+ files('i-10.0.0.1')
+ ]
+)
+test('TestHumanReadablePrivateUse2',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 172.16.0.1',
+ files('i-172.16.0.1')
+ ]
+)
+test('TestHumanReadablePrivateUse3',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 172.31.255.254',
+ files('i-172.31.255.254')
+ ]
+)
+test('TestHumanReadablePrivateUse4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.168.0.1',
+ files('i-192.168.0.1')
+ ]
+)
+test('TestHumanReadableSharedAddressSpace',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 100.64.0.1',
+ files('i-100.64.0.1')
+ ]
+)
+test('TestHumanReadableLoopback',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 127.0.0.1',
+ files('i-127.0.0.1')
+ ]
+)
+test('TestHumanReadableLoopback2',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 127.0.1.1',
+ files('i-127.0.1.1')
+ ]
+)
+test('TestHumanReadableLinkLocal',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 169.254.0.1',
+ files('i-169.254.0.1')
+ ]
+)
+test('TestHumanReadableIETFProtocolAssignmentsIPv4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.0.254',
+ files('i-192.0.0.254')
+ ]
+)
+test('TestHumanReadableServiceContinuityPrefixIPv4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.0.6',
+ files('i-192.0.0.6')
+ ]
+)
+test('TestHumanReadableDummyAddressIPv4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.0.8',
+ files('i-192.0.0.8')
+ ]
+)
+test('TestHumanReadablePortControlProtocolAnycastIPv4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.0.9',
+ files('i-192.0.0.9')
+ ]
+)
+test('TestHumanReadableTraversalUsingRelaysAroundNATAnycast',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.0.10',
+ files('i-192.0.0.10')
+ ]
+)
+test('TestHumanReadableNAT64DNS64Discovery1',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.0.170',
+ files('i-192.0.0.170')
+ ]
+)
+test('TestHumanReadableNAT64DNS64Discovery2',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.0.171',
+ files('i-192.0.0.171')
+ ]
+)
+test('TestHumanReadableAS112v4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.31.196.1',
+ files('i-192.31.196.1')
+ ]
+)
+test('TestHumanReadableDeprecated6to4RelayAnycast',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.88.99.1',
+ files('i-192.88.99.1')
+ ]
+)
+test('TestHumanReadableAMTIPv4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.52.193.5',
+ files('i-192.52.193.5')
+ ]
+)
+test('TestHumanReadableDirectDelegationAS112ServiceIPv4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.175.48.12',
+ files('i-192.175.48.12')
+ ]
+)
+test('TestHumanReadableTestNet1',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.0.2.1',
+ files('i-192.0.2.1')
+ ]
+)
+test('TestHumanReadableTestNet2',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 198.51.100.1',
+ files('i-198.51.100.1')
+ ]
+)
+test('TestHumanReadableTestNet3',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 203.0.113.1',
+ files('i-203.0.113.1')
+ ]
+)
+test('TestHumanReadableBenchmarking1',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 198.18.0.1',
+ files('i-198.18.0.1')
+ ]
+)
+test('TestHumanReadableBenchmarking2',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 198.19.201.71',
+ files('i-198.19.201.71')
+ ]
+)
+test('TestHumanReadableBenchmarking3',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 198.19.255.254',
+ files('i-198.19.255.254')
+ ]
+)
+test('TestHumanReadableMulticast',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 224.0.0.1',
+ files('i-224.0.0.1')
+ ]
+)
+test('TestHumanReadableReserved1',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 240.0.0.1',
+ files('i-240.0.0.1')
+ ]
+)
+test('TestHumanReadableReserved2',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 250.7.93.1',
+ files('i-250.7.93.1')
+ ]
+)
+test('TestHumanReadableReserved3',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 255.255.255.254',
+ files('i-255.255.255.254')
+ ]
+)
+test('TestHumanReadableLimitedBroadcast',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 255.255.255.255',
+ files('i-255.255.255.255')
+ ]
+)
+test('TestHumanReadableTranslat96',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 64:ff9b::2100:951a',
+ files('i-64:ff9b::2100:951a')
+ ]
+)
+test('TestHumanReadableTranslat48',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 64:ff9b:1:ea21:4316:55::1',
+ files('i-64:ff9b:1:ea21:4316:55::1')
+ ]
+)
+test('TestHumanReadableTEREDO',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:0000:50::d78a:0:c',
+ files('i-2001:0:50::d78a:0:c')
+ ]
+)
+test('TestHumanReadablePortControlProtocolAnycast',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:1::1',
+ files('i-2001:1::1')
+ ]
+)
+test('TestHumanReadableTraversalUsingRelays',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:1::2',
+ files('i-2001:1::2')
+ ]
+)
+test('TestHumanReadableBenchmarking',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:2:0:a::5:b7f',
+ files('i-2001:2:0:a::5:b7f')
+ ]
+)
+test('TestHumanReadableAMT',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:3:89:71::ab:1',
+ files('i-2001:3:89:71::ab:1')
+ ]
+)
+test('TestHumanReadableAS112v6',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:4:112::6483:bd12:9010',
+ files('i-2001:4:112::6483:bd12:9010')
+ ]
+)
+test('TestHumanReadableORCHID',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:1e:ab:7::',
+ files('i-2001:1e:ab:7::')
+ ]
+)
+test('TestHumanReadableORCHIDv2',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:2c:ab:7::',
+ files('i-2001:2c:ab:7::')
+ ]
+)
+test('TestHumanReadableDocumentation',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:db8:329::4a',
+ files('i-2001:db8:329::4a')
+ ]
+)
+test('TestHumanReadableIETFProtocolAssignments',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2001:190:70::e86a:0:b',
+ files('i-2001:190:70::e86a:0:b')
+ ]
+)
+test('TestHumanReadable6to4',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2002::34',
+ files('i-2002::34')
+ ]
+)
+test('TestHumanReadableDirectDelegationAS112Service',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 2620:4f:8000::7372:ad1',
+ files('i-2620:4f:8000::7372:ad1')
+ ]
+)
+test('TestHumanReadableUniqueLocalUnicast',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i fc00:0:a001::bcdf:4',
+ files('i-fc00:0:a001::bcdf:4')
+ ]
+)
+test('TestHumanReadableLinkScopedUnicast',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i fe80::b:0:7acd:0:5',
+ files('i-fe80::b:0:7acd:0:5')
+ ]
+)
+test('TestHumanReadableGenericInfoPrefix48',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i fd0b:a336:4e7d::/48',
+ files('i-fd0b:a336:4e7d::-48')
+ ]
+)
+
+# --split advanced tests
+test('SplitLinesByNetworkIPv4',
+ testrunner,
+ args : [
+ '--test-equal',
+ ipcalc.full_path() + ' -S 29 192.168.5.0/24 | grep ^Network | wc -l | tr -d [:space:]',
+ ipcalc.full_path() + ' -S 29 192.168.5.0/24 | grep ^Total | cut -d: -f 2 | tr -d [:space:]'
+ ]
+)
+test('SplitLinesByNetworkIPv6',
+ testrunner,
+ args : [
+ '--test-equal',
+ ipcalc.full_path() + ' -S 120 fcfa:b4ca:f1d8:125b:dc00::/112 | grep ^Network | wc -l | tr -d [:space:]',
+ ipcalc.full_path() + ' -S 120 fcfa:b4ca:f1d8:125b:dc00::/112 | grep ^Total|cut -d: -f 2 | tr -d [:space:]'
+ ]
+)
+
+# --help test
+test('TestHelpCommand',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' --help'
+ ]
+)
+
+# --check loopback tests
+test('ValidateLoopbackIPv4',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c 127.0.0.1'
+ ]
+)
+test('ValidateLoopbackExplicitIPv6',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c -6 ::1'
+ ]
+)
+test('ValidateLoopbackIPv6',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c ::1'
+ ]
+)
+
+# --check tests
+test('ValidatePrivateIPv4',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c 192.168.1.1'
+ ]
+)
+test('ValidateAbbreviatedGlobalIPv6',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c -6 2a01:198:200:300::2'
+ ]
+)
+test('ValidateExpandedGlobalIPv6',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c -6 2a01:198:200:300:0000:0000:0000:2'
+ ]
+)
+test('ValidateCompleteGlobalIPv6',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c -6 2a01:0198:0200:0300:0000:0000:0000:0002'
+ ]
+)
+test('ValidateLoopbackIPv6WithPrefix',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c -6 ::1/128'
+ ]
+)
+test('ValidateReservedIPv6WithPrefix',
+ testrunner,
+ args : [
+ '--test-success',
+ ipcalc.full_path() + ' -c -6 fec0::1:0:0:c0a8:8002/64'
+ ]
+)
+
+# --check invalid input tests
+test('NoValidateInvalidHexIPv6',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -c -6 gggg::'
+ ]
+)
+# FIXME: This test case unexpectedly works, so it is disabled for now.
+#test('NoValidateInvalidBroadcastIPv6',
+# testrunner,
+# args : [
+# '--test-failure',
+# ipcalc.full_path() + ' -b -6 ::1/128'
+# ]
+#)
+test('NoAllowIPv4AndIPv6',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -4 -6 2a01:198:200:300:0000:0000:0000:2'
+ ]
+)
+test('NoValidateIPv6InIPv4Mode',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -c -4 2a01:198:200:300:0000:0000:0000:2'
+ ]
+)
+test('NoValidateIPv4AndIPv6WithIPv4Address',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -c -4 -6 127.0.0.1'
+ ]
+)
+test('NoValidateInvalidPrefixIPv6',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -c ::1/999'
+ ]
+)
+
+# --netmask invalid input tests
+test('NoValidateNegativePrefix',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -m 192.168.1.1/-1'
+ ]
+)
+test('NoValidateIPv6PrefixInIPv4Mode',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -m 192.168.1.1/64'
+ ]
+)
+test('NoValidateInvalidPrefixIPv4',
+ testrunner,
+ args : [
+ '--test-failure',
+ ipcalc.full_path() + ' -m 192.168.1.1/99999'
+ ]
+)
+
+# --broadcast output tests
+test('CalculateBroadcastAddressFromPrefixIPv4',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -b 192.168.1.1/24',
+ 'BROADCAST=192.168.1.255'
+ ]
+)
+test('CalculateBroadcastAddressFromNetmaskIPv4',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -b 192.168.1.1 255.255.255.0',
+ 'BROADCAST=192.168.1.255'
+ ]
+)
+
+# --netmask output tests
+test('CalculateNetmaskPrefix24',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -m 192.168.1.1/24',
+ 'NETMASK=255.255.255.0'
+ ]
+)
+test('CalculateNetmaskPrefix22',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -m 172.16.59.222/22',
+ 'NETMASK=255.255.252.0'
+ ]
+)
+test('CalculateNetmaskNoPrefix',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -m 192.168.1.1',
+ 'NETMASK=255.255.255.255'
+ ]
+)
+
+# --prefix output tests
+test('CalculatePrefix24FromNetmask',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -p 192.168.1.1 255.255.255.0',
+ 'PREFIX=24'
+ ]
+)
+test('CalculatePrefix32FromNetmask',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -p 192.168.1.1 255.255.255.255',
+ 'PREFIX=32'
+ ]
+)
+test('CalculatePrefix0FromNetmask',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -p 192.168.1.1 0.0.0.0',
+ 'PREFIX=0'
+ ]
+)
+test('CalculatePrefix22FromNetmask',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -p 172.16.59.222 255.255.252.0',
+ 'PREFIX=22'
+ ]
+)
+
+# --class-prefix output tests
+test('CalculateClassNetmask24',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --class-prefix -m 192.168.1.1',
+ 'NETMASK=255.255.255.0'
+ ]
+)
+test('CalculateClassNetmask8',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --class-prefix -m 10.1.2.3',
+ 'NETMASK=255.0.0.0'
+ ]
+)
+test('CalculateClassNetmask16',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --class-prefix -m 129.22.4.3',
+ 'NETMASK=255.255.0.0'
+ ]
+)
+
+# --network output tests
+test('CalculateNetworkFromPrefix32',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -n 192.168.1.1/32',
+ 'NETWORK=192.168.1.1'
+ ]
+)
+test('CalculateNetworkFromPrefix0',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' -n 192.168.1.1/0',
+ 'NETWORK=0.0.0.0'
+ ]
+)
+
+# --reverse-dns output tests
+test('LookupReverseDNSFromPrefix32IPv4',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 193.92.150.3/32',
+ 'REVERSEDNS=3.150.92.193.in-addr.arpa.'
+ ]
+)
+test('LookupReverseDNSFromPrefix26IPv4',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 193.92.150.3/26',
+ 'REVERSEDNS=0-63.150.92.193.in-addr.arpa.'
+ ]
+)
+test('LookupReverseDNSFromPrefix16IPv4',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 193.92.150.3/16',
+ 'REVERSEDNS=92.193.in-addr.arpa.'
+ ]
+)
+test('LookupReverseDNSFromPrefix12IPv4',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 193.92.150.3/12',
+ 'REVERSEDNS=80-95.193.in-addr.arpa.'
+ ]
+)
+test('LookupReverseDNS4321IPv6',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 4321:0:1:2:3:4:567:89ab',
+ 'REVERSEDNS=b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.ip6.arpa.'
+ ]
+)
+test('LookupReverseDNSFirstIPv6',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 1::',
+ 'REVERSEDNS=0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.'
+ ]
+)
+test('LookupReverseDNSLoopbackIPv6',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns ::1',
+ 'REVERSEDNS=1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.'
+ ]
+)
+test('LookupReverseDNSFromPrefix128IPv6',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 1234::4321/128',
+ 'REVERSEDNS=1.2.3.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.3.2.1.ip6.arpa.'
+ ]
+)
+test('LookupReverseDNSFromPrefix124IPv6',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 1234::4321/124',
+ 'REVERSEDNS=2.3.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.3.2.1.ip6.arpa.'
+ ]
+)
+test('LookupReverseDNSFromPrefix120IPv6',
+ testrunner,
+ args : [
+ '--test-output',
+ ipcalc.full_path() + ' --reverse-dns 1234::4321/120',
+ 'REVERSEDNS=3.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.4.3.2.1.ip6.arpa.'
+ ]
+)
+
+# specific info decorated & no-decorate test
+test('SpecificInfoOutput',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp --minaddr --maxaddr --addresses 192.168.2.6/24',
+ files('192.168.2.6')
+ ]
+)
+test('SpecificInfoOutputNoDecorate',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -abmnp --minaddr --maxaddr --addresses --no-decorate 192.168.2.7/24',
+ files('192.168.2.7')
+ ]
+)
+
+# --json output tests
+test('JsonSplitPrefix24',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -S 24 10.10.10.0/16',
+ files('json-split-10.10.10.0-16-24')
+ ]
+)
+test('JsonSplitPrefix26',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -S 26 192.168.5.45/24',
+ files('json-split-192.168.5.45-24-26')
+ ]
+)
+test('JsonNoDecorateSplitPrefix24',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j --no-decorate -S 24 10.10.10.0/16',
+ files('json-nsplit-10.10.10.0-16-24')
+ ]
+)
+test('JsonNoDecorateSplitPrefix26',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j --no-decorate -S 26 192.168.5.45/24',
+ files('json-nsplit-192.168.5.45-24-26')
+ ]
+)
+test('JsonSplitPrefix64',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -S 64 2a03:2880:20:4f06:face::/56',
+ files('json-nsplit-2a03:2880:20:4f06:face::-56-64')
+ ]
+)
+test('JsonNoDecorateSplitPrefix64',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j --no-decorate -S 64 2a03:2880:20:4f06:face::/56',
+ files('json-nsplit-2a03:2880:20:4f06:face::-56-64')
+ ]
+)
+test('JsonTestHumanReadableGenericInfoPrefix56',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -i 2a03:2880:20:4f06:face:b00c:0:1/56',
+ files('json-i-2a03:2880:20:4f06:face:b00c:0:1-56')
+ ]
+)
+test('JsonTestHumanReadableSpecificInfo',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -n 2a03:2880:20:4f06:face:b00c:0:1/56',
+ files('json-i-2a03:2880:20:4f06:face:b00c:0:1-56')
+ ]
+)
+test('AllInfo',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --all-info 192.168.2.7/24',
+ files('all-info-192.168.2.7')
+ ]
+)
+test('Info',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -i 192.168.2.7/24',
+ files('info-192.168.2.7')
+ ]
+)
+test('InfoImplicit',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' 192.168.2.7/24',
+ files('info-192.168.2.7')
+ ]
+)
+
+# --deagrregate tests
+test('DeaggregateNoDecorate',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -d 192.168.2.7-192.168.2.13',
+ files('deaggregate-192.168.2.7-192.168.2.13')
+ ]
+)
+test('Deaggregate',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -d 192.168.2.0-192.168.3.255',
+ files('deaggregate-192.168.2.0-192.168.3.255')
+ ]
+)
+test('DeaggregateSpaces',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -d " 192.168.2.0 - 192.168.3.255 "',
+ files('deaggregate-192.168.2.0-192.168.3.255')
+ ]
+)
+test('DeaggregateJson',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -d 192.168.2.33-192.168.3.2',
+ files('deaggregate-192.168.2.33-192.168.3.2')
+ ]
+)
+test('DeaggregateIPv6NoDecorate',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate -d 2a03:2880:20:4f06:face::0-2a03:2880:20:4f06:face::fffe',
+ files('deaggregate-2a03:2880:20:4f06:face::0-2a03:2880:20:4f06:face::fffe')
+ ]
+)
+test('DeaggregateIPv6',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -d fcd3:57d1:733:c18f:b498:25e1:788:0-fcd3:57d1:733:c18f:b498:25e1:788:ffff',
+ files('deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:0-fcd3:57d1:733:c18f:b498:25e1:788:ffff')
+ ]
+)
+test('DeaggregateIPv6Json',
+ testrunner,
+ args : [
+ '--test-outfile',
+ ipcalc.full_path() + ' -j -d fcd3:57d1:733:c18f:b498:25e1:788:f-fcd3:57d1:733:c18f:b498:25e1:789:ffa9',
+ files('deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:f-fcd3:57d1:733:c18f:b498:25e1:789:ffa9')
+ ]
+)
+test('StandardInfo',
+ testrunner,
+ args : [ '--test-outfile',
+ ipcalc.full_path() + ' 192.168.2.0/24',
+ files('standard-192.168.2.0-24')
+ ]
+)
+test('NoDecorateInfo',
+ testrunner,
+ args : [ '--test-outfile',
+ ipcalc.full_path() + ' --no-decorate 192.168.2.0/24',
+ files('no-decorate-192.168.2.0-24')
+ ]
+)
+test('NoDecorateAllInfo',
+ testrunner,
+ args : [ '--test-outfile',
+ ipcalc.full_path() + ' --all-info --no-decorate 192.168.2.0/24',
+ files('no-decorate-all-info-192.168.2.0-24')
+ ]
+)
+# Test whether we can deaggregate a randomly generated network
+test('DeaggregateIPv6Random',
+ find_program('ipcalc-delegate-ipv6-random.sh'),
+ env : ['IPCALC=' + ipcalc.full_path()]
+)
+test('DeaggregateSplitIPv6',
+ find_program('ipcalc-delegate-split-ipv6.sh'),
+ env : ['IPCALC=' + ipcalc.full_path()]
+)
+test('DeaggregateSplitIPv4',
+ find_program('ipcalc-delegate-split-ipv4.sh'),
+ env : ['IPCALC=' + ipcalc.full_path()]
+)
diff --git a/tests/no-decorate-192.168.2.0-24 b/tests/no-decorate-192.168.2.0-24
new file mode 100644
index 0000000..588b5fe
--- /dev/null
+++ b/tests/no-decorate-192.168.2.0-24
@@ -0,0 +1,8 @@
+Network: 192.168.2.0/24
+Netmask: 255.255.255.0 = 24
+Broadcast: 192.168.2.255
+
+Address space: Private Use
+HostMin: 192.168.2.1
+HostMax: 192.168.2.254
+Hosts/Net: 254
diff --git a/tests/no-decorate-all-info-192.168.2.0-24 b/tests/no-decorate-all-info-192.168.2.0-24
new file mode 100644
index 0000000..5f1efdf
--- /dev/null
+++ b/tests/no-decorate-all-info-192.168.2.0-24
@@ -0,0 +1,10 @@
+Network: 192.168.2.0/24
+Netmask: 255.255.255.0 = 24
+Broadcast: 192.168.2.255
+Reverse DNS: 2.168.192.in-addr.arpa.
+
+Address space: Private Use
+Address class: Class C
+HostMin: 192.168.2.1
+HostMax: 192.168.2.254
+Hosts/Net: 254
diff --git a/tests/nsplit-10.10.10.0-16-18 b/tests/nsplit-10.10.10.0-16-18
new file mode 100644
index 0000000..071670d
--- /dev/null
+++ b/tests/nsplit-10.10.10.0-16-18
@@ -0,0 +1,4 @@
+10.10.0.0/18
+10.10.64.0/18
+10.10.128.0/18
+10.10.192.0/18
diff --git a/tests/nsplit-10.10.10.0-16-24 b/tests/nsplit-10.10.10.0-16-24
new file mode 100644
index 0000000..6335c3a
--- /dev/null
+++ b/tests/nsplit-10.10.10.0-16-24
@@ -0,0 +1,256 @@
+10.10.0.0/24
+10.10.1.0/24
+10.10.2.0/24
+10.10.3.0/24
+10.10.4.0/24
+10.10.5.0/24
+10.10.6.0/24
+10.10.7.0/24
+10.10.8.0/24
+10.10.9.0/24
+10.10.10.0/24
+10.10.11.0/24
+10.10.12.0/24
+10.10.13.0/24
+10.10.14.0/24
+10.10.15.0/24
+10.10.16.0/24
+10.10.17.0/24
+10.10.18.0/24
+10.10.19.0/24
+10.10.20.0/24
+10.10.21.0/24
+10.10.22.0/24
+10.10.23.0/24
+10.10.24.0/24
+10.10.25.0/24
+10.10.26.0/24
+10.10.27.0/24
+10.10.28.0/24
+10.10.29.0/24
+10.10.30.0/24
+10.10.31.0/24
+10.10.32.0/24
+10.10.33.0/24
+10.10.34.0/24
+10.10.35.0/24
+10.10.36.0/24
+10.10.37.0/24
+10.10.38.0/24
+10.10.39.0/24
+10.10.40.0/24
+10.10.41.0/24
+10.10.42.0/24
+10.10.43.0/24
+10.10.44.0/24
+10.10.45.0/24
+10.10.46.0/24
+10.10.47.0/24
+10.10.48.0/24
+10.10.49.0/24
+10.10.50.0/24
+10.10.51.0/24
+10.10.52.0/24
+10.10.53.0/24
+10.10.54.0/24
+10.10.55.0/24
+10.10.56.0/24
+10.10.57.0/24
+10.10.58.0/24
+10.10.59.0/24
+10.10.60.0/24
+10.10.61.0/24
+10.10.62.0/24
+10.10.63.0/24
+10.10.64.0/24
+10.10.65.0/24
+10.10.66.0/24
+10.10.67.0/24
+10.10.68.0/24
+10.10.69.0/24
+10.10.70.0/24
+10.10.71.0/24
+10.10.72.0/24
+10.10.73.0/24
+10.10.74.0/24
+10.10.75.0/24
+10.10.76.0/24
+10.10.77.0/24
+10.10.78.0/24
+10.10.79.0/24
+10.10.80.0/24
+10.10.81.0/24
+10.10.82.0/24
+10.10.83.0/24
+10.10.84.0/24
+10.10.85.0/24
+10.10.86.0/24
+10.10.87.0/24
+10.10.88.0/24
+10.10.89.0/24
+10.10.90.0/24
+10.10.91.0/24
+10.10.92.0/24
+10.10.93.0/24
+10.10.94.0/24
+10.10.95.0/24
+10.10.96.0/24
+10.10.97.0/24
+10.10.98.0/24
+10.10.99.0/24
+10.10.100.0/24
+10.10.101.0/24
+10.10.102.0/24
+10.10.103.0/24
+10.10.104.0/24
+10.10.105.0/24
+10.10.106.0/24
+10.10.107.0/24
+10.10.108.0/24
+10.10.109.0/24
+10.10.110.0/24
+10.10.111.0/24
+10.10.112.0/24
+10.10.113.0/24
+10.10.114.0/24
+10.10.115.0/24
+10.10.116.0/24
+10.10.117.0/24
+10.10.118.0/24
+10.10.119.0/24
+10.10.120.0/24
+10.10.121.0/24
+10.10.122.0/24
+10.10.123.0/24
+10.10.124.0/24
+10.10.125.0/24
+10.10.126.0/24
+10.10.127.0/24
+10.10.128.0/24
+10.10.129.0/24
+10.10.130.0/24
+10.10.131.0/24
+10.10.132.0/24
+10.10.133.0/24
+10.10.134.0/24
+10.10.135.0/24
+10.10.136.0/24
+10.10.137.0/24
+10.10.138.0/24
+10.10.139.0/24
+10.10.140.0/24
+10.10.141.0/24
+10.10.142.0/24
+10.10.143.0/24
+10.10.144.0/24
+10.10.145.0/24
+10.10.146.0/24
+10.10.147.0/24
+10.10.148.0/24
+10.10.149.0/24
+10.10.150.0/24
+10.10.151.0/24
+10.10.152.0/24
+10.10.153.0/24
+10.10.154.0/24
+10.10.155.0/24
+10.10.156.0/24
+10.10.157.0/24
+10.10.158.0/24
+10.10.159.0/24
+10.10.160.0/24
+10.10.161.0/24
+10.10.162.0/24
+10.10.163.0/24
+10.10.164.0/24
+10.10.165.0/24
+10.10.166.0/24
+10.10.167.0/24
+10.10.168.0/24
+10.10.169.0/24
+10.10.170.0/24
+10.10.171.0/24
+10.10.172.0/24
+10.10.173.0/24
+10.10.174.0/24
+10.10.175.0/24
+10.10.176.0/24
+10.10.177.0/24
+10.10.178.0/24
+10.10.179.0/24
+10.10.180.0/24
+10.10.181.0/24
+10.10.182.0/24
+10.10.183.0/24
+10.10.184.0/24
+10.10.185.0/24
+10.10.186.0/24
+10.10.187.0/24
+10.10.188.0/24
+10.10.189.0/24
+10.10.190.0/24
+10.10.191.0/24
+10.10.192.0/24
+10.10.193.0/24
+10.10.194.0/24
+10.10.195.0/24
+10.10.196.0/24
+10.10.197.0/24
+10.10.198.0/24
+10.10.199.0/24
+10.10.200.0/24
+10.10.201.0/24
+10.10.202.0/24
+10.10.203.0/24
+10.10.204.0/24
+10.10.205.0/24
+10.10.206.0/24
+10.10.207.0/24
+10.10.208.0/24
+10.10.209.0/24
+10.10.210.0/24
+10.10.211.0/24
+10.10.212.0/24
+10.10.213.0/24
+10.10.214.0/24
+10.10.215.0/24
+10.10.216.0/24
+10.10.217.0/24
+10.10.218.0/24
+10.10.219.0/24
+10.10.220.0/24
+10.10.221.0/24
+10.10.222.0/24
+10.10.223.0/24
+10.10.224.0/24
+10.10.225.0/24
+10.10.226.0/24
+10.10.227.0/24
+10.10.228.0/24
+10.10.229.0/24
+10.10.230.0/24
+10.10.231.0/24
+10.10.232.0/24
+10.10.233.0/24
+10.10.234.0/24
+10.10.235.0/24
+10.10.236.0/24
+10.10.237.0/24
+10.10.238.0/24
+10.10.239.0/24
+10.10.240.0/24
+10.10.241.0/24
+10.10.242.0/24
+10.10.243.0/24
+10.10.244.0/24
+10.10.245.0/24
+10.10.246.0/24
+10.10.247.0/24
+10.10.248.0/24
+10.10.249.0/24
+10.10.250.0/24
+10.10.251.0/24
+10.10.252.0/24
+10.10.253.0/24
+10.10.254.0/24
+10.10.255.0/24
diff --git a/tests/nsplit-192.168.5.0-24-29 b/tests/nsplit-192.168.5.0-24-29
new file mode 100644
index 0000000..3cc2f57
--- /dev/null
+++ b/tests/nsplit-192.168.5.0-24-29
@@ -0,0 +1,32 @@
+192.168.5.0/29
+192.168.5.8/29
+192.168.5.16/29
+192.168.5.24/29
+192.168.5.32/29
+192.168.5.40/29
+192.168.5.48/29
+192.168.5.56/29
+192.168.5.64/29
+192.168.5.72/29
+192.168.5.80/29
+192.168.5.88/29
+192.168.5.96/29
+192.168.5.104/29
+192.168.5.112/29
+192.168.5.120/29
+192.168.5.128/29
+192.168.5.136/29
+192.168.5.144/29
+192.168.5.152/29
+192.168.5.160/29
+192.168.5.168/29
+192.168.5.176/29
+192.168.5.184/29
+192.168.5.192/29
+192.168.5.200/29
+192.168.5.208/29
+192.168.5.216/29
+192.168.5.224/29
+192.168.5.232/29
+192.168.5.240/29
+192.168.5.248/29
diff --git a/tests/nsplit-192.168.5.0-24-31 b/tests/nsplit-192.168.5.0-24-31
new file mode 100644
index 0000000..3a1239c
--- /dev/null
+++ b/tests/nsplit-192.168.5.0-24-31
@@ -0,0 +1,128 @@
+192.168.5.0/31
+192.168.5.2/31
+192.168.5.4/31
+192.168.5.6/31
+192.168.5.8/31
+192.168.5.10/31
+192.168.5.12/31
+192.168.5.14/31
+192.168.5.16/31
+192.168.5.18/31
+192.168.5.20/31
+192.168.5.22/31
+192.168.5.24/31
+192.168.5.26/31
+192.168.5.28/31
+192.168.5.30/31
+192.168.5.32/31
+192.168.5.34/31
+192.168.5.36/31
+192.168.5.38/31
+192.168.5.40/31
+192.168.5.42/31
+192.168.5.44/31
+192.168.5.46/31
+192.168.5.48/31
+192.168.5.50/31
+192.168.5.52/31
+192.168.5.54/31
+192.168.5.56/31
+192.168.5.58/31
+192.168.5.60/31
+192.168.5.62/31
+192.168.5.64/31
+192.168.5.66/31
+192.168.5.68/31
+192.168.5.70/31
+192.168.5.72/31
+192.168.5.74/31
+192.168.5.76/31
+192.168.5.78/31
+192.168.5.80/31
+192.168.5.82/31
+192.168.5.84/31
+192.168.5.86/31
+192.168.5.88/31
+192.168.5.90/31
+192.168.5.92/31
+192.168.5.94/31
+192.168.5.96/31
+192.168.5.98/31
+192.168.5.100/31
+192.168.5.102/31
+192.168.5.104/31
+192.168.5.106/31
+192.168.5.108/31
+192.168.5.110/31
+192.168.5.112/31
+192.168.5.114/31
+192.168.5.116/31
+192.168.5.118/31
+192.168.5.120/31
+192.168.5.122/31
+192.168.5.124/31
+192.168.5.126/31
+192.168.5.128/31
+192.168.5.130/31
+192.168.5.132/31
+192.168.5.134/31
+192.168.5.136/31
+192.168.5.138/31
+192.168.5.140/31
+192.168.5.142/31
+192.168.5.144/31
+192.168.5.146/31
+192.168.5.148/31
+192.168.5.150/31
+192.168.5.152/31
+192.168.5.154/31
+192.168.5.156/31
+192.168.5.158/31
+192.168.5.160/31
+192.168.5.162/31
+192.168.5.164/31
+192.168.5.166/31
+192.168.5.168/31
+192.168.5.170/31
+192.168.5.172/31
+192.168.5.174/31
+192.168.5.176/31
+192.168.5.178/31
+192.168.5.180/31
+192.168.5.182/31
+192.168.5.184/31
+192.168.5.186/31
+192.168.5.188/31
+192.168.5.190/31
+192.168.5.192/31
+192.168.5.194/31
+192.168.5.196/31
+192.168.5.198/31
+192.168.5.200/31
+192.168.5.202/31
+192.168.5.204/31
+192.168.5.206/31
+192.168.5.208/31
+192.168.5.210/31
+192.168.5.212/31
+192.168.5.214/31
+192.168.5.216/31
+192.168.5.218/31
+192.168.5.220/31
+192.168.5.222/31
+192.168.5.224/31
+192.168.5.226/31
+192.168.5.228/31
+192.168.5.230/31
+192.168.5.232/31
+192.168.5.234/31
+192.168.5.236/31
+192.168.5.238/31
+192.168.5.240/31
+192.168.5.242/31
+192.168.5.244/31
+192.168.5.246/31
+192.168.5.248/31
+192.168.5.250/31
+192.168.5.252/31
+192.168.5.254/31
diff --git a/tests/nsplit-192.168.5.0-24-32 b/tests/nsplit-192.168.5.0-24-32
new file mode 100644
index 0000000..38490b9
--- /dev/null
+++ b/tests/nsplit-192.168.5.0-24-32
@@ -0,0 +1,256 @@
+192.168.5.0/32
+192.168.5.1/32
+192.168.5.2/32
+192.168.5.3/32
+192.168.5.4/32
+192.168.5.5/32
+192.168.5.6/32
+192.168.5.7/32
+192.168.5.8/32
+192.168.5.9/32
+192.168.5.10/32
+192.168.5.11/32
+192.168.5.12/32
+192.168.5.13/32
+192.168.5.14/32
+192.168.5.15/32
+192.168.5.16/32
+192.168.5.17/32
+192.168.5.18/32
+192.168.5.19/32
+192.168.5.20/32
+192.168.5.21/32
+192.168.5.22/32
+192.168.5.23/32
+192.168.5.24/32
+192.168.5.25/32
+192.168.5.26/32
+192.168.5.27/32
+192.168.5.28/32
+192.168.5.29/32
+192.168.5.30/32
+192.168.5.31/32
+192.168.5.32/32
+192.168.5.33/32
+192.168.5.34/32
+192.168.5.35/32
+192.168.5.36/32
+192.168.5.37/32
+192.168.5.38/32
+192.168.5.39/32
+192.168.5.40/32
+192.168.5.41/32
+192.168.5.42/32
+192.168.5.43/32
+192.168.5.44/32
+192.168.5.45/32
+192.168.5.46/32
+192.168.5.47/32
+192.168.5.48/32
+192.168.5.49/32
+192.168.5.50/32
+192.168.5.51/32
+192.168.5.52/32
+192.168.5.53/32
+192.168.5.54/32
+192.168.5.55/32
+192.168.5.56/32
+192.168.5.57/32
+192.168.5.58/32
+192.168.5.59/32
+192.168.5.60/32
+192.168.5.61/32
+192.168.5.62/32
+192.168.5.63/32
+192.168.5.64/32
+192.168.5.65/32
+192.168.5.66/32
+192.168.5.67/32
+192.168.5.68/32
+192.168.5.69/32
+192.168.5.70/32
+192.168.5.71/32
+192.168.5.72/32
+192.168.5.73/32
+192.168.5.74/32
+192.168.5.75/32
+192.168.5.76/32
+192.168.5.77/32
+192.168.5.78/32
+192.168.5.79/32
+192.168.5.80/32
+192.168.5.81/32
+192.168.5.82/32
+192.168.5.83/32
+192.168.5.84/32
+192.168.5.85/32
+192.168.5.86/32
+192.168.5.87/32
+192.168.5.88/32
+192.168.5.89/32
+192.168.5.90/32
+192.168.5.91/32
+192.168.5.92/32
+192.168.5.93/32
+192.168.5.94/32
+192.168.5.95/32
+192.168.5.96/32
+192.168.5.97/32
+192.168.5.98/32
+192.168.5.99/32
+192.168.5.100/32
+192.168.5.101/32
+192.168.5.102/32
+192.168.5.103/32
+192.168.5.104/32
+192.168.5.105/32
+192.168.5.106/32
+192.168.5.107/32
+192.168.5.108/32
+192.168.5.109/32
+192.168.5.110/32
+192.168.5.111/32
+192.168.5.112/32
+192.168.5.113/32
+192.168.5.114/32
+192.168.5.115/32
+192.168.5.116/32
+192.168.5.117/32
+192.168.5.118/32
+192.168.5.119/32
+192.168.5.120/32
+192.168.5.121/32
+192.168.5.122/32
+192.168.5.123/32
+192.168.5.124/32
+192.168.5.125/32
+192.168.5.126/32
+192.168.5.127/32
+192.168.5.128/32
+192.168.5.129/32
+192.168.5.130/32
+192.168.5.131/32
+192.168.5.132/32
+192.168.5.133/32
+192.168.5.134/32
+192.168.5.135/32
+192.168.5.136/32
+192.168.5.137/32
+192.168.5.138/32
+192.168.5.139/32
+192.168.5.140/32
+192.168.5.141/32
+192.168.5.142/32
+192.168.5.143/32
+192.168.5.144/32
+192.168.5.145/32
+192.168.5.146/32
+192.168.5.147/32
+192.168.5.148/32
+192.168.5.149/32
+192.168.5.150/32
+192.168.5.151/32
+192.168.5.152/32
+192.168.5.153/32
+192.168.5.154/32
+192.168.5.155/32
+192.168.5.156/32
+192.168.5.157/32
+192.168.5.158/32
+192.168.5.159/32
+192.168.5.160/32
+192.168.5.161/32
+192.168.5.162/32
+192.168.5.163/32
+192.168.5.164/32
+192.168.5.165/32
+192.168.5.166/32
+192.168.5.167/32
+192.168.5.168/32
+192.168.5.169/32
+192.168.5.170/32
+192.168.5.171/32
+192.168.5.172/32
+192.168.5.173/32
+192.168.5.174/32
+192.168.5.175/32
+192.168.5.176/32
+192.168.5.177/32
+192.168.5.178/32
+192.168.5.179/32
+192.168.5.180/32
+192.168.5.181/32
+192.168.5.182/32
+192.168.5.183/32
+192.168.5.184/32
+192.168.5.185/32
+192.168.5.186/32
+192.168.5.187/32
+192.168.5.188/32
+192.168.5.189/32
+192.168.5.190/32
+192.168.5.191/32
+192.168.5.192/32
+192.168.5.193/32
+192.168.5.194/32
+192.168.5.195/32
+192.168.5.196/32
+192.168.5.197/32
+192.168.5.198/32
+192.168.5.199/32
+192.168.5.200/32
+192.168.5.201/32
+192.168.5.202/32
+192.168.5.203/32
+192.168.5.204/32
+192.168.5.205/32
+192.168.5.206/32
+192.168.5.207/32
+192.168.5.208/32
+192.168.5.209/32
+192.168.5.210/32
+192.168.5.211/32
+192.168.5.212/32
+192.168.5.213/32
+192.168.5.214/32
+192.168.5.215/32
+192.168.5.216/32
+192.168.5.217/32
+192.168.5.218/32
+192.168.5.219/32
+192.168.5.220/32
+192.168.5.221/32
+192.168.5.222/32
+192.168.5.223/32
+192.168.5.224/32
+192.168.5.225/32
+192.168.5.226/32
+192.168.5.227/32
+192.168.5.228/32
+192.168.5.229/32
+192.168.5.230/32
+192.168.5.231/32
+192.168.5.232/32
+192.168.5.233/32
+192.168.5.234/32
+192.168.5.235/32
+192.168.5.236/32
+192.168.5.237/32
+192.168.5.238/32
+192.168.5.239/32
+192.168.5.240/32
+192.168.5.241/32
+192.168.5.242/32
+192.168.5.243/32
+192.168.5.244/32
+192.168.5.245/32
+192.168.5.246/32
+192.168.5.247/32
+192.168.5.248/32
+192.168.5.249/32
+192.168.5.250/32
+192.168.5.251/32
+192.168.5.252/32
+192.168.5.253/32
+192.168.5.254/32
+192.168.5.255/32
diff --git a/tests/nsplit-192.168.5.0-31-32 b/tests/nsplit-192.168.5.0-31-32
new file mode 100644
index 0000000..da706e2
--- /dev/null
+++ b/tests/nsplit-192.168.5.0-31-32
@@ -0,0 +1,2 @@
+192.168.5.0/32
+192.168.5.1/32
diff --git a/tests/nsplit-192.168.5.45-24-26 b/tests/nsplit-192.168.5.45-24-26
new file mode 100644
index 0000000..edfe2fc
--- /dev/null
+++ b/tests/nsplit-192.168.5.45-24-26
@@ -0,0 +1,4 @@
+192.168.5.0/26
+192.168.5.64/26
+192.168.5.128/26
+192.168.5.192/26
diff --git a/tests/nsplit-2a03:2880:20:4f06:face::-56-64 b/tests/nsplit-2a03:2880:20:4f06:face::-56-64
new file mode 100644
index 0000000..e69ed62
--- /dev/null
+++ b/tests/nsplit-2a03:2880:20:4f06:face::-56-64
@@ -0,0 +1,256 @@
+2a03:2880:20:4f00::/64
+2a03:2880:20:4f01::/64
+2a03:2880:20:4f02::/64
+2a03:2880:20:4f03::/64
+2a03:2880:20:4f04::/64
+2a03:2880:20:4f05::/64
+2a03:2880:20:4f06::/64
+2a03:2880:20:4f07::/64
+2a03:2880:20:4f08::/64
+2a03:2880:20:4f09::/64
+2a03:2880:20:4f0a::/64
+2a03:2880:20:4f0b::/64
+2a03:2880:20:4f0c::/64
+2a03:2880:20:4f0d::/64
+2a03:2880:20:4f0e::/64
+2a03:2880:20:4f0f::/64
+2a03:2880:20:4f10::/64
+2a03:2880:20:4f11::/64
+2a03:2880:20:4f12::/64
+2a03:2880:20:4f13::/64
+2a03:2880:20:4f14::/64
+2a03:2880:20:4f15::/64
+2a03:2880:20:4f16::/64
+2a03:2880:20:4f17::/64
+2a03:2880:20:4f18::/64
+2a03:2880:20:4f19::/64
+2a03:2880:20:4f1a::/64
+2a03:2880:20:4f1b::/64
+2a03:2880:20:4f1c::/64
+2a03:2880:20:4f1d::/64
+2a03:2880:20:4f1e::/64
+2a03:2880:20:4f1f::/64
+2a03:2880:20:4f20::/64
+2a03:2880:20:4f21::/64
+2a03:2880:20:4f22::/64
+2a03:2880:20:4f23::/64
+2a03:2880:20:4f24::/64
+2a03:2880:20:4f25::/64
+2a03:2880:20:4f26::/64
+2a03:2880:20:4f27::/64
+2a03:2880:20:4f28::/64
+2a03:2880:20:4f29::/64
+2a03:2880:20:4f2a::/64
+2a03:2880:20:4f2b::/64
+2a03:2880:20:4f2c::/64
+2a03:2880:20:4f2d::/64
+2a03:2880:20:4f2e::/64
+2a03:2880:20:4f2f::/64
+2a03:2880:20:4f30::/64
+2a03:2880:20:4f31::/64
+2a03:2880:20:4f32::/64
+2a03:2880:20:4f33::/64
+2a03:2880:20:4f34::/64
+2a03:2880:20:4f35::/64
+2a03:2880:20:4f36::/64
+2a03:2880:20:4f37::/64
+2a03:2880:20:4f38::/64
+2a03:2880:20:4f39::/64
+2a03:2880:20:4f3a::/64
+2a03:2880:20:4f3b::/64
+2a03:2880:20:4f3c::/64
+2a03:2880:20:4f3d::/64
+2a03:2880:20:4f3e::/64
+2a03:2880:20:4f3f::/64
+2a03:2880:20:4f40::/64
+2a03:2880:20:4f41::/64
+2a03:2880:20:4f42::/64
+2a03:2880:20:4f43::/64
+2a03:2880:20:4f44::/64
+2a03:2880:20:4f45::/64
+2a03:2880:20:4f46::/64
+2a03:2880:20:4f47::/64
+2a03:2880:20:4f48::/64
+2a03:2880:20:4f49::/64
+2a03:2880:20:4f4a::/64
+2a03:2880:20:4f4b::/64
+2a03:2880:20:4f4c::/64
+2a03:2880:20:4f4d::/64
+2a03:2880:20:4f4e::/64
+2a03:2880:20:4f4f::/64
+2a03:2880:20:4f50::/64
+2a03:2880:20:4f51::/64
+2a03:2880:20:4f52::/64
+2a03:2880:20:4f53::/64
+2a03:2880:20:4f54::/64
+2a03:2880:20:4f55::/64
+2a03:2880:20:4f56::/64
+2a03:2880:20:4f57::/64
+2a03:2880:20:4f58::/64
+2a03:2880:20:4f59::/64
+2a03:2880:20:4f5a::/64
+2a03:2880:20:4f5b::/64
+2a03:2880:20:4f5c::/64
+2a03:2880:20:4f5d::/64
+2a03:2880:20:4f5e::/64
+2a03:2880:20:4f5f::/64
+2a03:2880:20:4f60::/64
+2a03:2880:20:4f61::/64
+2a03:2880:20:4f62::/64
+2a03:2880:20:4f63::/64
+2a03:2880:20:4f64::/64
+2a03:2880:20:4f65::/64
+2a03:2880:20:4f66::/64
+2a03:2880:20:4f67::/64
+2a03:2880:20:4f68::/64
+2a03:2880:20:4f69::/64
+2a03:2880:20:4f6a::/64
+2a03:2880:20:4f6b::/64
+2a03:2880:20:4f6c::/64
+2a03:2880:20:4f6d::/64
+2a03:2880:20:4f6e::/64
+2a03:2880:20:4f6f::/64
+2a03:2880:20:4f70::/64
+2a03:2880:20:4f71::/64
+2a03:2880:20:4f72::/64
+2a03:2880:20:4f73::/64
+2a03:2880:20:4f74::/64
+2a03:2880:20:4f75::/64
+2a03:2880:20:4f76::/64
+2a03:2880:20:4f77::/64
+2a03:2880:20:4f78::/64
+2a03:2880:20:4f79::/64
+2a03:2880:20:4f7a::/64
+2a03:2880:20:4f7b::/64
+2a03:2880:20:4f7c::/64
+2a03:2880:20:4f7d::/64
+2a03:2880:20:4f7e::/64
+2a03:2880:20:4f7f::/64
+2a03:2880:20:4f80::/64
+2a03:2880:20:4f81::/64
+2a03:2880:20:4f82::/64
+2a03:2880:20:4f83::/64
+2a03:2880:20:4f84::/64
+2a03:2880:20:4f85::/64
+2a03:2880:20:4f86::/64
+2a03:2880:20:4f87::/64
+2a03:2880:20:4f88::/64
+2a03:2880:20:4f89::/64
+2a03:2880:20:4f8a::/64
+2a03:2880:20:4f8b::/64
+2a03:2880:20:4f8c::/64
+2a03:2880:20:4f8d::/64
+2a03:2880:20:4f8e::/64
+2a03:2880:20:4f8f::/64
+2a03:2880:20:4f90::/64
+2a03:2880:20:4f91::/64
+2a03:2880:20:4f92::/64
+2a03:2880:20:4f93::/64
+2a03:2880:20:4f94::/64
+2a03:2880:20:4f95::/64
+2a03:2880:20:4f96::/64
+2a03:2880:20:4f97::/64
+2a03:2880:20:4f98::/64
+2a03:2880:20:4f99::/64
+2a03:2880:20:4f9a::/64
+2a03:2880:20:4f9b::/64
+2a03:2880:20:4f9c::/64
+2a03:2880:20:4f9d::/64
+2a03:2880:20:4f9e::/64
+2a03:2880:20:4f9f::/64
+2a03:2880:20:4fa0::/64
+2a03:2880:20:4fa1::/64
+2a03:2880:20:4fa2::/64
+2a03:2880:20:4fa3::/64
+2a03:2880:20:4fa4::/64
+2a03:2880:20:4fa5::/64
+2a03:2880:20:4fa6::/64
+2a03:2880:20:4fa7::/64
+2a03:2880:20:4fa8::/64
+2a03:2880:20:4fa9::/64
+2a03:2880:20:4faa::/64
+2a03:2880:20:4fab::/64
+2a03:2880:20:4fac::/64
+2a03:2880:20:4fad::/64
+2a03:2880:20:4fae::/64
+2a03:2880:20:4faf::/64
+2a03:2880:20:4fb0::/64
+2a03:2880:20:4fb1::/64
+2a03:2880:20:4fb2::/64
+2a03:2880:20:4fb3::/64
+2a03:2880:20:4fb4::/64
+2a03:2880:20:4fb5::/64
+2a03:2880:20:4fb6::/64
+2a03:2880:20:4fb7::/64
+2a03:2880:20:4fb8::/64
+2a03:2880:20:4fb9::/64
+2a03:2880:20:4fba::/64
+2a03:2880:20:4fbb::/64
+2a03:2880:20:4fbc::/64
+2a03:2880:20:4fbd::/64
+2a03:2880:20:4fbe::/64
+2a03:2880:20:4fbf::/64
+2a03:2880:20:4fc0::/64
+2a03:2880:20:4fc1::/64
+2a03:2880:20:4fc2::/64
+2a03:2880:20:4fc3::/64
+2a03:2880:20:4fc4::/64
+2a03:2880:20:4fc5::/64
+2a03:2880:20:4fc6::/64
+2a03:2880:20:4fc7::/64
+2a03:2880:20:4fc8::/64
+2a03:2880:20:4fc9::/64
+2a03:2880:20:4fca::/64
+2a03:2880:20:4fcb::/64
+2a03:2880:20:4fcc::/64
+2a03:2880:20:4fcd::/64
+2a03:2880:20:4fce::/64
+2a03:2880:20:4fcf::/64
+2a03:2880:20:4fd0::/64
+2a03:2880:20:4fd1::/64
+2a03:2880:20:4fd2::/64
+2a03:2880:20:4fd3::/64
+2a03:2880:20:4fd4::/64
+2a03:2880:20:4fd5::/64
+2a03:2880:20:4fd6::/64
+2a03:2880:20:4fd7::/64
+2a03:2880:20:4fd8::/64
+2a03:2880:20:4fd9::/64
+2a03:2880:20:4fda::/64
+2a03:2880:20:4fdb::/64
+2a03:2880:20:4fdc::/64
+2a03:2880:20:4fdd::/64
+2a03:2880:20:4fde::/64
+2a03:2880:20:4fdf::/64
+2a03:2880:20:4fe0::/64
+2a03:2880:20:4fe1::/64
+2a03:2880:20:4fe2::/64
+2a03:2880:20:4fe3::/64
+2a03:2880:20:4fe4::/64
+2a03:2880:20:4fe5::/64
+2a03:2880:20:4fe6::/64
+2a03:2880:20:4fe7::/64
+2a03:2880:20:4fe8::/64
+2a03:2880:20:4fe9::/64
+2a03:2880:20:4fea::/64
+2a03:2880:20:4feb::/64
+2a03:2880:20:4fec::/64
+2a03:2880:20:4fed::/64
+2a03:2880:20:4fee::/64
+2a03:2880:20:4fef::/64
+2a03:2880:20:4ff0::/64
+2a03:2880:20:4ff1::/64
+2a03:2880:20:4ff2::/64
+2a03:2880:20:4ff3::/64
+2a03:2880:20:4ff4::/64
+2a03:2880:20:4ff5::/64
+2a03:2880:20:4ff6::/64
+2a03:2880:20:4ff7::/64
+2a03:2880:20:4ff8::/64
+2a03:2880:20:4ff9::/64
+2a03:2880:20:4ffa::/64
+2a03:2880:20:4ffb::/64
+2a03:2880:20:4ffc::/64
+2a03:2880:20:4ffd::/64
+2a03:2880:20:4ffe::/64
+2a03:2880:20:4fff::/64
diff --git a/tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-112-120 b/tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-112-120
new file mode 100644
index 0000000..4987356
--- /dev/null
+++ b/tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-112-120
@@ -0,0 +1,256 @@
+fcfa:b4ca:f1d8:125b:dc00::/120
+fcfa:b4ca:f1d8:125b:dc00::100/120
+fcfa:b4ca:f1d8:125b:dc00::200/120
+fcfa:b4ca:f1d8:125b:dc00::300/120
+fcfa:b4ca:f1d8:125b:dc00::400/120
+fcfa:b4ca:f1d8:125b:dc00::500/120
+fcfa:b4ca:f1d8:125b:dc00::600/120
+fcfa:b4ca:f1d8:125b:dc00::700/120
+fcfa:b4ca:f1d8:125b:dc00::800/120
+fcfa:b4ca:f1d8:125b:dc00::900/120
+fcfa:b4ca:f1d8:125b:dc00::a00/120
+fcfa:b4ca:f1d8:125b:dc00::b00/120
+fcfa:b4ca:f1d8:125b:dc00::c00/120
+fcfa:b4ca:f1d8:125b:dc00::d00/120
+fcfa:b4ca:f1d8:125b:dc00::e00/120
+fcfa:b4ca:f1d8:125b:dc00::f00/120
+fcfa:b4ca:f1d8:125b:dc00::1000/120
+fcfa:b4ca:f1d8:125b:dc00::1100/120
+fcfa:b4ca:f1d8:125b:dc00::1200/120
+fcfa:b4ca:f1d8:125b:dc00::1300/120
+fcfa:b4ca:f1d8:125b:dc00::1400/120
+fcfa:b4ca:f1d8:125b:dc00::1500/120
+fcfa:b4ca:f1d8:125b:dc00::1600/120
+fcfa:b4ca:f1d8:125b:dc00::1700/120
+fcfa:b4ca:f1d8:125b:dc00::1800/120
+fcfa:b4ca:f1d8:125b:dc00::1900/120
+fcfa:b4ca:f1d8:125b:dc00::1a00/120
+fcfa:b4ca:f1d8:125b:dc00::1b00/120
+fcfa:b4ca:f1d8:125b:dc00::1c00/120
+fcfa:b4ca:f1d8:125b:dc00::1d00/120
+fcfa:b4ca:f1d8:125b:dc00::1e00/120
+fcfa:b4ca:f1d8:125b:dc00::1f00/120
+fcfa:b4ca:f1d8:125b:dc00::2000/120
+fcfa:b4ca:f1d8:125b:dc00::2100/120
+fcfa:b4ca:f1d8:125b:dc00::2200/120
+fcfa:b4ca:f1d8:125b:dc00::2300/120
+fcfa:b4ca:f1d8:125b:dc00::2400/120
+fcfa:b4ca:f1d8:125b:dc00::2500/120
+fcfa:b4ca:f1d8:125b:dc00::2600/120
+fcfa:b4ca:f1d8:125b:dc00::2700/120
+fcfa:b4ca:f1d8:125b:dc00::2800/120
+fcfa:b4ca:f1d8:125b:dc00::2900/120
+fcfa:b4ca:f1d8:125b:dc00::2a00/120
+fcfa:b4ca:f1d8:125b:dc00::2b00/120
+fcfa:b4ca:f1d8:125b:dc00::2c00/120
+fcfa:b4ca:f1d8:125b:dc00::2d00/120
+fcfa:b4ca:f1d8:125b:dc00::2e00/120
+fcfa:b4ca:f1d8:125b:dc00::2f00/120
+fcfa:b4ca:f1d8:125b:dc00::3000/120
+fcfa:b4ca:f1d8:125b:dc00::3100/120
+fcfa:b4ca:f1d8:125b:dc00::3200/120
+fcfa:b4ca:f1d8:125b:dc00::3300/120
+fcfa:b4ca:f1d8:125b:dc00::3400/120
+fcfa:b4ca:f1d8:125b:dc00::3500/120
+fcfa:b4ca:f1d8:125b:dc00::3600/120
+fcfa:b4ca:f1d8:125b:dc00::3700/120
+fcfa:b4ca:f1d8:125b:dc00::3800/120
+fcfa:b4ca:f1d8:125b:dc00::3900/120
+fcfa:b4ca:f1d8:125b:dc00::3a00/120
+fcfa:b4ca:f1d8:125b:dc00::3b00/120
+fcfa:b4ca:f1d8:125b:dc00::3c00/120
+fcfa:b4ca:f1d8:125b:dc00::3d00/120
+fcfa:b4ca:f1d8:125b:dc00::3e00/120
+fcfa:b4ca:f1d8:125b:dc00::3f00/120
+fcfa:b4ca:f1d8:125b:dc00::4000/120
+fcfa:b4ca:f1d8:125b:dc00::4100/120
+fcfa:b4ca:f1d8:125b:dc00::4200/120
+fcfa:b4ca:f1d8:125b:dc00::4300/120
+fcfa:b4ca:f1d8:125b:dc00::4400/120
+fcfa:b4ca:f1d8:125b:dc00::4500/120
+fcfa:b4ca:f1d8:125b:dc00::4600/120
+fcfa:b4ca:f1d8:125b:dc00::4700/120
+fcfa:b4ca:f1d8:125b:dc00::4800/120
+fcfa:b4ca:f1d8:125b:dc00::4900/120
+fcfa:b4ca:f1d8:125b:dc00::4a00/120
+fcfa:b4ca:f1d8:125b:dc00::4b00/120
+fcfa:b4ca:f1d8:125b:dc00::4c00/120
+fcfa:b4ca:f1d8:125b:dc00::4d00/120
+fcfa:b4ca:f1d8:125b:dc00::4e00/120
+fcfa:b4ca:f1d8:125b:dc00::4f00/120
+fcfa:b4ca:f1d8:125b:dc00::5000/120
+fcfa:b4ca:f1d8:125b:dc00::5100/120
+fcfa:b4ca:f1d8:125b:dc00::5200/120
+fcfa:b4ca:f1d8:125b:dc00::5300/120
+fcfa:b4ca:f1d8:125b:dc00::5400/120
+fcfa:b4ca:f1d8:125b:dc00::5500/120
+fcfa:b4ca:f1d8:125b:dc00::5600/120
+fcfa:b4ca:f1d8:125b:dc00::5700/120
+fcfa:b4ca:f1d8:125b:dc00::5800/120
+fcfa:b4ca:f1d8:125b:dc00::5900/120
+fcfa:b4ca:f1d8:125b:dc00::5a00/120
+fcfa:b4ca:f1d8:125b:dc00::5b00/120
+fcfa:b4ca:f1d8:125b:dc00::5c00/120
+fcfa:b4ca:f1d8:125b:dc00::5d00/120
+fcfa:b4ca:f1d8:125b:dc00::5e00/120
+fcfa:b4ca:f1d8:125b:dc00::5f00/120
+fcfa:b4ca:f1d8:125b:dc00::6000/120
+fcfa:b4ca:f1d8:125b:dc00::6100/120
+fcfa:b4ca:f1d8:125b:dc00::6200/120
+fcfa:b4ca:f1d8:125b:dc00::6300/120
+fcfa:b4ca:f1d8:125b:dc00::6400/120
+fcfa:b4ca:f1d8:125b:dc00::6500/120
+fcfa:b4ca:f1d8:125b:dc00::6600/120
+fcfa:b4ca:f1d8:125b:dc00::6700/120
+fcfa:b4ca:f1d8:125b:dc00::6800/120
+fcfa:b4ca:f1d8:125b:dc00::6900/120
+fcfa:b4ca:f1d8:125b:dc00::6a00/120
+fcfa:b4ca:f1d8:125b:dc00::6b00/120
+fcfa:b4ca:f1d8:125b:dc00::6c00/120
+fcfa:b4ca:f1d8:125b:dc00::6d00/120
+fcfa:b4ca:f1d8:125b:dc00::6e00/120
+fcfa:b4ca:f1d8:125b:dc00::6f00/120
+fcfa:b4ca:f1d8:125b:dc00::7000/120
+fcfa:b4ca:f1d8:125b:dc00::7100/120
+fcfa:b4ca:f1d8:125b:dc00::7200/120
+fcfa:b4ca:f1d8:125b:dc00::7300/120
+fcfa:b4ca:f1d8:125b:dc00::7400/120
+fcfa:b4ca:f1d8:125b:dc00::7500/120
+fcfa:b4ca:f1d8:125b:dc00::7600/120
+fcfa:b4ca:f1d8:125b:dc00::7700/120
+fcfa:b4ca:f1d8:125b:dc00::7800/120
+fcfa:b4ca:f1d8:125b:dc00::7900/120
+fcfa:b4ca:f1d8:125b:dc00::7a00/120
+fcfa:b4ca:f1d8:125b:dc00::7b00/120
+fcfa:b4ca:f1d8:125b:dc00::7c00/120
+fcfa:b4ca:f1d8:125b:dc00::7d00/120
+fcfa:b4ca:f1d8:125b:dc00::7e00/120
+fcfa:b4ca:f1d8:125b:dc00::7f00/120
+fcfa:b4ca:f1d8:125b:dc00::8000/120
+fcfa:b4ca:f1d8:125b:dc00::8100/120
+fcfa:b4ca:f1d8:125b:dc00::8200/120
+fcfa:b4ca:f1d8:125b:dc00::8300/120
+fcfa:b4ca:f1d8:125b:dc00::8400/120
+fcfa:b4ca:f1d8:125b:dc00::8500/120
+fcfa:b4ca:f1d8:125b:dc00::8600/120
+fcfa:b4ca:f1d8:125b:dc00::8700/120
+fcfa:b4ca:f1d8:125b:dc00::8800/120
+fcfa:b4ca:f1d8:125b:dc00::8900/120
+fcfa:b4ca:f1d8:125b:dc00::8a00/120
+fcfa:b4ca:f1d8:125b:dc00::8b00/120
+fcfa:b4ca:f1d8:125b:dc00::8c00/120
+fcfa:b4ca:f1d8:125b:dc00::8d00/120
+fcfa:b4ca:f1d8:125b:dc00::8e00/120
+fcfa:b4ca:f1d8:125b:dc00::8f00/120
+fcfa:b4ca:f1d8:125b:dc00::9000/120
+fcfa:b4ca:f1d8:125b:dc00::9100/120
+fcfa:b4ca:f1d8:125b:dc00::9200/120
+fcfa:b4ca:f1d8:125b:dc00::9300/120
+fcfa:b4ca:f1d8:125b:dc00::9400/120
+fcfa:b4ca:f1d8:125b:dc00::9500/120
+fcfa:b4ca:f1d8:125b:dc00::9600/120
+fcfa:b4ca:f1d8:125b:dc00::9700/120
+fcfa:b4ca:f1d8:125b:dc00::9800/120
+fcfa:b4ca:f1d8:125b:dc00::9900/120
+fcfa:b4ca:f1d8:125b:dc00::9a00/120
+fcfa:b4ca:f1d8:125b:dc00::9b00/120
+fcfa:b4ca:f1d8:125b:dc00::9c00/120
+fcfa:b4ca:f1d8:125b:dc00::9d00/120
+fcfa:b4ca:f1d8:125b:dc00::9e00/120
+fcfa:b4ca:f1d8:125b:dc00::9f00/120
+fcfa:b4ca:f1d8:125b:dc00::a000/120
+fcfa:b4ca:f1d8:125b:dc00::a100/120
+fcfa:b4ca:f1d8:125b:dc00::a200/120
+fcfa:b4ca:f1d8:125b:dc00::a300/120
+fcfa:b4ca:f1d8:125b:dc00::a400/120
+fcfa:b4ca:f1d8:125b:dc00::a500/120
+fcfa:b4ca:f1d8:125b:dc00::a600/120
+fcfa:b4ca:f1d8:125b:dc00::a700/120
+fcfa:b4ca:f1d8:125b:dc00::a800/120
+fcfa:b4ca:f1d8:125b:dc00::a900/120
+fcfa:b4ca:f1d8:125b:dc00::aa00/120
+fcfa:b4ca:f1d8:125b:dc00::ab00/120
+fcfa:b4ca:f1d8:125b:dc00::ac00/120
+fcfa:b4ca:f1d8:125b:dc00::ad00/120
+fcfa:b4ca:f1d8:125b:dc00::ae00/120
+fcfa:b4ca:f1d8:125b:dc00::af00/120
+fcfa:b4ca:f1d8:125b:dc00::b000/120
+fcfa:b4ca:f1d8:125b:dc00::b100/120
+fcfa:b4ca:f1d8:125b:dc00::b200/120
+fcfa:b4ca:f1d8:125b:dc00::b300/120
+fcfa:b4ca:f1d8:125b:dc00::b400/120
+fcfa:b4ca:f1d8:125b:dc00::b500/120
+fcfa:b4ca:f1d8:125b:dc00::b600/120
+fcfa:b4ca:f1d8:125b:dc00::b700/120
+fcfa:b4ca:f1d8:125b:dc00::b800/120
+fcfa:b4ca:f1d8:125b:dc00::b900/120
+fcfa:b4ca:f1d8:125b:dc00::ba00/120
+fcfa:b4ca:f1d8:125b:dc00::bb00/120
+fcfa:b4ca:f1d8:125b:dc00::bc00/120
+fcfa:b4ca:f1d8:125b:dc00::bd00/120
+fcfa:b4ca:f1d8:125b:dc00::be00/120
+fcfa:b4ca:f1d8:125b:dc00::bf00/120
+fcfa:b4ca:f1d8:125b:dc00::c000/120
+fcfa:b4ca:f1d8:125b:dc00::c100/120
+fcfa:b4ca:f1d8:125b:dc00::c200/120
+fcfa:b4ca:f1d8:125b:dc00::c300/120
+fcfa:b4ca:f1d8:125b:dc00::c400/120
+fcfa:b4ca:f1d8:125b:dc00::c500/120
+fcfa:b4ca:f1d8:125b:dc00::c600/120
+fcfa:b4ca:f1d8:125b:dc00::c700/120
+fcfa:b4ca:f1d8:125b:dc00::c800/120
+fcfa:b4ca:f1d8:125b:dc00::c900/120
+fcfa:b4ca:f1d8:125b:dc00::ca00/120
+fcfa:b4ca:f1d8:125b:dc00::cb00/120
+fcfa:b4ca:f1d8:125b:dc00::cc00/120
+fcfa:b4ca:f1d8:125b:dc00::cd00/120
+fcfa:b4ca:f1d8:125b:dc00::ce00/120
+fcfa:b4ca:f1d8:125b:dc00::cf00/120
+fcfa:b4ca:f1d8:125b:dc00::d000/120
+fcfa:b4ca:f1d8:125b:dc00::d100/120
+fcfa:b4ca:f1d8:125b:dc00::d200/120
+fcfa:b4ca:f1d8:125b:dc00::d300/120
+fcfa:b4ca:f1d8:125b:dc00::d400/120
+fcfa:b4ca:f1d8:125b:dc00::d500/120
+fcfa:b4ca:f1d8:125b:dc00::d600/120
+fcfa:b4ca:f1d8:125b:dc00::d700/120
+fcfa:b4ca:f1d8:125b:dc00::d800/120
+fcfa:b4ca:f1d8:125b:dc00::d900/120
+fcfa:b4ca:f1d8:125b:dc00::da00/120
+fcfa:b4ca:f1d8:125b:dc00::db00/120
+fcfa:b4ca:f1d8:125b:dc00::dc00/120
+fcfa:b4ca:f1d8:125b:dc00::dd00/120
+fcfa:b4ca:f1d8:125b:dc00::de00/120
+fcfa:b4ca:f1d8:125b:dc00::df00/120
+fcfa:b4ca:f1d8:125b:dc00::e000/120
+fcfa:b4ca:f1d8:125b:dc00::e100/120
+fcfa:b4ca:f1d8:125b:dc00::e200/120
+fcfa:b4ca:f1d8:125b:dc00::e300/120
+fcfa:b4ca:f1d8:125b:dc00::e400/120
+fcfa:b4ca:f1d8:125b:dc00::e500/120
+fcfa:b4ca:f1d8:125b:dc00::e600/120
+fcfa:b4ca:f1d8:125b:dc00::e700/120
+fcfa:b4ca:f1d8:125b:dc00::e800/120
+fcfa:b4ca:f1d8:125b:dc00::e900/120
+fcfa:b4ca:f1d8:125b:dc00::ea00/120
+fcfa:b4ca:f1d8:125b:dc00::eb00/120
+fcfa:b4ca:f1d8:125b:dc00::ec00/120
+fcfa:b4ca:f1d8:125b:dc00::ed00/120
+fcfa:b4ca:f1d8:125b:dc00::ee00/120
+fcfa:b4ca:f1d8:125b:dc00::ef00/120
+fcfa:b4ca:f1d8:125b:dc00::f000/120
+fcfa:b4ca:f1d8:125b:dc00::f100/120
+fcfa:b4ca:f1d8:125b:dc00::f200/120
+fcfa:b4ca:f1d8:125b:dc00::f300/120
+fcfa:b4ca:f1d8:125b:dc00::f400/120
+fcfa:b4ca:f1d8:125b:dc00::f500/120
+fcfa:b4ca:f1d8:125b:dc00::f600/120
+fcfa:b4ca:f1d8:125b:dc00::f700/120
+fcfa:b4ca:f1d8:125b:dc00::f800/120
+fcfa:b4ca:f1d8:125b:dc00::f900/120
+fcfa:b4ca:f1d8:125b:dc00::fa00/120
+fcfa:b4ca:f1d8:125b:dc00::fb00/120
+fcfa:b4ca:f1d8:125b:dc00::fc00/120
+fcfa:b4ca:f1d8:125b:dc00::fd00/120
+fcfa:b4ca:f1d8:125b:dc00::fe00/120
+fcfa:b4ca:f1d8:125b:dc00::ff00/120
diff --git a/tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-127-128 b/tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-127-128
new file mode 100644
index 0000000..9c10236
--- /dev/null
+++ b/tests/nsplit-fcfa:b4ca:f1d8:125b:dc00::-127-128
@@ -0,0 +1,2 @@
+fcfa:b4ca:f1d8:125b:dc00::/128
+fcfa:b4ca:f1d8:125b:dc00::1/128
diff --git a/tests/run-coverage.sh b/tests/run-coverage.sh
new file mode 100755
index 0000000..145eb12
--- /dev/null
+++ b/tests/run-coverage.sh
@@ -0,0 +1,4 @@
+#! /bin/sh
+
+cat public/index.html|grep headerCovTableEntry|grep "%"|head -1|sed 's/^.*>\([0-9\.\ %]*\)<.*$/coverage lines: \1/'
+
diff --git a/tests/split-10.10.10.0-16-18 b/tests/split-10.10.10.0-16-18
new file mode 100644
index 0000000..ec76506
--- /dev/null
+++ b/tests/split-10.10.10.0-16-18
@@ -0,0 +1,8 @@
+[Split networks]
+Network: 10.10.0.0/18
+Network: 10.10.64.0/18
+Network: 10.10.128.0/18
+Network: 10.10.192.0/18
+
+Total: 4
+Hosts/Net: 16382
diff --git a/tests/split-10.10.10.0-16-24 b/tests/split-10.10.10.0-16-24
new file mode 100644
index 0000000..719020f
--- /dev/null
+++ b/tests/split-10.10.10.0-16-24
@@ -0,0 +1,260 @@
+[Split networks]
+Network: 10.10.0.0/24
+Network: 10.10.1.0/24
+Network: 10.10.2.0/24
+Network: 10.10.3.0/24
+Network: 10.10.4.0/24
+Network: 10.10.5.0/24
+Network: 10.10.6.0/24
+Network: 10.10.7.0/24
+Network: 10.10.8.0/24
+Network: 10.10.9.0/24
+Network: 10.10.10.0/24
+Network: 10.10.11.0/24
+Network: 10.10.12.0/24
+Network: 10.10.13.0/24
+Network: 10.10.14.0/24
+Network: 10.10.15.0/24
+Network: 10.10.16.0/24
+Network: 10.10.17.0/24
+Network: 10.10.18.0/24
+Network: 10.10.19.0/24
+Network: 10.10.20.0/24
+Network: 10.10.21.0/24
+Network: 10.10.22.0/24
+Network: 10.10.23.0/24
+Network: 10.10.24.0/24
+Network: 10.10.25.0/24
+Network: 10.10.26.0/24
+Network: 10.10.27.0/24
+Network: 10.10.28.0/24
+Network: 10.10.29.0/24
+Network: 10.10.30.0/24
+Network: 10.10.31.0/24
+Network: 10.10.32.0/24
+Network: 10.10.33.0/24
+Network: 10.10.34.0/24
+Network: 10.10.35.0/24
+Network: 10.10.36.0/24
+Network: 10.10.37.0/24
+Network: 10.10.38.0/24
+Network: 10.10.39.0/24
+Network: 10.10.40.0/24
+Network: 10.10.41.0/24
+Network: 10.10.42.0/24
+Network: 10.10.43.0/24
+Network: 10.10.44.0/24
+Network: 10.10.45.0/24
+Network: 10.10.46.0/24
+Network: 10.10.47.0/24
+Network: 10.10.48.0/24
+Network: 10.10.49.0/24
+Network: 10.10.50.0/24
+Network: 10.10.51.0/24
+Network: 10.10.52.0/24
+Network: 10.10.53.0/24
+Network: 10.10.54.0/24
+Network: 10.10.55.0/24
+Network: 10.10.56.0/24
+Network: 10.10.57.0/24
+Network: 10.10.58.0/24
+Network: 10.10.59.0/24
+Network: 10.10.60.0/24
+Network: 10.10.61.0/24
+Network: 10.10.62.0/24
+Network: 10.10.63.0/24
+Network: 10.10.64.0/24
+Network: 10.10.65.0/24
+Network: 10.10.66.0/24
+Network: 10.10.67.0/24
+Network: 10.10.68.0/24
+Network: 10.10.69.0/24
+Network: 10.10.70.0/24
+Network: 10.10.71.0/24
+Network: 10.10.72.0/24
+Network: 10.10.73.0/24
+Network: 10.10.74.0/24
+Network: 10.10.75.0/24
+Network: 10.10.76.0/24
+Network: 10.10.77.0/24
+Network: 10.10.78.0/24
+Network: 10.10.79.0/24
+Network: 10.10.80.0/24
+Network: 10.10.81.0/24
+Network: 10.10.82.0/24
+Network: 10.10.83.0/24
+Network: 10.10.84.0/24
+Network: 10.10.85.0/24
+Network: 10.10.86.0/24
+Network: 10.10.87.0/24
+Network: 10.10.88.0/24
+Network: 10.10.89.0/24
+Network: 10.10.90.0/24
+Network: 10.10.91.0/24
+Network: 10.10.92.0/24
+Network: 10.10.93.0/24
+Network: 10.10.94.0/24
+Network: 10.10.95.0/24
+Network: 10.10.96.0/24
+Network: 10.10.97.0/24
+Network: 10.10.98.0/24
+Network: 10.10.99.0/24
+Network: 10.10.100.0/24
+Network: 10.10.101.0/24
+Network: 10.10.102.0/24
+Network: 10.10.103.0/24
+Network: 10.10.104.0/24
+Network: 10.10.105.0/24
+Network: 10.10.106.0/24
+Network: 10.10.107.0/24
+Network: 10.10.108.0/24
+Network: 10.10.109.0/24
+Network: 10.10.110.0/24
+Network: 10.10.111.0/24
+Network: 10.10.112.0/24
+Network: 10.10.113.0/24
+Network: 10.10.114.0/24
+Network: 10.10.115.0/24
+Network: 10.10.116.0/24
+Network: 10.10.117.0/24
+Network: 10.10.118.0/24
+Network: 10.10.119.0/24
+Network: 10.10.120.0/24
+Network: 10.10.121.0/24
+Network: 10.10.122.0/24
+Network: 10.10.123.0/24
+Network: 10.10.124.0/24
+Network: 10.10.125.0/24
+Network: 10.10.126.0/24
+Network: 10.10.127.0/24
+Network: 10.10.128.0/24
+Network: 10.10.129.0/24
+Network: 10.10.130.0/24
+Network: 10.10.131.0/24
+Network: 10.10.132.0/24
+Network: 10.10.133.0/24
+Network: 10.10.134.0/24
+Network: 10.10.135.0/24
+Network: 10.10.136.0/24
+Network: 10.10.137.0/24
+Network: 10.10.138.0/24
+Network: 10.10.139.0/24
+Network: 10.10.140.0/24
+Network: 10.10.141.0/24
+Network: 10.10.142.0/24
+Network: 10.10.143.0/24
+Network: 10.10.144.0/24
+Network: 10.10.145.0/24
+Network: 10.10.146.0/24
+Network: 10.10.147.0/24
+Network: 10.10.148.0/24
+Network: 10.10.149.0/24
+Network: 10.10.150.0/24
+Network: 10.10.151.0/24
+Network: 10.10.152.0/24
+Network: 10.10.153.0/24
+Network: 10.10.154.0/24
+Network: 10.10.155.0/24
+Network: 10.10.156.0/24
+Network: 10.10.157.0/24
+Network: 10.10.158.0/24
+Network: 10.10.159.0/24
+Network: 10.10.160.0/24
+Network: 10.10.161.0/24
+Network: 10.10.162.0/24
+Network: 10.10.163.0/24
+Network: 10.10.164.0/24
+Network: 10.10.165.0/24
+Network: 10.10.166.0/24
+Network: 10.10.167.0/24
+Network: 10.10.168.0/24
+Network: 10.10.169.0/24
+Network: 10.10.170.0/24
+Network: 10.10.171.0/24
+Network: 10.10.172.0/24
+Network: 10.10.173.0/24
+Network: 10.10.174.0/24
+Network: 10.10.175.0/24
+Network: 10.10.176.0/24
+Network: 10.10.177.0/24
+Network: 10.10.178.0/24
+Network: 10.10.179.0/24
+Network: 10.10.180.0/24
+Network: 10.10.181.0/24
+Network: 10.10.182.0/24
+Network: 10.10.183.0/24
+Network: 10.10.184.0/24
+Network: 10.10.185.0/24
+Network: 10.10.186.0/24
+Network: 10.10.187.0/24
+Network: 10.10.188.0/24
+Network: 10.10.189.0/24
+Network: 10.10.190.0/24
+Network: 10.10.191.0/24
+Network: 10.10.192.0/24
+Network: 10.10.193.0/24
+Network: 10.10.194.0/24
+Network: 10.10.195.0/24
+Network: 10.10.196.0/24
+Network: 10.10.197.0/24
+Network: 10.10.198.0/24
+Network: 10.10.199.0/24
+Network: 10.10.200.0/24
+Network: 10.10.201.0/24
+Network: 10.10.202.0/24
+Network: 10.10.203.0/24
+Network: 10.10.204.0/24
+Network: 10.10.205.0/24
+Network: 10.10.206.0/24
+Network: 10.10.207.0/24
+Network: 10.10.208.0/24
+Network: 10.10.209.0/24
+Network: 10.10.210.0/24
+Network: 10.10.211.0/24
+Network: 10.10.212.0/24
+Network: 10.10.213.0/24
+Network: 10.10.214.0/24
+Network: 10.10.215.0/24
+Network: 10.10.216.0/24
+Network: 10.10.217.0/24
+Network: 10.10.218.0/24
+Network: 10.10.219.0/24
+Network: 10.10.220.0/24
+Network: 10.10.221.0/24
+Network: 10.10.222.0/24
+Network: 10.10.223.0/24
+Network: 10.10.224.0/24
+Network: 10.10.225.0/24
+Network: 10.10.226.0/24
+Network: 10.10.227.0/24
+Network: 10.10.228.0/24
+Network: 10.10.229.0/24
+Network: 10.10.230.0/24
+Network: 10.10.231.0/24
+Network: 10.10.232.0/24
+Network: 10.10.233.0/24
+Network: 10.10.234.0/24
+Network: 10.10.235.0/24
+Network: 10.10.236.0/24
+Network: 10.10.237.0/24
+Network: 10.10.238.0/24
+Network: 10.10.239.0/24
+Network: 10.10.240.0/24
+Network: 10.10.241.0/24
+Network: 10.10.242.0/24
+Network: 10.10.243.0/24
+Network: 10.10.244.0/24
+Network: 10.10.245.0/24
+Network: 10.10.246.0/24
+Network: 10.10.247.0/24
+Network: 10.10.248.0/24
+Network: 10.10.249.0/24
+Network: 10.10.250.0/24
+Network: 10.10.251.0/24
+Network: 10.10.252.0/24
+Network: 10.10.253.0/24
+Network: 10.10.254.0/24
+Network: 10.10.255.0/24
+
+Total: 256
+Hosts/Net: 254
diff --git a/tests/split-192.168.5.0-24-29 b/tests/split-192.168.5.0-24-29
new file mode 100644
index 0000000..ca06f8e
--- /dev/null
+++ b/tests/split-192.168.5.0-24-29
@@ -0,0 +1,36 @@
+[Split networks]
+Network: 192.168.5.0/29
+Network: 192.168.5.8/29
+Network: 192.168.5.16/29
+Network: 192.168.5.24/29
+Network: 192.168.5.32/29
+Network: 192.168.5.40/29
+Network: 192.168.5.48/29
+Network: 192.168.5.56/29
+Network: 192.168.5.64/29
+Network: 192.168.5.72/29
+Network: 192.168.5.80/29
+Network: 192.168.5.88/29
+Network: 192.168.5.96/29
+Network: 192.168.5.104/29
+Network: 192.168.5.112/29
+Network: 192.168.5.120/29
+Network: 192.168.5.128/29
+Network: 192.168.5.136/29
+Network: 192.168.5.144/29
+Network: 192.168.5.152/29
+Network: 192.168.5.160/29
+Network: 192.168.5.168/29
+Network: 192.168.5.176/29
+Network: 192.168.5.184/29
+Network: 192.168.5.192/29
+Network: 192.168.5.200/29
+Network: 192.168.5.208/29
+Network: 192.168.5.216/29
+Network: 192.168.5.224/29
+Network: 192.168.5.232/29
+Network: 192.168.5.240/29
+Network: 192.168.5.248/29
+
+Total: 32
+Hosts/Net: 6
diff --git a/tests/split-192.168.5.0-24-31 b/tests/split-192.168.5.0-24-31
new file mode 100644
index 0000000..fd2dd8a
--- /dev/null
+++ b/tests/split-192.168.5.0-24-31
@@ -0,0 +1,132 @@
+[Split networks]
+Network: 192.168.5.0/31
+Network: 192.168.5.2/31
+Network: 192.168.5.4/31
+Network: 192.168.5.6/31
+Network: 192.168.5.8/31
+Network: 192.168.5.10/31
+Network: 192.168.5.12/31
+Network: 192.168.5.14/31
+Network: 192.168.5.16/31
+Network: 192.168.5.18/31
+Network: 192.168.5.20/31
+Network: 192.168.5.22/31
+Network: 192.168.5.24/31
+Network: 192.168.5.26/31
+Network: 192.168.5.28/31
+Network: 192.168.5.30/31
+Network: 192.168.5.32/31
+Network: 192.168.5.34/31
+Network: 192.168.5.36/31
+Network: 192.168.5.38/31
+Network: 192.168.5.40/31
+Network: 192.168.5.42/31
+Network: 192.168.5.44/31
+Network: 192.168.5.46/31
+Network: 192.168.5.48/31
+Network: 192.168.5.50/31
+Network: 192.168.5.52/31
+Network: 192.168.5.54/31
+Network: 192.168.5.56/31
+Network: 192.168.5.58/31
+Network: 192.168.5.60/31
+Network: 192.168.5.62/31
+Network: 192.168.5.64/31
+Network: 192.168.5.66/31
+Network: 192.168.5.68/31
+Network: 192.168.5.70/31
+Network: 192.168.5.72/31
+Network: 192.168.5.74/31
+Network: 192.168.5.76/31
+Network: 192.168.5.78/31
+Network: 192.168.5.80/31
+Network: 192.168.5.82/31
+Network: 192.168.5.84/31
+Network: 192.168.5.86/31
+Network: 192.168.5.88/31
+Network: 192.168.5.90/31
+Network: 192.168.5.92/31
+Network: 192.168.5.94/31
+Network: 192.168.5.96/31
+Network: 192.168.5.98/31
+Network: 192.168.5.100/31
+Network: 192.168.5.102/31
+Network: 192.168.5.104/31
+Network: 192.168.5.106/31
+Network: 192.168.5.108/31
+Network: 192.168.5.110/31
+Network: 192.168.5.112/31
+Network: 192.168.5.114/31
+Network: 192.168.5.116/31
+Network: 192.168.5.118/31
+Network: 192.168.5.120/31
+Network: 192.168.5.122/31
+Network: 192.168.5.124/31
+Network: 192.168.5.126/31
+Network: 192.168.5.128/31
+Network: 192.168.5.130/31
+Network: 192.168.5.132/31
+Network: 192.168.5.134/31
+Network: 192.168.5.136/31
+Network: 192.168.5.138/31
+Network: 192.168.5.140/31
+Network: 192.168.5.142/31
+Network: 192.168.5.144/31
+Network: 192.168.5.146/31
+Network: 192.168.5.148/31
+Network: 192.168.5.150/31
+Network: 192.168.5.152/31
+Network: 192.168.5.154/31
+Network: 192.168.5.156/31
+Network: 192.168.5.158/31
+Network: 192.168.5.160/31
+Network: 192.168.5.162/31
+Network: 192.168.5.164/31
+Network: 192.168.5.166/31
+Network: 192.168.5.168/31
+Network: 192.168.5.170/31
+Network: 192.168.5.172/31
+Network: 192.168.5.174/31
+Network: 192.168.5.176/31
+Network: 192.168.5.178/31
+Network: 192.168.5.180/31
+Network: 192.168.5.182/31
+Network: 192.168.5.184/31
+Network: 192.168.5.186/31
+Network: 192.168.5.188/31
+Network: 192.168.5.190/31
+Network: 192.168.5.192/31
+Network: 192.168.5.194/31
+Network: 192.168.5.196/31
+Network: 192.168.5.198/31
+Network: 192.168.5.200/31
+Network: 192.168.5.202/31
+Network: 192.168.5.204/31
+Network: 192.168.5.206/31
+Network: 192.168.5.208/31
+Network: 192.168.5.210/31
+Network: 192.168.5.212/31
+Network: 192.168.5.214/31
+Network: 192.168.5.216/31
+Network: 192.168.5.218/31
+Network: 192.168.5.220/31
+Network: 192.168.5.222/31
+Network: 192.168.5.224/31
+Network: 192.168.5.226/31
+Network: 192.168.5.228/31
+Network: 192.168.5.230/31
+Network: 192.168.5.232/31
+Network: 192.168.5.234/31
+Network: 192.168.5.236/31
+Network: 192.168.5.238/31
+Network: 192.168.5.240/31
+Network: 192.168.5.242/31
+Network: 192.168.5.244/31
+Network: 192.168.5.246/31
+Network: 192.168.5.248/31
+Network: 192.168.5.250/31
+Network: 192.168.5.252/31
+Network: 192.168.5.254/31
+
+Total: 128
+Hosts/Net: 2
diff --git a/tests/split-192.168.5.0-24-32 b/tests/split-192.168.5.0-24-32
new file mode 100644
index 0000000..caa42eb
--- /dev/null
+++ b/tests/split-192.168.5.0-24-32
@@ -0,0 +1,260 @@
+[Split networks]
+Network: 192.168.5.0/32
+Network: 192.168.5.1/32
+Network: 192.168.5.2/32
+Network: 192.168.5.3/32
+Network: 192.168.5.4/32
+Network: 192.168.5.5/32
+Network: 192.168.5.6/32
+Network: 192.168.5.7/32
+Network: 192.168.5.8/32
+Network: 192.168.5.9/32
+Network: 192.168.5.10/32
+Network: 192.168.5.11/32
+Network: 192.168.5.12/32
+Network: 192.168.5.13/32
+Network: 192.168.5.14/32
+Network: 192.168.5.15/32
+Network: 192.168.5.16/32
+Network: 192.168.5.17/32
+Network: 192.168.5.18/32
+Network: 192.168.5.19/32
+Network: 192.168.5.20/32
+Network: 192.168.5.21/32
+Network: 192.168.5.22/32
+Network: 192.168.5.23/32
+Network: 192.168.5.24/32
+Network: 192.168.5.25/32
+Network: 192.168.5.26/32
+Network: 192.168.5.27/32
+Network: 192.168.5.28/32
+Network: 192.168.5.29/32
+Network: 192.168.5.30/32
+Network: 192.168.5.31/32
+Network: 192.168.5.32/32
+Network: 192.168.5.33/32
+Network: 192.168.5.34/32
+Network: 192.168.5.35/32
+Network: 192.168.5.36/32
+Network: 192.168.5.37/32
+Network: 192.168.5.38/32
+Network: 192.168.5.39/32
+Network: 192.168.5.40/32
+Network: 192.168.5.41/32
+Network: 192.168.5.42/32
+Network: 192.168.5.43/32
+Network: 192.168.5.44/32
+Network: 192.168.5.45/32
+Network: 192.168.5.46/32
+Network: 192.168.5.47/32
+Network: 192.168.5.48/32
+Network: 192.168.5.49/32
+Network: 192.168.5.50/32
+Network: 192.168.5.51/32
+Network: 192.168.5.52/32
+Network: 192.168.5.53/32
+Network: 192.168.5.54/32
+Network: 192.168.5.55/32
+Network: 192.168.5.56/32
+Network: 192.168.5.57/32
+Network: 192.168.5.58/32
+Network: 192.168.5.59/32
+Network: 192.168.5.60/32
+Network: 192.168.5.61/32
+Network: 192.168.5.62/32
+Network: 192.168.5.63/32
+Network: 192.168.5.64/32
+Network: 192.168.5.65/32
+Network: 192.168.5.66/32
+Network: 192.168.5.67/32
+Network: 192.168.5.68/32
+Network: 192.168.5.69/32
+Network: 192.168.5.70/32
+Network: 192.168.5.71/32
+Network: 192.168.5.72/32
+Network: 192.168.5.73/32
+Network: 192.168.5.74/32
+Network: 192.168.5.75/32
+Network: 192.168.5.76/32
+Network: 192.168.5.77/32
+Network: 192.168.5.78/32
+Network: 192.168.5.79/32
+Network: 192.168.5.80/32
+Network: 192.168.5.81/32
+Network: 192.168.5.82/32
+Network: 192.168.5.83/32
+Network: 192.168.5.84/32
+Network: 192.168.5.85/32
+Network: 192.168.5.86/32
+Network: 192.168.5.87/32
+Network: 192.168.5.88/32
+Network: 192.168.5.89/32
+Network: 192.168.5.90/32
+Network: 192.168.5.91/32
+Network: 192.168.5.92/32
+Network: 192.168.5.93/32
+Network: 192.168.5.94/32
+Network: 192.168.5.95/32
+Network: 192.168.5.96/32
+Network: 192.168.5.97/32
+Network: 192.168.5.98/32
+Network: 192.168.5.99/32
+Network: 192.168.5.100/32
+Network: 192.168.5.101/32
+Network: 192.168.5.102/32
+Network: 192.168.5.103/32
+Network: 192.168.5.104/32
+Network: 192.168.5.105/32
+Network: 192.168.5.106/32
+Network: 192.168.5.107/32
+Network: 192.168.5.108/32
+Network: 192.168.5.109/32
+Network: 192.168.5.110/32
+Network: 192.168.5.111/32
+Network: 192.168.5.112/32
+Network: 192.168.5.113/32
+Network: 192.168.5.114/32
+Network: 192.168.5.115/32
+Network: 192.168.5.116/32
+Network: 192.168.5.117/32
+Network: 192.168.5.118/32
+Network: 192.168.5.119/32
+Network: 192.168.5.120/32
+Network: 192.168.5.121/32
+Network: 192.168.5.122/32
+Network: 192.168.5.123/32
+Network: 192.168.5.124/32
+Network: 192.168.5.125/32
+Network: 192.168.5.126/32
+Network: 192.168.5.127/32
+Network: 192.168.5.128/32
+Network: 192.168.5.129/32
+Network: 192.168.5.130/32
+Network: 192.168.5.131/32
+Network: 192.168.5.132/32
+Network: 192.168.5.133/32
+Network: 192.168.5.134/32
+Network: 192.168.5.135/32
+Network: 192.168.5.136/32
+Network: 192.168.5.137/32
+Network: 192.168.5.138/32
+Network: 192.168.5.139/32
+Network: 192.168.5.140/32
+Network: 192.168.5.141/32
+Network: 192.168.5.142/32
+Network: 192.168.5.143/32
+Network: 192.168.5.144/32
+Network: 192.168.5.145/32
+Network: 192.168.5.146/32
+Network: 192.168.5.147/32
+Network: 192.168.5.148/32
+Network: 192.168.5.149/32
+Network: 192.168.5.150/32
+Network: 192.168.5.151/32
+Network: 192.168.5.152/32
+Network: 192.168.5.153/32
+Network: 192.168.5.154/32
+Network: 192.168.5.155/32
+Network: 192.168.5.156/32
+Network: 192.168.5.157/32
+Network: 192.168.5.158/32
+Network: 192.168.5.159/32
+Network: 192.168.5.160/32
+Network: 192.168.5.161/32
+Network: 192.168.5.162/32
+Network: 192.168.5.163/32
+Network: 192.168.5.164/32
+Network: 192.168.5.165/32
+Network: 192.168.5.166/32
+Network: 192.168.5.167/32
+Network: 192.168.5.168/32
+Network: 192.168.5.169/32
+Network: 192.168.5.170/32
+Network: 192.168.5.171/32
+Network: 192.168.5.172/32
+Network: 192.168.5.173/32
+Network: 192.168.5.174/32
+Network: 192.168.5.175/32
+Network: 192.168.5.176/32
+Network: 192.168.5.177/32
+Network: 192.168.5.178/32
+Network: 192.168.5.179/32
+Network: 192.168.5.180/32
+Network: 192.168.5.181/32
+Network: 192.168.5.182/32
+Network: 192.168.5.183/32
+Network: 192.168.5.184/32
+Network: 192.168.5.185/32
+Network: 192.168.5.186/32
+Network: 192.168.5.187/32
+Network: 192.168.5.188/32
+Network: 192.168.5.189/32
+Network: 192.168.5.190/32
+Network: 192.168.5.191/32
+Network: 192.168.5.192/32
+Network: 192.168.5.193/32
+Network: 192.168.5.194/32
+Network: 192.168.5.195/32
+Network: 192.168.5.196/32
+Network: 192.168.5.197/32
+Network: 192.168.5.198/32
+Network: 192.168.5.199/32
+Network: 192.168.5.200/32
+Network: 192.168.5.201/32
+Network: 192.168.5.202/32
+Network: 192.168.5.203/32
+Network: 192.168.5.204/32
+Network: 192.168.5.205/32
+Network: 192.168.5.206/32
+Network: 192.168.5.207/32
+Network: 192.168.5.208/32
+Network: 192.168.5.209/32
+Network: 192.168.5.210/32
+Network: 192.168.5.211/32
+Network: 192.168.5.212/32
+Network: 192.168.5.213/32
+Network: 192.168.5.214/32
+Network: 192.168.5.215/32
+Network: 192.168.5.216/32
+Network: 192.168.5.217/32
+Network: 192.168.5.218/32
+Network: 192.168.5.219/32
+Network: 192.168.5.220/32
+Network: 192.168.5.221/32
+Network: 192.168.5.222/32
+Network: 192.168.5.223/32
+Network: 192.168.5.224/32
+Network: 192.168.5.225/32
+Network: 192.168.5.226/32
+Network: 192.168.5.227/32
+Network: 192.168.5.228/32
+Network: 192.168.5.229/32
+Network: 192.168.5.230/32
+Network: 192.168.5.231/32
+Network: 192.168.5.232/32
+Network: 192.168.5.233/32
+Network: 192.168.5.234/32
+Network: 192.168.5.235/32
+Network: 192.168.5.236/32
+Network: 192.168.5.237/32
+Network: 192.168.5.238/32
+Network: 192.168.5.239/32
+Network: 192.168.5.240/32
+Network: 192.168.5.241/32
+Network: 192.168.5.242/32
+Network: 192.168.5.243/32
+Network: 192.168.5.244/32
+Network: 192.168.5.245/32
+Network: 192.168.5.246/32
+Network: 192.168.5.247/32
+Network: 192.168.5.248/32
+Network: 192.168.5.249/32
+Network: 192.168.5.250/32
+Network: 192.168.5.251/32
+Network: 192.168.5.252/32
+Network: 192.168.5.253/32
+Network: 192.168.5.254/32
+Network: 192.168.5.255/32
+
+Total: 256
+Hosts/Net: 1
diff --git a/tests/split-192.168.5.0-31-32 b/tests/split-192.168.5.0-31-32
new file mode 100644
index 0000000..6841471
--- /dev/null
+++ b/tests/split-192.168.5.0-31-32
@@ -0,0 +1,6 @@
+[Split networks]
+Network: 192.168.5.0/32
+Network: 192.168.5.1/32
+
+Total: 2
+Hosts/Net: 1
diff --git a/tests/split-192.168.5.45-24-26 b/tests/split-192.168.5.45-24-26
new file mode 100644
index 0000000..dc34128
--- /dev/null
+++ b/tests/split-192.168.5.45-24-26
@@ -0,0 +1,8 @@
+[Split networks]
+Network: 192.168.5.0/26
+Network: 192.168.5.64/26
+Network: 192.168.5.128/26
+Network: 192.168.5.192/26
+
+Total: 4
+Hosts/Net: 62
diff --git a/tests/split-2a03:2880:20:4f06:face::-56-64 b/tests/split-2a03:2880:20:4f06:face::-56-64
new file mode 100644
index 0000000..4621336
--- /dev/null
+++ b/tests/split-2a03:2880:20:4f06:face::-56-64
@@ -0,0 +1,260 @@
+[Split networks]
+Network: 2a03:2880:20:4f00::/64
+Network: 2a03:2880:20:4f01::/64
+Network: 2a03:2880:20:4f02::/64
+Network: 2a03:2880:20:4f03::/64
+Network: 2a03:2880:20:4f04::/64
+Network: 2a03:2880:20:4f05::/64
+Network: 2a03:2880:20:4f06::/64
+Network: 2a03:2880:20:4f07::/64
+Network: 2a03:2880:20:4f08::/64
+Network: 2a03:2880:20:4f09::/64
+Network: 2a03:2880:20:4f0a::/64
+Network: 2a03:2880:20:4f0b::/64
+Network: 2a03:2880:20:4f0c::/64
+Network: 2a03:2880:20:4f0d::/64
+Network: 2a03:2880:20:4f0e::/64
+Network: 2a03:2880:20:4f0f::/64
+Network: 2a03:2880:20:4f10::/64
+Network: 2a03:2880:20:4f11::/64
+Network: 2a03:2880:20:4f12::/64
+Network: 2a03:2880:20:4f13::/64
+Network: 2a03:2880:20:4f14::/64
+Network: 2a03:2880:20:4f15::/64
+Network: 2a03:2880:20:4f16::/64
+Network: 2a03:2880:20:4f17::/64
+Network: 2a03:2880:20:4f18::/64
+Network: 2a03:2880:20:4f19::/64
+Network: 2a03:2880:20:4f1a::/64
+Network: 2a03:2880:20:4f1b::/64
+Network: 2a03:2880:20:4f1c::/64
+Network: 2a03:2880:20:4f1d::/64
+Network: 2a03:2880:20:4f1e::/64
+Network: 2a03:2880:20:4f1f::/64
+Network: 2a03:2880:20:4f20::/64
+Network: 2a03:2880:20:4f21::/64
+Network: 2a03:2880:20:4f22::/64
+Network: 2a03:2880:20:4f23::/64
+Network: 2a03:2880:20:4f24::/64
+Network: 2a03:2880:20:4f25::/64
+Network: 2a03:2880:20:4f26::/64
+Network: 2a03:2880:20:4f27::/64
+Network: 2a03:2880:20:4f28::/64
+Network: 2a03:2880:20:4f29::/64
+Network: 2a03:2880:20:4f2a::/64
+Network: 2a03:2880:20:4f2b::/64
+Network: 2a03:2880:20:4f2c::/64
+Network: 2a03:2880:20:4f2d::/64
+Network: 2a03:2880:20:4f2e::/64
+Network: 2a03:2880:20:4f2f::/64
+Network: 2a03:2880:20:4f30::/64
+Network: 2a03:2880:20:4f31::/64
+Network: 2a03:2880:20:4f32::/64
+Network: 2a03:2880:20:4f33::/64
+Network: 2a03:2880:20:4f34::/64
+Network: 2a03:2880:20:4f35::/64
+Network: 2a03:2880:20:4f36::/64
+Network: 2a03:2880:20:4f37::/64
+Network: 2a03:2880:20:4f38::/64
+Network: 2a03:2880:20:4f39::/64
+Network: 2a03:2880:20:4f3a::/64
+Network: 2a03:2880:20:4f3b::/64
+Network: 2a03:2880:20:4f3c::/64
+Network: 2a03:2880:20:4f3d::/64
+Network: 2a03:2880:20:4f3e::/64
+Network: 2a03:2880:20:4f3f::/64
+Network: 2a03:2880:20:4f40::/64
+Network: 2a03:2880:20:4f41::/64
+Network: 2a03:2880:20:4f42::/64
+Network: 2a03:2880:20:4f43::/64
+Network: 2a03:2880:20:4f44::/64
+Network: 2a03:2880:20:4f45::/64
+Network: 2a03:2880:20:4f46::/64
+Network: 2a03:2880:20:4f47::/64
+Network: 2a03:2880:20:4f48::/64
+Network: 2a03:2880:20:4f49::/64
+Network: 2a03:2880:20:4f4a::/64
+Network: 2a03:2880:20:4f4b::/64
+Network: 2a03:2880:20:4f4c::/64
+Network: 2a03:2880:20:4f4d::/64
+Network: 2a03:2880:20:4f4e::/64
+Network: 2a03:2880:20:4f4f::/64
+Network: 2a03:2880:20:4f50::/64
+Network: 2a03:2880:20:4f51::/64
+Network: 2a03:2880:20:4f52::/64
+Network: 2a03:2880:20:4f53::/64
+Network: 2a03:2880:20:4f54::/64
+Network: 2a03:2880:20:4f55::/64
+Network: 2a03:2880:20:4f56::/64
+Network: 2a03:2880:20:4f57::/64
+Network: 2a03:2880:20:4f58::/64
+Network: 2a03:2880:20:4f59::/64
+Network: 2a03:2880:20:4f5a::/64
+Network: 2a03:2880:20:4f5b::/64
+Network: 2a03:2880:20:4f5c::/64
+Network: 2a03:2880:20:4f5d::/64
+Network: 2a03:2880:20:4f5e::/64
+Network: 2a03:2880:20:4f5f::/64
+Network: 2a03:2880:20:4f60::/64
+Network: 2a03:2880:20:4f61::/64
+Network: 2a03:2880:20:4f62::/64
+Network: 2a03:2880:20:4f63::/64
+Network: 2a03:2880:20:4f64::/64
+Network: 2a03:2880:20:4f65::/64
+Network: 2a03:2880:20:4f66::/64
+Network: 2a03:2880:20:4f67::/64
+Network: 2a03:2880:20:4f68::/64
+Network: 2a03:2880:20:4f69::/64
+Network: 2a03:2880:20:4f6a::/64
+Network: 2a03:2880:20:4f6b::/64
+Network: 2a03:2880:20:4f6c::/64
+Network: 2a03:2880:20:4f6d::/64
+Network: 2a03:2880:20:4f6e::/64
+Network: 2a03:2880:20:4f6f::/64
+Network: 2a03:2880:20:4f70::/64
+Network: 2a03:2880:20:4f71::/64
+Network: 2a03:2880:20:4f72::/64
+Network: 2a03:2880:20:4f73::/64
+Network: 2a03:2880:20:4f74::/64
+Network: 2a03:2880:20:4f75::/64
+Network: 2a03:2880:20:4f76::/64
+Network: 2a03:2880:20:4f77::/64
+Network: 2a03:2880:20:4f78::/64
+Network: 2a03:2880:20:4f79::/64
+Network: 2a03:2880:20:4f7a::/64
+Network: 2a03:2880:20:4f7b::/64
+Network: 2a03:2880:20:4f7c::/64
+Network: 2a03:2880:20:4f7d::/64
+Network: 2a03:2880:20:4f7e::/64
+Network: 2a03:2880:20:4f7f::/64
+Network: 2a03:2880:20:4f80::/64
+Network: 2a03:2880:20:4f81::/64
+Network: 2a03:2880:20:4f82::/64
+Network: 2a03:2880:20:4f83::/64
+Network: 2a03:2880:20:4f84::/64
+Network: 2a03:2880:20:4f85::/64
+Network: 2a03:2880:20:4f86::/64
+Network: 2a03:2880:20:4f87::/64
+Network: 2a03:2880:20:4f88::/64
+Network: 2a03:2880:20:4f89::/64
+Network: 2a03:2880:20:4f8a::/64
+Network: 2a03:2880:20:4f8b::/64
+Network: 2a03:2880:20:4f8c::/64
+Network: 2a03:2880:20:4f8d::/64
+Network: 2a03:2880:20:4f8e::/64
+Network: 2a03:2880:20:4f8f::/64
+Network: 2a03:2880:20:4f90::/64
+Network: 2a03:2880:20:4f91::/64
+Network: 2a03:2880:20:4f92::/64
+Network: 2a03:2880:20:4f93::/64
+Network: 2a03:2880:20:4f94::/64
+Network: 2a03:2880:20:4f95::/64
+Network: 2a03:2880:20:4f96::/64
+Network: 2a03:2880:20:4f97::/64
+Network: 2a03:2880:20:4f98::/64
+Network: 2a03:2880:20:4f99::/64
+Network: 2a03:2880:20:4f9a::/64
+Network: 2a03:2880:20:4f9b::/64
+Network: 2a03:2880:20:4f9c::/64
+Network: 2a03:2880:20:4f9d::/64
+Network: 2a03:2880:20:4f9e::/64
+Network: 2a03:2880:20:4f9f::/64
+Network: 2a03:2880:20:4fa0::/64
+Network: 2a03:2880:20:4fa1::/64
+Network: 2a03:2880:20:4fa2::/64
+Network: 2a03:2880:20:4fa3::/64
+Network: 2a03:2880:20:4fa4::/64
+Network: 2a03:2880:20:4fa5::/64
+Network: 2a03:2880:20:4fa6::/64
+Network: 2a03:2880:20:4fa7::/64
+Network: 2a03:2880:20:4fa8::/64
+Network: 2a03:2880:20:4fa9::/64
+Network: 2a03:2880:20:4faa::/64
+Network: 2a03:2880:20:4fab::/64
+Network: 2a03:2880:20:4fac::/64
+Network: 2a03:2880:20:4fad::/64
+Network: 2a03:2880:20:4fae::/64
+Network: 2a03:2880:20:4faf::/64
+Network: 2a03:2880:20:4fb0::/64
+Network: 2a03:2880:20:4fb1::/64
+Network: 2a03:2880:20:4fb2::/64
+Network: 2a03:2880:20:4fb3::/64
+Network: 2a03:2880:20:4fb4::/64
+Network: 2a03:2880:20:4fb5::/64
+Network: 2a03:2880:20:4fb6::/64
+Network: 2a03:2880:20:4fb7::/64
+Network: 2a03:2880:20:4fb8::/64
+Network: 2a03:2880:20:4fb9::/64
+Network: 2a03:2880:20:4fba::/64
+Network: 2a03:2880:20:4fbb::/64
+Network: 2a03:2880:20:4fbc::/64
+Network: 2a03:2880:20:4fbd::/64
+Network: 2a03:2880:20:4fbe::/64
+Network: 2a03:2880:20:4fbf::/64
+Network: 2a03:2880:20:4fc0::/64
+Network: 2a03:2880:20:4fc1::/64
+Network: 2a03:2880:20:4fc2::/64
+Network: 2a03:2880:20:4fc3::/64
+Network: 2a03:2880:20:4fc4::/64
+Network: 2a03:2880:20:4fc5::/64
+Network: 2a03:2880:20:4fc6::/64
+Network: 2a03:2880:20:4fc7::/64
+Network: 2a03:2880:20:4fc8::/64
+Network: 2a03:2880:20:4fc9::/64
+Network: 2a03:2880:20:4fca::/64
+Network: 2a03:2880:20:4fcb::/64
+Network: 2a03:2880:20:4fcc::/64
+Network: 2a03:2880:20:4fcd::/64
+Network: 2a03:2880:20:4fce::/64
+Network: 2a03:2880:20:4fcf::/64
+Network: 2a03:2880:20:4fd0::/64
+Network: 2a03:2880:20:4fd1::/64
+Network: 2a03:2880:20:4fd2::/64
+Network: 2a03:2880:20:4fd3::/64
+Network: 2a03:2880:20:4fd4::/64
+Network: 2a03:2880:20:4fd5::/64
+Network: 2a03:2880:20:4fd6::/64
+Network: 2a03:2880:20:4fd7::/64
+Network: 2a03:2880:20:4fd8::/64
+Network: 2a03:2880:20:4fd9::/64
+Network: 2a03:2880:20:4fda::/64
+Network: 2a03:2880:20:4fdb::/64
+Network: 2a03:2880:20:4fdc::/64
+Network: 2a03:2880:20:4fdd::/64
+Network: 2a03:2880:20:4fde::/64
+Network: 2a03:2880:20:4fdf::/64
+Network: 2a03:2880:20:4fe0::/64
+Network: 2a03:2880:20:4fe1::/64
+Network: 2a03:2880:20:4fe2::/64
+Network: 2a03:2880:20:4fe3::/64
+Network: 2a03:2880:20:4fe4::/64
+Network: 2a03:2880:20:4fe5::/64
+Network: 2a03:2880:20:4fe6::/64
+Network: 2a03:2880:20:4fe7::/64
+Network: 2a03:2880:20:4fe8::/64
+Network: 2a03:2880:20:4fe9::/64
+Network: 2a03:2880:20:4fea::/64
+Network: 2a03:2880:20:4feb::/64
+Network: 2a03:2880:20:4fec::/64
+Network: 2a03:2880:20:4fed::/64
+Network: 2a03:2880:20:4fee::/64
+Network: 2a03:2880:20:4fef::/64
+Network: 2a03:2880:20:4ff0::/64
+Network: 2a03:2880:20:4ff1::/64
+Network: 2a03:2880:20:4ff2::/64
+Network: 2a03:2880:20:4ff3::/64
+Network: 2a03:2880:20:4ff4::/64
+Network: 2a03:2880:20:4ff5::/64
+Network: 2a03:2880:20:4ff6::/64
+Network: 2a03:2880:20:4ff7::/64
+Network: 2a03:2880:20:4ff8::/64
+Network: 2a03:2880:20:4ff9::/64
+Network: 2a03:2880:20:4ffa::/64
+Network: 2a03:2880:20:4ffb::/64
+Network: 2a03:2880:20:4ffc::/64
+Network: 2a03:2880:20:4ffd::/64
+Network: 2a03:2880:20:4ffe::/64
+Network: 2a03:2880:20:4fff::/64
+
+Total: 256
+Hosts/Net: 18446744073709551616
diff --git a/tests/split-fcfa:b4ca:f1d8:125b:dc00::-112-120 b/tests/split-fcfa:b4ca:f1d8:125b:dc00::-112-120
new file mode 100644
index 0000000..08b8059
--- /dev/null
+++ b/tests/split-fcfa:b4ca:f1d8:125b:dc00::-112-120
@@ -0,0 +1,260 @@
+[Split networks]
+Network: fcfa:b4ca:f1d8:125b:dc00::/120
+Network: fcfa:b4ca:f1d8:125b:dc00::100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::1f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::2f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::3f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::4f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::5f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::6f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::7f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::8f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9a00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9b00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9c00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9d00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9e00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::9f00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::a900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::aa00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ab00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ac00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ad00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ae00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::af00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::b900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ba00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::bb00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::bc00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::bd00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::be00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::bf00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::c900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ca00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::cb00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::cc00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::cd00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ce00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::cf00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::d900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::da00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::db00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::dc00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::dd00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::de00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::df00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::e900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ea00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::eb00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ec00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ed00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ee00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ef00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f000/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f100/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f200/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f300/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f400/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f500/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f600/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f700/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f800/120
+Network: fcfa:b4ca:f1d8:125b:dc00::f900/120
+Network: fcfa:b4ca:f1d8:125b:dc00::fa00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::fb00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::fc00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::fd00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::fe00/120
+Network: fcfa:b4ca:f1d8:125b:dc00::ff00/120
+
+Total: 256
+Hosts/Net: 256
diff --git a/tests/split-fcfa:b4ca:f1d8:125b:dc00::-127-128 b/tests/split-fcfa:b4ca:f1d8:125b:dc00::-127-128
new file mode 100644
index 0000000..9500596
--- /dev/null
+++ b/tests/split-fcfa:b4ca:f1d8:125b:dc00::-127-128
@@ -0,0 +1,6 @@
+[Split networks]
+Network: fcfa:b4ca:f1d8:125b:dc00::/128
+Network: fcfa:b4ca:f1d8:125b:dc00::1/128
+
+Total: 2
+Hosts/Net: 1
diff --git a/tests/standard-192.168.2.0-24 b/tests/standard-192.168.2.0-24
new file mode 100644
index 0000000..588b5fe
--- /dev/null
+++ b/tests/standard-192.168.2.0-24
@@ -0,0 +1,8 @@
+Network: 192.168.2.0/24
+Netmask: 255.255.255.0 = 24
+Broadcast: 192.168.2.255
+
+Address space: Private Use
+HostMin: 192.168.2.1
+HostMax: 192.168.2.254
+Hosts/Net: 254