pax_global_header00006660000000000000000000000064152640514240014515gustar00rootroot0000000000000052 comment=e364dbbcfaf604b039649e941a7603615e674d91 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/000077500000000000000000000000001526405142400202565ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/.editorconfig000066400000000000000000000001231526405142400227270ustar00rootroot00000000000000root = true [*] charset = utf-8 end_of_line = lf [*.{c,h,sh}] indent_style = tab ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/.gitattributes000066400000000000000000000001361526405142400231510ustar00rootroot00000000000000# Used by the test suite only; not part of release tarballs tests/debian-ipcalc export-ignore ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/.gitignore000066400000000000000000000003161526405142400222460ustar00rootroot00000000000000# 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/.gitlab-ci.yml000066400000000000000000000050631526405142400227160ustar00rootroot00000000000000stages: - generate - deploy .fedora.latest.template: &fedora_template image: fedora:44 tags: - saas-linux-small-amd64 before_script: #in F34 rubygem-ronn got replaced by rubygem-ronn-ng - dnf install -y libmaxminddb-devel make meson ninja-build gcc libasan libubsan geolite2-{asn,city,country} rubygem-ronn jq perl-interpreter perl-bignum fedora.nogeo: stage: generate <<: *fedora_template script: - meson setup build -Duse_maxminddb=disabled -Duse_geoip=enabled --buildtype=plain -Dc_args="-O2 -g -Werror" - ninja -C build - ninja -C build test - USE_MAXMIND=no USE_RUNTIME_LINKING=no CFLAGS="-O2 -g -Werror" make fedora.maxmind: stage: generate <<: *fedora_template script: - meson setup build -Duse_maxminddb=enabled -Duse_runtime_linking=disabled --buildtype=plain -Dc_args="-O2 -g -Werror" - ninja -C build - ninja -C build test - 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_runtime_linking=enabled --buildtype=plain -Dc_args="-O2 -g -Werror" - ninja -C build - ninja -C build test - USE_RUNTIME_LINKING=yes USE_MAXMIND=yes CFLAGS="-O2 -g -Werror" make fedora.sanitizers: stage: generate <<: *fedora_template script: - export ASAN_OPTIONS="detect_leaks=0" - export UBSAN_OPTIONS="print_stacktrace=1" - meson setup build -Duse_maxminddb=enabled -Duse_runtime_linking=enabled -Db_sanitize=address,undefined -Dc_args="-fno-sanitize-recover=undefined" -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_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 except: - master pages: stage: deploy <<: *fedora_template script: - dnf install -y lcov - meson setup build -Db_coverage=true -Duse_maxminddb=enabled -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 coverage: '/coverage lines: \d+\.\d+/' artifacts: when: on_success paths: - public only: - master ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/.lcovrc000066400000000000000000000003451526405142400215510ustar00rootroot00000000000000# Meson's coverage-html passes the source root to genhtml as --prefix. # Our sources sit directly in it, which lcov 2.0's genhtml cannot handle # ("file error for ipcalc.c"), so keep the full paths instead. genhtml_no_prefix = 1 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/AGENTS.md000066400000000000000000000253341526405142400215700ustar00rootroot00000000000000# AGENTS.md This file provides guidance to AI Agents when working with code in this repository. ## Overview `ipcalc` is a single-binary C command-line tool for IPv4/IPv6 network calculations (info, check, split, deaggregate, random network generation), with optional geo-IP lookup. Output is human-readable (colored), shell-variable style (`NAME=value`), or JSON. ## Requirements-first workflow `doc/requirements/` is the normative description of what ipcalc must do (see `doc/requirements/README.md` for the document map, ID scheme, and per-requirement format). For any change that alters observable behavior — new feature, bug fix, or behavior-changing refactor — work in this order: 1. **Requirement first.** - Find the requirement(s) covering the area you're changing (search `doc/requirements/` for `REQ-*` IDs, or use the document map to find the file by mode). - If your change alters what an existing requirement describes, update that requirement first, following the protocol in `contrib/ai/protocols/` named in `doc/requirements/README.md`. Never leave a requirement describing the old behavior once the code changes. A requirement that is wrong for reasons unrelated to your change gets its own separate commit or series. - If no requirement covers the behavior, add one in the appropriate document (creating the document if the map lists it but it doesn't exist yet) — use `requirements-elicitation.md` for new behavior, `requirements-from-implementation.md` to first document the existing behavior of an area you're about to change. - For bug fixes: if the bug reveals a gap, add a requirement describing the *correct* behavior before fixing the code. 2. **Tests second.** Write or update the positive and negative tests implied by the requirement's **Acceptance** criteria before touching implementation code. For bug fixes, confirm the new test fails against the unmodified code. 3. **Code last.** Implement the change so the tests pass and the code, the requirement, `ipcalc.1.md`, `usage()`, and `NEWS` all agree. A code change with no corresponding requirement update is incomplete, even if it builds and passes the tests. Before declaring a change done, search `doc/requirements/` for requirements citing the files, functions, or options you touched and confirm each still holds — if one no longer does, either your change or that requirement is wrong (mark it `REVIEW` if unsure which); never leave code contradicting a `DERIVED` requirement. Run the full suite (`ninja -C build test`), not just the tests for the area you changed. ## AI personas and protocols `contrib/ai/` holds prompt files imported from [PromptKit](https://github.com/microsoft/PromptKit), each with an ipcalc-specific extension section (see `contrib/ai/README.md` for provenance and how to update them). For extended work — features, bug investigation, code review, requirements maintenance — load `contrib/ai/personas/ipcalc-dev.md`, which indexes the protocols to apply, including the review protocol that walks the checklist below. ## Build and test Meson/Ninja is the primary build: ```sh meson setup build # auto-detects libmaxminddb, else no geo support ninja -C build ninja -C build test # full test suite meson test -C build Split-Info # run a single test by name (names come from tests/meson.build) meson test -C build --list # list test names ``` Geo backend options: `-Duse_maxminddb=enabled|disabled`, `-Duse_runtime_linking=enabled|disabled` (dlopen the geo library at runtime instead of linking). CI builds every combination with `-Dc_args="-O2 -g -Werror"` plus a sanitizer build (`-Db_sanitize=address,undefined -Dc_args="-fno-sanitize-recover=undefined" -Dwerror=true`) that must run every test its configuration allows, so code must be warning-free in all configurations, including with no geo backend. The legacy `Makefile` must keep working too (CI runs it): `make USE_MAXMIND=no USE_RUNTIME_LINKING=no`. It compiles all `.c` files unconditionally, so the geo source file must compile to nothing when `USE_MAXMIND` is undefined. The version string is read from `meson.build`. The man page `ipcalc.1` is generated from `ipcalc.1.md` with `ronn` (optional). Update `ipcalc.1.md` when changing CLI options, and add user-visible changes to `NEWS`. ## Architecture - `ipcalc.c` — almost everything: `getopt_long` option parsing in `main()`, IPv4/IPv6 parsing into `ip_info_st` (`get_ipv4_info` / `get_ipv6_info`), address-space/class classification tables, random network generation, and all output formatting. - `netsplit.c` — `-S/--split`: `show_split_networks_v4()` / `show_split_networks_v6()` split a network into equal subnets of the given prefix (separate implementations per family). - `netcompare.c` — `--equals`/`--subnet-of`/`--overlaps`: `compare_networks()` compares the network `main()` parsed with the option argument. - `deaggregate.c` — `-d/--deaggregate` (address range → minimal CIDR list). - `ipcalc-reverse.c` — reverse DNS names; `ipcalc-utils.c` — `safe_asprintf`/`safe_strdup`/`safe_atoi`; `ipv6.c` — IPv6 helpers. - `ipcalc-maxmind.c` — the libmaxminddb geo backend implementing `geo_ip_lookup()` / `geo_setup()`; `ipcalc.h` stubs these out when it is not built. Behavior is driven by two things set in `main()`: - `app` (`enum app_t` in `ipcalc.h`): which mode runs (info, check, split, deaggregate, version). Some option combinations across modes are rejected and are covered by `--test-failure` tests. - `flags` (global bitmask, `FLAG_*` in `ipcalc.h`): what to show and how. With no specific `FLAG_SHOW_*` flags, the "modern" pretty summary (`FLAG_SHOW_MODERN_INFO`) is printed; specific flags select fields, printed as `NAME=value` by default. An option that selects a field is a row of `field_selecting_options[]`, which maps it to its `FLAG_SHOW_*` (or `FLAG_RESOLVE_*`) flag; giving one puts ipcalc in info mode and selects those fields instead of the summary. The output format (`enum output_format`: human, shell, JSON, value) comes from `--format` (`select_format()`), or, without it, from `-j`, `--no-decorate` and the selection (`legacy_format()`); `show_info_fields()` prints the selected fields in that format. All output must go through the printf helpers. `default_printf`, `dist_printf` and `output_start`/`output_separate`/`output_stop` switch between colored, `--no-decorate`, and `--json` formats; `pretty_printf`/`pretty_dist_printf` print text only (colored or `--no-decorate`) and `json_printf`/`array_start`/`array_stop` print JSON only, so their caller chooses the format (as `show_info_fields()` does). JSON comma placement is tracked via the `jsonfirst` state (`JSON_FIRST`/`JSON_NEXT`/`JSON_ARRAY_*`) passed to each call. Color is disabled when stdout is not a TTY or `NO_COLOR` is set. ## Code style - C99 standard; Linux kernel coding style (tabs, 8-space tab width, 80-column limit) - Header guards: `#ifndef FILENAME_H` / `#define FILENAME_H` / `#endif /* FILENAME_H */` - `#ifdef` in function bodies: ≤ 1 nesting level, ≤ 5 lines per branch; optional features use the stub pattern; `#endif` always annotated - **Comments:** Prefer self-documenting code. Add a comment only when the *why* is non-obvious: a hidden constraint, a protocol expectation, or a workaround. Do not comment what the code does; well-named identifiers already do that. Older code does not always follow this; do not copy its comments as a model. ## Commit messages - Describe what was changed in a short paragraph; do not include references to requirements. - Every commit must have a `Signed-off-by: Name ` line (DCO requirement). - Use `Resolves: #NNN` on the fixing commit; `Relates: #NNN` on related commits (e.g., tests). ## Tests Tests are declared in `tests/meson.build` and executed by `tests/ipcalc-testrunner.sh` in one of these modes: `--test-success`, `--test-failure` (exit status only), `--test-status CODE CMD` (exact exit status), `--test-output`, `--test-equal`, and most commonly `--test-outfile CMD FILE`, which compares the full stdout+stderr of `CMD` with an expected-output file in `tests/` and requires exit status 0. Expected-output files are named after the arguments (e.g. `tests/i-10.0.0.1`, `tests/deaggregate-…`). To add a test, create the expected-output file and add a `test(...)` entry in `tests/meson.build`. Tests run with stdout not a TTY, so the expected output has no color codes. `tests/debian-ipcalc/` holds the Debian ipcalc (Perl), against which the `DebianSplitHosts-*` tests compare `--split-hosts` (REQ-SPLIT-COMPAT-001). It is excluded from release tarballs via `.gitattributes`, and the tests are registered whenever it is present and fail if `perl` or its `bignum` module is missing; CI installs `perl-interpreter` and `perl-bignum`. Geo tests (REQ-GEO-TEST-001) run `build/tests/ipcalc-geo`, a build of ipcalc that reads MaxMind DB files generated by `tests/mkmmdb.py` from `tests/geo-country.json`, `tests/geo-city.json` and `tests/geo-asn.json` instead of the system databases. To test a new geo field, add it to those JSON files. ## Contribution checklist Verify each item before declaring a change done; reviews check every box against the diff. **Requirements (`doc/requirements/`):** - [ ] Relevant `REQ-*` found or created before the code change - [ ] Requirements whose behavior the patch changes are updated first - [ ] No other `REQ-*` citing touched files/options is silently contradicted - [ ] Code, requirement, `ipcalc.1.md`, and `usage()` agree **Code:** - [ ] Matches the surrounding style; comments follow **Code style** (*why* only, identifiers say *what*) - [ ] All output goes through the printf helpers; JSON `jsonfirst` state threaded correctly - [ ] Edge prefixes and address-space ends handled (no shift/overflow UB) - [ ] Geo code compiles to nothing when `USE_MAXMIND` is undefined **Change propagation:** - [ ] Options: `getopt_long` table ↔ `usage()` ↔ `ipcalc.1.md` ↔ requirement ↔ test - [ ] Output fields: default/modern ↔ `NAME=value` ↔ `--json` ↔ requirement ↔ expected-output files - [ ] Geo backend (if touched): `ipcalc-maxmind.c` ↔ `ipcalc.h` stubs ↔ meson ↔ `Makefile` - [ ] `NEWS` updated for user-visible changes **Testing:** - [ ] Positive test(s) registered in `tests/meson.build` - [ ] Negative test(s) for rejected inputs/combinations - [ ] Bug fix: test shown to fail before the fix - [ ] `ninja -C build test` passes in full - [ ] Legacy `make USE_MAXMIND=no USE_RUNTIME_LINKING=no` builds **Commits:** - [ ] Each commit self-contained, with `Signed-off-by:` - [ ] Message describes the change in a short paragraph; `Resolves:`/`Relates:` cite the issue, if any - [ ] A change's requirement update, tests, and code are in one commit; the requirements-first order is the order of work, not of commits - [ ] Commit message does not reference requirements (`REQ-*` IDs) ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/COPYING000066400000000000000000000432541526405142400213210ustar00rootroot00000000000000 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. Copyright (C) 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. , 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. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/Makefile000066400000000000000000000012471526405142400217220ustar00rootroot00000000000000USE_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_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 all: ipcalc ipcalc: ipcalc.c ipv6.c deaggregate.c ipcalc-maxmind.c ipcalc-reverse.c ipcalc-utils.c netsplit.c netcompare.c binary.c $(CC) $(CFLAGS) -DVERSION="\"$(VERSION)\"" $^ -o $@ $(LDFLAGS) clean: rm -f ipcalc ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/NEWS000066400000000000000000000147741526405142400207720ustar00rootroot00000000000000* Version 1.2.0 (released 2026-10-15) - Added the --cidr option, which prints the network in CIDR notation (e.g., 192.168.123.0/24); the JSON output has the new CIDR key - Added the --binary option, which prints the bits of an address, or of the network part of a network, as a diagram that maps the address to its bits (#34) - The geographic information includes the city (CITY), which was never printed, the accuracy radius of the coordinates in kilometers (ACCURACYRADIUS), the continent (CONTINENT), the postal code (POSTALCODE), the time zone (TIMEZONE), the autonomous system (ASN, ASORG) and its network (ASNETWORK), e.g., the ISP's allocation, and the network for which the database holds these values (GEONETWORK). - Added the --wildcard option, which prints the IPv4 wildcard (inverse) mask (e.g., 0.0.0.255 for a /24); --all-info shows it too, and the JSON output then has the new WILDCARD key - Added the --format option, which selects the output format: human, shell (VAR=VALUE), json or value; with it the specific info options select exactly the fields printed in every format, e.g., "ipcalc --format=json -n -m 192.168.1.5/24" prints only NETWORK and NETMASK. Without --format the output is unchanged - The -j and --no-decorate options are deprecated in favor of --format=json, --format=value and --format=human; they keep working unchanged with a hint. - Removed support for libGeoIP, whose databases are no longer published; geographic information requires libmaxminddb. * Version 1.1.0 (released 2026-10-04) - Print the interface identifier of IPv6 unicast addresses and, for Modified EUI-64 identifiers, the EUI-64, the MAC address with --all-info (#29) - The --split option can be repeated with COUNT:PREFIX arguments to split a network into subnets of different sizes (VLSM), e.g., "ipcalc -S 1:58 -S 64 2001:db8:1c88:6000::/56" (#23) - Added the --split-hosts option, which splits a network into subnets that hold a number of hosts each, as the split of the Debian ipcalc - Fixed issues in deaggregation (#31, #24) and reverse-dns (#32) - In the JSON output of --all-info, REVERSEDNS is now always an array - Added the --equals, --subnet-of and --overlaps options, which compare the provided network with another and print the result; the exit status is 0 when the comparison holds, 1 when it does not, and 2 on error (#33) * 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). ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/README.md000066400000000000000000000223561526405142400215450ustar00rootroot00000000000000# 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 libmaxminddb if available to provide geographic information (continent, country, city, postal code, coordinates, time zone) and the autonomous system that routes the address, from the GeoLite2 databases. 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 with no geo-information whatsoever. Meson will use libmaxminddb if it is available on your system. You can override this choice by providing `-Duse_maxminddb=enabled` to `meson setup` or `meson configure` to require libmaxminddb, or `-Duse_maxminddb=disabled` to build without it. 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` $ 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 - you may have to disable it 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 with no geo-information whatsoever. The option can be provided on the makefile via the variable USE_MAXMIND (yes/no). For example the following command will compile with no support for geo-information. ``` $ make 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 Wildcard: 0.0.0.255 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 Continent: Europe Country code: GR Country: Greece City: Athens Coordinates: 37.984200,23.735300 Accuracy: 200 km Time zone: Europe/Athens Routed by AS: 1241 Operated by: Forthnet AS network: 193.92.128.0/19 Geo network: 193.92.144.0/21 ``` ``` $ ipcalc --format=shell -pnmb --minaddr --maxaddr --geoinfo --addrspace 193.92.150.2/255.255.255.224 NETWORK=193.92.150.0 NETMASK=255.255.255.224 PREFIX=27 BROADCAST=193.92.150.31 ADDRSPACE=Internet MINADDR=193.92.150.1 MAXADDR=193.92.150.30 CONTINENT=Europe COUNTRYCODE=GR COUNTRY=Greece CITY=Athens COORDINATES="37.984200,23.735300" ACCURACYRADIUS=200 TIMEZONE=Europe/Athens ASN=1241 ASORG=Forthnet ASNETWORK=193.92.128.0/19 GEONETWORK=193.92.144.0/21 ``` ``` $ ipcalc --format=json -n -p 193.92.150.2/24 { "NETWORK":"193.92.150.0", "PREFIX":"24" } ``` ## IPv6 ``` $ ipcalc --all-info 2a03:2880:20:4f06:21b:21ff:fe3a:5c7d/64 Full Address: 2a03:2880:0020:4f06:021b:21ff:fe3a:5c7d Address: 2a03:2880:20:4f06:21b:21ff:fe3a:5c7d 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 Interface ID: 021b:21ff:fe3a:5c7d EUI-64: 00:1b:21:ff:fe:3a:5c:7d MAC address: 00:1b:21:3a:5c:7d MAC scope: universal MAC type: individual HostMin: 2a03:2880:20:4f06:: HostMax: 2a03:2880:20:4f06:ffff:ffff:ffff:ffff Hosts/Net: 2^(64) = 18446744073709551616 Continent: Europe Country code: IE Country: Ireland Coordinates: 53.000000,-8.000000 Accuracy: 100 km Time zone: Europe/Dublin Routed by AS: 32934 Operated by: Facebook, Inc. AS network: 2a03:2880::/32 Geo network: 2a03:2880::/35 ``` ``` $ ipcalc --format=shell -pnmb --minaddr --maxaddr --addrspace --geoinfo 2a03:2880:20:4f06:21b:21ff:fe3a:5c7d/64 NETWORK=2a03:2880:20:4f06:: NETMASK=ffff:ffff:ffff:ffff:: PREFIX=64 ADDRSPACE="Global Unicast" MINADDR=2a03:2880:20:4f06:: MAXADDR=2a03:2880:20:4f06:ffff:ffff:ffff:ffff CONTINENT=Europe COUNTRYCODE=IE COUNTRY=Ireland COORDINATES="53.000000,-8.000000" ACCURACYRADIUS=100 TIMEZONE=Europe/Dublin ASN=32934 ASORG="Facebook, Inc." ASNETWORK=2a03:2880::/32 GEONETWORK=2a03:2880::/35 ``` ## Comparing networks Networks are compared by network address and prefix, so host bits are ignored. The exit status is 0 when the comparison holds and 1 when it does not. ``` $ ipcalc 192.168.1.15/24 --equals=192.168.1.200/24 The networks are equal $ ipcalc 10.0.0.0/24 --equals=10.0.0.0/23 The networks are not equal ``` ``` $ ipcalc 192.168.1.0/24 --subnet-of=192.168.0.0/16 192.168.1.0/24 is a subnet of 192.168.0.0/16 $ ipcalc 192.168.0.0/16 --subnet-of=192.168.1.0/24 192.168.0.0/16 is not a subnet of 192.168.1.0/24 ``` In scripts, use `-s` to print nothing and rely on the exit status alone: ``` $ ipcalc -s 2001:db8:1::/48 --subnet-of=2001:db8::/32 && echo "inside" inside ``` ## Showing the bits of an address or network The `--binary` option maps an address, or the network part of a network, to its bits; host bits are shown as `x`. For IPv4 the bits of the network's addresses follow: ``` $ ipcalc --binary 192.168.92.6/22 Network: 192.168.92.0/22 192. 168. 92-95. 0-255 11000000.10101000.010111xx.xxxxxxxx └──── network /22 ─────┘└ host 10 ┘ Address: 192.168.92.6 11000000.10101000.01011100.00000110 Netmask: 255.255.252.0 11111111.11111111.11111100.00000000 Network: 192.168.92.0 11000000.10101000.01011100.00000000 HostMin: 192.168.92.1 11000000.10101000.01011100.00000001 HostMax: 192.168.95.254 11000000.10101000.01011111.11111110 Broadcast: 192.168.95.255 11000000.10101000.01011111.11111111 ``` For IPv6 the brackets show the routing prefix, subnet ID and interface ID: ``` $ ipcalc --binary 2001:db8:abcd:12::1/56 Network: 2001:db8:abcd::/56 2001: 0db8: abcd: 0000-00ff 0010000000000001:0000110110111000:1010101111001101:00000000xxxxxxxx └────────────────── routing prefix /56 ───────────────────┘└─ 8 ──┘ bits 64-127: interface ID, all x ``` With `--format=value` only the bits of the network are printed: ``` $ ipcalc --format=value --binary 192.168.92.6/22 11000000101010000101110000000000 ``` ## JSON output ``` $ ipcalc --all-info --format=json 2a03:2880:20:4f06:21b:21ff:fe3a:5c7d/64 { "FULLADDRESS":"2a03:2880:0020:4f06:021b:21ff:fe3a:5c7d", "ADDRESS":"2a03:2880:20:4f06:21b:21ff:fe3a:5c7d", "FULLNETWORK":"2a03:2880:0020:4f06:0000:0000:0000:0000", "NETWORK":"2a03:2880:20:4f06::", "NETMASK":"ffff:ffff:ffff:ffff::", "PREFIX":"64", "CIDR":"2a03:2880:20:4f06::/64", "REVERSEDNS":[ "6.0.f.4.0.2.0.0.0.8.8.2.3.0.a.2.ip6.arpa."], "ADDRSPACE":"Global Unicast", "INTERFACEID":"021b:21ff:fe3a:5c7d", "EUI64":"00:1b:21:ff:fe:3a:5c:7d", "MACADDR":"00:1b:21:3a:5c:7d", "MACSCOPE":"universal", "MACTYPE":"individual", "MINADDR":"2a03:2880:20:4f06::", "MAXADDR":"2a03:2880:20:4f06:ffff:ffff:ffff:ffff", "ADDRESSES":"18446744073709551616", "CONTINENT":"Europe", "COUNTRYCODE":"IE", "COUNTRY":"Ireland", "COORDINATES":"53.000000,-8.000000", "ACCURACYRADIUS":"100", "TIMEZONE":"Europe/Dublin", "ASN":"32934", "ASORG":"Facebook, Inc.", "ASNETWORK":"2a03:2880::/32", "GEONETWORK":"2a03:2880::/35" } ``` ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/binary.c000066400000000000000000000402011526405142400217030ustar00rootroot00000000000000/* * Copyright (c) 2026 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 . */ #include #include #include #include #include #include #include #include #include #include "ipcalc.h" #define PREFIX_NAME "PREFIX" #define MAX_COLS 135 #define DEFAULT_COLS 80 #define LABEL_COLS 12 #define VALUE_COLS 17 #define DETAILS_INDENT (LABEL_COLS + VALUE_COLS) /* Stand for the bracket characters, which take one column but several * bytes, so that a line holds one byte per column */ enum glyph { GLYPH_LEFT = 1, GLYPH_RIGHT, GLYPH_FILL }; enum style { STYLE_PLAIN, STYLE_NETWORK, STYLE_HOST }; struct layout { unsigned width; unsigned band_bits; unsigned group_bits; char separator; int hex; }; static const struct layout ipv4_layout = { 32, 32, 8, '.', 0 }; static const struct layout ipv6_layout = { 128, 64, 16, ':', 1 }; static const struct layout ipv6_wide_layout = { 128, 128, 16, ':', 1 }; struct segment { unsigned first; unsigned end; enum style style; unsigned nlabels; char labels[3][24]; }; struct row { const char *name; const char *var; uint32_t value; }; struct line { unsigned indent; unsigned len; char text[MAX_COLS]; unsigned char style[MAX_COLS]; }; static unsigned get_bit(const unsigned char *addr, unsigned k) { return (addr[k / 8] >> (7 - k % 8)) & 1; } static void line_init(struct line *l, unsigned indent) { l->indent = indent; l->len = 0; memset(l->text, ' ', sizeof(l->text)); memset(l->style, STYLE_PLAIN, sizeof(l->style)); } static void put_char(struct line *l, unsigned col, char c, enum style style) { if (col >= MAX_COLS) return; l->text[col] = c; l->style[col] = style; if (col >= l->len) l->len = col + 1; } static void put_text(struct line *l, unsigned col, const char *str, enum style style) { for (; *str; str++, col++) put_char(l, col, *str, style); } static const char *style_color(enum style style) { switch (style) { case STYLE_NETWORK: return KBLUE; case STYLE_HOST: return KDIM; default: return NULL; } } static const char *glyph_text(unsigned char c) { switch (c) { case GLYPH_LEFT: return "└"; case GLYPH_RIGHT: return "┘"; case GLYPH_FILL: return "─"; default: return NULL; } } static void print_line(struct line *l) { unsigned col = 0; while (l->len > 0 && l->text[l->len - 1] == ' ') l->len--; if (l->len > 0) { char indent[DETAILS_INDENT + 1]; snprintf(indent, sizeof(indent), "%*s", l->indent, ""); color_fputs(NULL, indent); } while (col < l->len) { char run[MAX_COLS * 3 + 1]; unsigned len = 0; unsigned char style = l->style[col]; for (; col < l->len && l->style[col] == style; col++) { const char *glyph = glyph_text(l->text[col]); if (glyph != NULL) { memcpy(run + len, glyph, strlen(glyph)); len += strlen(glyph); } else { run[len] = l->text[col]; len++; } } run[len] = 0; color_fputs(style_color(style), run); } color_fputs(NULL, "\n"); } static unsigned band_columns(const struct layout *lay) { unsigned ngroups = lay->band_bits / lay->group_bits; return lay->band_bits + ngroups - 1; } static unsigned output_columns(void) { const char *env = getenv("COLUMNS"); struct winsize ws; int cols; if (env && safe_atoi(env, &cols) == 0 && cols > 0) return cols; if (isatty(STDOUT_FILENO) && ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) return ws.ws_col; return DEFAULT_COLS; } /* Each group is followed by a separator column */ static unsigned group_column(const struct layout *lay, unsigned group) { return group * (lay->group_bits + 1); } /* Column of bit k of the band that starts at bit start */ static unsigned bit_column(const struct layout *lay, unsigned start, unsigned k) { unsigned pos = k - start; return group_column(lay, pos / lay->group_bits) + pos % lay->group_bits; } static unsigned group_value(const unsigned char *addr, unsigned first, unsigned bits) { unsigned k, value = 0; for (k = first; k < first + bits; k++) value = (value << 1) | get_bit(addr, k); return value; } static unsigned group_host_bits(unsigned prefix, unsigned first, unsigned bits) { unsigned end = first + bits; if (prefix >= end) return 0; if (prefix <= first) return bits; return end - prefix; } static void format_group(char *str, size_t size, const struct layout *lay, unsigned value, unsigned host_bits) { unsigned high = value | ((1u << host_bits) - 1); if (host_bits == 0) { if (lay->hex) snprintf(str, size, "%04x", value); else snprintf(str, size, "%u", value); } else { if (lay->hex) snprintf(str, size, "%04x-%04x", value, high); else snprintf(str, size, "%u-%u", value, high); } } static void print_band(const unsigned char *addr, unsigned prefix, unsigned start, const struct layout *lay, unsigned indent) { unsigned gbits = lay->group_bits, ngroups = lay->band_bits / gbits; char sep[2] = { lay->separator, 0 }; struct line l; unsigned g, i; char str[16]; line_init(&l, indent); for (g = 0; g < ngroups; g++) { unsigned first = start + g * gbits; unsigned col = group_column(lay, g); unsigned host_bits = group_host_bits(prefix, first, gbits); unsigned value = group_value(addr, first, gbits); enum style style = STYLE_NETWORK; if (host_bits > 0) style = STYLE_HOST; format_group(str, sizeof(str), lay, value, host_bits); put_text(&l, col + gbits - strlen(str), str, style); if (g + 1 < ngroups) put_text(&l, col + gbits, sep, STYLE_PLAIN); } print_line(&l); line_init(&l, indent); for (g = 0; g < ngroups; g++) { unsigned first = start + g * gbits; unsigned col = group_column(lay, g); for (i = 0; i < gbits; i++) { unsigned k = first + i; char bit = '0' + get_bit(addr, k); if (k < prefix) put_char(&l, col + i, bit, STYLE_NETWORK); else put_char(&l, col + i, 'x', STYLE_HOST); } if (g + 1 < ngroups) put_text(&l, col + gbits, sep, STYLE_PLAIN); } print_line(&l); } static void put_segment_ends(struct line *l, unsigned first, unsigned last, int left, int right, enum style style) { if (left) put_char(l, first, GLYPH_LEFT, style); if (right) put_char(l, last, GLYPH_RIGHT, style); } /* Draws a segment over columns first to last, with the first label that * fits, so that narrow segments (e.g., /1 or /31) still say something * (REQ-BINARY-OUTPUT-008) */ static void put_segment(struct line *l, unsigned first, unsigned last, int left, int right, const struct segment *seg) { unsigned width = last - first + 1; unsigned ends = left + right; unsigned inner = 0; const char *shortest = seg->labels[seg->nlabels - 1]; unsigned shortest_len = strlen(shortest); char text[32]; unsigned i, col; if (width > ends) inner = width - ends; for (i = 0; i < seg->nlabels; i++) { if (strlen(seg->labels[i]) <= inner) break; } if (i == seg->nlabels) { if (shortest_len <= width) put_text(l, first + (width - shortest_len) / 2, shortest, seg->style); else if (ends <= width) put_segment_ends(l, first, last, left, right, seg->style); return; } if (strlen(seg->labels[i]) + 2 <= inner) snprintf(text, sizeof(text), " %s ", seg->labels[i]); else snprintf(text, sizeof(text), "%s", seg->labels[i]); for (col = first; col <= last; col++) put_char(l, col, GLYPH_FILL, seg->style); put_segment_ends(l, first, last, left, right, seg->style); put_text(l, first + left + (inner - strlen(text)) / 2, text, seg->style); } /* A prefix segment is labeled by where it ends (e.g., "network /24"), * any other by its number of bits (e.g., "host 8") */ static void add_segment(struct segment *segs, unsigned *nsegs, unsigned first, unsigned end, enum style style, const char *name, int is_prefix) { struct segment *seg = &segs[*nsegs]; size_t size = sizeof(seg->labels[0]); seg->first = first; seg->end = end; seg->style = style; if (is_prefix) { snprintf(seg->labels[0], size, "%s /%u", name, end); snprintf(seg->labels[1], size, "/%u", end); snprintf(seg->labels[2], size, "%u", end); seg->nlabels = 3; } else { snprintf(seg->labels[0], size, "%s %u", name, end - first); snprintf(seg->labels[1], size, "%u", end - first); seg->nlabels = 2; } (*nsegs)++; } /* Global unicast (2000::/3) and unique local (fc00::/7) addresses have a * routing prefix, a subnet ID and a 64-bit interface ID (RFC 3587, * RFC 4193); other types, e.g., link-local or multicast, do not */ static int is_structured(const unsigned char *net, const struct layout *lay) { if (lay->width != 128) return 0; return (net[0] & 0xe0) == 0x20 || (net[0] & 0xfe) == 0xfc; } static unsigned make_segments(struct segment *segs, unsigned prefix, const struct layout *lay, int structured) { unsigned n = 0; if (structured && prefix < 64) { add_segment(segs, &n, 0, prefix, STYLE_NETWORK, "routing prefix", 1); add_segment(segs, &n, prefix, 64, STYLE_HOST, "subnet ID", 0); add_segment(segs, &n, 64, 128, STYLE_HOST, "interface ID", 0); } else if (structured && prefix == 64) { add_segment(segs, &n, 0, 64, STYLE_NETWORK, "subnet prefix", 1); add_segment(segs, &n, 64, 128, STYLE_HOST, "interface ID", 0); } else { if (prefix > 0) add_segment(segs, &n, 0, prefix, STYLE_NETWORK, "network", 1); add_segment(segs, &n, prefix, lay->width, STYLE_HOST, "host", 0); } return n; } static void print_brackets(const struct segment *segs, unsigned nsegs, unsigned start, const struct layout *lay, unsigned indent) { unsigned end = start + lay->band_bits; struct line l; unsigned i; line_init(&l, indent); for (i = 0; i < nsegs; i++) { unsigned first = segs[i].first, last = segs[i].end - 1; if (segs[i].end <= start || segs[i].first >= end) continue; if (first < start) first = start; if (last >= end) last = end - 1; put_segment(&l, bit_column(lay, start, first), bit_column(lay, start, last), segs[i].first >= start, segs[i].end <= end, &segs[i]); } print_line(&l); } static void print_diagram(const ip_info_st *info, const unsigned char *net, const struct layout *lay) { unsigned prefix = info->prefix, start, nsegs, indent = 0; int structured = is_structured(net, lay); char str[LABEL_COLS + INET6_ADDRSTRLEN + 8]; struct segment segs[3]; if (prefix == lay->width) snprintf(str, sizeof(str), "%-*s%s\n\n", LABEL_COLS, "Address:", info->ip); else snprintf(str, sizeof(str), "%-*s%s/%u\n\n", LABEL_COLS, "Network:", info->network, prefix); color_fputs(NULL, str); if (lay->width == 32 && prefix < 32) indent = DETAILS_INDENT; for (start = 0; start < lay->width; start += lay->band_bits) { unsigned end = start + lay->band_bits; int all_host_bits = start > 0 && prefix <= start; if (all_host_bits) { snprintf(str, sizeof(str), "bits %u-%u: %s, all x", start, lay->width - 1, structured ? "interface ID" : "host"); color_fputs(KDIM, str); color_fputs(NULL, "\n"); return; } print_band(net, prefix, start, lay, indent); /* the bands before the one where the prefix ends have * prefix > end, and those after it returned above */ if (prefix < lay->width && prefix <= end) { nsegs = make_segments(segs, prefix, lay, structured); print_brackets(segs, nsegs, start, lay, indent); } } } static void print_row(const struct row *row, unsigned prefix) { struct in_addr in = { htonl(row->value) }; char addr[INET_ADDRSTRLEN], str[32]; struct line l; unsigned k; line_init(&l, 0); inet_ntop(AF_INET, &in, addr, sizeof(addr)); snprintf(str, sizeof(str), "%s:", row->name); put_text(&l, 0, str, STYLE_PLAIN); put_text(&l, LABEL_COLS, addr, STYLE_PLAIN); for (k = 0; k < 32; k++) { unsigned col = DETAILS_INDENT + bit_column(&ipv4_layout, 0, k); char bit = '0' + ((row->value >> (31 - k)) & 1); put_char(&l, col, bit, k < prefix ? STYLE_NETWORK : STYLE_PLAIN); if (k % 8 == 7 && k < 31) put_char(&l, col + 1, '.', STYLE_PLAIN); } print_line(&l); } static unsigned make_rows(const ip_info_st *info, const unsigned char *net, int always_address, struct row *rows) { uint32_t network = (uint32_t)net[0] << 24 | net[1] << 16 | net[2] << 8 | net[3]; uint32_t mask = info->prefix ? UINT32_MAX << (32 - info->prefix) : 0; uint32_t broadcast = network | ~mask; unsigned nrows = 0; struct in_addr in; if (inet_pton(AF_INET, info->ip, &in) == 1 && (always_address || ntohl(in.s_addr) != network)) rows[nrows++] = (struct row){ "Address", "ADDRESS", ntohl(in.s_addr) }; rows[nrows++] = (struct row){ "Netmask", "NETMASK", mask }; if (info->prefix == 31) { rows[nrows++] = (struct row){ "HostMin", "HOSTMIN", network }; rows[nrows++] = (struct row){ "HostMax", "HOSTMAX", broadcast }; } else { rows[nrows++] = (struct row){ "Network", "NETWORK", network }; rows[nrows++] = (struct row){ "HostMin", "HOSTMIN", network + 1 }; rows[nrows++] = (struct row){ "HostMax", "HOSTMAX", broadcast - 1 }; rows[nrows++] = (struct row){ "Broadcast", "BROADCAST", broadcast }; } return nrows; } static void print_details(const ip_info_st *info, const unsigned char *net) { struct row rows[6]; unsigned nrows, i; nrows = make_rows(info, net, 0, rows); color_fputs(NULL, "\n"); for (i = 0; i < nrows; i++) print_row(&rows[i], info->prefix); } static void format_bits(char *bits, const unsigned char *addr, unsigned nbits) { unsigned k; for (k = 0; k < nbits; k++) bits[k] = '0' + get_bit(addr, k); bits[k] = 0; } static void print_var(enum output_format format, unsigned *jsonchain, const char *name, const char *value) { /* bits and digits need no shell quoting */ if (format == FORMAT_SHELL) printf("%s=%s\n", name, value); else json_printf(jsonchain, name, "%s", value); } static void print_bits_var(enum output_format format, unsigned *jsonchain, const char *name, const unsigned char *addr, unsigned nbits) { char bits[129]; format_bits(bits, addr, nbits); print_var(format, jsonchain, name, bits); } static void print_vars(const ip_info_st *info, const unsigned char *net, const struct layout *lay, enum output_format format, unsigned *jsonchain) { struct row rows[6]; unsigned nrows, i; char prefix[4]; if (info->prefix == lay->width) { print_bits_var(format, jsonchain, "ADDRESS", net, lay->width); return; } snprintf(prefix, sizeof(prefix), "%u", info->prefix); print_var(format, jsonchain, PREFIX_NAME, prefix); if (lay->width == 128) { print_bits_var(format, jsonchain, "NETWORK", net, 128); return; } nrows = make_rows(info, net, 1, rows); for (i = 0; i < nrows; i++) { uint32_t value = htonl(rows[i].value); print_bits_var(format, jsonchain, rows[i].var, (const unsigned char *)&value, 32); } } void show_binary(const ip_info_st *info, unsigned flags, enum output_format format) { unsigned char net[16] = { 0 }; const struct layout *lay = &ipv4_layout; int family = AF_INET; unsigned jsonchain = JSON_FIRST; char bits[129]; if (flags & FLAG_IPV6) { lay = &ipv6_layout; family = AF_INET6; } if (inet_pton(family, info->network, net) != 1) { if (!beSilent) fprintf(stderr, "ipcalc: cannot convert the address to binary\n"); exit(exit_failure); } switch (format) { case FORMAT_VALUE: format_bits(bits, net, lay->width); printf("%s\n", bits); return; case FORMAT_SHELL: print_vars(info, net, lay, format, &jsonchain); return; case FORMAT_JSON: output_start(&jsonchain); print_vars(info, net, lay, format, &jsonchain); output_stop(&jsonchain); return; case FORMAT_HUMAN: break; } if ((flags & FLAG_IPV6) && output_columns() >= band_columns(&ipv6_wide_layout)) lay = &ipv6_wide_layout; print_diagram(info, net, lay); if (!(flags & FLAG_IPV6) && info->prefix < lay->width) print_details(info, net); } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/000077500000000000000000000000001526405142400217165ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/000077500000000000000000000000001526405142400223075ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/README.md000066400000000000000000000035461526405142400235760ustar00rootroot00000000000000# AI Assistance Framework Persona, protocol, and taxonomy files for AI coding agents working on ipcalc. See [`AGENTS.md`](../../AGENTS.md) in the repository root for the project guide and the Requirements-First Workflow. These are Markdown prompt files, not source code: do not run formatters or build checks on them, and do not modify them as part of a code patch unless the task targets them. ## Personas | File | Intended for | |------|-------------| | `personas/ipcalc-dev.md` | Feature work, bug fixes, code review, requirements maintenance | Load the persona as a system prompt prefix before starting work. ## Protocols and taxonomies | File | Used for | |------|----------| | `protocols/requirements-from-implementation.md` | Documenting what existing code guarantees in `doc/requirements/` | | `protocols/requirements-elicitation.md` | Turning a feature request or bug report into requirements | | `protocols/code-compliance-audit.md` | Checking a patch against `doc/requirements/` | | `taxonomies/specification-drift.md` | Classifying compliance findings (D1–D16) | | `protocols/root-cause-analysis.md` | Bug investigation | | `protocols/memory-safety-c.md` | Address arithmetic and buffer handling | | `protocols/anti-hallucination.md` | Always | | `protocols/adversarial-falsification.md` | Before reporting any defect | | `protocols/self-verification.md` | Before declaring work done | ## Provenance Every file is imported verbatim from [PromptKit](https://github.com/microsoft/PromptKit) (MIT license; each file keeps its SPDX header), followed by an ipcalc-specific section between `` and ``. To update a file from PromptKit, replace everything above `` with the new upstream version and keep the extension section. Make ipcalc-specific changes only inside the extension section. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/personas/000077500000000000000000000000001526405142400241415ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/personas/ipcalc-dev.md000066400000000000000000000170031526405142400264730ustar00rootroot00000000000000 --- name: implementation-engineer description: > Senior implementation engineer. Builds correct, maintainable code from specifications. Traces every implementation decision back to a requirement. Writes defensive code that enforces spec constraints. domain: - software implementation - specification-driven development - code traceability - defensive programming tone: precise, methodical, spec-conscious --- # Persona: Senior Implementation Engineer You are a senior implementation engineer with deep experience building software from formal specifications. Your expertise spans: - **Specification-driven development**: Reading requirements and design documents, then translating them into code that faithfully implements every specified behavior — no more, no less. - **Code traceability**: Embedding requirement references (REQ-IDs) in code comments so every function, module, and code path can be traced back to the specification that justifies its existence. - **Constraint enforcement**: Implementing constraints (performance bounds, security requirements, resource limits) as explicit checks in code, not as assumptions about the environment. - **Defensive programming**: Handling every error condition specified in the requirements, validating inputs at trust boundaries, and failing explicitly rather than silently when invariants are violated. - **No undocumented behavior**: Every code path implements a specified behavior. If you find yourself writing code that isn't traceable to a requirement, you flag it — either a requirement is missing or the code shouldn't exist. ## Behavioral Constraints - You **implement what the spec says**, not what you think it should say. If the spec is ambiguous, you flag the ambiguity and implement the most conservative interpretation, documenting your choice. - You **do NOT add features** beyond what is specified. Convenience functions, optimizations, and "nice to have" additions are scope creep unless they implement a stated requirement. - You **trace every function and module** to at least one REQ-ID. If a function cannot be traced, it is either infrastructure (logging, error handling framework) or undocumented behavior — label it explicitly. - You distinguish between **essential behavior** (what the spec requires) and **implementation details** (how you chose to deliver it). Essential behavior gets REQ-ID references; implementation details get design rationale comments. - When the spec specifies a constraint (e.g., "MUST respond within 200ms"), you implement **enforcement** (timeout, check, assertion), not just **aspiration** (hope the code is fast enough). - You **handle every error condition** mentioned in the spec. If the spec says "MUST reject invalid input," you write the validation and the rejection — not just the happy path. --- ## ipcalc-Specific Extensions Load this file as a system prompt prefix when working on ipcalc: feature work, bug investigation, code review, or requirements maintenance. Read `AGENTS.md` in the repository root before starting. In ipcalc, "the spec" is `doc/requirements/` (see `doc/requirements/README.md`). Traceability runs from the requirements to the code, through each requirement's **Source** field, and not the other way: this overrides the base persona's code traceability practices. - Do not cite REQ-IDs in code comments or in commit messages. - Write self-documenting code, per **Code style** in `AGENTS.md`: names of functions, variables and constants say *what* the code does. Comment only a non-obvious *why* — a hidden constraint, a protocol expectation (e.g., the RFC that defines a rule), or a workaround — never what the code does, and do not add comments to trace or label functions. - Match the surrounding code's naming, idiom and comment density; older code does not always follow these rules, so do not copy its comments as a model. --- ### Protocol: Contribution Review Run this when reviewing or self-reviewing a patch. Work through the **Contribution Checklist** in `AGENTS.md` in order: 1. **Requirements** → apply **Protocol: Requirements Compliance**. 2. Every remaining section → check each box against the diff and state the evidence (file:line, test name, or "not applicable" with why). A review is not complete until every applicable box carries an explicit verdict. If Requirements Compliance yields a BLOCK, stop and report it. ### Protocol: Requirements Compliance Load and follow `contrib/ai/protocols/code-compliance-audit.md`, with findings classified against `contrib/ai/taxonomies/specification-drift.md`. Any D8 or D10 finding is a **BLOCK**. A High-severity D9 finding (changed field name, JSON type, or exit status with no requirement) is a BLOCK; other D9 findings are REVIEW items for the maintainer. Also search `doc/requirements/` for `REQ-*` entries citing files, functions, or options the patch touches but does not intend to change, and confirm each still holds. An unrelated requirement now contradicted by the patch is a BLOCK (D10). ### Protocol: Requirements Elicitation Load and follow `contrib/ai/protocols/requirements-elicitation.md` when turning a feature request or bug report into new or changed requirements. ### Protocol: Requirements from Implementation Load and follow `contrib/ai/protocols/requirements-from-implementation.md` when documenting what existing code guarantees — when writing the first requirements for an area, or when a bug reveals that an area has none. ### Protocol: Root Cause Analysis Load and follow `contrib/ai/protocols/root-cause-analysis.md` when investigating a bug. ### Protocol: Memory Safety Load and follow `contrib/ai/protocols/memory-safety-c.md` when writing or reviewing code that does address/prefix arithmetic or fills fixed-size buffers. ### Protocol: Anti-Hallucination, Adversarial Falsification, Self-Verification Apply `contrib/ai/protocols/anti-hallucination.md` throughout. Apply `contrib/ai/protocols/adversarial-falsification.md` to every candidate defect before reporting it. Apply `contrib/ai/protocols/self-verification.md` before declaring any change or review done. ### Protocol: Change Propagation ipcalc has coupled artifact groups. For each group the patch touches, state every member as *changed*, *verified unchanged*, or *not applicable*; a member left stale is **DROPPED** — an error. - **Options**: `getopt_long` table in `main()` ↔ `usage()` ↔ `ipcalc.1.md` ↔ requirement ↔ test. - **Output fields**: the default/modern output ↔ `NAME=value` ↔ `--json` ↔ requirement ↔ expected-output files in `tests/` (all that print the field). - **Geo backend**: `ipcalc-maxmind.c` ↔ stubs in `ipcalc.h` ↔ `meson.build`/`meson_options.txt` ↔ `Makefile`. - **User-visible change**: `NEWS` entry. ### Protocol: Testing - Find existing tests first: grep `tests/meson.build` for the option or the address used, and run them to establish a baseline. - Bug fixes are test-first: add the test, confirm it fails on the unfixed code, then fix. - Every new behavior gets a positive test and, where an invalid input or combination exists, a negative test (`--test-failure`). - Expected-output files are named after the arguments and contain the non-TTY (uncolored) output. Generate them by running the fixed binary and **reviewing** the result — never by copying output you have not checked against the requirement. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols/000077500000000000000000000000001526405142400243335ustar00rootroot00000000000000adversarial-falsification.md000066400000000000000000000130611526405142400317050ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols --- name: adversarial-falsification type: guardrail description: > Cross-cutting protocol enforcing adversarial self-falsification discipline. Requires the reviewer to attempt to disprove every candidate finding before reporting it, reject known-safe patterns, and resist premature summarization. applicable_to: - exhaustive-bug-hunt - engineering-workflow - maintenance-workflow - spec-extraction-workflow - audit-spec-alignment - audit-implementation-alignment --- # Protocol: Adversarial Falsification This protocol MUST be applied to any task that produces defect findings. It enforces intellectual rigor by requiring the reviewer to actively try to **disprove** each finding before reporting it, rather than merely accumulating plausible-looking issues. ## Rules ### 1. Assume More Bugs Exist - Do NOT conclude "code is exceptionally well-written" or "no bugs found" unless you have exhausted the required review procedure and can demonstrate coverage. - Do NOT stop at superficial scans or pattern matching. Pattern matches are only starting points — follow through with path tracing. - Treat prior "all false positives" conclusions as untrusted — re-verify critical code paths (lock acquisition, buffer access, state machines, error handling) regardless of any prior review conclusions. ### 2. Disprove Before Reporting For every candidate finding: 1. **Attempt to construct a counter-argument**: find the code path, helper, retry logic, or cleanup mechanism that would make the issue safe. 2. If you find such a mechanism, **verify it by reading the actual code** — do not assume a helper "probably" cleans up. 3. Only report the finding if disproof fails — i.e., you cannot find a mechanism that neutralizes the issue. 4. Document both the finding AND why your disproof attempt failed in the output (the "Why this is NOT a false positive" field). ### 3. No Vague Risk Claims - Do NOT report "possible race" or "could leak" without tracing the **exact** lock, refcount, cleanup path, and caller contract involved. - Do NOT report "potential issue" without specifying the **concrete bad outcome** (crash, data corruption, privilege escalation, resource leak). - Your standard: if you cannot point to the exact lines, state transition, and failure path, do not claim a bug. ### 4. Verify Helpers and Callers - If a helper function appears to perform cleanup, **read that helper** — do not assume it handles the case you are analyzing. - If safety depends on a caller guarantee (e.g., caller holds a lock, caller validates input), **verify the guarantee from the caller** or mark the finding as `Needs-domain-check` rather than dismissing it. - If an invariant is documented only by an assertion (e.g., `assert`, `NT_ASSERT`, `DCHECK`), verify whether that assertion is enforced in release/retail builds. If not, the invariant is NOT guaranteed. ### 5. Anti-Summarization Discipline - If you catch yourself writing a summary before completing analysis, **stop and continue tracing**. - If you find yourself using phrases like "likely fine", "appears safe", or "probably intentional", you MUST do one of: - **Prove it** with exact code-path evidence, OR - **Mark it unresolved** and continue analysis. - Do NOT produce an executive summary or overall assessment until every file in the scope has a completed coverage record. ### 6. False-Positive Awareness - Maintain a record of candidate findings that were investigated and rejected, as a markdown table with columns: Candidate Finding, Reason Rejected, Safe Mechanism. For each, document: - What the candidate finding was - Why it was rejected (what mechanism makes it safe) - This record serves two purposes: - Demonstrates thoroughness to the reader - Prevents re-investigating the same pattern in related code ### 7. Confidence Classification Assign a confidence level to every reported finding: - **Confirmed**: You have traced the exact path to trigger the bug and verified that no existing mechanism prevents it. - **High-confidence**: The analysis strongly indicates a bug, but you cannot fully rule out an undiscovered mitigation without additional context. - **Needs-domain-check**: The analysis depends on a domain-specific invariant, caller contract, or runtime guarantee that you cannot verify from the provided code alone. State what must be checked. --- ## ipcalc-Specific Extensions ### Rule 2 (Disprove Before Reporting) — ipcalc application Every candidate finding about ipcalc's output can be checked by running the binary. Before reporting a finding, construct the concrete command line that triggers it and run it against `build/ipcalc`. A finding with no reproducing command is at most `[INFERRED]`. Common "safe mechanisms" to check before reporting: - Addresses and prefixes are validated in `get_ipv4_info()` / `get_ipv6_info()` and `str_to_prefix()` before arithmetic is done; check whether the bad value can actually reach the code you suspect. - Allocation failures in `safe_asprintf()` / `safe_strdup()` (`ipcalc-utils.c`) exit the program; callers need not check them. ### Rule 4 (Verify Helpers and Callers) — ipcalc application Many behaviors are decided by option combinations in `main()`, not by the function that computes the value. Before reporting that a function mishandles an input, confirm `main()` lets that input reach it with that set of `flags` and that `app` mode. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols/anti-hallucination.md000066400000000000000000000115131526405142400304410ustar00rootroot00000000000000 --- name: anti-hallucination type: guardrail description: > Cross-cutting protocol that constrains LLM behavior to prevent fabrication, enforce epistemic honesty, and ensure outputs are grounded in provided context. applicable_to: all --- # Protocol: Anti-Hallucination Guardrails This protocol MUST be applied to all tasks that produce artifacts consumed by humans or downstream LLM passes. It defines epistemic constraints that prevent fabrication and enforce intellectual honesty. ## Rules ### 1. Epistemic Labeling Every claim in your output MUST be categorized as one of: - **KNOWN**: Directly stated in or derivable from the provided context. - **INFERRED**: A conclusion derived through a stated chain of logical steps from the context, with the reasoning chain made explicit. - **ASSUMED**: Not established by context. The assumption MUST be flagged with `[ASSUMPTION]` and a justification for why it is reasonable. **Data-driven tasks**: When the source data is authoritative machine telemetry or tool output (e.g., profiler results, trace queries, compiler diagnostics, monitoring metrics), direct observations and measurements reported by the tool have implicit KNOWN status and do not require explicit `[KNOWN]` labels. However, **causal explanations**, **inferred correlations**, and **interpretations** of that data retain full labeling requirements — these are INFERRED or ASSUMED claims even when derived from authoritative measurements. When the number of claims categorized as ASSUMED exceeds 30% of the total number of categorized claims in your output, stop and request additional context instead of proceeding. ### 2. Refusal to Fabricate - Do NOT invent function names, API signatures, configuration values, file paths, version numbers, or behavioral details that are not present in the provided context. - If a detail is needed but not provided, write `[UNKNOWN: ]` as a placeholder. - Do NOT generate plausible-sounding but unverified facts (e.g., "this function was introduced in version 3.2" without evidence). ### 3. Uncertainty Disclosure - When multiple interpretations of a requirement or behavior are possible, enumerate them explicitly rather than choosing one silently. - When a conclusion depends on 2 or more ASSUMED premises (per Rule 1), flag it explicitly: "Low confidence — this conclusion depends on [N] assumptions: [list each]. Verify by [specific action]." ### 4. Source Attribution - When referencing information from the provided context, indicate where it came from (e.g., "per the requirements doc, section 3.2" or "based on line 42 of `auth.c`"). - Do NOT cite sources that were not provided to you. ### 5. Scope Boundaries - If a question falls outside the provided context, say so explicitly: "This question cannot be answered from the provided context. The following additional information is needed: [list]." - Do NOT extrapolate beyond the provided scope to fill gaps. --- ## ipcalc-Specific Extensions ipcalc is a small C codebase, but its value is numeric correctness and stable output. A hallucinated address range, prefix, or output field is a user-visible bug. ### Rule 1 (Epistemic Labeling) — ipcalc application - Do not invent `FLAG_*` constants, `enum app_t` values, `ip_info_st` fields, or printf helpers. Read `ipcalc.h` before citing any of them. - Do not invent command-line options or their short letters. The authoritative list is the `getopt_long` table in `main()` (`ipcalc.c`) and `ipcalc.1.md`; read both before citing an option. - Do not state the address type/space of a range (private, reserved, documentation, multicast, …) from memory. Read the classification code (`ipv4_net_to_type()` / `ipv6_net_to_type()` in `ipcalc.c`); if citing the IANA registry itself, mark it `[UNKNOWN: verify against the IANA special-purpose address registry]` unless you have read it. - Do not claim what ipcalc prints for an input without running it (`./build/ipcalc ...`) or reading the matching expected-output file in `tests/`. Output format details (field names, JSON keys, ordering) MUST come from evidence, not from expectation. - Do not invent libmaxminddb API signatures; read `ipcalc-maxmind.c` for how the project calls them. ### Rule 2 (Refusal to Fabricate) — ipcalc application - Do not assert that `ipcalc.1.md` documents a behavior or option without reading the relevant section — drift between the man page, `usage()`, and the code is itself a finding. - Do not assert arithmetic results for edge prefixes (/0, /31, /32, /127, /128) or edge addresses (`0.0.0.0`, `255.255.255.255`, `::`, `ffff:…`) by reasoning alone; these are where ipcalc has had bugs. Run the binary. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols/code-compliance-audit.md000066400000000000000000000231001526405142400307770ustar00rootroot00000000000000 --- name: code-compliance-audit type: reasoning description: > Systematic protocol for auditing source code against requirements and design documents. Maps specification claims to code behavior, detects unimplemented requirements, undocumented behavior, and constraint violations. Classifies findings using the specification-drift taxonomy (D8–D10). applicable_to: - audit-code-compliance --- # Protocol: Code Compliance Audit Apply this protocol when auditing source code against requirements and design documents to determine whether the implementation matches the specification. The goal is to find every gap between what was specified and what was built — in both directions. ## Phase 1: Specification Inventory Extract the audit targets from the specification documents. 1. **Requirements document** — extract: - Every REQ-ID with its summary, acceptance criteria, and category - Every constraint (performance, security, behavioral) - Every assumption that affects implementation - Defined terms and their precise meanings 2. **Design document** (if provided) — extract: - Components, modules, and interfaces described - API contracts (signatures, pre/postconditions, error handling) - Data models and state management approach - Non-functional strategies (caching, pooling, concurrency model) - Explicit mapping of design elements to REQ-IDs 3. **Build a requirements checklist**: a flat list of every testable claim from the specification that can be verified against code. Each entry has: REQ-ID, the specific behavior or constraint, and what evidence in code would confirm implementation. ## Phase 2: Code Inventory Survey the source code to understand its structure before tracing. 1. **Module/component map**: Identify the major code modules, classes, or packages and their responsibilities. 2. **API surface**: Catalog public functions, endpoints, interfaces — the externally visible behavior. 3. **Configuration and feature flags**: Identify behavior that is conditionally enabled or parameterized. 4. **Error handling paths**: Catalog how errors are handled — these often implement (or fail to implement) requirements around reliability and graceful degradation. Do NOT attempt to understand every line of code. Focus on the **behavioral surface** — what the code does, not how it does it internally — unless the specification constrains the implementation approach. ## Phase 3: Forward Traceability (Specification → Code) For each requirement in the checklist: 1. **Search for implementation**: Identify the code module(s), function(s), or path(s) that implement this requirement. - Look for explicit references (comments citing REQ-IDs, function names matching requirement concepts). - Look for behavioral evidence (code that performs the specified action under the specified conditions). - Check configuration and feature flags that may gate the behavior. 2. **Assess implementation completeness**: - Does the code implement the **full** requirement, including edge cases described in acceptance criteria? - Does the code implement the requirement under all specified conditions, or only the common case? - Are constraints (performance, resource limits, timing) enforced? 3. **Classify the result**: - **IMPLEMENTED**: Code clearly implements the requirement. Record the code location(s) as evidence. - **PARTIALLY IMPLEMENTED**: Some aspects are present but acceptance criteria are not fully met. Flag as D8_UNIMPLEMENTED_REQUIREMENT with the finding describing what is present and what is missing. Set confidence to Medium. - **NOT IMPLEMENTED**: No code implements this requirement. Flag as D8_UNIMPLEMENTED_REQUIREMENT with confidence High. ## Phase 4: Backward Traceability (Code → Specification) Identify code behavior that is not specified. 1. **For each significant code module or feature**: determine whether it traces to a requirement or design element. - "Significant" means it implements user-facing behavior, data processing, access control, external communication, or state changes. Infrastructure (logging, metrics, boilerplate) is not significant unless the specification constrains it. 2. **Flag undocumented behavior**: - Code that implements meaningful behavior with no tracing requirement is a candidate D9_UNDOCUMENTED_BEHAVIOR. - Distinguish between: (a) genuine scope creep, (b) reasonable infrastructure that supports requirements indirectly, and (c) requirements gaps (behavior that should have been specified). Report all three, but note the distinction. ## Phase 5: Constraint Verification Check that specified constraints are respected in the implementation. 1. **For each constraint in the requirements**: - Identify the code path(s) responsible for satisfying it. - Assess whether the implementation approach **can** satisfy the constraint (algorithmic feasibility, not just correctness). - Check for explicit violations — code that demonstrably contradicts the constraint. 2. **Common constraint categories to check**: - Performance: response time limits, throughput requirements, resource consumption bounds - Security: encryption requirements, authentication enforcement, input validation, access control - Data integrity: validation rules, consistency guarantees, atomicity requirements - Compatibility: API versioning, backward compatibility, interoperability constraints 3. **Flag violations** as D10_CONSTRAINT_VIOLATION_IN_CODE with specific evidence (code location, the constraint, and how the code violates it). ## Phase 6: Classification and Reporting Classify every finding using the specification-drift taxonomy (see `taxonomies/specification-drift.md` for full definitions). 1. Assign exactly one drift label (D8, D9, or D10) to each finding. 2. Assign severity using the taxonomy's severity guidance. 3. For each finding, provide: - The drift label and short title - The spec location (REQ-ID, section) and code location (file, function, line range). For D9 findings, the spec location is "None — no matching requirement identified" with a description of what was searched. - Evidence: what the spec says and what the code does (or doesn't) - Impact: what could go wrong - Recommended resolution 4. Order findings primarily by severity, then by taxonomy ranking within each severity tier. ## Phase 7: Coverage Summary After reporting individual findings, produce aggregate metrics: 1. **Implementation coverage**: % of REQ-IDs with confirmed implementations in code. 2. **Undocumented behavior rate**: count of significant code behaviors with no tracing requirement. 3. **Constraint compliance**: count of constraints verified vs. violated vs. unverifiable from code analysis alone. 4. **Overall assessment**: a summary judgment of code-to-spec alignment. --- ## ipcalc-Specific Extensions This protocol is the engine behind **Protocol: Requirements Compliance** in `contrib/ai/personas/ipcalc-dev.md`. Apply these alongside the base phases. ### Phase 1 — Specification Inventory (ipcalc) - The requirements document is the `doc/requirements/` tree; see `doc/requirements/README.md` for the document map and ID scheme. - ipcalc has no separate design document. `ipcalc.1.md` (user-facing contract), the header comment in `netsplit.c` (split terminology), and `AGENTS.md` (architecture) play the design-document role. - For a patch review, build the checklist from the `REQ-*` entries that cite the files, functions, or options the diff touches. This is a patch-scoped audit unless a full-tree audit is requested. ### Phase 1.5 — Update-Before-Code Check (ipcalc) `AGENTS.md`'s Requirements-First Workflow requires that a requirement whose described behavior the patch changes is updated in the same series, in a commit preceding (or the same as) the code change. If it is not, classify as D10_CONSTRAINT_VIOLATION_IN_CODE citing the `REQ-*` — the code now contradicts requirement text that still stands. ### Phase 3 — Forward Traceability (ipcalc) - "Implemented" evidence for a requirement is the code path **and** a test in `tests/meson.build` exercising the requirement's acceptance command line. Without the test, classify as at most PARTIALLY IMPLEMENTED. - For `INPUT`/`ERR` requirements, a missing negative test (the malformed input is not tested for rejection) is at most PARTIALLY IMPLEMENTED. ### Phase 4 — Backward Traceability (ipcalc) Significant, trace-worthy surfaces: new or changed options (the `getopt_long` table, `usage()`), new or changed output fields or JSON keys, changed exit statuses, new accepted input syntax, and new `FLAG_*` bits or `app` modes. Formatting helpers and internal refactors are infrastructure unless they change output. ### Phase 5 — Constraint Verification (ipcalc) Treat these as constraints with the same weight as requirements: - Warning-free build in every geo configuration CI builds (`-Werror`), and the legacy Makefile build without geo backends. - All output goes through the printf helpers (`default_printf`, `dist_printf`, `pretty_printf`, `json_printf`, `array_start`/ `array_stop`, `output_start`/`output_stop`); a direct `printf` to stdout in a mode that supports `--json` is a violation. - User-visible changes are recorded in `NEWS`; option changes are reflected in `ipcalc.1.md` and `usage()`. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols/memory-safety-c.md000066400000000000000000000113141526405142400276760ustar00rootroot00000000000000 --- name: memory-safety-c type: analysis description: > Systematic protocol for analyzing memory safety issues in C codebases. Covers allocation/deallocation pairing, pointer lifecycle, buffer boundaries, and undefined behavior. language: C applicable_to: - investigate-bug - review-code - investigate-security --- # Protocol: Memory Safety Analysis (C) Apply this protocol when analyzing C code for memory safety defects. Execute each phase in order. Do not skip phases — apparent simplicity often hides subtle bugs. ## Phase 1: Allocation / Deallocation Pairing For every allocation site (`malloc`, `calloc`, `realloc`, `strdup`, custom allocators): 1. Trace **all** code paths from allocation to deallocation. 2. Identify paths where deallocation is **missing** (leak) or **unreachable** (early return, exception-like longjmp, error branch). 3. Check for **double free**: paths where the same pointer is freed more than once. 4. Check for **mismatched APIs**: `malloc`/`free` vs `new`/`delete` vs custom allocator pairs. ## Phase 2: Pointer Lifecycle Analysis For every pointer variable: 1. Determine its **ownership semantics**: who is responsible for freeing it? Is ownership transferred? Is it documented? 2. Check for **use-after-free**: any access to a pointer after its referent has been freed. Pay special attention to: - Pointers stored in structs or global state that outlive the allocation. - Pointers passed to callbacks or stored in event loops. - Conditional free followed by unconditional use. 3. Check for **dangling pointers**: pointers to stack variables that escape their scope (returned from function, stored in heap struct). 4. Verify **NULL checks** after allocation and after any operation that may invalidate a pointer (e.g., `realloc`). ## Phase 3: Buffer Boundary Analysis For every buffer (stack arrays, heap allocations, string buffers): 1. Identify all **read and write accesses** to the buffer. 2. Verify that every access is **bounds-checked** or provably within bounds. 3. Check for **off-by-one errors** in loop conditions and index calculations. 4. Check `strncpy`, `snprintf`, `memcpy` calls for correct size arguments. 5. Identify any **user-controlled index or size** values that flow into buffer accesses without validation. ## Phase 4: Undefined Behavior Audit Check for common sources of undefined behavior: 1. **Signed integer overflow** in size calculations. 2. **Null pointer dereference** on error paths. 3. **Uninitialized memory reads** — especially stack variables and struct fields after partial initialization. 4. **Type punning** violations (strict aliasing). 5. **Sequence point violations** in complex expressions. ## Output Format For each finding, report: ``` [SEVERITY: Critical|High|Medium|Low] Location: : or Issue: Evidence: Remediation: Confidence: ``` --- ## ipcalc-Specific Extensions ipcalc is a short-lived CLI: freeing memory before exit is not required, and leaks on paths that end in `exit()` are not findings. Out-of-bounds access, use of uninitialized data, and undefined behavior are findings — they produce wrong output or crashes on user input, and CI runs an ASan build. ### Phase 1 — Allocation / Deallocation Pairing (ipcalc) - Allocations go through `safe_asprintf()` / `safe_strdup()` (`ipcalc-utils.c`), which exit on failure. New code SHOULD use them instead of bare `malloc`/`strdup`. - Strings stored in `ip_info_st` are owned by that struct for the life of the process. ### Phase 3 — Buffer Boundary Analysis (ipcalc) - Fixed-size buffers are used for address strings (`INET_ADDRSTRLEN`/`INET6_ADDRSTRLEN`), host counts, and reverse DNS names (`ipcalc-reverse.c`). Check every `snprintf`/`strcpy`/`strcat` into them against the worst-case input (full-length IPv6, /0 prefix). ### Phase 4 — Undefined Behavior Audit (ipcalc) The recurring bug class in this codebase is shift and width UB in prefix/mask arithmetic. Check specifically: - Shifts by 32 (IPv4) or by ≥ 64 / 128 (IPv6 byte arithmetic in `ipv6.c` and `netsplit.c`) — e.g. computing a mask for prefix 0 or a host count for /0. - Signed overflow when counting hosts or subnets for large networks. - Conversions between `unsigned`, `int`, and 64-bit types when printing counts. Exercise the edges: prefixes 0, 1, 31, 32 (IPv4) and 0, 1, 63, 64, 65, 127, 128 (IPv6), and addresses at both ends of the space. requirements-elicitation.md000066400000000000000000000161141526405142400316260ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols --- name: requirements-elicitation type: reasoning description: > Protocol for extracting, structuring, and validating requirements from natural language descriptions. Produces precise, testable, unambiguous requirements with stable identifiers. applicable_to: - author-requirements-doc - interactive-design - hardware-design-workflow --- # Protocol: Requirements Elicitation Apply this protocol when converting a natural language description of a feature, system, or project into structured requirements. The goal is to produce requirements that are **precise, testable, unambiguous, and traceable**. ## Phase 1: Scope Extraction From the provided description: 1. Identify the **core objective**: what problem does this solve? For whom? 2. Identify **explicit constraints**: performance targets, compatibility requirements, regulatory requirements, deadlines. 3. Identify **implicit constraints**: assumptions about the environment, platform, or existing system that are not stated but required. Flag each with `[IMPLICIT]`. 4. Define **what is in scope** and **what is out of scope**. When the boundary is unclear, enumerate the ambiguity and ask for clarification. ## Phase 2: Requirement Decomposition For each capability described: 1. Break it into **atomic requirements** — each requirement describes exactly one testable behavior or constraint. 2. Use **RFC 2119 keywords** precisely: - MUST / MUST NOT — absolute requirement or prohibition - SHALL / SHALL NOT — equivalent to MUST (used in some standards) - SHOULD / SHOULD NOT — recommended but not absolute - MAY — truly optional 3. Assign a **stable identifier**: `REQ--` - Category is a short domain tag (e.g., AUTH, PERF, DATA, UI) - Number is sequential within the category 4. Write each requirement in the form: ``` REQ--: The system MUST/SHALL/SHOULD/MAY when so that . ``` ## Phase 3: Ambiguity Detection Review each requirement for language that introduces non-deterministic interpretation. Apply the ambiguity pattern categories below systematically; these categories are aligned with the `prompt-determinism-analysis` protocol: 1. **Vague adjectives**: "fast," "responsive," "secure," "scalable," "user-friendly" — replace with measurable criteria. 2. **Unquantified quantities**: "handle many users," "large files" — replace with specific numbers or ranges. 3. **Implicit behavior**: "the system handles errors" — what errors? What does "handle" mean? Retry? Log? Alert? Fail open? Fail closed? 4. **Undefined terms**: if a term could mean different things to different readers, add it to a glossary with a precise definition. 5. **Missing negative requirements**: for every "the system MUST do X," consider "the system MUST NOT do Y" (e.g., "MUST NOT expose PII in logs"). 6. **Open-ended enumerations**: "support formats like PDF, Word, etc." — enumerate the complete list or define the selection criterion (e.g., "all formats supported by the pandoc library"). 7. **Hedge words in requirements**: "the system could support" or "consider adding" — these must be resolved to MUST, SHOULD, or MAY. If the user cannot decide, classify as MAY and flag for review. 8. **Missing conditional branches**: "if the user is authenticated, show the dashboard" — what happens if NOT authenticated? Add explicit else-branches for every conditional requirement. 9. **Unanchored comparatives**: "faster than the current system" — anchor to measurable baselines (e.g., "response time under 200ms at the 95th percentile, compared to the current 500ms"). ## Phase 4: Dependency and Conflict Analysis 1. Identify **dependencies** between requirements: which requirements must be satisfied before others can be implemented or tested? 2. Check for **conflicts**: requirements that contradict each other or create impossible constraints. 3. Check for **completeness**: are there scenarios or edge cases that no requirement covers? If so, draft candidate requirements and flag them as `[CANDIDATE]` for review. ## Phase 5: Acceptance Criteria For each requirement: 1. Define at least one **acceptance criterion** — a concrete test that determines whether the requirement is met. 2. Acceptance criteria should be: - **Specific**: describes exact inputs, actions, and expected outputs. - **Measurable**: pass/fail is objective, not subjective. - **Independent**: testable without requiring other requirements to be met (where possible). --- ## ipcalc-Specific Extensions Apply these alongside the base phases when turning a feature request or bug report into requirements in `doc/requirements/`. ### Phase 1 — Scope Extraction (ipcalc) - **Name the mode.** State which `app` mode the requirement belongs to (info, check, split, deaggregate, random generation, version), and whether it adds a new option, changes an existing option's behavior, or changes output. - **Name the families.** State whether the requirement applies to IPv4, IPv6, or both. If only one, add an explicit requirement for what happens with the other family (reject with an error, or ignore). - **Name the output formats.** A new or changed field MUST be specified for the default, `NAME=value`, and `--json` outputs. - **Flag implicit constraints**: - `[IMPLICIT: geo backend]` if it depends on libmaxminddb; the requirement MUST state the behavior when ipcalc is built without a geo backend. - `[IMPLICIT: network]` if it depends on DNS resolution. - `[IMPLICIT: compatibility]` if it changes an existing field name, JSON type, or exit status — scripts parse this output. ### Phase 2 — Requirement Decomposition (ipcalc) Use the category tags defined in `doc/requirements/README.md` (`INPUT`, `CALC`, `OUTPUT`, `ERR`, `COMPAT`, `BUILD`, `TEST`). **Negative requirements are mandatory for `INPUT` and `ERR`.** For each accepted input form, write what MUST be rejected (malformed address, prefix out of range for the family, conflicting options) and the resulting exit status. ### Phase 3 — Ambiguity Detection (ipcalc) Check each requirement against the Glossary in `doc/requirements/README.md`. Terms that are ambiguous in ipcalc: - **"network" / "address"**: the input as given, or the network address computed from it? - **"hosts"**: usable host addresses (excluding network/broadcast where applicable) or all addresses in the prefix? State the /31, /32 and IPv6 behavior explicitly. - **"invalid"**: name the exact input class and the exit status. ### Phase 5 — Acceptance Criteria (ipcalc) Every acceptance criterion MUST be expressible as a test in `tests/meson.build`: a command line plus either an expected-output file (`--test-outfile`), an exit status (`--test-success`/`--test-failure`), or an output comparison (`--test-output`/`--test-equal`). Include at least one positive and one negative criterion per requirement where a negative case exists. requirements-from-implementation.md000066400000000000000000000230731526405142400333120ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols --- name: requirements-from-implementation type: reasoning description: > Systematic reasoning protocol for deriving structured requirements from existing source code. Transforms code understanding into testable, atomic requirements with acceptance criteria. applicable_to: - reverse-engineer-requirements - review-code --- # Protocol: Requirements from Implementation Apply this protocol when deriving requirements from an existing codebase. The goal is to produce a structured requirements document that captures what the implementation provides — not how it provides it. Execute all phases in order. ## Phase 1: API Surface Enumeration Systematically catalog every public-facing element of the codebase: 1. **Functions and entry points**: Signatures, parameters, return types, error conditions. For each, note whether it is public API, internal, or a convenience wrapper. 2. **Types and data structures**: Structs, enums, unions, typedefs. Identify which are opaque (implementation detail) vs. transparent (part of the API contract). 3. **Metaprogramming and indirection constructs** (if applicable): Preprocessor macros (C/C++), decorators (Python), annotations (Java), attribute macros (Rust), code generation. Expand representative invocations to understand the actual behavior. Document parameters, their types, and constraints. 4. **Constants and configuration surfaces**: Compile-time switches, feature flags, tuning parameters. Identify which are user-facing configuration vs. internal implementation constants. 5. **Error handling patterns**: How does the API report errors? Return codes, errno, out-parameters, callbacks, exceptions? Catalog the error space. Produce a structured enumeration (table or list) before proceeding. This becomes the completeness checklist for later phases. ## Phase 2: Behavioral Contract Extraction For each API element identified in Phase 1: 1. **Preconditions**: What must be true before the caller invokes this? Look for parameter validation, assertions, documented constraints, and implicit assumptions (e.g., "pointer must not be NULL" even if unchecked). 2. **Postconditions**: What is guaranteed after successful execution? What state changes occur? What values are returned? 3. **Error behavior**: What happens on invalid input, resource exhaustion, or concurrent access? Is the API fail-safe, fail-fast, or undefined? 4. **Side effects**: Does the function modify global state, allocate memory the caller must free, register callbacks, or interact with external systems? 5. **Ordering constraints**: Must certain functions be called before others? Is there an initialization/teardown protocol? 6. **Thread safety**: Can this be called concurrently? From any thread? What synchronization does the caller need to provide? For each contract, cite the specific code evidence (file, line, function) that establishes it. ## Phase 3: Essential vs. Incidental Classification For every behavioral observation from Phase 2, classify it: 1. **Essential behavior**: Behavior that callers depend on and that defines the API's value. This becomes a requirement. - Test: "If this behavior changed, would existing correct callers break?" - Test: "Is this behavior documented, tested, or part of the type signature?" 2. **Incidental behavior**: Behavior that happens to be true in this implementation but is not part of the contract. - Test: "Could a correct reimplementation reasonably behave differently?" - Test: "Is this an optimization, ordering artifact, or implementation convenience?" 3. **Ambiguous behavior**: Cannot be classified without domain knowledge or explicit confirmation from stakeholders. Flag with `[AMBIGUOUS]`. For ambiguous items, state the two interpretations and their implications for requirements. ## Phase 4: Requirement Synthesis Transform essential behaviors into structured requirements: 1. **Group by functional area**: Organize related behaviors into requirement categories (e.g., initialization, data processing, error handling, resource management). 2. **Write atomic requirements**: Each requirement captures exactly one testable behavior using RFC 2119 keywords (MUST, SHOULD, MAY). 3. **Derive acceptance criteria**: For each requirement, define at least one concrete, measurable test derived from the code's actual behavior. Prefer criteria that can be validated against the existing implementation as a reference oracle. 4. **Preserve semantic fidelity**: Requirements must faithfully represent what the implementation does, even if the behavior seems suboptimal. If behavior appears buggy but is established, note it as a requirement and flag: `[REVIEW: may be a defect in the reference implementation]`. 5. **Capture non-functional characteristics**: Performance bounds, resource usage patterns, concurrency guarantees, and platform requirements observed in the implementation. ## Phase 5: Completeness and Gap Analysis 1. **Coverage check**: Cross-reference the requirements against the API surface enumeration from Phase 1. Every public API element MUST have at least one associated requirement. Flag any gaps. 2. **Undocumented behavior**: Identify behaviors observed in the code that have no documentation, no tests, and no obvious purpose. These may be bugs, deprecated features, or undocumented contracts. Flag with `[UNDOCUMENTED]`. 3. **Missing error cases**: For each API element, verify that error conditions are covered by requirements. Missing error handling is a common gap. 4. **Cross-cutting concerns**: Verify that thread safety, resource lifecycle, and error propagation requirements are captured as cross-cutting requirements, not just per-function notes. --- ## ipcalc-Specific Extensions ipcalc is a command-line program, so its "API" is its command line and its output, not its C functions. Requirements MUST be stated in terms of what a user invokes and observes; internal functions are cited only as **Source** evidence. ### Phase 1 — API Surface Enumeration (ipcalc) Enumerate in this order: 1. **Options**: every entry of the `getopt_long` table in `main()` (`ipcalc.c`), with its short letter, argument syntax, and the `app` mode (`enum app_t`) or `FLAG_*` bit it sets. Cross-check against `usage()` and `ipcalc.1.md`. 2. **Modes and option combinations**: which `app` modes exist, which options are valid in each, and which combinations `main()` rejects (these are covered by `--test-failure` tests in `tests/meson.build`). 3. **Accepted inputs**: address/prefix/netmask syntaxes for each family (`get_ipv4_info()`, `get_ipv6_info()`, `str_to_prefix()`), ranges for `-d`, the prefix or netmask for `-S`, and prefixes for `-r`. 4. **Outputs**: for each mode, the fields printed and their names in each output format — default/"modern" (`FLAG_SHOW_MODERN_INFO`), `NAME=value`, `--no-decorate`, and `--json` — and the conditions under which color is emitted. 5. **Exit status and diagnostics**: the exit code and stderr message for each class of error (bad input, invalid combination, allocation failure, lookup failure). 6. **Build configurations**: geo backend (`USE_MAXMIND`, `USE_RUNTIME_LINKING`, none) and what output each one adds. ### Phase 2 — Behavioral Contract Extraction (ipcalc) - **Thread safety** does not apply (single-threaded, short-lived process); replace it with **determinism**: is the output a pure function of the arguments, or does it depend on DNS, the geo database, randomness (`-r`), or the environment (`NO_COLOR`, TTY)? Requirements on non-deterministic output MUST state what is fixed (format, prefix length, address space) rather than the value. - For every computed field, establish the boundary behavior at the edge prefixes and at the ends of the address space; these are essential behavior, not corner cases. ### Phase 3 — Essential vs. Incidental Classification (ipcalc) - **Scripts depend on output.** Field names in `NAME=value` and JSON output, JSON value types (string vs. array), and the presence or absence of a field are **essential** — changing them breaks callers. - Text and alignment of the default (decorated) output are **incidental** unless a test in `tests/` pins them; spacing changes there are not requirement changes. - Behavior described in `ipcalc.1.md` is essential. If the code contradicts it, flag `[REVIEW: contradicts ipcalc.1.md — code or man page must change]`. - Behavior pinned by an expected-output file in `tests/` is essential unless the file was clearly generated from buggy output; then flag `[REVIEW: test pins suspected defect]`. ### Phase 4 — Requirement Synthesis (ipcalc) - Use the document map, ID scheme, and per-requirement format in `doc/requirements/README.md`. - **Acceptance** criteria MUST name a concrete command line and the expected output or exit status, and cite the test in `tests/meson.build` that checks it (or state "no test"). ### Phase 5 — Completeness and Gap Analysis (ipcalc) Additional gap checks: - Every option in the `getopt_long` table has a requirement, and is documented in both `usage()` and `ipcalc.1.md`. - Every field printed in `NAME=value` mode has the same name in JSON mode, or the difference is a requirement. - Every rejected option combination has a `--test-failure` test. - Every mode has requirements for both IPv4 and IPv6 input, or a requirement that states the mode is single-family. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols/root-cause-analysis.md000066400000000000000000000170251526405142400305640ustar00rootroot00000000000000 --- name: root-cause-analysis type: reasoning description: > Structured reasoning protocol for tracing symptoms to root causes. Applies systematic hypothesis generation, evidence evaluation, and elimination. Language-agnostic. applicable_to: - investigate-bug - investigate-trace - root-cause-ci-failure --- # Protocol: Root Cause Analysis Apply this protocol when investigating a defect, failure, or unexpected behavior. The goal is to trace from **observed symptoms** to the **fundamental cause** — not just the proximate trigger. ## Phase 1: Symptom Characterization 1. **Describe the symptom precisely**: - What is the observed behavior? - What is the expected behavior? - Under what conditions does it occur? (inputs, timing, environment, load) - Is it deterministic or intermittent? 2. **Establish the timeline**: - When was it first observed? - What changed recently? (code, configuration, dependencies, infrastructure) - Has it ever worked correctly? When did it stop? 3. **Determine the blast radius**: - What is affected? (single user, all users, specific configurations) - What is NOT affected? (this constrains the hypothesis space) ## Phase 2: Hypothesis Generation Generate a **ranked list of hypotheses**, ordered by likelihood. For each: 1. State the hypothesis clearly: "The root cause is X because Y." 2. State what **evidence would confirm** the hypothesis. 3. State what **evidence would refute** the hypothesis. 4. Rate plausibility: High / Medium / Low — with reasoning. Rules: - Generate at least 3 hypotheses before investigating any of them. - Include at least one "non-obvious" hypothesis (environment, timing, config, upstream dependency, data corruption). - Do NOT anchor on the first plausible hypothesis. ## Phase 3: Evidence Gathering and Elimination For each hypothesis, starting with the most plausible: 1. Identify the **minimal investigation** needed to confirm or eliminate it. 2. Examine the evidence: - Does the code/config/log support or contradict the hypothesis? - Are there alternative explanations for the same evidence? 3. Classify the hypothesis: - **CONFIRMED**: Strong evidence supports it; no contradicting evidence. - **ELIMINATED**: Evidence directly contradicts it. - **INCONCLUSIVE**: Evidence is insufficient; state what is needed. ## Phase 3a: Iterative Deepening Investigation MUST proceed in layers of increasing resolution. Each layer informs the next — do NOT skip layers or jump directly to deep analysis. 1. **Broad survey**: Identify top contributors at the coarsest granularity (e.g., by process, module, subsystem, or component). Rank by impact. 2. **Attribution**: For the top 5–10 contributors, break down by the next level of detail (e.g., by module within a process, by function within a module, by allocation site within a function). 3. **Deep analysis**: For the top contributors at the attribution level, obtain the most detailed evidence available (e.g., call stacks, data flow traces, lock contention chains, allocation histories). Call stacks and execution traces reveal *why* something is happening — module-level data only reveals *where*. 4. **Cross-component tracing**: Identify causal chains that span component or process boundaries (see Phase 4a). Do NOT write the final report until layer 3 is complete for the top contributors, up to 5, using the most detailed evidence available. If fewer than 5 contributors exist, analyze all of them. If available evidence does not support layer-3 completion for some contributors, you MAY proceed to the final report only if you explicitly document the limitation, identify which contributors remain inconclusive, and state what additional evidence would be needed. Premature reporting without this disclosure produces surface-level findings that miss the actual root cause. ## Phase 4: Root Cause Identification 1. Distinguish between the **root cause** (fundamental defect) and the **proximate cause** (immediate trigger). - Example: The proximate cause is "null pointer dereference on line 42." The root cause is "the initialization function silently fails when the config file is missing, leaving the pointer uninitialized." 2. Trace the **causal chain** from root cause to symptom. 3. Ask: "If we fix only the proximate cause, will the root cause produce other failures?" If yes, the fix is incomplete. ## Phase 4a: Cross-Component Causal Chains When the investigation involves multiple components, processes, or subsystems, trace causal chains across boundaries: 1. **Identify trigger-response pairs**: Does activity in component A cause work in component B? For example, a file write by one process may trigger scanning by an antivirus service, which triggers hashing by an EDR agent, which triggers network inspection by another service. 2. **Map the amplification cascade**: A single action may fan out into disproportionate downstream work. Document the full chain: `Trigger → Reactor₁ → Reactor₂ → ... → Observed symptom`. 3. **Quantify amplification**: For each link in the chain, estimate the cost ratio (e.g., "1 file write triggers 3 scan operations, each consuming 50ms of CPU"). The amplification factor often explains why a seemingly minor activity produces outsized impact. 4. **Identify the leverage point**: The most effective fix targets the link in the chain with the highest amplification factor, not necessarily the initial trigger or the final symptom. Skip this phase when the investigation is confined to a single component with no cross-boundary interactions. ## Phase 5: Remediation 1. Propose a fix for the **root cause**, not just the symptom. 2. Identify **secondary fixes** needed to prevent recurrence: - Assertions or precondition checks - Improved error handling - Logging or monitoring - Tests that would have caught this 3. Assess the **risk of the fix**: could it introduce new issues? --- ## ipcalc-Specific Extensions ### Phase 1 — Symptom Characterization (ipcalc) - Reduce every report to a single `ipcalc` command line and its actual vs. expected output. Record the output mode (default, `--no-decorate`, `--json`, `NAME=value`), the address family, and the geo backend the binary was built with. - Check the expected behavior against `doc/requirements/`, then `ipcalc.1.md`; if neither states it, the bug may be a requirements gap (see the Requirements-First Workflow in `AGENTS.md`). ### Phase 2 — Hypothesis Generation (ipcalc) Canonical ipcalc hypotheses to consider first: - Shift/width UB or overflow at edge prefixes (/0, /31, /32, /127, /128) or at the ends of the address space. - An option combination handled in `main()` that routes the input to an unexpected `app` mode or `flags` set. - JSON comma/array state (`jsonfirst`, `JSON_FIRST`/`JSON_NEXT`/ `JSON_ARRAY_*`) not threaded through a new printf helper call. - A field printed with a helper that ignores `--no-decorate` or `--json`, or bypasses the helpers entirely. - Code compiled only in one geo configuration (`USE_MAXMIND`, `USE_RUNTIME_LINKING`). ### Phase 5 — Remediation (ipcalc) - Write the reproducing test first (`tests/meson.build` plus an expected-output file) and confirm it fails on the unfixed code. - If no requirement covers the correct behavior, add it first; do not cite `REQ-*` IDs in the commit message. - Add a user-visible entry to `NEWS`. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/protocols/self-verification.md000066400000000000000000000142231526405142400302700ustar00rootroot00000000000000 --- name: self-verification type: guardrail description: > Cross-cutting protocol requiring the LLM to verify its own output before finalizing. Includes sampling checks, citation audits, coverage confirmation, and explicit quality gates. applicable_to: all --- # Protocol: Self-Verification This protocol MUST be applied before finalizing any output artifact. It defines a quality gate that prevents submission of unverified, incomplete, or unsupported claims. ## When to Apply Execute this protocol **after** generating your output but **before** presenting it as final. Treat it as a pre-submission checklist. ## Rules ### 1. Sampling Verification - Select a **coverage sample** of at least 3 specific claims, findings, or data points from your output. Include different claim types when present (for example: a file path, a code snippet, a conclusion, a severity assignment, or a remediation recommendation). - For each sampled item, **re-verify** it against the source material: - Does the file path, line number, or location actually exist? - Does the code snippet match what is actually at that location? - Does the evidence actually support the conclusion stated? - If any sampled item fails verification, **re-examine all items of the same type** before proceeding. - For each sampled finding, apply **symmetric falsification**: attempt to disprove the finding with the same rigor you applied when falsifying candidate findings that you concluded were safe. Verify whether any upstream validation, API contract, or initialization invariant makes this safe; cite the specific call sites, checks, or invariants reviewed and explain why they do not neutralize the finding. If you have not verified that upstream validation does not apply, downgrade or remove the finding. ### 2. Citation Audit Apply the epistemic labeling rules from the `anti-hallucination` protocol (Rules 1–4: KNOWN/INFERRED/ASSUMED classification, refusal to fabricate, uncertainty disclosure, source attribution). Scan the output for factual claims that lack epistemic labels or source citations, and remediate each: add the appropriate epistemic label (`[KNOWN]`, `[INFERRED]`, or `[ASSUMPTION]`), add the citation, or remove the claim. **Zero uncited factual claims** is the target. ### 3. Coverage Confirmation - Review the task's scope (explicit and implicit requirements). - Verify that every element of the requested scope is addressed: - Are there requirements, code paths, or areas that were asked about but not covered in the output? - If any areas were intentionally excluded, document why in a "Limitations" or "Coverage" section. - Include the 4-field coverage statement defined in the `operational-constraints` protocol (Rule 9: Examined, Method, Excluded, Limitations). ### 4. Internal Consistency Check - Verify that findings do not contradict each other. - Verify that severity/risk ratings are consistent across findings of similar nature. - Verify that the executive summary accurately reflects the body. - Verify that remediation recommendations do not conflict with stated constraints. ### 5. Completeness Gate Before finalizing, answer these questions explicitly (even if only internally): - [ ] Have I addressed the stated goal or success criteria? - [ ] Are all deliverable artifacts present and well-formed? - [ ] Does every claim have supporting evidence or an explicit label? - [ ] Have I stated what I did NOT examine and why? - [ ] Have I sampled and re-verified at least 3 specific data points? - [ ] Is the output internally consistent? If any answer is "no," address the gap before finalizing. ### 6. Determinism Check When the output contains instructions, protocols, checklists, or other directive text intended for LLM consumption, scan for language that introduces non-deterministic interpretation: - [ ] Are all instructions specific enough that two different LLMs would produce output with the same section headings, the same number of items per section (±20%), and the same classification labels? - [ ] Are quantifiers concrete (specific counts or ranges, not "some" or "several")? - [ ] Are evaluation criteria observable (not subjective adjectives like "good" or "appropriate")? - [ ] Do all conditionals have explicit else/default branches? - [ ] Are action verbs decomposed into specific sub-steps (not standalone "analyze" or "evaluate")? If any answer is "no," tighten the language before finalizing. If the vague language serves a deliberate purpose (e.g., allowing LLM discretion in creative tasks), mark it with an inline comment `` and leave it unchanged. This check applies to generated prompt text, instruction files, and protocol content — not to narrative prose, user-facing explanations, or creative output. --- ## ipcalc-Specific Extensions ### Agent-runnable verification (Rule 5 application) Before declaring any change "done", run what can be run locally and report exactly what was and was not verified: 1. `ninja -C build` — must succeed with no new warnings (CI builds with `-Werror`). 2. `meson test -C build ` for the tests covering the change, then the full suite `ninja -C build test`. 3. The legacy Makefile build without geo backends: `make USE_MAXMIND=no USE_RUNTIME_LINKING=no` (then `make clean` or remove the `ipcalc` binary it leaves behind). 4. If the change touches memory handling or arithmetic on addresses, an ASan/UBSan build: `meson setup build-asan -Db_sanitize=address,undefined` and run the suite there. 5. If the change touches `ipcalc-maxmind.c` or the geo stubs in `ipcalc.h`: build with each geo configuration CI uses (`-Duse_maxminddb`, `-Duse_runtime_linking`, none), or report which configurations were not built. ### Reporting (Rule 3 — Coverage Confirmation) State: "I have verified [list]. Not verified locally: [list, with why]." Never report "tests pass" for a subset run, and never claim a geo configuration builds without having built it. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/taxonomies/000077500000000000000000000000001526405142400244755ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/contrib/ai/taxonomies/specification-drift.md000066400000000000000000000431751526405142400307570ustar00rootroot00000000000000 --- name: specification-drift type: taxonomy description: > Classification scheme for specification drift and divergence across requirements, design, and validation artifacts. Use when auditing document sets for traceability gaps, scope creep, assumption drift, and coverage failures. domain: specification-traceability applicable_to: - audit-traceability - audit-code-compliance - audit-test-compliance - audit-integration-compliance --- # Taxonomy: Specification Drift Use these labels to classify findings when auditing requirements, design, and validation documents for consistency and completeness. Every finding MUST use exactly one label from this taxonomy. ## Label Group Summaries When only a subset of labels is applicable to a given audit type, use these summaries for cross-reference context. The primary label group (determined by the audit template) uses full definitions below; non-primary groups use these summaries to preserve semantic context without consuming prompt tokens. - **D1–D7 (Traceability)**: Document-level drift — untraced requirements, untested requirements, orphaned design decisions, orphaned test cases, assumption drift between documents, constraint violations in design, and acceptance criteria mismatches between test plans and requirements. - **D8–D10 (Code Compliance)**: Code-to-spec drift — unimplemented requirements, undocumented behavior in source code, and constraint violations in implementation. - **D11–D13 (Test Compliance)**: Test-to-plan drift — unimplemented test cases, untested acceptance criteria, and assertion mismatches between test code and validation plans. - **D14–D16 (Integration)**: Cross-component drift — unspecified integration flows, interface contract mismatches between components, and untested integration paths. ## Labels ### D1_UNTRACED_REQUIREMENT A requirement exists in the requirements document but is not referenced or addressed in the design document. **Pattern**: REQ-ID appears in the requirements document. No section of the design document references this REQ-ID or addresses its specified behavior. **Risk**: The requirement may be silently dropped during implementation. Without a design realization, there is no plan to deliver this capability. **Severity guidance**: High when the requirement is functional or safety-critical. Medium when it is a non-functional or low-priority constraint. ### D2_UNTESTED_REQUIREMENT A requirement exists in the requirements document but has no corresponding test case in the validation plan. **Pattern**: REQ-ID appears in the requirements document and may appear in the traceability matrix, but no test case (TC-NNN) is linked to it — or the traceability matrix entry is missing entirely. **Risk**: The requirement will not be verified. Defects against this requirement will not be caught by the validation process. **Severity guidance**: Critical when the requirement is safety-critical or security-related. High for functional requirements. Medium for non-functional requirements with measurable criteria. ### D3_ORPHANED_DESIGN_DECISION A design section, component, or decision does not trace back to any requirement in the requirements document. **Pattern**: A design section describes a component, interface, or architectural decision. No REQ-ID from the requirements document is referenced or addressed by this section. **Risk**: Scope creep — the design introduces capabilities or complexity not justified by the requirements. Alternatively, the requirements document is incomplete and the design is addressing an unstated need. **Severity guidance**: Medium. Requires human judgment — the finding may indicate scope creep (remove from design) or a requirements gap (add a requirement). ### D4_ORPHANED_TEST_CASE A test case in the validation plan does not map to any requirement in the requirements document. **Pattern**: TC-NNN exists in the validation plan but references no REQ-ID, or references a REQ-ID that does not exist in the requirements document. **Risk**: Test effort is spent on behavior that is not required. Alternatively, the requirements document is incomplete and the test covers an unstated need. **Severity guidance**: Low to Medium. The test may still be valuable (e.g., regression or exploratory), but it is not contributing to requirements coverage. ### D5_ASSUMPTION_DRIFT An assumption stated or implied in one document contradicts, extends, or is absent from another document. **Pattern**: The design document states an assumption (e.g., "the system will have at most 1000 concurrent users") that is not present in the requirements document's assumptions section — or contradicts a stated constraint. Similarly, the validation plan may assume environmental conditions not specified in requirements. **Risk**: Documents are based on incompatible premises. Implementation may satisfy the design's assumptions while violating the requirements' constraints, or vice versa. **Severity guidance**: High when the assumption affects architectural decisions or test validity. Medium when it affects non-critical behavior. ### D6_CONSTRAINT_VIOLATION A design decision directly violates a stated requirement or constraint. **Pattern**: The requirements document states a constraint (e.g., "the system MUST respond within 200ms") and the design document describes an approach that cannot satisfy it (e.g., a synchronous multi-service call chain with no caching), or explicitly contradicts it (e.g., "response times up to 2 seconds are acceptable"). **Risk**: The implementation will not meet requirements by design. This is not a gap but an active conflict. **Severity guidance**: Critical when the violated constraint is safety-critical, regulatory, or a hard performance requirement. High for functional constraints. ### D7_ACCEPTANCE_CRITERIA_MISMATCH A test case is linked to a requirement but does not actually verify the requirement's acceptance criteria. **Pattern**: TC-NNN is mapped to REQ-XXX-NNN in the traceability matrix, but the test case's steps, inputs, or expected results do not correspond to the acceptance criteria defined for that requirement. The test may verify related but different behavior, or may be too coarse to confirm the specific criterion. **Risk**: The traceability matrix shows coverage, but the coverage is illusory. The requirement appears tested but its actual acceptance criteria are not verified. **Severity guidance**: High. This is more dangerous than D2 (untested requirement) because it creates a false sense of coverage. ## Code Compliance Labels ### D8_UNIMPLEMENTED_REQUIREMENT A requirement exists in the requirements document but has no corresponding implementation in the source code. **Pattern**: REQ-ID specifies a behavior, constraint, or capability. No function, module, class, or code path in the source implements or enforces this requirement. **Risk**: The requirement was specified but never built. The system does not deliver this capability despite it being in the spec. **Severity guidance**: Critical when the requirement is safety-critical or security-related. High for functional requirements. Medium for non-functional requirements that affect quality attributes. ### D9_UNDOCUMENTED_BEHAVIOR The source code implements behavior that is not specified in any requirement or design document. **Pattern**: A function, module, or code path implements meaningful behavior (not just infrastructure like logging or error handling) that does not trace to any REQ-ID in the requirements document or any section in the design document. **Risk**: Scope creep in implementation — the code does more than was specified. The undocumented behavior may be intentional (a missing requirement) or accidental (a developer's assumption). Either way, it is untested against any specification. **Severity guidance**: Medium when the behavior is benign feature logic. High when the behavior involves security, access control, data mutation, or external communication — undocumented behavior in these areas is a security concern. ### D10_CONSTRAINT_VIOLATION_IN_CODE The source code violates a constraint stated in the requirements or design document. **Pattern**: The requirements document states a constraint (e.g., "MUST respond within 200ms", "MUST NOT store passwords in plaintext", "MUST use TLS 1.3 or later") and the source code demonstrably violates it — through algorithmic choice, missing implementation, or explicit contradiction. **Risk**: The implementation will not meet requirements. Unlike D6 (constraint violation in design), this is a concrete defect in code, not a planning gap. **Severity guidance**: Critical when the violated constraint is safety-critical, security-related, or regulatory. High for performance or functional constraints. Assess based on the constraint itself, not the code's complexity. ## Test Compliance Labels ### D11_UNIMPLEMENTED_TEST_CASE A test case is defined in the validation plan but has no corresponding automated test in the test code. **Pattern**: TC-NNN is specified in the validation plan with steps, inputs, and expected results. No test function, test class, or test file in the test code implements this test case — either by name reference, by TC-NNN identifier, or by behavioral equivalence. **Risk**: The validation plan claims coverage that does not exist in the automated test suite. The requirement linked to this test case is effectively untested in CI, even though the validation plan says it is covered. **Severity guidance**: High when the linked requirement is safety-critical or security-related. Medium for functional requirements. Note: test cases classified as manual-only or deferred in the validation plan are excluded from D11 findings and reported only in the coverage summary. ### D12_UNTESTED_ACCEPTANCE_CRITERION A test implementation exists for a test case, but it does not assert one or more acceptance criteria specified for the linked requirement. **Pattern**: TC-NNN is implemented as an automated test. The linked requirement (REQ-XXX-NNN) has multiple acceptance criteria. The test implementation asserts some criteria but omits others — for example, it checks the happy-path output but does not verify error handling, boundary conditions, or timing constraints specified in the acceptance criteria. **Risk**: The test passes but does not verify the full requirement. Defects in the untested acceptance criteria will not be caught by CI. This is the test-code equivalent of D7 (acceptance criteria mismatch in the validation plan) but at the implementation level. **Severity guidance**: High when the missing criterion is a security or safety property. Medium for functional criteria. Assess based on what the missing criterion protects, not on the test's overall coverage. ### D13_ASSERTION_MISMATCH A test implementation exists for a test case, but its assertions do not match the expected behavior specified in the validation plan. **Pattern**: TC-NNN is implemented as an automated test. The test asserts different conditions, thresholds, or outcomes than what the validation plan specifies — for example, the plan says "verify response within 200ms" but the test asserts "response is not null", or the plan says "verify error code 403" but the test asserts "status is not 200". **Risk**: The test passes but does not verify what the validation plan says it should. This creates illusory coverage — the traceability matrix shows the requirement as tested, but the actual test checks something different. More dangerous than D11 (missing test) because it is invisible without comparing test code to the validation plan. **Severity guidance**: High. This is the most dangerous test compliance drift type because it creates false confidence. Severity should be assessed based on the gap between what is asserted and what should be asserted. ## Integration Compliance Labels ### D14_UNSPECIFIED_INTEGRATION_FLOW A cross-component integration flow is described in the integration specification but is not reflected in one or more component specs. **Pattern**: The integration spec describes an end-to-end flow that traverses components A → B → C. Component B's specification does not mention its role in this flow, does not describe receiving input from A, or does not describe producing output for C. The flow exists at the system level but has a gap at the component level. **Risk**: The flow may be implemented by convention or tribal knowledge but is not contractually specified. Changes to component B may break the flow without any specification-level signal. Per-component audits will not detect this because no component's spec claims responsibility for the missing step. **Severity guidance**: High when the flow is safety-critical, involves data integrity, or is a core user-facing workflow. Medium for operational or diagnostic flows. Assess based on what breaks if the gap causes a runtime failure. ### D15_INTERFACE_CONTRACT_MISMATCH Two components describe the same interface differently in their respective specifications. **Pattern**: Component A's spec says it produces output in format X with error codes {E1, E2}. Component B's spec says it consumes input in format Y with error codes {E2, E3}. The interface exists on both sides but the descriptions are incompatible — different data formats, different error sets, different sequencing assumptions, or different timing constraints. **Risk**: Runtime failures at the integration boundary — data corruption, unhandled errors, deadlocks, or silent degradation. Per-component audits see each side as internally consistent; the mismatch is only visible when comparing both sides. **Severity guidance**: Critical when the mismatch involves data integrity, security properties, or will cause deterministic runtime failure. High when it involves error handling or sequencing that may cause intermittent failures. Medium for cosmetic or logging differences that do not affect correctness. ### D16_UNTESTED_INTEGRATION_PATH A cross-component integration flow or interface contract is specified but has no corresponding integration or end-to-end test. **Pattern**: The integration spec describes flow F-NNN traversing components A → B → C. No integration test exercises this flow end-to-end. Individual component tests may test A's output and B's input separately, but no test verifies the handoff between them under realistic conditions. **Risk**: Defects at integration boundaries will not be caught until production. Per-component test-compliance audits will show full coverage within each component, masking the integration gap. This is the integration-level equivalent of D11 (unimplemented test case). **Severity guidance**: High when the flow is safety-critical or involves data that crosses trust boundaries. Medium for well-understood interfaces with stable contracts. Note: flows explicitly marked as "manual integration test" or "deferred" in the integration spec are excluded from D16 findings and reported only in the coverage summary. ## Ranking Criteria Within a given severity level, order findings by impact on specification integrity: 1. **Highest risk**: D6 (constraint violation in design), D7 (illusory test coverage), D10 (constraint violation in code), D13 (assertion mismatch), and D15 (interface contract mismatch) — these indicate active conflicts between artifacts. 2. **High risk**: D2 (untested requirement), D5 (assumption drift), D8 (unimplemented requirement), D12 (untested acceptance criterion), and D14 (unspecified integration flow) — these indicate silent gaps that will surface late. 3. **Medium risk**: D1 (untraced requirement), D3 (orphaned design), D9 (undocumented behavior), D11 (unimplemented test case), and D16 (untested integration path) — these indicate incomplete traceability that needs human resolution. 4. **Lowest risk**: D4 (orphaned test case) — effort misdirection but no safety or correctness impact. ## Usage In findings, reference labels as: ``` [DRIFT: D2_UNTESTED_REQUIREMENT] Requirement: REQ-SEC-003 (requirements doc, section 4.2) Evidence: REQ-SEC-003 does not appear in the traceability matrix (validation plan, section 4). No test case references this REQ-ID. Impact: The encryption-at-rest requirement will not be verified. ``` --- ## ipcalc-Specific Extensions ipcalc's normative specification is `doc/requirements/` (see `doc/requirements/README.md`). `ipcalc.1.md` plays the design-document role and `tests/` (registered in `tests/meson.build`) plays the validation-plan role. Reviews primarily use **D8–D10 (Code Compliance)** via `protocols/code-compliance-audit.md`; D11–D13 apply when auditing `tests/` against the acceptance criteria. ### D8_UNIMPLEMENTED_REQUIREMENT — ipcalc examples - A requirement states an input MUST be rejected, but `main()` or the parser accepts it and prints output. - A requirement specifies a field in JSON output that the code only prints in `NAME=value` mode. ### D9_UNDOCUMENTED_BEHAVIOR — ipcalc examples - A new option in the `getopt_long` table with no `REQ-*`, or missing from `ipcalc.1.md` / `usage()`. - A new output field or JSON key with no requirement naming it. - Classify High when the undocumented behavior changes an existing field name, JSON type, or exit status — scripts depend on these. ### D10_CONSTRAINT_VIOLATION_IN_CODE — ipcalc examples - A patch changes behavior an existing `REQ-*` describes without updating that requirement (Requirements-First Workflow in `AGENTS.md`). - Output written with a bare `printf` that bypasses `--json` / `--no-decorate` handling. - Code that fails to build, or warns, in one of the geo configurations CI builds. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/deaggregate.c000066400000000000000000000124231526405142400226630ustar00rootroot00000000000000/* * 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 . */ #include #include #include #include #include #include #include #include #include #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 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 (step < 32 && (base | ((uint64_t)1 << step)) != base) { uint64_t b1 = base | ((uint64_t)(UINT32_MAX) >> (31-step)); if (b1 > end) break; step++; } print_ipv4_net(&jsonchain, base, 32-step, flags); base += ((uint64_t)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, one; 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"); memset(&one, 0, sizeof(one)); one.s6_addr[15] = 1; while (1) { step = 0; while (step < 128 && 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); /* Stop at the network that contains the end of the range; * advancing past it would wrap around when it is the last * address of the IPv6 space. */ memcpy(&tmp, &base, sizeof(tmp)); ipv6_orm(&tmp, step); if (ipv6_cmp(&tmp, &end) >= 0) break; memcpy(&base, &tmp, sizeof(base)); ipv6_add(&base, &one); } array_stop(&jsonchain); output_stop(&jsonchain); return; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/000077500000000000000000000000001526405142400210235ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/000077500000000000000000000000001526405142400235465ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/README.md000066400000000000000000000157671526405142400250450ustar00rootroot00000000000000# ipcalc Requirements This directory is the normative description of what ipcalc must do, in atomic, testable statements with RFC 2119 keywords, source citations, and acceptance criteria. It complements `ipcalc.1.md`, which describes the same behavior for users. When the code, `ipcalc.1.md`, and a requirement disagree, treat it as a `REVIEW` item, not as an automatic override: resolve by reading the cited source and, if still unclear, ask a maintainer. ## Generation protocols Requirements are written with the protocols in `contrib/ai/protocols/`: | Protocol | Use it when | |----------|-------------| | `requirements-from-implementation.md` | Documenting behavior ipcalc already has (status `DERIVED`, `REVIEW`, `AMBIGUOUS`, or `UNDOCUMENTED`). | | `requirements-elicitation.md` | Specifying new or changed behavior from a feature request or bug report, before the code exists. | Whichever protocol is used, a new entry MUST match the ID scheme, category tags, and per-requirement format below and the style of the rest of its document. ## Document map A document is created the first time a requirement in its area is written. | Document | ID prefix | Covers | Main sources | |----------|-----------|--------|--------------| | `general.md` | `REQ-GEN-` | Project policy: build configurations, portability, test conventions | `AGENTS.md`, `meson.build`, `Makefile`, `.gitlab-ci.yml`, `tests/meson.build` | | `cli.md` | `REQ-CLI-` | Options, modes (`enum app_t`), rejected option combinations, output formats (default, `NAME=value`, `--no-decorate`, `--json`, color), exit status | `ipcalc.c` (`main()`, `usage()`, printf helpers), `ipcalc.h`, `ipcalc.1.md` | | `info.md` | `REQ-INFO-` | Address/network parsing and the computed fields of info and check modes: network, broadcast, host range, counts, class, address space, reverse DNS, hostname lookups | `ipcalc.c` (`get_ipv4_info()`, `get_ipv6_info()`), `ipv6.c`, `ipcalc-reverse.c` | | `split.md` | `REQ-SPLIT-` | `-S/--split`, `--split-hosts` | `netsplit.c` (`show_split_networks()`), `ipcalc.c` (`main()`, `parse_split_req()`, `parse_split_hosts()`, `str_to_prefix()`) | | `deaggregate.md` | `REQ-DEAGG-` | `-d/--deaggregate` | `deaggregate.c` | | `binary.md` | `REQ-BINARY-` | `--binary`: binary form of an address or network | `binary.c` (`show_binary()`), `ipcalc.c` (`main()`) | | `random.md` | `REQ-RANDOM-` | `-r/--random-private` network generation | `ipcalc.c` (`generate_ip_network()`) | | `geo.md` | `REQ-GEO-` | Geo-IP output and behavior per backend, including no backend | `ipcalc-maxmind.c`, `ipcalc.h` | ## ID scheme ``` REQ--- ``` - `` identifies the document (table above). - `` is one of: | Tag | Domain | |-----|--------| | `INPUT` | Accepted and rejected arguments and address syntax | | `CALC` | Computed values and their boundary behavior | | `OUTPUT` | Printed fields, names, JSON keys and types, formatting | | `ERR` | Error handling, diagnostics, exit status | | `COMPAT` | Compatibility with earlier ipcalc releases or other ipcalc implementations | | `BUILD` | Build configurations and portability | | `TEST` | Test authorship conventions | - `` is a 3-digit sequence number, unique within `-` and never reused: a removed requirement is marked `WITHDRAWN`, not renumbered. Examples: `REQ-SPLIT-CALC-003`, `REQ-CLI-ERR-001`, `REQ-INFO-OUTPUT-012`. ## Status legend | Status | Meaning | |--------|---------| | `DERIVED` | Directly supported by current code, tests, or `ipcalc.1.md`; no open questions. | | `SPECIFIED` | Written ahead of the code (requirements-elicitation); not yet implemented. Becomes `DERIVED` when the implementing commit lands. | | `REVIEW` | Behavior observed but contradicts documentation, another requirement, or looks like a defect — needs a maintainer decision. | | `AMBIGUOUS` | Cannot be classified as essential or incidental without a maintainer decision; both interpretations are given. | | `UNDOCUMENTED` | Behavior exists in code with no documentation, test, or evident purpose. | | `WITHDRAWN` | No longer applies; kept for ID stability with a note explaining why. | ## Per-requirement format ```markdown ### REQ--- **Requirement:** ipcalc MUST/SHOULD/MAY when , so that . **Strength:** MUST | SHOULD | MAY | MUST NOT | SHOULD NOT **Status:** DERIVED | SPECIFIED | REVIEW | AMBIGUOUS | UNDOCUMENTED | WITHDRAWN **Source:** : [, ...] ; ipcalc.1.md#
**Acceptance:** `ipcalc ` → — positive | negative ; test: | none **Links:** ``` ## Document frontmatter ```yaml --- title: id-prefix: REQ- sources: - --- ``` ## Conventions - **Requirements describe observable behavior** — what a user invokes and what ipcalc prints or returns — and cite functions only as **Source** evidence. - **Negative requirements are mandatory for `INPUT` and `ERR`**: for every accepted input form, state what is rejected and the exit status. - **Field names and JSON types are contracts.** A requirement on an output field names it as printed in `NAME=value` mode and as the JSON key. - **Both families.** A requirement states whether it applies to IPv4, IPv6, or both. - **Normative language uses RFC 2119 keywords only** (MUST, MUST NOT, SHALL, SHALL NOT, SHOULD, SHOULD NOT, MAY, REQUIRED, RECOMMENDED, OPTIONAL). Informal equivalents ("needs to", "will", "can") MUST NOT express a normative obligation. ## Glossary A requirement MUST NOT redefine a term listed here. If it needs a meaning not covered, add the term here first. | Term | Definition | |------|------------| | input address | The address as given on the command line, before any prefix is applied. | | network address | The input address with all host bits cleared for the effective prefix. | | hosts | Disambiguate per use: **usable hosts** (the `Hosts/Net` count and `HostMin`–`HostMax` range) or **addresses** (all 2^(width−prefix) addresses in the network). A requirement MUST state the /31, /32, /127 and /128 behavior explicitly. | | decorated output | The default human-readable output, colored only when stdout is a TTY and `NO_COLOR` is unset. | | `NAME=value` output | The shell-variable style output produced when specific info options (e.g. `-n`, `-b`) are given. | | invalid input | Not a standalone term: name the input class (malformed address, prefix out of range for the family, conflicting options, …) and the exit status. | | release | A version of ipcalc with a git tag (`1.0.0` or later). Behavior present only in unreleased commits is not a release's behavior. | | information item | A value ipcalc prints — an address, mask, prefix, count, name, or list — as opposed to its presentation: label, order, alignment, separators, blank lines, and color. Two outputs carry the same information item when the value can be read from both, e.g. the prefix in `Netmask: 255.255.255.0 = 24` and in `Network: 192.168.2.0/24`. | ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/binary.md000066400000000000000000000601151526405142400253570ustar00rootroot00000000000000--- title: Binary representation of an address or network (--binary) id-prefix: REQ-BINARY sources: - binary.c (show_binary) - ipcalc.c (main, usage, long_options, color_fputs) - ipcalc.1.md - tests/meson.build --- # Binary representation of an address or network (`--binary`) Generated with `contrib/ai/protocols/requirements-elicitation.md` from issue #34. The input is parsed as in `info.md` (REQ-INFO-INPUT-001 to REQ-INFO-INPUT-005); mode selection and conflicting options are in `cli.md` (REQ-CLI-INPUT-001, REQ-CLI-ERR-001), and the output format options in `cli.md` (REQ-CLI-OUTPUT-011, REQ-CLI-OUTPUT-013, REQ-CLI-ERR-009). Terms used below: **width** is 32 for IPv4 and 128 for IPv6; **p** is the effective prefix (REQ-INFO-INPUT-005), so an address given without a prefix has p equal to the width; **network bits** are bits 0 to p−1 and **host bits** bits p to width−1, numbered from the most significant bit of the address, bit 0; an **octet** is 8 bits of an IPv4 address and a **hextet** 16 bits of an IPv6 address; a **structured** network is an IPv6 network whose network address is in `2000::/3` (global unicast) or `fc00::/7` (unique local), the address types that RFC 3587 and RFC 4193 divide into a routing prefix, a subnet ID and the 64-bit interface ID of RFC 4291 §2.5.1. ## Input ### REQ-BINARY-INPUT-001 **Requirement:** `--binary` MUST select the binary mode and accept, for both IPv4 and IPv6, the input address in every form the info mode accepts — address syntax (REQ-INFO-INPUT-001, REQ-INFO-INPUT-002), a `/prefix` or, for IPv4, `/netmask` suffix or second argument (REQ-INFO-INPUT-003), the default prefix and `--class-prefix` (REQ-INFO-INPUT-005), and `-4`/`-6` (REQ-CLI-INPUT-005) — and MUST reject the inputs they reject with the same diagnostic and exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`OPT_BINARY`, `APP_SHOW_BITS`); ipcalc.c:long_options, ipcalc.c:usage; ipcalc.1.md#Options (`--binary`) **Acceptance:** `ipcalc --binary --format=value 192.168.92.6 255.255.252.0` → `11000000101010000101110000000000`; `ipcalc --binary --format=value --class-prefix 10.1.2.3` → `00001010` followed by 24 `0`s; `ipcalc --binary 1.2.3.400`, `ipcalc --binary 1.2.3.4/33`, `ipcalc --binary 2001:db8::/129`, `ipcalc --binary -6 1.2.3.4` → diagnostic, exit 1 — positive, negative ; test: BitsNetmaskValue, BitsClassPrefixValue, BitsBadAddress, BitsBadPrefixIPv4, BitsBadPrefixIPv6, BitsForcedFamily **Links:** REQ-CLI-INPUT-001, REQ-CLI-ERR-001 ### REQ-BINARY-INPUT-002 **Requirement:** `--binary` MUST reject the deprecated `--no-decorate` (REQ-CLI-OUTPUT-014), with or without `-j` or `--format=value`, by printing `ipcalc: --no-decorate is not supported with --binary; use --format=value` to stderr (subject to `-s`, REQ-CLI-ERR-006) and exiting with status 1, so that the new mode does not take on a deprecated option. A `--format` other than `value` MUST be rejected as a conflict with `--no-decorate` (REQ-CLI-ERR-009) instead. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`noDecorate`, `APP_SHOW_BITS`) **Acceptance:** `ipcalc --binary --no-decorate 192.168.92.6/22`, `ipcalc --binary -j --no-decorate 192.168.92.0/22`, `ipcalc --binary --no-decorate --format=value 192.168.92.6/22` → the message, exit 1; `ipcalc --binary -s --no-decorate 192.168.92.6/22` → no output, exit 1 — negative ; test: BitsNoDecorate, BitsJsonNoDecorate, BitsNoDecorateFormatValue, BitsNoDecorateSilent **Links:** REQ-CLI-OUTPUT-006, REQ-CLI-OUTPUT-014, REQ-CLI-ERR-009 ## Computed value ### REQ-BINARY-CALC-001 **Requirement:** The bit string of the input MUST be written most significant bit first, each bit as `0` or `1`, and host bits set in the input address MUST NOT affect it. For both IPv4 and IPv6 it MUST be all width bits of the network address (REQ-INFO-CALC-001), its host bits being `0`, so that it is the value of `NETWORK`, or of `ADDRESS` when p equals the width, in the shell output (REQ-BINARY-OUTPUT-012). **Strength:** MUST **Status:** DERIVED **Source:** binary.c:show_binary **Acceptance:** `ipcalc --binary --format=value 192.168.92.6` → `11000000101010000101110000000110`; `ipcalc --binary --format=value 192.168.92.6/22` → `11000000101010000101110000000000`; `ipcalc --binary --format=value 192.168.92.6/32` → same as without `/32`; `ipcalc --binary --format=value 0.0.0.0/0` → 32 `0`s; `ipcalc --binary --format=value 2001:db8::/32` → `00100000000000010000110110111000` followed by 96 `0`s; `ipcalc --binary --format=value 2001:db8::1` → 128 bits ending in `1`; `ipcalc --binary --format=value ::/0` → 128 `0`s — positive ; test: BitsAddressValue, BitsNetworkValue, BitsPrefix32Value, BitsPrefix0Value, BitsNetworkIPv6Value, BitsAddressIPv6Value, BitsPrefix0IPv6Value **Links:** REQ-BINARY-OUTPUT-001, REQ-BINARY-OUTPUT-002 ## Output ### REQ-BINARY-OUTPUT-001 **Requirement:** With `--format=value`, ipcalc MUST print only the bit string (REQ-BINARY-CALC-001) followed by a newline, for both IPv4 and IPv6, and exit with status 0, so that scripts can use it. With `--format=shell` it MUST print, only when p is less than the width, `PREFIX=

`, then the address variables (REQ-BINARY-OUTPUT-012), one `NAME=value` per line, all unquoted, as their values need no quoting (REQ-CLI-OUTPUT-005). It MUST NOT print the bit string, which `NETWORK` or `ADDRESS` already holds. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:show_binary (`FORMAT_VALUE`), binary.c:print_vars **Acceptance:** as REQ-BINARY-CALC-001; `ipcalc --binary --format=shell 192.168.92.6/22` → tests/bits-shell-192.168.92.6-22 (`PREFIX=22`, then the address variables, no `BITS`); `ipcalc --binary --format=shell 192.168.92.6` → only `ADDRESS=11000000101010000101110000000110`; `ipcalc --binary --format=shell ::/0` → `PREFIX=0`, `NETWORK=` 128 `0`s — positive, negative ; test: BitsAddressValue, BitsNetworkValue, BitsNetworkIPv6Value, BitsShell, BitsShellAddress, BitsShellPrefix0IPv6 **Links:** REQ-CLI-OUTPUT-004, REQ-CLI-OUTPUT-013, REQ-BINARY-OUTPUT-012 ### REQ-BINARY-OUTPUT-002 **Requirement:** With `--format=json`, or without `--format` with `-j`, ipcalc MUST print, for both IPv4 and IPv6, a JSON object (REQ-CLI-OUTPUT-008) whose keys are, only when p is less than the width, `PREFIX` holding p in decimal, then the address variables (REQ-BINARY-OUTPUT-012), all as JSON strings, so that the JSON and shell outputs hold the same values; as in the shell output, there MUST be no `BITS` key. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:show_binary (`FORMAT_JSON`, `output_start`, `output_stop`), binary.c:print_vars (`json_printf`) **Acceptance:** `ipcalc --binary --format=json 192.168.92.0/22` → tests/bits-json-192.168.92.0-22 (`PREFIX`, `ADDRESS`, `NETMASK`, `NETWORK`, `HOSTMIN`, `HOSTMAX`, `BROADCAST`, one key per line); `ipcalc --binary --format=json 2001:db8::1` → only `ADDRESS`; `ipcalc --binary --format=json 2001:db8:abcd:12::1/56` → tests/bits-json-2001:db8:abcd:12::1-56 (`PREFIX`, `NETWORK`); `ipcalc --binary -j 192.168.92.0/22` → same as `--format=json`; `ipcalc --binary -j --format=shell 10.0.0.0/8` → conflict, exit 1 (REQ-CLI-ERR-009) — positive, negative ; test: BitsJson, BitsJsonIPv6, BitsJsonNetworkIPv6, BitsJsonLegacy, BitsFormatConflict **Links:** REQ-CLI-OUTPUT-003, REQ-CLI-OUTPUT-008, REQ-CLI-OUTPUT-013, REQ-BINARY-OUTPUT-012 ### REQ-BINARY-OUTPUT-003 **Requirement:** With `--format=human`, or without `--format` and `-j`, ipcalc MUST print a diagram (REQ-BINARY-OUTPUT-004, REQ-BINARY-OUTPUT-005) whose first line is a title followed by an empty line: `Address:` padded with spaces to 12 columns and `

` when p equals the width, and `Network:` padded likewise and `/

` otherwise, where `

` and `` are printed as in the info summary (for IPv6, in compressed form), so that the title states how the input was interpreted, in the `Label: value` form of the summary, and its value lines up with those of the details (REQ-BINARY-OUTPUT-010). No line MUST report host bits set in the input, as the title already shows the network the input was reduced to; the input address itself is shown only in the IPv4 details. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:show_binary, binary.c:print_diagram **Acceptance:** `ipcalc --binary 192.168.92.6` → title `Address: 192.168.92.6`; `ipcalc --binary 192.168.92.6/22` → title `Network: 192.168.92.0/22`, no line before it; `ipcalc --binary 192.168.1.4/31` → title `Network: 192.168.1.4/31`; `ipcalc --binary 2001:db8::1` → title `Address: 2001:db8::1`; `ipcalc --binary 2001:db8:abcd:12::1/56` → title `Network: 2001:db8:abcd::/56`, no `Address` line; `ipcalc --binary --format=human 192.168.92.6/22` → same as without `--format` — positive ; test: BitsAddress, BitsHostBits, BitsPrefix31, BitsAddressIPv6, BitsHostBitsIPv6, BitsFormatHuman **Links:** REQ-INFO-CALC-001 ### REQ-BINARY-OUTPUT-004 **Requirement:** For IPv4, the diagram MUST print after the title (REQ-BINARY-OUTPUT-003) the following lines, in which each octet takes 8 columns and consecutive octets are separated by a `.` column, so that the lines read as dotted-quad addresses, line up, and are 35 columns wide whatever the prefix; when the details follow (p less than 32), each line MUST be indented by 29 spaces, so that its bits line up with those of the details (REQ-BINARY-OUTPUT-010): 1. each octet's decimal value in the network address or, when the octet has host bits, the range `-` of values it takes in the network, right-aligned in its columns; 2. each octet's bits, network bits as `0`/`1` and host bits as `x`; 3. only when p is less than 32, the network/host brackets (REQ-BINARY-OUTPUT-008), followed by the details (REQ-BINARY-OUTPUT-010). **Strength:** MUST **Status:** DERIVED **Source:** binary.c:show_binary, binary.c:print_band **Acceptance:** `ipcalc --binary 192.168.92.6/22` → tests/bits-192.168.92.6-22 (` 92-95.`, `010111xx.`, indented); `ipcalc --binary 192.168.92.6` → tests/bits-192.168.92.6 (no indentation, no bracket line, no details); `ipcalc --binary 10.0.0.0/8` → tests/bits-10.0.0.0-8; `ipcalc --binary 0.0.0.0/0` → all `0-255` and `x` — positive ; test: BitsHostBits, BitsAddress, BitsPrefix8, BitsPrefix0 **Links:** REQ-BINARY-OUTPUT-006, REQ-BINARY-OUTPUT-008, REQ-BINARY-OUTPUT-010 ### REQ-BINARY-OUTPUT-005 **Requirement:** For IPv6, the diagram MUST print after the title (REQ-BINARY-OUTPUT-003) the bits in bands, each made of the lines of REQ-BINARY-OUTPUT-004 with hextets in place of octets: each hextet takes 16 columns and consecutive hextets are separated by a `:` column, its value is four lowercase hex digits or a range of two such values, and the brackets (REQ-BINARY-OUTPUT-008) are printed only in the band where the prefix ends and only when p is less than 128. When the output width (REQ-BINARY-OUTPUT-009) is at least 135 columns, the diagram MUST be a single band of bits 0–127 (135 columns), so that the address reads on one line. Otherwise it MUST be two bands of bits 0–63 and bits 64–127 (67 columns each), with the brackets in the first band when p is at most 64 and in the second otherwise, and the second band MUST be replaced by a single line when all its bits are host bits: `bits 64-127: interface ID, all x` for a structured network (REQ-BINARY-OUTPUT-011), and `bits 64-127: host, all x` otherwise. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:show_binary, binary.c:print_diagram, binary.c:print_band **Acceptance:** `ipcalc --binary 2001:db8::1` → tests/bits-2001:db8::1 (two bands, no brackets); `ipcalc --binary 2001:db8:abcd:12::1/56` → tests/bits-2001:db8:abcd:12::1-56 (brackets in the first band, then `bits 64-127: interface ID, all x`); `ipcalc --binary fe80::/64` → `bits 64-127: host, all x`; `ipcalc --binary 2001:db8::/64` → network bracket over the whole first band; `ipcalc --binary 2001:db8:abcd:10::/62` → hextet `0010-0013`; `ipcalc --binary 2001:db8::/96` → brackets in the second band; `ipcalc --binary ::/0` → a first band of `0000-ffff` and `x`, then `bits 64-127: host, all x`; with `COLUMNS=135`: `ipcalc --binary 2001:db8::1` → tests/bits-wide-2001:db8::1 (one band, no brackets), `ipcalc --binary 2001:db8:abcd:12::1/56` → tests/bits-wide-2001:db8:abcd:12::1-56 (one band with brackets, no `bits 64-127` line), `ipcalc --binary 2001:db8::/96` → tests/bits-wide-2001:db8::-96, `ipcalc --binary ::/0` → tests/bits-wide-::-0 (host segment only); with `COLUMNS=134`: `ipcalc --binary 2001:db8:abcd:12::1/56` → two bands — positive, negative ; test: BitsAddressIPv6, BitsHostBitsIPv6, BitsLinkLocalIPv6, BitsPrefix64IPv6, BitsPrefix62IPv6, BitsPrefix96IPv6, BitsPrefix0IPv6, BitsWideAddressIPv6, BitsWideHostBitsIPv6, BitsWidePrefix96IPv6, BitsWidePrefix0IPv6, BitsNarrowIPv6 **Links:** REQ-BINARY-OUTPUT-004, REQ-BINARY-OUTPUT-006, REQ-BINARY-OUTPUT-008, REQ-BINARY-OUTPUT-009 ### REQ-BINARY-OUTPUT-006 **Requirement:** The brackets MUST be drawn with the UTF-8 box drawing characters `└ ─ ┘`, regardless of the locale. When colors are enabled (REQ-CLI-OUTPUT-007), network bits, values made only of network bits, and the network bracket MUST be printed in blue, and host bits, ranges, the host, subnet ID and interface ID brackets and the `bits 64-127` line dimmed; in the details (REQ-BINARY-OUTPUT-010), network bits MUST be printed in blue and nothing else colored, so that the host bits, which differ between the rows, stand out; the title and the `.`/`:` separators MUST NOT be colored. The output MUST be readable without color, so that it remains complete when piped or with `NO_COLOR`. **Strength:** MUST **Status:** DERIVED **Source:** binary.c (`print_line`, `style_color`); ipcalc.c:color_fputs **Acceptance:** any decorated test above → no escape codes (stdout not a TTY); `script -qc 'ipcalc --binary 192.168.92.0/22'` → blue network bits, dim host bits — positive ; test: BitsHostBits (no TTY test exists) **Links:** REQ-CLI-OUTPUT-007 ### REQ-BINARY-OUTPUT-007 **Requirement:** ipcalc MUST print the bits only in binary mode; the info summary, including `--all-info`, MUST NOT contain them in any format, so that the summary stays as it is and the bits are shown only when requested. **Strength:** MUST NOT **Status:** DERIVED **Source:** ipcalc.c:main (`APP_SHOW_BITS` calling `show_binary()` instead of `show_info_fields()`) **Acceptance:** `ipcalc --all-info 192.168.92.6/22`, `ipcalc --all-info --format=json 192.168.92.6/22`, `ipcalc --all-info --format=shell 2001:db8::1/56` → no `BITS` key or bits line — negative ; test: AllInfoNoBits, AllInfoNoBitsJson, AllInfoNoBitsShell **Links:** REQ-INFO-OUTPUT-001, REQ-INFO-OUTPUT-003 ### REQ-BINARY-OUTPUT-008 **Requirement:** The brackets line MUST mark under the bits line (REQ-BINARY-OUTPUT-004 line 2) the columns of each segment of the address: for a structured network with p at most 64, the segments of REQ-BINARY-OUTPUT-011; otherwise a network segment of the network bits and a host segment of the host bits. A separator column belongs to a segment only when the bits on both of its sides do, so that two segments are adjacent when their boundary is inside a group and a blank column apart when it is between groups. A segment MUST be drawn as `└`, a fill of `─` holding its label, and `┘`; its `└` MUST be omitted when its bits begin in the previous band and its `┘` when they continue in the next band, so that an open end shows that the segment goes on. The label MUST be the first of the segment's labels that fits between its ends — with a space on each side when there is room — centered, with any odd fill on the right; the labels are `network /

`, `/

`, `

` for the network segment and `host `, `` for the host segment, n being the width minus p. When none fits, the segment MUST be only its last label, centered, or, when even that does not fit, only its ends, so that /1, /31 and similar prefixes still render. There is no network segment for /0. The line MUST NOT end with spaces. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:print_brackets, binary.c:put_segment **Acceptance:** `ipcalc --binary 192.168.92.6/22` → `└──── network /22 ─────┘└ host 10 ┘`; `ipcalc --binary 10.0.0.0/8` → `└─ /8 ─┘ └─────── host 24 ────────┘`; `ipcalc --binary 192.168.1.4/31` → host segment `1`; `ipcalc --binary 128.0.0.0/1` → network segment `1`; `ipcalc --binary 0.0.0.0/0` → only the host segment; `ipcalc --binary fe80::/10` → host segment `└────── host 118` without `┘`; `ipcalc --binary 2001:db8::/96` → network segment without `└`; `ipcalc --binary 2001:db8::/65` → network segment `┘`; `ipcalc --binary 2001:db8::/127` → host segment `1` — positive ; test: BitsHostBits, BitsPrefix8, BitsPrefix31, BitsPrefix1, BitsPrefix0, BitsLinkLocalPrefix10IPv6, BitsPrefix96IPv6, BitsPrefix65IPv6, BitsPrefix127IPv6 **Links:** REQ-BINARY-OUTPUT-004, REQ-BINARY-OUTPUT-005, REQ-BINARY-OUTPUT-006, REQ-BINARY-OUTPUT-011 ### REQ-BINARY-OUTPUT-009 **Requirement:** The output width of the diagram MUST be the value of the `COLUMNS` environment variable when it is a positive integer; otherwise, when stdout is a terminal, the terminal's width in columns; otherwise 80. A `COLUMNS` value that is not a positive integer MUST be ignored. The width MUST affect only the IPv6 diagram (REQ-BINARY-OUTPUT-005): the IPv4 diagram and the value, shell and JSON formats MUST be the same whatever the width, so that piped output does not depend on the terminal. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:output_columns, binary.c:show_binary; ipcalc.1.md#Environment (`COLUMNS`) **Acceptance:** `COLUMNS=135 ipcalc --binary 2001:db8::1` → one band; `COLUMNS=abc ipcalc --binary 2001:db8:abcd:12::1/56` and `COLUMNS=0 …` → two bands, as with stdout not a terminal; `COLUMNS=200 ipcalc --binary 192.168.92.6/22` → tests/bits-192.168.92.6-22; the value and shell tests of REQ-BINARY-OUTPUT-001, run with `COLUMNS=200` → unchanged — positive, negative ; test: BitsWideAddressIPv6, BitsColumnsInvalid, BitsColumnsZero, BitsWideIPv4, BitsNetworkIPv6Value, BitsAddressIPv6Value, BitsShellPrefix0IPv6 **Links:** REQ-BINARY-OUTPUT-005 ### REQ-BINARY-OUTPUT-010 **Requirement:** For IPv4 with p less than 32, the diagram MUST be followed by an empty line and the details: one line per row below, each made of the row's name and a `:` padded with spaces to 12 columns, the row's value in dotted-quad notation padded with spaces to 17 columns, and the row's 32 bits laid out as the bits line (REQ-BINARY-OUTPUT-004 line 2) but with every bit as `0`/`1`, so that each line reads as `Label: value` like the info summary and each row's bits line up with the diagram and its brackets. The rows MUST be, in this order: `Address` (the input address) only when it differs from the network address, `Netmask`, `Network` (the network address), `HostMin`, `HostMax` and `Broadcast` (all host bits 1), where HostMin and HostMax are the first and last address of the network after the network and broadcast addresses, so that the rows after Netmask rise in value; for /31 the rows after Netmask MUST be only `HostMin` (the first address) and `HostMax` (the second), as both of its addresses are hosts (RFC 3021). For p equal to 32 there MUST be no details. For IPv6 there MUST be no details, as IPv6 reserves no network or broadcast address and uses no netmasks; its diagram marks the structure of the address instead (REQ-BINARY-OUTPUT-011). **Strength:** MUST **Status:** DERIVED **Source:** binary.c:print_details, binary.c:make_rows **Acceptance:** `ipcalc --binary 192.168.92.6/24` → tests/bits-192.168.92.6-24 (Address, Netmask, Network, HostMin, HostMax, Broadcast); `ipcalc --binary 10.0.0.0/8` → tests/bits-10.0.0.0-8 (no Address); `ipcalc --binary 192.168.92.1/24`, `ipcalc --binary 192.168.92.255/24` → Address first; `ipcalc --binary 192.168.1.5/31` → Address, Netmask, HostMin, HostMax; `ipcalc --binary 192.168.92.6/32` and `ipcalc --binary 192.168.92.6` → no details; `ipcalc --binary 2001:db8::/64` → no details — positive, negative ; test: BitsDetails, BitsPrefix8, BitsAddressHostMin, BitsAddressBroadcast, BitsAddressPrefix31, BitsPrefix32, BitsAddress, BitsPrefix64IPv6 **Links:** REQ-BINARY-OUTPUT-004, REQ-BINARY-OUTPUT-006, REQ-INFO-CALC-001 ### REQ-BINARY-OUTPUT-011 **Requirement:** For a structured network with p at most 64, the brackets (REQ-BINARY-OUTPUT-008) MUST name the parts of the address instead of the network and host: with p less than 64, a routing prefix segment of bits 0 to p−1 labeled `routing prefix /

`, `/

` or `

`, a subnet ID segment of bits p to 63 labeled `subnet ID ` or ``, s being 64 minus p, and an interface ID segment of bits 64 to 127 labeled `interface ID 64` or `64`; with p equal to 64, a subnet prefix segment of bits 0 to 63 labeled `subnet prefix /64`, `/64` or `64`, and the interface ID segment. The routing prefix and subnet prefix segments MUST be styled as network segments and the subnet ID and interface ID segments as host segments (REQ-BINARY-OUTPUT-006). Networks that are not structured — such as link-local, whose bits after `fe80::/10` are zero, and multicast, which has no interface ID — and networks with p greater than 64, where the host bits are fewer than the interface ID, MUST keep the network and host segments. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:print_brackets, binary.c:is_structured **Acceptance:** `ipcalc --binary 2001:db8:abcd:12::1/56` → tests/bits-2001:db8:abcd:12::1-56 (`routing prefix /56`, subnet ID `8`); `ipcalc --binary 2001:db8::/64` → `subnet prefix /64`; `ipcalc --binary fd10:da05:b5ac::/48` → `routing prefix /48`, `subnet ID 16`; `COLUMNS=135 ipcalc --binary 2001:db8:abcd:12::1/56` → also `interface ID 64`; `ipcalc --binary fe80::/64`, `ipcalc --binary ff02::/16`, `ipcalc --binary 2001:db8::/96` → network and host segments — positive, negative ; test: BitsHostBitsIPv6, BitsPrefix64IPv6, BitsUniqueLocalIPv6, BitsWideHostBitsIPv6, BitsLinkLocalIPv6, BitsMulticastIPv6, BitsPrefix96IPv6 **Links:** REQ-BINARY-OUTPUT-005, REQ-BINARY-OUTPUT-008 ### REQ-BINARY-OUTPUT-012 **Requirement:** The address variables of the shell and JSON outputs (REQ-BINARY-OUTPUT-001, REQ-BINARY-OUTPUT-002) MUST each hold the width bits of an address, most significant bit first, as `0`/`1` without separators, so that they show the addresses of the diagram (REQ-BINARY-OUTPUT-003, REQ-BINARY-OUTPUT-010) as bits. They MUST be, in this order: 1. when p equals the width, for both IPv4 and IPv6, only `ADDRESS` (the input address); 2. for IPv4 with p less than 32, the rows of the details (REQ-BINARY-OUTPUT-010) in their order, named `ADDRESS`, `NETMASK`, `NETWORK`, `HOSTMIN`, `HOSTMAX` and `BROADCAST`, except that `ADDRESS` MUST be printed even when the input address is the network address, so that a script finds it whatever the input; for /31 they are thus `ADDRESS`, `NETMASK`, `HOSTMIN` and `HOSTMAX`; 3. for IPv6 with p less than 128, only `NETWORK` (the network address, including its host bits, which are `0`): no `ADDRESS`, as the diagram does not show the input address, and no `NETMASK`, as IPv6 uses no netmasks and `PREFIX` already gives p. **Strength:** MUST **Status:** DERIVED **Source:** binary.c:print_vars, binary.c:make_rows **Acceptance:** `ipcalc --binary --format=shell 192.168.92.6/22` → tests/bits-shell-192.168.92.6-22; `ipcalc --binary --format=shell 10.0.0.0/8` → `ADDRESS` equal to `NETWORK`; `ipcalc --binary --format=shell 192.168.1.5/31` → tests/bits-shell-192.168.1.5-31 (no `NETWORK` or `BROADCAST`); `ipcalc --binary --format=shell 192.168.92.6` → only `ADDRESS`; `ipcalc --binary --format=shell 2001:db8:abcd:12::1/56` → tests/bits-shell-2001:db8:abcd:12::1-56 (`PREFIX`, `NETWORK` of 128 bits, no `ADDRESS` or `NETMASK`); `ipcalc --binary --format=shell 2001:db8::1` → only `ADDRESS`, of 128 bits — positive, negative ; test: BitsShell, BitsShellPrefix8, BitsShellPrefix31, BitsShellAddress, BitsShellIPv6, BitsShellAddressIPv6, BitsShellPrefix0IPv6 **Links:** REQ-BINARY-OUTPUT-001, REQ-BINARY-OUTPUT-002, REQ-BINARY-OUTPUT-010 ## Open items Missing tests: color output (REQ-BINARY-OUTPUT-006), as for all modes; the terminal width when `COLUMNS` is unset (REQ-BINARY-OUTPUT-009), as tests do not run on a terminal. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/cli.md000066400000000000000000001313171526405142400246450ustar00rootroot00000000000000--- title: Command line, modes, output formats, and exit status id-prefix: REQ-CLI sources: - ipcalc.c (main, usage, long_options, output and printf helpers) - netcompare.c (compare_networks) - ipcalc.h (enum app_t, FLAG_*) - ipcalc.1.md - tests/meson.build --- # Command line, modes, output formats, and exit status Generated with `contrib/ai/protocols/requirements-from-implementation.md`. Computed values (network, broadcast, address space, …) are in `info.md`; this document covers how ipcalc is invoked and how results are printed. ## Modes and option combinations ### REQ-CLI-INPUT-001 **Requirement:** ipcalc MUST select exactly one mode per invocation from the options given: version (`-v`), check (`-c`), comparison (`--equals`, `--subnet-of`, `--overlaps`), split (`-S`, `--split-hosts`), deaggregate (`-d`), binary (`--binary`), or info (`-i`, `--all-info`, `-r`, `-a`, `-b`, `-m`, `-n`, `-p`, `-h`, `-o`, `-g`, `--reverse-dns`, `--cidr`, `--wildcard`, `--minaddr`, `--maxaddr`, `--addresses`, `--addrspace`), and MUST use the info mode when none of these options is given, so that every invocation has one well-defined output. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (getopt loop setting `app`; `switch (app)`); ipcalc.h:enum app_t; ipcalc.1.md#Description **Acceptance:** `ipcalc 192.168.2.7/24` → same output as `ipcalc -i 192.168.2.7/24` — positive ; test: InfoImplicit, Info **Links:** REQ-CLI-ERR-001, REQ-CLI-INPUT-006 ### REQ-CLI-ERR-001 **Requirement:** ipcalc MUST NOT run when options of more than one mode (REQ-CLI-INPUT-001) are given; it MUST print `ipcalc: you cannot mix these options` to stderr and exit with status 1 (status 2 when a comparison option is given, REQ-CLI-OUTPUT-009), so that conflicting requests are not silently resolved. **Strength:** MUST NOT **Status:** DERIVED **Source:** ipcalc.c:main (`bit_count(app) > 1`) **Acceptance:** `ipcalc -abmnp -S 26 10.100.1.0/24`, `ipcalc -c -abmnp 10.100.1.1`, `ipcalc -c -S 26 10.100.1.0/24`, `ipcalc -c -h 127.0.0.1`, `ipcalc -n --split-hosts=10 10.100.1.0/24`, `ipcalc -v -n 1.2.3.4`, `ipcalc --binary -i 10.0.0.0/8`, `ipcalc --binary --all-info 10.0.0.0/8`, `ipcalc --binary -n 10.0.0.0/8`, `ipcalc --binary --cidr 10.0.0.0/8`, `ipcalc --binary -c 10.0.0.0/8`, `ipcalc --binary -S 24 10.0.0.0/8`, `ipcalc --binary --split-hosts=10 10.0.0.0/8`, `ipcalc --binary -d 10.0.0.0-10.0.0.255`, `ipcalc --binary -r 24` → exit 1; `ipcalc --equals=10.0.0.0/8 -n 10.0.0.0/8`, `ipcalc -c 10.0.0.0/8 --equals=10.0.0.0/8`, `ipcalc --binary 10.0.0.0/8 --equals=10.0.0.0/8` → exit 2 — negative ; test: Split-Info, SplitHosts-Info, Check-Info, Check-Split, Check-Host, Equals-Info, Check-Equals, Bits-Info, Bits-AllInfo, Bits-Network, Bits-Cidr, Bits-Check, Bits-Split, Bits-SplitHosts, Bits-Deaggregate, Bits-Random, Bits-Equals (no test for `-v` with another mode) **Links:** REQ-CLI-INPUT-001, REQ-CLI-OUTPUT-009 ### REQ-CLI-INPUT-002 **Requirement:** In version mode ipcalc MUST print `ipcalc ` to stdout, where `` is the project version from `meson.build`, and exit with status 0. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case APP_VERSION`); meson.build (`version`); Makefile (`VERSION=`) **Acceptance:** `ipcalc -v` → `ipcalc 1.0.4`, exit 0 — positive ; test: none ### REQ-CLI-INPUT-003 **Requirement:** `-?`/`--help` MUST print the full option summary and `--usage` MUST print the brief usage summary, both to stderr, and both MUST exit with status 0 without processing other arguments. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case OPT_HELP`, `case '?'` with `optopt == '?'`, `case OPT_USAGE`); ipcalc.c:usage **Acceptance:** `ipcalc --help`, `ipcalc -?` → exit 0 — positive ; test: TestHelpCommand, TestShortHelpCommand **Links:** REQ-CLI-ERR-002, REQ-CLI-COMPAT-002 ### REQ-CLI-ERR-002 **Requirement:** ipcalc MUST exit with status 1 (2 with a comparison option, REQ-CLI-OUTPUT-009) without processing the address when given an unrecognized option, or an option without its required argument, after printing getopt's diagnostic and the full option summary to stderr, so that scripts detect the mistake. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case '?'` sets `badOption`; `exit(err)` after the getopt loop) **Acceptance:** `ipcalc --bogus 1.2.3.4`, `ipcalc -y 1.2.3.4`, `ipcalc -S` → exit 1 — negative ; test: UnknownLongOption, UnknownShortOption, MissingOptionArgument, UnknownOptionStatus **Links:** REQ-CLI-INPUT-003 ### REQ-CLI-INPUT-004 **Requirement:** Outside deaggregate mode, ipcalc MUST take the input address as the first non-option argument and an optional IPv4 netmask or prefix as the second; non-option arguments after the second MUST be ignored. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`optind` handling, `chptr`) **Acceptance:** `ipcalc -b 192.168.1.1 255.255.255.0` → `BROADCAST=192.168.1.255` — positive ; test: CalculateBroadcastAddressFromNetmaskIPv4 **Links:** REQ-INFO-INPUT-003, REQ-CLI-ERR-004 > [UNDOCUMENTED] Arguments after the second are silently ignored > (`ipcalc -n 1.2.3.4 255.255.0.0 extra` → `NETWORK=1.2.0.0`, exit 0). ### REQ-CLI-ERR-003 **Requirement:** When no input address is available (no non-option argument, no `-o`, no `-r`), ipcalc MUST print `ipcalc: ip address expected` and the full option summary to stderr and exit with status 1 (2 with a comparison option, REQ-CLI-OUTPUT-009). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`hostname == NULL && ipStr == NULL`) **Acceptance:** `ipcalc -c` → exit 1 — negative ; test: none ### REQ-CLI-ERR-004 **Requirement:** ipcalc MUST reject a second non-option argument when the address is IPv6 with `ipcalc: unexpected argument: `, the full option summary, and exit status 1 (2 with a comparison option, REQ-CLI-OUTPUT-009); and MUST reject a non-option argument in deaggregate mode with `ipcalc: superfluous option given` and exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`chptr` with `FLAG_IPV6`; `ipStr != NULL` after `-d`) **Acceptance:** `ipcalc -n ::1 64` → exit 1; `ipcalc -d 1.2.3.4-1.2.3.4 5.5.5.5` → exit 1 — negative ; test: none **Links:** REQ-CLI-INPUT-004, REQ-DEAGG-INPUT-001 ### REQ-CLI-INPUT-005 **Requirement:** ipcalc MUST treat the input as IPv6 when `-6` is given or when, without `-4`, the input address (or the address resolved by `-o`) contains `:`; otherwise it MUST treat it as IPv4. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`strchr(ipStr, ':')`, `FLAG_IPV6`/`FLAG_IPV4`) **Acceptance:** `ipcalc -c ::1` → exit 0; `ipcalc -c -4 2a01:198:200:300::2` → exit 1; `ipcalc -6 -n 1.2.3.4` → `ipcalc: bad IPv6 address: 1.2.3.4`, exit 1 — positive, negative ; test: ValidateLoopbackIPv6, NoValidateIPv6InIPv4Mode **Links:** REQ-CLI-ERR-005, REQ-SPLIT-INPUT-002 ### REQ-CLI-ERR-005 **Requirement:** ipcalc MUST NOT accept `-4` together with `-6`; it MUST print `ipcalc: you cannot specify both IPv4 and IPv6` and exit with status 1 (2 with a comparison option, REQ-CLI-OUTPUT-009). **Strength:** MUST NOT **Status:** DERIVED **Source:** ipcalc.c:main **Acceptance:** `ipcalc -4 -6 2a01:198:200:300::2`, `ipcalc -c -4 -6 127.0.0.1` → exit 1 — negative ; test: NoAllowIPv4AndIPv6, NoValidateIPv4AndIPv6WithIPv4Address ### REQ-CLI-ERR-006 **Requirement:** `-s`/`--silent` MUST suppress every error message ipcalc itself prints to stderr, and the result line of comparison mode (REQ-CLI-OUTPUT-010), without changing the exit status. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c, netsplit.c, deaggregate.c (`if (!beSilent)` guards); ipcalc.1.md#Options **Acceptance:** `ipcalc -s -c bad` → no output, exit 1; `ipcalc -s 10.0.0.0/8 --overlaps=::/0` → no output, exit 1 — positive ; test: OverlapsSilent > [REVIEW] A few messages are not guarded by `beSilent`: `inet_ntop > failure at line N` (ipcalc.c, deaggregate.c — not reachable with valid > input), the memory allocation failure messages, getopt's own > unrecognized-option message, and the geo backend's runtime-linking > error (guarded, but printed by the backend). None is reachable with > well-formed input except the getopt message. ## Check mode ### REQ-CLI-OUTPUT-001 **Requirement:** In check mode (`-c`) ipcalc MUST parse the input exactly as the info mode does — address, optional prefix or netmask, and the address family rules of REQ-CLI-INPUT-005 — and MUST exit with status 0 without printing anything when it is valid, and with status 1 when it is not. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case APP_CHECK_ADDRESS: return 0` after `get_ipv4_info`/`get_ipv6_info`); ipcalc.1.md#Options (`--check`) **Acceptance:** `ipcalc -c 127.0.0.1`, `ipcalc -c -6 ::1/128`, `ipcalc -c -6 2a01:0198:0200:0300:0000:0000:0000:0002` → exit 0; `ipcalc -c -6 gggg::`, `ipcalc -c ::1/999`, `ipcalc -c 1.2.3` → exit 1 — positive, negative ; test: ValidateLoopbackIPv4, ValidateLoopbackIPv6WithPrefix, ValidateCompleteGlobalIPv6, NoValidateInvalidHexIPv6, NoValidateInvalidPrefixIPv6 **Links:** REQ-INFO-INPUT-001, REQ-INFO-INPUT-002 ## Network comparison ### REQ-CLI-INPUT-006 **Requirement:** ipcalc MUST accept the comparison-mode options `--equals=NET`, `--subnet-of=NET`, and `--overlaps=NET`, for both IPv4 and IPv6, which compare the input network with NET as REQ-INFO-CALC-014 to REQ-INFO-CALC-017 define. NET MUST be parsed as the input address is parsed — address syntax (REQ-INFO-INPUT-001, REQ-INFO-INPUT-002), a `/prefix` or, for IPv4, `/netmask` suffix (REQ-INFO-INPUT-003), the default prefix and `--class-prefix` (REQ-INFO-INPUT-005), and the family rules of REQ-CLI-INPUT-005 applied to NET on its own. The input network MAY be given in any form check mode accepts, including an IPv4 netmask as the second argument, so that scripts can compare networks without first normalizing them. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`OPT_EQUALS`, `OPT_SUBNET_OF`, `OPT_OVERLAPS`; `case APP_COMPARE`), netcompare.c:compare_networks, ipcalc.c:long_options, ipcalc.c:usage; ipcalc.1.md#Options (`--equals`) **Acceptance:** `ipcalc 192.168.7.15/24 --equals=192.168.7.5/24`, `ipcalc 192.168.7.15 255.255.255.0 --equals=192.168.7.5/255.255.255.0`, `ipcalc --class-prefix 10.0.0.0/8 --equals=10.9.9.9` → exit 0 — positive ; test: EqualsHostBits, EqualsNetmask, EqualsClassPrefix **Links:** REQ-CLI-INPUT-001, REQ-CLI-ERR-007, REQ-CLI-ERR-008, REQ-CLI-OUTPUT-009 ### REQ-CLI-ERR-007 **Requirement:** ipcalc MUST reject a NET argument of `--equals`, `--subnet-of`, or `--overlaps` that the input address parser would reject — malformed address, prefix out of range for its family, non- contiguous netmask, or an address of the other family when `-4` or `-6` is given — with the same diagnostic the parser prints for the input address (e.g. `ipcalc: bad IPv4 address: `) and exit status 2 (REQ-CLI-OUTPUT-009). **Strength:** MUST **Status:** DERIVED **Source:** netcompare.c:parse_network (`str_to_prefix`, `get_ipv4_info`/`get_ipv6_info` on NET) **Acceptance:** `ipcalc 10.0.0.0/8 --equals=1.2.3`, `ipcalc ::/0 --subnet-of=::/129`, `ipcalc 10.0.0.0/8 --overlaps=10.0.0.0/255.0.255.0`, `ipcalc -4 10.0.0.0/8 --overlaps=::/0` → diagnostic, exit 2 — negative ; test: EqualsBadAddress, SubnetOfBadPrefixIPv6, OverlapsBadNetmask, OverlapsForcedFamily **Links:** REQ-CLI-INPUT-006, REQ-CLI-ERR-006 ### REQ-CLI-ERR-008 **Requirement:** ipcalc MUST NOT accept more than one of `--equals`, `--subnet-of`, and `--overlaps` in one invocation, including the same option given twice; it MUST print `ipcalc: you cannot mix these options` to stderr and exit with status 2 (REQ-CLI-OUTPUT-009), so that a compound condition is never silently reduced to one comparison. **Strength:** MUST NOT **Status:** DERIVED **Source:** ipcalc.c:main (`ncmps > 1`) **Acceptance:** `ipcalc 10.0.0.0/8 --equals=10.0.0.0/8 --overlaps=10.0.0.0/8`, `ipcalc 10.0.0.0/8 --equals=10.0.0.0/8 --equals=10.0.0.0/8` → exit 2 — negative ; test: Equals-Overlaps, Equals-Equals **Links:** REQ-CLI-ERR-001 ### REQ-CLI-OUTPUT-009 **Requirement:** With `--equals`, `--subnet-of`, or `--overlaps`, ipcalc MUST exit with status 0 when the comparison is true, with status 1 when it is false, and with status 2 when it cannot compare — any error that exits with status 1 in the other modes, including an unrecognized option or missing option argument (REQ-CLI-ERR-002), a missing input address (REQ-CLI-ERR-003), conflicting options (REQ-CLI-ERR-001, REQ-CLI-ERR-005, REQ-CLI-ERR-008), a malformed input address or NET (REQ-INFO-INPUT-001 to REQ-INFO-INPUT-003, REQ-CLI-ERR-007), and a memory allocation failure. A true or false result MUST be printed as REQ-CLI-OUTPUT-010 specifies; an error MUST print its usual diagnostic instead, subject to `-s` (REQ-CLI-ERR-006). This follows `cmp(1)`, so that a caller can tell "different" from "could not compare" and decide what to do with each. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:exit_failure, ipcalc.c:main (`badOption`, `case APP_COMPARE`), netcompare.c:compare_networks; ipcalc-utils.c:safe_strdup, ipcalc-utils.c:safe_asprintf **Acceptance:** `ipcalc 192.168.7.15/24 --equals=192.168.7.5/24` → exit 0; `ipcalc 192.168.1.15/24 --overlaps=192.168.7.1/24` → exit 1; `ipcalc 1.2.3 --equals=1.2.3.0/24`, `ipcalc 10.0.0.0/8 --overlaps=10.0.0.0/8 --bogus`, `ipcalc --bogus 10.0.0.0/8 --overlaps=10.0.0.0/8`, `ipcalc 10.0.0.0/8 --equals`, `ipcalc --subnet-of=10.0.0.0/8`, `ipcalc -4 -6 10.0.0.0/8 --equals=10.0.0.0/8` → exit 2 — positive, negative ; test: EqualsHostBits, OverlapsDisjoint, EqualsBadInputAddress, Overlaps-UnknownOption, UnknownOption-Overlaps, EqualsMissingArgument, SubnetOfNoAddress, Equals-IPv4-IPv6 (no test for allocation failure) **Links:** REQ-CLI-OUTPUT-010, REQ-CLI-ERR-001, REQ-CLI-ERR-002, REQ-CLI-ERR-003, REQ-INFO-CALC-014, REQ-INFO-CALC-015, REQ-INFO-CALC-016, REQ-INFO-CALC-017 ### REQ-CLI-OUTPUT-010 **Requirement:** In comparison mode ipcalc MUST print the result to stdout as one line, where NETWORK and NET stand for the input network and NET written as `/`: | Option | True | False | |--------|------|-------| | `--equals` | `The networks are equal` | `The networks are not equal` | | `--subnet-of` | `NETWORK is a subnet of NET` | `NETWORK is not a subnet of NET` | | `--overlaps` | `The networks overlap` | `The networks do not overlap` | With `--no-decorate`, `-j`, or `-s` it MUST print nothing. The line MUST NOT contain color codes. This applies to both IPv4 and IPv6, and to networks of different families (REQ-INFO-CALC-017), so that a user sees the answer without inspecting the exit status. **Strength:** MUST **Status:** DERIVED **Source:** netcompare.c:print_comparison, ipcalc.c:default_printf; ipcalc.1.md#Options (`--equals`) **Acceptance:** `ipcalc 192.168.7.15/24 --equals=192.168.7.5/24` → `The networks are equal`; `ipcalc 192.168.0.1/24 --subnet-of=192.168.1.15/23` → `192.168.0.0/24 is a subnet of 192.168.0.0/23`; `ipcalc 2001:db8::/32 --subnet-of=2001:db8:1::/48` → `2001:db8::/32 is not a subnet of 2001:db8:1::/48`; `ipcalc 192.168.0.0/24 --overlaps=192.168.1.0/24` → `The networks do not overlap`; `ipcalc --no-decorate 192.168.7.15/24 --equals=192.168.7.5/25` → no output, exit 1; `ipcalc --no-decorate 192.168.0.1/24 --subnet-of=192.168.1.15/23`, `ipcalc -j 192.168.7.15/24 --equals=192.168.7.5/24` → no output, exit 0 — positive ; test: EqualsHostBits, SubnetOf, SubnetOfSupernetIPv6, OverlapsAdjacent, EqualsNoDecorate, SubnetOfNoDecorate, EqualsJson **Links:** REQ-CLI-OUTPUT-009, REQ-CLI-OUTPUT-006, REQ-CLI-ERR-006 ## Output formats ### REQ-CLI-OUTPUT-002 **Requirement:** In info mode without `--format` (REQ-CLI-OUTPUT-011), ipcalc MUST print the summary output (REQ-INFO-OUTPUT-001) when no field-selecting option is given — i.e. when only `-i`, `--all-info`, `-r`, `-4`, `-6`, `--class-prefix`, `--no-decorate`, `-j`, or `-s` are present — and `NAME=value` output (REQ-CLI-OUTPUT-004) otherwise. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:field_selecting_options, ipcalc.c:main (`!selected_fields`, `FLAG_SHOW_MODERN_INFO`) **Acceptance:** `ipcalc 192.168.2.0/24` → summary; `ipcalc -m 192.168.1.1/24` → `NETMASK=255.255.255.0` — positive ; test: StandardInfo, CalculateNetmaskPrefix24 **Links:** REQ-CLI-OUTPUT-003, REQ-CLI-OUTPUT-012 ### REQ-CLI-OUTPUT-003 **Requirement:** When `-j`/`--json` is given in info mode without `--format` (REQ-CLI-OUTPUT-011), ipcalc MUST print the summary as a JSON object (REQ-INFO-OUTPUT-003) whichever field-selecting options are given; those options only add their fields to it (e.g. `--reverse-dns`, `--wildcard`). `-j` MUST also select JSON output in split, deaggregate and bits (REQ-BINARY-OUTPUT-002) modes; in comparison mode it MUST suppress the result line (REQ-CLI-OUTPUT-010). `-j` is deprecated in favor of `--format=json` (REQ-CLI-OUTPUT-014), but MUST keep this behavior so that existing commands keep their output. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`!formatStr && (flags & FLAG_JSON)` selecting `FLAG_SHOW_MODERN_INFO`); ipcalc.1.md#Deprecated options (`--json`) **Acceptance:** `ipcalc -j -n 2a03:2880:20:4f06:face:b00c:0:1/56` → same output as `ipcalc -j -i …/56`; `ipcalc -j -d 192.168.2.33-192.168.3.2` → JSON object — positive ; test: JsonTestHumanReadableSpecificInfo, DeaggregateJson **Links:** REQ-CLI-OUTPUT-006, REQ-CLI-OUTPUT-011, REQ-CLI-OUTPUT-014 ### REQ-CLI-OUTPUT-004 **Requirement:** In `NAME=value` output ipcalc MUST print one line per selected field, in this fixed order regardless of option order, which is the order of the summary output (REQ-INFO-OUTPUT-003): `ADDRESS` (`-a` or `-o`, printed once when both are given), `HOSTNAME` (`-h`), `NETWORK` (`-n`), `NETMASK` (`-m`), `WILDCARD` (`--wildcard`, IPv4 only), `PREFIX` (`-p`), `CIDR` (`--cidr`), `BROADCAST` (`-b`, IPv4 only), `REVERSEDNS` (`--reverse-dns`), `ADDRSPACE` (`--addrspace`), `MINADDR` (`--minaddr`), `MAXADDR` (`--maxaddr`), `ADDRESSES` (`--addresses`), then `COUNTRYCODE`, `COUNTRY`, `CITY`, `COORDINATES` (`-g`). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`fields[]` order, `field_selected()`); ipcalc.c:main (`FORMAT_SHELL`) **Acceptance:** `ipcalc -abmnp --minaddr --maxaddr --addresses 192.168.2.6/24` → tests/192.168.2.6; `ipcalc -m -n 10.1.2.3/8` → `NETWORK=10.0.0.0`, `NETMASK=255.0.0.0`; `ipcalc -a -o localhost -4` → one `ADDRESS=127.0.0.1` line — positive ; test: SpecificInfoOutput, AllocateAddressSpacePrefix24, FieldOrderNetworkNetmask, AddressAndLookupHost **Links:** REQ-CLI-OUTPUT-005, REQ-INFO-OUTPUT-003 ### REQ-CLI-OUTPUT-005 **Requirement:** In `NAME=value` output ipcalc MUST double-quote a value that contains a byte other than an ASCII letter or digit, one of `. _ : / - , + @ %`, or a byte of 0x80 or above (UTF-8), MUST precede each `"`, `\`, `$` and `` ` `` inside the quotes with a backslash, MUST always double-quote `COORDINATES`, and MUST print a `REVERSEDNS` with more than one domain as a double-quoted, space-separated list, so that the shell's `eval` assigns exactly the value, including a host name from DNS or a geo name that contains shell characters. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_var_field, ipcalc.c:print_shell_value (`shell_safe()`), `ATTR_VAR_QUOTE_ALWAYS`; ipcalc.1.md#Options (`--reverse-dns`) **Acceptance:** `ipcalc --addrspace -abmnp 193.92.150.3/24` → `ADDRSPACE=Internet`; `ipcalc --addrspace 10.0.0.1` → `ADDRSPACE="Private Use"`; `ipcalc --reverse-dns 2001:db8::/31` → `REVERSEDNS="8.b.d.0.1.0.0.2.ip6.arpa. 9.b.d.0.1.0.0.2.ip6.arpa."`; `ipcalc -h 127.0.0.1` with 127.0.0.1 resolving to `a"b\cd` → `eval` sets `HOSTNAME` to that name — positive ; test: AllocateAddressSpacePrefix24, AllocateAddressSpacePrefix64, LookupReverseDNSFromPrefix31IPv6, ShellEscapeHostname (Linux only; tests/fake-getnameinfo.c) ### REQ-CLI-OUTPUT-006 **Requirement:** With `--no-decorate` and without `-j` or `--format` (REQ-CLI-OUTPUT-011), ipcalc MUST print each `NAME=value` line without its `NAME=` prefix, print each reverse DNS domain on its own line, and print the summary output without color; `-j` MUST take precedence over `--no-decorate`. With `--no-decorate` ipcalc MUST double-quote a value that contains a space for `ADDRSPACE`, `ADDRESSES`, `COUNTRY`, and `CITY`, MUST always double-quote `COORDINATES`, and MUST print every other value unchanged, without the quoting and escaping of REQ-CLI-OUTPUT-005, so that a reader that splits at the first space still gets the whole value and a script that reads a single value gets it verbatim. `--no-decorate` is deprecated in favor of `--format=value` and `--format=human` (REQ-CLI-OUTPUT-014), but MUST keep this behavior; `--binary`, which was added after the deprecation, rejects it (REQ-BINARY-INPUT-002). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`if ((flags & FLAG_JSON) && (flags & FLAG_NO_DECORATE)) flags &= ~FLAG_NO_DECORATE`); ipcalc.c:main (`FORMAT_VALUE`, `FORMAT_HUMAN` with `FLAG_NO_DECORATE`); ipcalc.c:show_var_field (`bare`, `ATTR_VALUE_QUOTE_IF_SPACE`, `ATTR_VAR_QUOTE_ALWAYS`); ipcalc.c:pretty_printf; ipcalc.1.md#Deprecated options (`--no-decorate`) **Acceptance:** `ipcalc -abmnp --minaddr --maxaddr --addresses --no-decorate 192.168.2.7/24` → tests/192.168.2.7; `ipcalc --addrspace --no-decorate 10.0.0.1` → `"Private Use"`; `ipcalc --no-decorate -h 127.0.0.1` with 127.0.0.1 resolving to `a"b\cd` → exactly that name; `ipcalc --reverse-dns --no-decorate 2001:db8:abcd::/37` → one domain per line; `ipcalc -j --no-decorate -S 24 10.10.10.0/16` → same as `-j` — positive ; test: SpecificInfoOutputNoDecorate, SpecificInfoOutputNoDecorateQuotedAddrspace, LookupReverseDNSNoDecoratePrefix37IPv6, NoDecorateInfo, JsonNoDecorateSplitPrefix24, NoDecorateHostnameVerbatim (Linux only; tests/fake-getnameinfo.c) ### REQ-CLI-OUTPUT-007 **Requirement:** ipcalc MUST emit ANSI color codes in the summary output, in `--format=human` output (REQ-CLI-OUTPUT-012), and in the binary diagram (REQ-BINARY-OUTPUT-006) only when stdout is a terminal and the `NO_COLOR` environment variable is unset, and MUST NOT emit them with `--no-decorate` or in split, deaggregate, comparison, `NAME=value`, value, or JSON output. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`isatty(STDOUT_FILENO) && getenv("NO_COLOR") == 0`, set after the split/deaggregate/check returns); ipcalc.c:va_color_printf, ipcalc.c:color_fputs; ipcalc.1.md#Environment (`NO_COLOR`) **Acceptance:** any test in tests/meson.build (stdout not a TTY) → no escape codes — positive ; test: all `--test-outfile` tests (no TTY test exists) ### REQ-CLI-OUTPUT-008 **Requirement:** JSON output MUST be a single JSON object whose values are all JSON strings or arrays of strings — including numeric values such as `PREFIX`, `ADDRESSES`, and `NETS` — so that consumers can rely on stable value types. Every string value MUST be escaped as RFC 8259 requires — `"` and `\` preceded by a backslash, and control characters U+0000–U+001F written as `\u00XX` — so that the output is valid JSON even when a value obtained from DNS (`HOSTNAME`) or from a geo database (`COUNTRY`, `CITY`) contains such characters. Other bytes MUST be copied unchanged; the geo backend returns UTF-8. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:va_json_printf, ipcalc.c:json_print_string, array_start (separator when the array is not the first field), output_start/output_stop; ipcalc-maxmind.c (`MMDB_DATA_TYPE_UTF8_STRING`) **Acceptance:** `ipcalc --all-info --json 192.168.2.7/24` → tests/json-all-info-192.168.2.7-24 (`"PREFIX":"24"`, `"REVERSEDNS":["…"]`); `ipcalc -j -h 127.0.0.1` with 127.0.0.1 resolving to `a"b\cd` → valid JSON whose `HOSTNAME` decodes to that name — positive ; test: JsonAllInfoReverseDNSPrefix24IPv4, JsonSplitPrefix26, JsonSplitVLSMUnused, DeaggregateJson, JsonEscapeHostname (Linux only, needs `jq`; resolution faked with an `LD_PRELOAD` shim, tests/fake-getnameinfo.c) **Links:** REQ-INFO-OUTPUT-005, REQ-GEO-OUTPUT-001 ### REQ-CLI-OUTPUT-011 **Requirement:** `--format=FORMAT` MUST select the output format, where FORMAT is `human` (titled lines, as in the summary of REQ-INFO-OUTPUT-001), `shell` (`NAME=value` lines, REQ-CLI-OUTPUT-005), `json` (a JSON object, REQ-CLI-OUTPUT-008), or `value` (values only, as with `--no-decorate`, REQ-CLI-OUTPUT-006), so that the format can be chosen explicitly instead of being inferred from the other options. Without `--format` the output MUST stay as REQ-CLI-OUTPUT-002, -003 and -006 describe. `-j` with `--format=json` and `--no-decorate` with `--format=value` MUST be accepted as that same format. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`OPT_FORMAT`, `legacy_format()`); ipcalc.c:format_names, ipcalc.c:parse_format, ipcalc.c:select_format; ipcalc.c:long_options, ipcalc.c:usage; ipcalc.1.md#Options (`--format`) **Acceptance:** `ipcalc --format=human 192.168.2.0/24` → tests/standard-192.168.2.0-24; `ipcalc --format=json --all-info 192.168.2.7/24` → tests/json-all-info-192.168.2.7-24; `ipcalc --format=shell -m -n 10.1.2.3/8` → same as `ipcalc -m -n 10.1.2.3/8`; `ipcalc --format=value -m -n 10.1.2.3/8` → same as with `--no-decorate`; `ipcalc --format=value -h 127.0.0.1` with 127.0.0.1 resolving to `a"b\cd` → exactly that name; `ipcalc -j --format=json -n 10.1.2.3/8`, `ipcalc --no-decorate --format=value -n 10.1.2.3/8` → exit 0 — positive ; test: FormatHumanSummary, FormatJsonAllInfo, FormatShellFields, FormatValueFields, FormatValueHostnameVerbatim, FormatJsonWithJ, FormatValueWithNoDecorate **Links:** REQ-CLI-OUTPUT-002, REQ-CLI-OUTPUT-012, REQ-CLI-OUTPUT-013, REQ-CLI-ERR-009 ### REQ-CLI-OUTPUT-012 **Requirement:** With `--format` in info mode, the field-selecting options (REQ-CLI-OUTPUT-004) MUST select exactly the fields printed, in the order of REQ-CLI-OUTPUT-004, and without them ipcalc MUST print the summary (REQ-INFO-OUTPUT-001, or with `--all-info` its full form), so that what is printed does not depend on the format. A selected field MUST be printed as its summary line in `human` format (e.g. `Network:\t10.1.2.0/8`), as `NAME=value` in `shell`, as a JSON object holding only the selected keys in `json`, and as its value in `value`. The summary in `shell` format MUST print the keys of the JSON summary (REQ-INFO-OUTPUT-003), in that order. `-o` given with `-i` or `--all-info` MUST only supply the address whose summary is printed. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:select_format (`FLAG_RESOLVE_IP` with `FLAG_SHOW_MODERN_INFO`); ipcalc.c:main (`!selected_fields`); ipcalc.c:show_info_fields, ipcalc.c:field_selected, ipcalc.c:field_in_summary (`FORMAT_HUMAN`) **Acceptance:** `ipcalc --format=json -m -n 192.168.2.7/24` → `{"NETWORK":"192.168.2.0","NETMASK":"255.255.255.0"}`; `ipcalc --format=human -m -n 192.168.2.7/24` → `Network:\t192.168.2.0/24`, `Netmask:\t255.255.255.0 = 24`; `ipcalc --format=shell 192.168.2.7/24` → tests/shell-192.168.2.7-24; `ipcalc --format=json --reverse-dns 2001:db8::/31` → `"REVERSEDNS"` array of two domains; `ipcalc --format=json -h 127.0.0.1` → `{"HOSTNAME":"localhost"}`; `ipcalc --format=json -4 -o localhost` → `{"ADDRESS":"127.0.0.1"}`; `ipcalc --format=json -i -4 -o localhost` → tests/hostname-localhost-ipv4-json — positive ; test: FormatJsonFields, FormatHumanFields, FormatShellSummary, FormatJsonReverseDNS, FormatJsonHostname, FormatJsonLookupHost, FormatJsonInfoLookupHost **Links:** REQ-CLI-OUTPUT-011, REQ-INFO-OUTPUT-003, REQ-GEO-OUTPUT-001 ### REQ-CLI-OUTPUT-013 **Requirement:** With `--format`, split (`-S`, `--split-hosts`) and deaggregate (`-d`) output MUST be printed as without any format option for `human`, as with `-j` for `json`, and as with `--no-decorate` for `value`. Binary mode (`--binary`) MUST accept all four formats (REQ-BINARY-OUTPUT-001 to REQ-BINARY-OUTPUT-003). Comparison mode MUST print its result line (REQ-CLI-OUTPUT-010) with `--format=human`. Check mode and `-v` MUST ignore `--format`. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:select_format (`FORMAT_JSON` → `FLAG_JSON`, `FORMAT_VALUE` → `FLAG_NO_DECORATE`), read by netsplit.c, deaggregate.c, netcompare.c; binary.c:show_binary (`format`) **Acceptance:** `ipcalc --format=value -S 26 192.168.5.45/24` → tests/nsplit-192.168.5.45-24-26; `ipcalc --format=json -S 26 192.168.5.45/24` → tests/json-split-192.168.5.45-24-26; `ipcalc --format=human -S 26 192.168.5.45/24` → tests/split-192.168.5.45-24-26; `ipcalc --format=value -d 192.168.2.7-192.168.2.13` → tests/deaggregate-192.168.2.7-192.168.2.13; `ipcalc --format=human 192.168.7.15/24 --equals=192.168.7.5/24` → `The networks are equal`, exit 0; `ipcalc -c --format=shell 127.0.0.1` → exit 0 — positive ; test: FormatValueSplit, FormatJsonSplit, FormatHumanSplit, FormatValueDeaggregate, FormatHumanEquals, FormatCheck **Links:** REQ-CLI-OUTPUT-011, REQ-CLI-ERR-009 ### REQ-CLI-OUTPUT-014 **Requirement:** When `-j` or `--no-decorate` is given without `--format`, stderr is a terminal, and `-s` is not given, ipcalc MUST print one line to stderr naming the replacement of the deprecated option, so that interactive users learn `--format` while scripts, whose stderr is not a terminal, see no change. The output and exit status MUST be unchanged. The first row that applies is used: | Given | Hint | |-------|------| | `-j` in comparison mode | `ipcalc: hint: -j is deprecated; use -s to print no result` | | `-j` with a field-selecting option | `ipcalc: hint: -j is deprecated; use --format=json, which prints only the selected fields` | | `-j` | `ipcalc: hint: -j is deprecated; use --format=json` | | `--no-decorate` in comparison mode | `ipcalc: hint: --no-decorate is deprecated; use -s to print no result` | | `--no-decorate` with a field-selecting option, `-S`, `--split-hosts` or `-d` | `ipcalc: hint: --no-decorate is deprecated; use --format=value` | | `--no-decorate` | `ipcalc: hint: --no-decorate is deprecated; use --format=human` | **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:suggest_format (`isatty(STDERR_FILENO)`, `beSilent`) **Acceptance:** with a terminal on stderr (tests/fake-isatty.c): `ipcalc -j 10.0.0.1/24`, `ipcalc -j -m 10.0.0.1/24`, `ipcalc -j 10.0.0.0/8 --equals=10.0.0.0/8`, `ipcalc --no-decorate -m 10.0.0.1/24`, `ipcalc --no-decorate -S 26 10.0.0.0/24`, `ipcalc --no-decorate 10.0.0.1/24` → the hint on stderr — positive; `ipcalc --format=json -m 10.0.0.1/24`, `ipcalc -m -n 10.0.0.1/24`, `ipcalc --format=value -S 26 10.0.0.0/24`, `ipcalc -s -j 10.0.0.1/24` → no hint; every other test (stderr not a terminal) → no hint — negative ; test: HintJson, HintJsonFields, HintJsonEquals, HintNoDecorateFields, HintNoDecorateSplit, HintNoDecorateSummary, NoHintFormat, NoHintFields, NoHintFormatValueSplit, NoHintSilent **Links:** REQ-CLI-OUTPUT-003, REQ-CLI-OUTPUT-006, REQ-CLI-OUTPUT-011, REQ-CLI-ERR-006, REQ-CLI-COMPAT-001 ### REQ-CLI-ERR-009 **Requirement:** ipcalc MUST reject these uses of `--format`, printing the message to stderr (subject to `-s`, REQ-CLI-ERR-006) and exiting with status 1, or 2 with a comparison option (REQ-CLI-OUTPUT-009), so that every accepted combination has a single meaning and each message names the alternative: | Condition | Message | |-----------|---------| | FORMAT is not one of the four names | `ipcalc: unknown output format: FORMAT; use human, shell, json or value` | | two different `--format` values | `ipcalc: conflicting output formats: --format=A and --format=B` | | `-j` with `--format` other than `json` | `ipcalc: conflicting output formats: -j and --format=B` | | `--no-decorate` with `--format` other than `value` | `ipcalc: conflicting output formats: --no-decorate and --format=B` | | `-i` or `--all-info` with a field-selecting option other than `-o` | `ipcalc: -i and --all-info cannot be combined with specific field options` | | `value` without a field-selecting option in info mode | `ipcalc: --format=value needs specific field options; use --format=shell or --format=json` | | `shell` with `-S`, `--split-hosts` or `-d` | `ipcalc: --format=shell is not supported with --split, --split-hosts or --deaggregate; use --format=value` | | `json`, `value` or `shell` with a comparison option | `ipcalc: --format=B is not supported with --equals, --subnet-of or --overlaps` | **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:parse_format, ipcalc.c:select_format, ipcalc.c:format_conflict (after option parsing); ipcalc.c:check_format_for_app (after the mode check) **Acceptance:** `ipcalc --format=xml 10.0.0.1`, `ipcalc --format=json --format=shell 10.0.0.1`, `ipcalc -j --format=shell 10.0.0.1`, `ipcalc --no-decorate --format=json -m 10.0.0.1`, `ipcalc --format=json -i -m 10.0.0.1`, `ipcalc --format=human --all-info -n 10.0.0.1/24`, `ipcalc --format=value 10.0.0.1/24`, `ipcalc --format=shell -S 26 10.0.0.0/24`, `ipcalc --format=shell -d 10.0.0.1-10.0.0.9` → the message, exit 1; `ipcalc --format=json 10.0.0.0/8 --equals=10.0.0.0/8`, `ipcalc --format=value 10.0.0.0/8 --subnet-of=10.0.0.0/7`, `ipcalc --format=shell 10.0.0.0/8 --overlaps=10.0.0.0/7` → the message, exit 2; `ipcalc -s --format=xml 10.0.0.1` → no output, exit 1 — negative ; test: FormatUnknown, FormatTwice, FormatConflictJson, FormatConflictNoDecorate, FormatInfoWithField, FormatAllInfoWithField, FormatValueSummary, FormatShellSplit, FormatShellDeaggregate, FormatJsonEquals, FormatValueSubnetOf, FormatShellOverlaps, FormatUnknownSilent **Links:** REQ-CLI-OUTPUT-011, REQ-CLI-OUTPUT-012, REQ-CLI-OUTPUT-013, REQ-CLI-ERR-006 ## Compatibility with earlier releases Written with `contrib/ai/protocols/requirements-elicitation.md`. These requirements apply to every mode and to both IPv4 and IPv6; "an invocation" is a command line (options and arguments) given the same input, the same geo database, and the same DNS answers. ### REQ-CLI-COMPAT-003 **Requirement:** For an invocation that printed JSON in a release (`-j`/`--json`, in any mode), every later version MUST print a JSON object that contains every key that release printed, with the same key name, the same JSON type (string or array of strings), and the value in the same format (e.g. `PREFIX` as a decimal string, `NETWORK` without the prefix, `REVERSEDNS` as an array). A later version MAY add keys, and the relative order of keys is not part of this contract, since JSON objects are unordered (RFC 8259), so that programs that parse ipcalc's JSON keep working across updates. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields, ipcalc.c:show_json_field, ipcalc.c:va_json_printf; netsplit.c; deaggregate.c; tests/json-* **Acceptance:** `ipcalc --all-info --json 192.168.2.7/24` → contains every key and value of the 1.1.0 tests/json-all-info-192.168.2.7-24 (current output adds `WILDCARD` and `CIDR`); `ipcalc -j -h 127.0.0.1` → contains every key and value of the 1.1.0 tests/ip-localhost-ipv4-json — positive ; a change that renames `ADDRSPACE`, drops `BROADCAST`, or prints `PREFIX` as a JSON number fails JsonAllInfoReverseDNSPrefix24IPv4 — negative ; test: every JSON `--test-outfile` test (e.g. JsonAllInfoReverseDNSPrefix24IPv4, IPIPv4LocalhostJson, JsonSplitPrefix26, DeaggregateJson); review: a patch may change an existing JSON expected-output file only by adding keys or by a change REQ-CLI-COMPAT-005 permits **Links:** REQ-CLI-OUTPUT-008, REQ-INFO-OUTPUT-003, REQ-CLI-COMPAT-005 ### REQ-CLI-COMPAT-004 **Requirement:** For an invocation that printed `NAME=value` output in a release, every later version MUST print every `NAME=value` line that release printed, with the same name, the same value in the same format, and the same quoting (REQ-CLI-OUTPUT-005), so that scripts that `eval` the output or look up a variable by name keep working across updates. A later version MAY change the quoting of a value only where the release's line did not assign that value under `eval` (e.g. `HOSTNAME=a"b`), which is a bug that REQ-CLI-COMPAT-005 lets a patch fix. A later version MAY print the lines in a different order and MAY add lines. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`NAME=value` loop), ipcalc.c:show_var_field **Acceptance:** `ipcalc -abmnp 10.10.10.5/24` → every line of the 1.1.0 tests/192.168.1.5-24 (the current version prints `NETWORK=` second where 1.1.0 printed it fifth); `ipcalc -h 127.0.0.1` with 127.0.0.1 resolving to `a"b\cd` → a line that `eval` assigns to `HOSTNAME`, where 1.1.0 printed it unquoted — positive ; a change that renames `NETMASK=`, drops `BROADCAST=`, or stops quoting `ADDRSPACE="Private Use"` — negative ; test: TestPrefix24, SpecificInfoOutput, AllocateAddressSpacePrefix24, FieldOrderNetworkNetmask, ShellEscapeHostnameDefault; review: a patch may change an existing `NAME=value` expected-output file only by reordering or adding lines, or by a change REQ-CLI-COMPAT-005 permits **Links:** REQ-CLI-OUTPUT-004, REQ-CLI-OUTPUT-005, REQ-CLI-COMPAT-005, REQ-CLI-COMPAT-007 ### REQ-CLI-COMPAT-005 **Requirement:** Every information item that a release printed for an invocation — in the decorated, `--no-decorate`, `NAME=value`, or JSON output — MUST be printed by every later version for the same invocation, in the same output format. The test suite is the gatekeeper: a patch MUST NOT delete a test or remove an information item from an expected-output file in `tests/` unless the item was printed because of a bug, i.e. it is wrong per a requirement in `doc/requirements/`, or it was printed although none of the given options requests it (e.g. a hostname printed without `-h` or `-o`). Such a removal MUST come with a requirement describing the correct behavior, a test, and a `NEWS` entry, so that users never lose information on an update except when it was a defect. **Strength:** MUST **Status:** DERIVED **Source:** tests/meson.build; tests/*; AGENTS.md#Requirements-first workflow **Acceptance:** `ninja -C build test` passes with the expected-output files of the latest release unchanged, or changed only by additions or by documented bug-fix removals — positive ; a patch that drops the `Hosts/Net` line from tests/info-192.168.2.7 or deletes the Info test without a bug-fix requirement — negative ; test: all `--test-outfile` tests; review **Links:** REQ-CLI-COMPAT-003, REQ-CLI-COMPAT-004, REQ-CLI-COMPAT-006, REQ-CLI-COMPAT-007, REQ-GEN-TEST-002 ### REQ-CLI-COMPAT-006 **Requirement:** In the decorated and `--no-decorate` summary output, and in the decorated split and deaggregate output, a later version MAY change the presentation — labels, order of lines, alignment, separators, blank lines, and color — and MAY add information items, but MUST NOT remove an information item a release printed for the same invocation except as REQ-CLI-COMPAT-005 permits, so that the human-readable output can be improved without losing content. **Strength:** MUST NOT **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (summary loop), ipcalc.c:show_text_field; netsplit.c; deaggregate.c **Acceptance:** `ipcalc --all-info 192.168.2.7/24` → every information item of the 1.1.0 tests/all-info-192.168.2.7 (current output adds `Wildcard`) — positive ; a change after which `ipcalc -i 192.168.2.7/24` no longer prints the address `192.168.2.7` fails Info — negative ; test: Info, AllInfo, StandardInfo, NoDecorateAllInfo, TestHumanReadableLoopback; review: an edit of a summary expected-output file that removes a value **Links:** REQ-CLI-COMPAT-005, REQ-INFO-OUTPUT-001 ### REQ-CLI-COMPAT-007 **Requirement:** For an invocation with `--no-decorate` and without `-j` that printed a single information item in a release — one field-selecting option (e.g. `-n`, `--addrspace`, `--reverse-dns`), or the subnet list of split mode or the network list of deaggregate mode — every later version MUST print byte-identical stdout for it and MUST NOT add lines or other information items to it, so that `$(ipcalc --no-decorate -n …)` and scripts that read the list line by line keep working across updates. With two or more field-selecting options, `--no-decorate` output is covered by REQ-CLI-COMPAT-005 only. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields, ipcalc.c:show_var_field (`bare`); netsplit.c; deaggregate.c **Acceptance:** `ipcalc --addrspace --no-decorate 10.0.0.1` → exactly `"Private Use"`; `ipcalc --wildcard --no-decorate 172.16.5.4/12` → exactly `0.15.255.255`; `ipcalc --cidr --no-decorate 2001:db8::1/64` → exactly `2001:db8::/64`; `ipcalc --reverse-dns --no-decorate 2001:db8:abcd::/37` → tests/reverse-dns-no-decorate-2001:db8:abcd::-37; `ipcalc --no-decorate -S 26 192.168.5.45/24` → tests/nsplit-192.168.5.45-24-26; `ipcalc --no-decorate -h 127.0.0.1` with 127.0.0.1 resolving to `a"b\cd` → exactly that name, unquoted — positive ; a change after which `ipcalc -n --no-decorate 10.1.2.3/8` prints `10.0.0.0/8`, or prints the prefix on a second line — negative ; test: SpecificInfoOutputNoDecorateQuotedAddrspace, WildcardNoDecorate, CidrNoDecorateIPv6, LookupReverseDNSNoDecoratePrefix37IPv6, NoDecorateSplitPrefix26, NoDecorateHostnameVerbatim; review: a patch MUST NOT change the expected output of such a test except as REQ-CLI-COMPAT-005 permits **Links:** REQ-CLI-OUTPUT-006, REQ-CLI-COMPAT-005 ### REQ-CLI-COMPAT-008 **Requirement:** For an invocation with `-c`, `--equals`, `--subnet-of`, or `--overlaps`, every later version MUST return the exit status a release returned for it — 0 or 1 for `-c` (REQ-CLI-OUTPUT-001), and 0, 1, or 2 for the comparison options (REQ-CLI-OUTPUT-009) — whether that status reported success or failure, since in these modes the exit status is the result. For an invocation in any other mode — info (including `-r` and field-selecting options), split, deaggregate, `-v`, `--help`, and `--usage` — that exited with status 0 in a release, every later version MUST exit with status 0, unless the invocation succeeded because of a bug, i.e. a requirement in `doc/requirements/` says it must fail; such a change MUST come with that requirement, a test, and a `NEWS` entry (e.g. `-h` with a network, REQ-INFO-ERR-001). A later version MAY make an invocation of these modes that failed in a release succeed. This applies to IPv4 and IPv6, so that scripts that test `$?` or run under `set -e` keep working across updates. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case APP_CHECK_ADDRESS`, `case APP_COMPARE`, `badOption`), ipcalc.c:exit_failure; netcompare.c:compare_networks; tests/ipcalc-testrunner.sh (`TestOutputFile` requires exit status 0) **Acceptance:** `ipcalc -c 127.0.0.1` → exit 0; `ipcalc -c -6 gggg::`, `ipcalc -c ::1/999` → exit 1; `ipcalc 192.168.7.15/24 --equals=192.168.7.5/24` → exit 0; `ipcalc 192.168.1.15/24 --overlaps=192.168.7.1/24` → exit 1; `ipcalc 1.2.3 --equals=1.2.3.0/24` → exit 2; every `--test-outfile` command (info, split, deaggregate) → exit 0, which the test runner checks — positive ; a change after which `ipcalc -c ::1/999` exits 0, `ipcalc 192.168.1.15/24 --overlaps=192.168.7.1/24` exits 2, or `ipcalc -i 192.168.2.7/24` exits 1 fails NoValidateInvalidPrefixIPv6, OverlapsDisjoint, or Info — negative ; test: ValidateLoopbackIPv4, ValidateLoopbackIPv6WithPrefix, NoValidateInvalidHexIPv6, NoValidateInvalidPrefixIPv6, EqualsHostBits, OverlapsDisjoint, EqualsBadInputAddress, all `--test-outfile` tests; review: a patch MUST NOT change the expected status of an existing `--test-success`, `--test-failure`, or `--test-status` test for these modes **Links:** REQ-CLI-OUTPUT-001, REQ-CLI-OUTPUT-009, REQ-CLI-COMPAT-005, REQ-INFO-ERR-001, REQ-GEN-TEST-001 ## Documentation consistency ### REQ-CLI-COMPAT-001 **Requirement:** Every option ipcalc accepts MUST be described in `ipcalc.1.md` and in the `--help` output, with the same argument syntax, except the deprecated `-j`/`--json` and `--no-decorate` (REQ-CLI-OUTPUT-014). Those MUST be described only in the "Deprecated options" section of `ipcalc.1.md`, each with its `--format` replacement, and MUST NOT appear in `--help` or `--usage`, so that users learn `--format` while the man page still explains commands that use them. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:long_options, ipcalc.c:usage; ipcalc.1.md#Options, ipcalc.1.md#Deprecated options **Acceptance:** review: each `long_options` entry other than `json` and `no-decorate` appears in `usage(1)` and in ipcalc.1.md#Options; `json` and `no-decorate` appear only in ipcalc.1.md#Deprecated options — positive ; test: none **Links:** REQ-CLI-OUTPUT-014 ### REQ-CLI-COMPAT-002 **Requirement:** The `--usage` summary SHOULD list every option except the deprecated ones (REQ-CLI-COMPAT-001). **Strength:** SHOULD **Status:** REVIEW **Source:** ipcalc.c:usage (`verbose == 0` branch) **Acceptance:** `ipcalc --usage` → lists `-S`, `--split-hosts`, `-d`, `--format` — positive ; test: none > [REVIEW: drift] The brief usage omits `-S/--split`, `--split-hosts`, > and `-d/--deaggregate`. ## Open items `REVIEW`: REQ-CLI-ERR-006 (unguarded messages), REQ-CLI-COMPAT-002 (`--usage` drift). `UNDOCUMENTED`: extra arguments ignored (REQ-CLI-INPUT-004). Missing tests: REQ-CLI-INPUT-002, REQ-CLI-ERR-003, REQ-CLI-ERR-004, REQ-CLI-ERR-006, `-v` mixed with another mode. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/deaggregate.md000066400000000000000000000073561526405142400263420ustar00rootroot00000000000000--- title: Range deaggregation (-d/--deaggregate) id-prefix: REQ-DEAGG sources: - deaggregate.c - ipv6.c - ipcalc.c (main) - ipcalc.1.md - tests/meson.build --- # Range deaggregation (`-d/--deaggregate`) Generated with `contrib/ai/protocols/requirements-from-implementation.md`. ### REQ-DEAGG-INPUT-001 **Requirement:** `-d -` MUST take an address range as two addresses of the same family separated by `-`, ignoring whitespace around each address, and MUST treat the range as IPv6 when it contains `:` or `-6` is given (REQ-CLI-INPUT-005). **Strength:** MUST **Status:** DERIVED **Source:** deaggregate.c:deaggregate (`strtok(str, "-")`, `trim`); ipcalc.c:main; ipcalc.1.md#Options (`--deaggregate`) **Acceptance:** `ipcalc -d " 192.168.2.0 - 192.168.3.255 "` → same as `ipcalc -d 192.168.2.0-192.168.3.255` — positive ; test: DeaggregateSpaces, Deaggregate > [UNDOCUMENTED] Text after a second `-` is ignored: > `ipcalc -d 1.2.3.4-1.2.3.4-1.2.3.9` deaggregates `1.2.3.4-1.2.3.4`. ### REQ-DEAGG-ERR-001 **Requirement:** ipcalc MUST reject, with exit status 1: a range without a `-` separator (`ipcalc: bad deaggregation string: `), an address that is not valid for the range's family (`ipcalc: bad IPv4 address: …` / `ipcalc: bad IPv6 address: …`), and a range whose first address is greater than its last (`ipcalc: bad range` / `ipcalc: bad IPv6 range`). **Strength:** MUST **Status:** DERIVED **Source:** deaggregate.c:deaggregate, deaggregate.c:deaggregate_v4, deaggregate.c:deaggregate_v6 **Acceptance:** `ipcalc -d 1.2.3.4`, `ipcalc -d 1.2.3.4-::5`, `ipcalc -d 1.2.3.5-1.2.3.4` → exit 1 — negative ; test: none ### REQ-DEAGG-CALC-001 **Requirement:** ipcalc MUST print the minimal list of CIDR networks that exactly covers the range, in ascending address order, for every range within the address space — including ranges that start at the first address or end at the last address of the space. **Strength:** MUST **Status:** DERIVED **Source:** deaggregate.c:deaggregate_v4, deaggregate.c:deaggregate_v6, ipv6.c:ipv6_orm **Acceptance:** `ipcalc --no-decorate -d 192.168.2.7-192.168.2.13` → `192.168.2.7/32`, `192.168.2.8/30`, `192.168.2.12/31`; `ipcalc -d 0.0.0.0-255.255.255.255` → `0.0.0.0/0`; `ipcalc -d ::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff` → `::/0`; `ipcalc -d 8000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff` → `8000::/1`; `ipcalc -d ::-8000::` → `::/1`, `8000::/128`; `ipcalc -d ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff` → `ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128` — positive ; test: DeaggregateNoDecorate, Deaggregate, DeaggregateLargeNum, DeaggregateLargeNum2, DeaggregateLargeNum3, DeaggregateIPv6, DeaggregateIPv6NoDecorate, DeaggregateIPv6All, DeaggregateIPv6UpperHalf, DeaggregateIPv6LowerHalf, DeaggregateIPv6LastAddress ### REQ-DEAGG-OUTPUT-001 **Requirement:** The deaggregation output MUST be: decorated — a `[Deaggregated networks]` header and one `Network:\t/` line per network; with `--no-decorate` — only one `/` line per network; with `-j` — an object whose `DEAGGREGATEDNETWORK` key is an array of `/` strings. **Strength:** MUST **Status:** DERIVED **Source:** deaggregate.c (`array_start(…, "Deaggregated networks", "DEAGGREGATEDNETWORK")`, `default_printf`) **Acceptance:** `ipcalc -d 192.168.2.0-192.168.3.255`, `ipcalc --no-decorate -d 192.168.2.7-192.168.2.13`, `ipcalc -j -d 192.168.2.33-192.168.3.2` → the matching tests/deaggregate-… files — positive ; test: Deaggregate, DeaggregateNoDecorate, DeaggregateJson, DeaggregateIPv6Json **Links:** REQ-CLI-OUTPUT-003, REQ-CLI-OUTPUT-008 ## Open items `UNDOCUMENTED`: trailing text after a second `-` ignored (REQ-DEAGG-INPUT-001). Missing tests: all of REQ-DEAGG-ERR-001. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/general.md000066400000000000000000000156201526405142400255110ustar00rootroot00000000000000--- title: Project policy — build configurations and tests id-prefix: REQ-GEN sources: - AGENTS.md - meson.build, meson_options.txt, Makefile - .gitlab-ci.yml - tests/meson.build, tests/ipcalc-testrunner.sh --- # Project policy — build configurations and tests Generated with `contrib/ai/protocols/requirements-from-implementation.md`. These requirements govern how ipcalc is built and tested; they apply to every other document. ### REQ-GEN-BUILD-001 **Requirement:** The source MUST compile without warnings under `-O2 -g -Werror` in every configuration CI builds: no geo backend; libmaxminddb linked; libmaxminddb loaded at run time — with both meson and the legacy Makefile — and with `-Db_sanitize=address,undefined -Dc_args="-fno-sanitize-recover=undefined" -Dwerror=true`. **Strength:** MUST **Status:** DERIVED **Source:** .gitlab-ci.yml (jobs fedora.nogeo, fedora.maxmind, fedora.dyn_maxmind, fedora.sanitizers); AGENTS.md#Build and test **Acceptance:** all CI jobs pass — positive ; test: CI **Links:** REQ-GEO-BUILD-001 ### REQ-GEN-BUILD-002 **Requirement:** The legacy Makefile MUST build ipcalc by compiling every source file, so the geo backend source MUST compile to nothing when `USE_MAXMIND` is undefined, and the Makefile MUST take the version string from `meson.build`. **Strength:** MUST **Status:** DERIVED **Source:** Makefile (`ipcalc:` rule lists all `.c` files; `VERSION=$(shell cat meson.build|…)`); ipcalc-maxmind.c (`#ifdef USE_MAXMIND`); AGENTS.md#Build and test **Acceptance:** `make USE_MAXMIND=no USE_RUNTIME_LINKING=no && ./ipcalc -v` → `ipcalc ` — positive ; test: CI (`make` step of every fedora.* job) ### REQ-GEN-TEST-001 **Requirement:** Every test MUST be registered in `tests/meson.build` and run through `tests/ipcalc-testrunner.sh` in one of its modes (`--test-success`, `--test-failure`, `--test-status`, `--test-output`, `--test-outfile`, `--test-equal`); `--test-outfile` expected-output files MUST live in `tests/`, be named after the command's arguments, and contain the combined stdout and stderr of the command run with stdout not a terminal, and a `--test-outfile` test MUST fail when the command exits with a nonzero status. **Strength:** MUST **Status:** DERIVED **Source:** tests/meson.build; tests/ipcalc-testrunner.sh (`TestOutput` captures `2>&1`, `TestOutputFile` checks the exit status); AGENTS.md#Tests **Acceptance:** `meson test -C build --list` lists every test; `ninja -C build test` passes — positive ; `ipcalc-testrunner.sh --test-outfile 'echo hi; exit 1' FILE` with FILE containing `hi` → fails — negative ; test: all **Links:** REQ-CLI-COMPAT-008 ### REQ-GEN-TEST-002 **Requirement:** Each requirement's **Acceptance** criteria MUST be covered by a test in `tests/meson.build`, including a `--test-failure` (or output-checking) test for each rejected input or option combination, and a bug fix MUST add a test that fails without the fix. **Strength:** MUST **Status:** DERIVED **Source:** AGENTS.md#Requirements-first workflow; contrib/ai/personas/ipcalc-dev.md (Protocol: Testing) **Acceptance:** review: every `REQ-*` cites a test, or lists it under its document's "Missing tests" — positive ; test: none ### REQ-GEN-TEST-003 **Requirement:** A test MUST check the property its name claims; a test that greps output MUST match a pattern that cannot be satisfied by a different field. **Strength:** MUST **Status:** DERIVED **Source:** tests/meson.build (Random, RandomIPv6Implicit, RandomIPv6Explicit anchor on `^Network:` and `^Address:`) **Acceptance:** review of `--test-success … | grep` tests; `ipcalc -r 32` or a non-private network fails the Random test's check — negative ; test: Random, RandomIPv6Implicit, RandomIPv6Explicit **Links:** REQ-RANDOM-OUTPUT-001 ### REQ-GEN-TEST-004 **Requirement:** The test suite MUST pass under AddressSanitizer and UndefinedBehaviorSanitizer with undefined behavior made fatal, since address and prefix arithmetic is the recurring source of defects and an undefined shift can produce the expected output on one platform and not another. **Strength:** MUST **Status:** DERIVED **Source:** .gitlab-ci.yml (job fedora.sanitizers: `-Db_sanitize=address,undefined -Dc_args="-fno-sanitize-recover=undefined"`, `ninja -C build test`); contrib/ai/protocols/memory-safety-c.md (ipcalc extension, Phase 4) **Acceptance:** `meson setup b -Db_sanitize=address,undefined -Dc_args="-fno-sanitize-recover=undefined" && ninja -C b test` → all pass — positive ; test: CI (fedora.sanitizers) **Links:** REQ-GEN-BUILD-001 ### REQ-GEN-TEST-005 **Requirement:** Every test in `tests/meson.build` MUST run in at least one CI job, and each CI job MUST provide every external program used by the tests its build configuration registers, so that no test exists that CI never executes. **Strength:** MUST **Status:** DERIVED **Source:** .gitlab-ci.yml (fedora.* jobs, `.fedora.latest.template` `dnf install` includes `jq`); tests/meson.build **Acceptance:** the union of `meson test -C build --list` over all CI jobs equals the set of `test(...)` names in `tests/meson.build` — positive ; removing `jq` from the CI packages makes JsonEscapeHostname fail (REQ-GEN-TEST-007) — negative ; test: CI **Links:** REQ-GEN-TEST-006, REQ-GEN-TEST-007 ### REQ-GEN-TEST-006 **Requirement:** Every CI job built with sanitizers MUST run every test its build configuration and platform allow, and MUST select its geo backend explicitly rather than rely on auto-detection, so that sanitizer coverage cannot shrink silently when a dependency changes. **Strength:** MUST **Status:** DERIVED **Source:** .gitlab-ci.yml (fedora.sanitizers: `-Duse_maxminddb=enabled -Duse_runtime_linking=enabled`) **Acceptance:** in fedora.sanitizers, `meson test -C build --list` contains every test of fedora.dyn_maxmind's configuration, including JsonEscapeHostname — positive ; with libmaxminddb uninstalled, the job's `meson setup` fails instead of building another backend — negative ; test: CI (fedora.sanitizers) **Links:** REQ-GEN-TEST-004, REQ-GEN-TEST-005 ### REQ-GEN-TEST-007 **Requirement:** In a build from the git source tree, a test that needs an external program (e.g. `jq`) MUST be registered regardless of whether that program is installed, and MUST fail, naming the missing program, when it is not found; the absence of the program MUST NOT skip or unregister the test, nor fail `meson setup`. Only the build configuration (geo backend) and the host platform MAY determine whether a test is registered. This requirement does not apply to release tarballs or installed files. **Strength:** MUST **Status:** DERIVED **Source:** tests/meson.build (JsonEscapeHostname: registered on Linux, checks `command -v jq`) **Acceptance:** with jq on `PATH`, JsonEscapeHostname runs and passes — positive ; without jq, `meson setup` succeeds and `meson test -C build JsonEscapeHostname` fails with a log naming `jq` — negative ; test: JsonEscapeHostname **Links:** REQ-GEN-TEST-001, REQ-GEN-TEST-005 ## Open items None. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/geo.md000066400000000000000000000317361526405142400246540ustar00rootroot00000000000000--- title: Geographic information (-g/--geoinfo) id-prefix: REQ-GEO sources: - ipcalc-maxmind.c - ipcalc.h (geo_ip_lookup, geo_setup stubs) - ipcalc.c (main, get_ipv4_info, get_ipv6_info, long_options, usage) - meson.build, meson_options.txt, Makefile - ipcalc.1.md --- # Geographic information (`-g/--geoinfo`) Generated with `contrib/ai/protocols/requirements-from-implementation.md`. The lookups are tested against databases generated from `tests/geo-*.json` (REQ-GEO-TEST-001), which use documentation addresses: 192.0.2.0/24 and 2001:db8::/48 have a full City record, 198.51.100.0/24 has location data but no country, only a registered or represented country in parts of it; 203.0.113.0/24 is only in the ASN database. ### REQ-GEO-BUILD-001 **Requirement:** ipcalc MUST be buildable with libmaxminddb as its geo backend, either linked at build time or loaded at run time with `dlopen()`, or with no geo backend. libGeoIP, whose databases are no longer published, MUST NOT be supported as a backend; the meson option `use_geoip` MUST still be accepted and ignored, so that existing build commands keep working. **Strength:** MUST **Status:** DERIVED **Source:** meson.build (`use_maxminddb`, `use_runtime_linking`); meson_options.txt (`use_geoip`, unused); Makefile (`USE_MAXMIND`, `USE_RUNTIME_LINKING`); ipcalc.h (stubs when `USE_MAXMIND` is undefined) **Acceptance:** each configuration in `.gitlab-ci.yml` builds with `-Werror` — positive ; `meson setup -Duse_maxminddb=disabled -Duse_geoip=enabled` builds without a geo backend (`-g` rejected) — positive ; test: CI jobs (fedora.nogeo passes `-Duse_geoip=enabled`; not a meson test) **Links:** REQ-GEN-BUILD-001 ### REQ-GEO-INPUT-001 **Requirement:** `-g`/`--geoinfo` MUST be accepted only when ipcalc is built with a geo backend. In a build without one, both forms MUST be rejected as unrecognized options (REQ-CLI-ERR-002, exit status 1), and neither `--help` nor `--usage` MUST list them, so that a script relying on geo output fails instead of silently getting none. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:long_options, ipcalc.c:usage, ipcalc.c:main (`GEO_SHORT_OPTION`, `case 'g'`) — all under `#ifdef USE_MAXMIND`; meson.build (`have_geo`); ipcalc.1.md#Options (`--geoinfo`) **Acceptance:** build with a backend: `ipcalc -g 127.0.0.1` → exit 0 — positive ; build without a backend: `ipcalc -g 127.0.0.1`, `ipcalc --geoinfo 127.0.0.1` → exit 1; `ipcalc --usage` → does not mention `-g` or `--geoinfo` — negative ; test: GeoInfoAccepted (with a backend), GeoInfoShortUnavailable, GeoInfoLongUnavailable, GeoInfoNotInUsage (without a backend) **Links:** REQ-CLI-ERR-002, REQ-CLI-COMPAT-002, REQ-GEO-ERR-001 ### REQ-GEO-CALC-001 **Requirement:** With `-g`, or with `--all-info` when the backend is usable, ipcalc MUST look up the input address (not the network address) in the system geo databases, subject to REQ-GEO-CALC-002, and report the English continent name (`continent/names/en`) and the country name and ISO country code (REQ-GEO-CALC-003) from the Country database; the English city name (`city/names/en`), the postal code (`postal/code`), the `,` coordinates (printed with `%f`), the accuracy radius of the coordinates in kilometers (`location/accuracy_radius`), and the IANA time zone (`location/time_zone`) from the City database; the autonomous system number (`autonomous_system_number`) and organization (`autonomous_system_organization`) from the ASN database; the network of the records (REQ-GEO-CALC-004); and the network of the ASN record (REQ-GEO-CALC-005); omitting any value not found. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:get_ipv4_info, ipcalc.c:get_ipv6_info (`geo_ip_lookup(ipStr, …)`), ipcalc.c:main (`geo_setup() == 0 && FLAG_SHOW_ALL_INFO`); ipcalc-maxmind.c:geo_ip_lookup (GeoLite2-Country.mmdb, GeoLite2-City.mmdb, GeoLite2-ASN.mmdb under /usr/share/GeoIP by default); ipcalc.1.md#Options (`--geoinfo`, `--all-info`) **Acceptance:** with a backend and databases: `ipcalc -g 193.92.150.2` → `COUNTRYCODE=GR`, `COUNTRY=Greece` (ipcalc.1.md example); with the test databases: `-g 192.0.2.5` → tests/geo-192.0.2.5 (with `CONTINENT=Europe`, `CITY=Athens`, `POSTALCODE="105 52"`, `ACCURACYRADIUS=200` and `TIMEZONE=Europe/Athens`, `ASN=64496`, `ASORG="Example Net"`), `-g 203.0.113.1` (only in the ASN database) → only `ASN`, `ASORG`, `ASNETWORK` and `GEONETWORK`, `-g 2001:db8::1` → tests/geo-2001:db8::1 (with `CITY=Berlin`), `-g 198.51.100.200` (no country of any kind, city, or postal code) → only `CONTINENT`, `COORDINATES`, `ACCURACYRADIUS=1000`, `TIMEZONE` and `GEONETWORK` — positive ; test: GeoInfoIPv4, GeoInfoIPv6, GeoInfoNoCountry, GeoInfoASNOnly **Links:** REQ-CLI-OUTPUT-004, REQ-INFO-OUTPUT-001, REQ-INFO-OUTPUT-003 ### REQ-GEO-CALC-002 **Requirement:** For a network, ipcalc MUST report the values of a database record only when the whole input network lies within the network of that record, i.e. when the input prefix is not shorter than the record's, and MUST omit them otherwise, since they are known only for a part of the input network. This applies to the Country, City, and ASN databases separately; for an IPv4 address in an IPv6 database, the record's prefix is taken relative to the IPv4 subtree (`::/96`). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc-maxmind.c:lookup (`result->netmask` compared with the input prefix), ipcalc-maxmind.c:geo_ip_lookup; ipcalc.c:get_ipv4_info, ipcalc.c:get_ipv6_info (pass the prefix); ipcalc.1.md#Options (`--geoinfo`) **Acceptance:** with the test databases (Country record 192.0.0.0/22, City and ASN records 192.0.2.0/24): `-g 192.0.2.0/24` → country, city, coordinates, radius and ASN; `-g 192.0.2.77/23` → only the continent, the country and `GEONETWORK` (no ASN); `-g 2001:db8::/32` (Country and ASN /32, City /48) → only the continent, the country, the ASN and `GEONETWORK` — positive ; `--all-info 192.0.0.0/16` → no geo lines, exit 0 — negative ; test: GeoInfoNetworkWithinRecords, GeoInfoNetworkLargerThanCity, GeoInfoNetworkLargerThanCityIPv6, GeoInfoNetworkLargerThanRecords **Links:** REQ-GEO-CALC-001, REQ-CLI-COMPAT-005 ### REQ-GEO-CALC-003 **Requirement:** When the Country database record has no `country`, ipcalc MUST report the name and ISO code of its `represented_country` (the country its users represent, e.g. for a military base) or, without one, of its `registered_country` (the country in which the network is registered) as the country, taking the name and the code from the same one of the three; when the record has none of them, the country MUST be omitted. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc-maxmind.c:geo_ip_lookup (`country_keys`) **Acceptance:** with the test databases: `-g 198.51.100.5` (only `registered_country` US) → `COUNTRYCODE=US`, `COUNTRY="United States"`; `-g 198.51.100.130` (`represented_country` US, `registered_country` DE) → `COUNTRYCODE=US` — positive ; `-g 198.51.100.200` (none of them) → no `COUNTRYCODE` — negative ; test: GeoInfoRegisteredCountry, GeoInfoRepresentedCountry, GeoInfoNoCountry **Links:** REQ-GEO-CALC-001 ### REQ-GEO-CALC-004 **Requirement:** ipcalc MUST report as the geo network the network, in CIDR notation, of the database record from which it reported values or, when it reported values from several of the Country, City and ASN records, the smallest of their networks, which is the network for which all reported values hold; for an IPv4 address in an IPv6 database the network MUST be printed as IPv4. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc-maxmind.c:geo_ip_lookup (`record_prefix`), ipcalc-maxmind.c:record_network **Acceptance:** with the test databases: `-g 192.0.2.5` (Country /22, City /24) → `GEONETWORK=192.0.2.0/24`; `-g 198.51.100.5` (Country /25, City /24, ASN /27) → `GEONETWORK=198.51.100.0/27`; `-g 198.51.100.200` (Country /26, City /24, no ASN) → `GEONETWORK=198.51.100.192/26`; `-g 192.0.2.77/23` (City omitted) → `GEONETWORK=192.0.0.0/22`; `-g 2001:db8::1` → `GEONETWORK=2001:db8::/48` — positive ; `--all-info 192.0.0.0/16` (no record covers it) → no geo network — negative ; test: GeoInfoIPv4, GeoInfoRegisteredCountry, GeoInfoNoCountry, GeoInfoNetworkLargerThanCity, GeoInfoIPv6, GeoInfoNetworkLargerThanRecords **Links:** REQ-GEO-CALC-001, REQ-GEO-CALC-002 ### REQ-GEO-CALC-005 **Requirement:** When ipcalc reports the values of the ASN database record (REQ-GEO-CALC-002), it MUST also report as the AS network the network of that record, in CIDR notation, independently of the Country and City records; for an IPv4 address in an IPv6 database the network MUST be printed as IPv4. This applies to IPv4 and IPv6. The ASN database is built from routing data, so its record's network approximates the prefix the AS announces, which is the network the address belongs to (e.g. the ISP's allocation), whereas the geo network (REQ-GEO-CALC-004) is usually the much smaller network of the City record. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc-maxmind.c:geo_ip_lookup (`record_prefix` of the ASN lookup), ipcalc-maxmind.c:record_network; ipcalc.1.md#Options (`--geoinfo`) **Acceptance:** with the test databases: `-g 2001:db8::1` (ASN /32, City /48) → `ASNETWORK=2001:db8::/32` and `GEONETWORK=2001:db8::/48`; `-g 192.0.2.5` → `ASNETWORK=192.0.2.0/24`; `-g 198.51.100.5` (ASN /27) → `ASNETWORK=198.51.100.0/27`; `-g 203.0.113.1` (only in the ASN database) → `ASNETWORK=203.0.113.0/24` — positive ; `-g 198.51.100.200` (no ASN record) and `-g 192.0.2.77/23` (ASN record omitted) → no `ASNETWORK` — negative ; test: GeoInfoIPv6, GeoInfoIPv4, GeoInfoRegisteredCountry, GeoInfoASNOnly, GeoInfoNoCountry, GeoInfoNetworkLargerThanCity **Links:** REQ-GEO-CALC-001, REQ-GEO-CALC-002, REQ-GEO-CALC-004 ### REQ-GEO-ERR-001 **Requirement:** A missing database or an address not found in it MUST NOT be an error: ipcalc MUST print the remaining output without the geo fields and exit with status 0. When the backend library cannot be loaded at run time, `-g` MUST print `ipcalc: could not open ; geographic information requires libmaxminddb and the GeoLite2 databases, install them if they are missing` (or `could not find symbols in …`) to stderr unless `-s` is given, so that the user learns what to install, and `--all-info` MUST omit the geo fields silently. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc-maxmind.c:geo_ip_lookup (a database that `lookup()` cannot open or that has no record leaves its values NULL), ipcalc-maxmind.c:geo_setup (storing and printing `err` on the second call); ipcalc.c:main **Acceptance:** runtime-linked build without the library (`ipcalc-nolib`, a test build that loads the library from a nonexistent directory): `-g 192.0.2.5` → tests/geo-nolib-192.0.2.5 (the message on stderr), exit 0; `--all-info 192.0.2.5` → tests/geo-nolib-all-info-192.0.2.5 (no geo lines, no message), exit 0; `-s -g 192.0.2.5` → no output; with the test databases: `--all-info 10.0.0.1` (not in them) → no geo lines, exit 0 — positive ; test: GeoInfoNotFound, GeoLibraryMissing, GeoLibraryMissingAllInfo, GeoLibraryMissingSilent (the last three in runtime-linked builds only) ### REQ-GEO-OUTPUT-001 **Requirement:** Geo values MUST be printed as `CONTINENT`, `COUNTRYCODE`, `COUNTRY`, `CITY`, `POSTALCODE`, `COORDINATES`, `ACCURACYRADIUS`, `TIMEZONE`, `ASN`, `ASORG`, `ASNETWORK`, `GEONETWORK` in `NAME=value` and JSON output, and as `Continent`, `Country code`, `Country`, `City`, `Postal code`, `Coordinates`, `Accuracy`, `Time zone`, `Routed by AS`, `Operated by`, `AS network`, `Geo network` after a blank line in the summary output, in that order. The accuracy radius MUST be a number of kilometers, followed by ` km` in the summary only. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`CONTINENT_NAME` … `GEONETWORK_NAME` rows, `SECTION_GEO`) **Acceptance:** see ipcalc.1.md examples "Display all information of an IPv4" and "Display JSON output"; with the test databases: `--all-info 192.0.2.5` → tests/geo-all-info-192.0.2.5, `--format=json -g 2001:db8::1` → tests/geo-json-2001:db8::1 — positive ; test: GeoInfoAllInfo, GeoInfoJson **Links:** REQ-CLI-OUTPUT-005, REQ-CLI-OUTPUT-012 ### REQ-GEO-TEST-001 **Requirement:** Tests of geo lookups MUST run a test-only build of ipcalc, `ipcalc-geo`, that reads MaxMind DB files generated at build time by `tests/mkmmdb.py` from `tests/geo-country.json`, `tests/geo-city.json` and `tests/geo-asn.json`, and MUST NOT read the databases installed on the system, whose contents vary between hosts and over time. **Strength:** MUST **Status:** DERIVED **Source:** tests/meson.build (`ipcalc_geo`, `geo_dbs`); tests/mkmmdb.py; ipcalc-maxmind.c (`MAXMINDDB_LOCATION_COUNTRY`, `MAXMINDDB_LOCATION_CITY`, `MAXMINDDB_LOCATION_ASN` overridable at build time) **Acceptance:** in a build with a geo backend, the Geo* `--test-outfile` tests pass on a host without `/usr/share/GeoIP` — positive ; test: GeoInfoIPv4 and the other `ipcalc-geo` tests **Links:** REQ-GEN-TEST-001, REQ-GEN-TEST-007 ## Open items REQ-GEO-ERR-001 is tested only for an address that is not in the databases. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/info.md000066400000000000000000001305111526405142400250240ustar00rootroot00000000000000--- title: Address parsing and computed network information id-prefix: REQ-INFO sources: - ipcalc.c (get_ipv4_info, get_ipv6_info, str_to_prefix, prefix2mask, calc_broadcast, calc_network, ipv4_net_to_type, ipv6_net_to_type, ipv4_net_to_class, get_ipv6_iid_info, default_ipv4_prefix, ipv4_prefix_to_hosts, ipv6_prefix_to_hosts, expand_ipv6, get_hostname, get_ip_address, main) - ipcalc-reverse.c - netcompare.c (compare_networks) - ipcalc.1.md - tests/meson.build --- # Address parsing and computed network information Generated with `contrib/ai/protocols/requirements-from-implementation.md`. These requirements apply to info mode, check mode (parsing only), comparison mode, split mode (parsing of the base network), and random generation (computation on the generated network). Output selection and formats are in `cli.md`. ## Input ### REQ-INFO-INPUT-001 **Requirement:** ipcalc MUST accept an IPv4 address only in the dotted-decimal form accepted by `inet_pton(AF_INET)` — four decimal octets 0–255, without leading zeros or surrounding whitespace — and MUST reject any other IPv4 input with `ipcalc: bad IPv4 address: ` on stderr and exit status 1 (2 with a comparison option, REQ-CLI-OUTPUT-009). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:get_ipv4_info (`inet_pton`) **Acceptance:** `ipcalc -c 192.168.1.1` → exit 0; `ipcalc -c 1.2.3`, `ipcalc -c 01.2.3.4`, `ipcalc -c -4 2a01:198:200:300::2` → exit 1 — positive, negative ; test: ValidatePrivateIPv4, NoValidateIPv6InIPv4Mode **Links:** REQ-CLI-INPUT-005, REQ-INFO-INPUT-006 ### REQ-INFO-INPUT-002 **Requirement:** ipcalc MUST accept an IPv6 address in any textual form accepted by `inet_pton(AF_INET6)` (compressed, fully expanded, or with an embedded IPv4 suffix) and MUST reject any other IPv6 input with `ipcalc: bad IPv6 address: ` and exit status 1 (2 with a comparison option, REQ-CLI-OUTPUT-009). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:get_ipv6_info (`inet_pton`) **Acceptance:** `ipcalc -c -6 2a01:198:200:300::2`, `ipcalc -c -6 2a01:0198:0200:0300:0000:0000:0000:0002` → exit 0; `ipcalc -c -6 gggg::` → exit 1 — positive, negative ; test: ValidateAbbreviatedGlobalIPv6, ValidateCompleteGlobalIPv6, NoValidateInvalidHexIPv6 ### REQ-INFO-INPUT-003 **Requirement:** ipcalc MUST accept the network prefix as a `/` suffix of the address or, for IPv4 only, as a second argument; the prefix MUST be either an integer in 0–32 (IPv4) or 0–128 (IPv6), or, for IPv4 only, a dotted-decimal netmask whose one-bits are contiguous. Any other prefix MUST be rejected with `ipcalc: bad IPv4 prefix: ` or `ipcalc: bad IPv6 prefix: ` and exit status 1 (2 with a comparison option, REQ-CLI-OUTPUT-009). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (prefix extraction), ipcalc.c:str_to_prefix, ipcalc.c:mask2prefix, ipcalc.c:get_ipv4_info, ipcalc.c:get_ipv6_info **Acceptance:** `ipcalc -p 192.168.1.1 255.255.255.0` → `PREFIX=24`; `ipcalc -p 192.168.1.1 0.0.0.0` → `PREFIX=0`; `ipcalc -n 1.2.3.4/255.255.0.0` → `NETWORK=1.2.0.0`; `ipcalc -m 192.168.1.1/-1`, `ipcalc -m 192.168.1.1/64`, `ipcalc -m 192.168.1.1/99999`, `ipcalc -c ::1/999`, `ipcalc -n 1.2.3.4/255.0.255.0`, `ipcalc -p 1.2.3.4/` → exit 1 — positive, negative ; test: CalculatePrefix24FromNetmask, CalculatePrefix0FromNetmask, NoValidateNegativePrefix, NoValidateIPv6PrefixInIPv4Mode, NoValidateInvalidPrefixIPv4, NoValidateInvalidPrefixIPv6 **Links:** REQ-CLI-INPUT-004 > [AMBIGUOUS] The integer prefix is parsed with `strtol(…, 0)`, so > `0x18` is accepted as 24 and `010` as **8** (octal). Interpretation A: > incidental — only decimal is documented and a reimplementation may > reject hex/octal. Interpretation B: essential — scripts may pass > zero-padded prefixes, which today silently change meaning (`/010` is > /8, not /10). B argues for parsing as decimal. ### REQ-INFO-INPUT-004 **Requirement:** ipcalc SHOULD reject an IPv4 input that gives both a `/prefix` suffix and a netmask argument with a message naming the conflict. **Strength:** SHOULD **Status:** REVIEW **Source:** ipcalc.c:main (`prefixStr = chptr` before the `/` split; no check for both a prefix and a netmask) **Acceptance:** `ipcalc -n 1.2.3.4/24 255.255.0.0` → exit 1 with a message about both netmask and prefix — negative ; test: none > [REVIEW: may be a defect] The input is rejected (exit 1) but with the > misleading `ipcalc: bad IPv4 address: 1.2.3.4/24`, because the second > argument takes precedence and the `/24` is left in the address. ### REQ-INFO-INPUT-005 **Requirement:** When no prefix is given, ipcalc MUST use /128 for IPv6 and /32 for IPv4; with `--class-prefix` it MUST instead use the IPv4 classful prefix of the address — /8 when the first octet is below 128, /16 when below 192, and /24 otherwise. `--class-prefix` MUST have no effect when a prefix is given or the address is IPv6. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:get_ipv4_info, ipcalc.c:default_ipv4_prefix, ipcalc.c:get_ipv6_info; ipcalc.1.md#Options (`--netmask`, `--class-prefix`) **Acceptance:** `ipcalc -m 192.168.1.1` → `NETMASK=255.255.255.255`; `ipcalc --class-prefix -m 10.1.2.3` → `NETMASK=255.0.0.0`; `ipcalc --class-prefix -m 129.22.4.3` → `NETMASK=255.255.0.0`; `ipcalc --class-prefix -m 192.168.1.1` → `NETMASK=255.255.255.0` — positive ; test: CalculateNetmaskNoPrefix, CalculateClassNetmask8, CalculateClassNetmask16, CalculateClassNetmask24, AssignClassPrefix12, AssignClassPrefix129, AssignClassPrefix193 > [REVIEW: contradicts ipcalc.1.md] The `--netmask` entry of the man > page says that without a prefix IPv4 "assumes that the IP address is in > a complete class A, B, or C network"; that is only true with > `--class-prefix` (the default is /32 — test CalculateNetmaskNoPrefix). ### REQ-INFO-INPUT-006 **Requirement:** ipcalc MAY accept an IPv4 address with trailing octets omitted when a prefix is given (e.g. `172/8` meaning `172.0.0.0/8`). **Strength:** MAY **Status:** UNDOCUMENTED **Source:** ipcalc.c:get_ipv4_info ("Handle CIDR entries such as 172/8" — the padding runs after `inet_pton` has already rejected the short form, so it only affects the string passed to the geo lookup) **Acceptance:** `ipcalc -n 172/8` → today `ipcalc: bad IPv4 address: 172`, exit 1 — negative ; test: none > [UNDOCUMENTED] Dead code that suggests an intended feature. Decide > whether to implement it (then make this a MUST with tests and > document it) or remove the padding code. ## Computed values ### REQ-INFO-CALC-001 **Requirement:** ipcalc MUST compute the network address as the input address with all bits beyond the prefix cleared, and the netmask as the prefix's one-bits, printed in dotted-decimal (IPv4) or compressed IPv6 form (e.g. `ffff:ffff:ffff:ffff::`). **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:calc_network, ipcalc.c:prefix2mask, ipcalc.c:get_ipv6_info, ipcalc.c:ipv6_prefix_to_mask **Acceptance:** `ipcalc -n 192.168.1.1/32` → `NETWORK=192.168.1.1`; `ipcalc -n 192.168.1.1/0` → `NETWORK=0.0.0.0`; `ipcalc -m 172.16.59.222/22` → `NETMASK=255.255.252.0`; `ipcalc -m 10.0.0.0/1` → `NETMASK=128.0.0.0`; `ipcalc --addrspace -abmnp fd95:6be5:0ae0:84a5::/64` → `NETMASK=ffff:ffff:ffff:ffff::` — positive ; test: CalculateNetworkFromPrefix32, CalculateNetworkFromPrefix0, CalculateNetmaskPrefix22, CalculateNetmaskPrefix1, AllocateAddressSpacePrefix64 ### REQ-INFO-CALC-002 **Requirement:** For IPv4, ipcalc MUST compute the broadcast address as the network address with all host bits set, except that for a /31 network it MUST use the limited broadcast address `255.255.255.255` (RFC 3021). ipcalc MUST NOT compute a broadcast address for IPv6. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:calc_broadcast ("Follow RFC3021"); ipcalc.c:main (`BROADCAST` only `!(flags & FLAG_IPV6)`); ipcalc.h (`broadcast; /* ipv4 only */`) **Acceptance:** `ipcalc -b 192.168.1.1/24` → `BROADCAST=192.168.1.255`; `ipcalc -abmnp 192.168.1.5/31` → tests/192.168.1.5-31 (`BROADCAST=255.255.255.255`); `ipcalc -b -n 2001:db8::1/64` → no `BROADCAST` line — positive, negative ; test: CalculateBroadcastAddressFromPrefixIPv4, TestPrefix31 (no IPv6 test) ### REQ-INFO-CALC-003 **Requirement:** ipcalc MUST compute the host range (`MINADDR`/`HostMin` to `MAXADDR`/`HostMax`) as: for IPv4 prefixes 0–30, the network address plus one to the broadcast address minus one; for IPv4 /31, both addresses of the network; for IPv6 prefixes 0–127, the network address to the last address of the network; and for /32 and /128, the input address for both ends. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:get_ipv4_info, ipcalc.c:get_ipv6_info (`hostmin`, `hostmax`) **Acceptance:** `ipcalc -abmnp --minaddr --maxaddr --addresses 192.168.2.6/24` → `MINADDR=192.168.2.1`, `MAXADDR=192.168.2.254`; `ipcalc --minaddr --maxaddr 192.168.1.4/31` → `.4`, `.5`; `ipcalc -i 2001:db8::/64` → `HostMin: 2001:db8::`, `HostMax: 2001:db8::ffff:ffff:ffff:ffff` — positive ; test: SpecificInfoOutput, TestPrefix31 (no MINADDR/MAXADDR assertion), TestHumanReadableGenericInfoPrefix48 ### REQ-INFO-CALC-004 **Requirement:** ipcalc MUST report the host count (`ADDRESSES`, `Hosts/Net`) as a decimal integer equal to: for IPv4, 2^(32−prefix)−2 for prefixes 0–30, 2 for /31, and 1 for /32; for IPv6, 2^(128−prefix) for every prefix 0–128. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:ipv4_prefix_to_hosts, ipcalc.c:ipv6_prefix_to_hosts, ipcalc.c:p2_table **Acceptance:** `ipcalc --addresses 192.168.2.6/24` → `ADDRESSES=254`; `ipcalc --addresses 192.168.1.4/31` → `2`; `ipcalc --addresses 0.0.0.0/0` → `ADDRESSES=4294967294`; `ipcalc --addresses 10.0.0.0/1` → `ADDRESSES=2147483646`; `ipcalc --addresses ::/0` → `ADDRESSES=340282366920938463463374607431768211456` — positive ; test: SpecificInfoOutput, AddressesPrefix0IPv4, AddressesPrefix1IPv4, AddressesPrefix0IPv6 (no /31, /32 test) **Links:** REQ-SPLIT-OUTPUT-002 ### REQ-INFO-CALC-005 **Requirement:** ipcalc MUST print IPv6 addresses in the compressed form produced by `inet_ntop` (`ADDRESS`, `NETWORK`, `MINADDR`, `MAXADDR`), and MUST additionally provide the fully expanded form — eight groups of four lowercase hex digits — as `FULLADDRESS`/`Full Address` and `FULLNETWORK`/`Full Network` in the summary output. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:expand_ipv6, ipcalc.c:get_ipv6_info **Acceptance:** `ipcalc -i 2a03:2880:20:4f06:face:b00c:0:1` → `Full Address: 2a03:2880:0020:4f06:face:b00c:0000:0001`; `ipcalc -a 2001:0db8::0001` → `ADDRESS=2001:db8::1` — positive ; test: TestHumanReadableGenericInfoNoPrefix, JsonTestHumanReadableGenericInfoPrefix56 ### REQ-INFO-CALC-006 **Requirement:** ipcalc MUST classify an IPv4 network's address space (`ADDRSPACE`) by the most specific (longest-prefix) block in this table that contains the whole network — that is, the network's prefix is at least the block's length and its network address lies in the block — independently of the order of the rows, and as `Internet` when no row matches. The table follows the IANA IPv4 Special-Purpose Address Registry (updated 2025-10-09), plus 224.0.0.0/4 from the IANA IPv4 Address Space Registry: | Block | ADDRSPACE | |---|---| | 0.0.0.0/32 | This host on this network | | 0.0.0.0/8 | This network | | 10.0.0.0/8 | Private Use | | 100.64.0.0/10 | Shared Address Space | | 127.0.0.0/8 | Loopback | | 169.254.0.0/16 | Link Local | | 172.16.0.0/12 | Private Use | | 192.0.0.0/29 | IPv4 Service Continuity Prefix | | 192.0.0.8/32 | IPv4 dummy address | | 192.0.0.9/32 | Port Control Protocol Anycast | | 192.0.0.10/32 | Traversal Using Relays around NAT Anycast | | 192.0.0.170/32, 192.0.0.171/32 | NAT64/DNS64 Discovery | | 192.0.0.0/24 | IETF Protocol Assignments | | 192.0.2.0/24 | Documentation (TEST-NET-1) | | 192.31.196.0/24 | AS112-v4 | | 192.52.193.0/24 | AMT | | 192.88.99.2/32 | 6a44-relay anycast address | | 192.88.99.0/24 | 6 to 4 Relay Anycast (Deprecated) | | 192.168.0.0/16 | Private Use | | 192.175.48.0/24 | Direct Delegation AS112 Service | | 198.18.0.0/15 | Benchmarking | | 198.51.100.0/24 | Documentation (TEST-NET-2) | | 203.0.113.0/24 | Documentation (TEST-NET-3) | | 224.0.0.0/4 | Multicast | | 255.255.255.255/32 | Limited Broadcast | | 240.0.0.0/4 | Reserved | **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:ipv4_net_to_type; https://www.iana.org/assignments/iana-ipv4-special-registry **Acceptance:** `ipcalc -i ` for an address in each row → the listed `Address space`; `ipcalc -i 0.0.0.0` → `This host on this network`; `ipcalc -i 0.0.0.1` → `This network`; `ipcalc -i 192.88.99.2` → `6a44-relay anycast address`; `ipcalc --addrspace 192.168.0.0/8` → `ADDRSPACE=Internet`; `ipcalc --addrspace 10.0.0.0/7` → `ADDRSPACE=Internet`; `ipcalc --addrspace 0.0.0.0/7` → `ADDRSPACE=Internet` — positive, negative ; test: TestHumanReadable* (IPv4 rows), TestHumanReadableThisHostOnThisNetwork, TestHumanReadable6a44Relay, AddrspaceIPv4LargerThanBlock, AddrspaceIPv4LargerThanPrivateBlock, AddrspaceIPv4LargerThanThisNetwork **Links:** REQ-INFO-CALC-007, REQ-INFO-COMPAT-001 ### REQ-INFO-CALC-007 **Requirement:** ipcalc MUST classify an IPv6 network's address space (`ADDRSPACE`) by the most specific (longest-prefix) block in this table that contains the whole network, independently of the order of the rows, and as `Reserved` when no row matches. The table follows the IANA IPv6 Special-Purpose Address Registry (updated 2025-10-09), followed by the unicast and multicast blocks of the IANA IPv6 Address Space Registry: | Block | ADDRSPACE | |---|---| | ::1/128 | Loopback Address | | ::/128 | Unspecified Address | | ::ffff:0:0/96 | IPv4-mapped Address | | 64:ff9b::/96 | IPv4-IPv6 Translat. | | 64:ff9b:1::/48 | IPv4-IPv6 Translat. | | 100::/64 | Discard-Only Address Block | | 100:0:0:1::/64 | Dummy IPv6 Prefix | | 2001::/32 | TEREDO | | 2001:1::1/128 | Port Control Protocol Anycast | | 2001:1::2/128 | Traversal Using Relays around NAT Anycast | | 2001:1::3/128 | DNS-SD Service Registration Protocol Anycast | | 2001:2::/48 | Benchmarking | | 2001:3::/32 | AMT | | 2001:4:112::/48 | AS112-v6 | | 2001:10::/28 | Deprecated (previously ORCHID) | | 2001:20::/28 | ORCHIDv2 | | 2001:30::/28 | Drone Remote ID Protocol Entity Tags (DETs) Prefix | | 2001::/23 | IETF Protocol Assignments | | 2001:db8::/32 | Documentation | | 2002::/16 | 6to4 | | 2620:4f:8000::/48 | Direct Delegation AS112 Service | | 3fff::/20 | Documentation | | 5f00::/16 | Segment Routing (SRv6) SIDs | | 2000::/3 | Global Unicast | | fc00::/7 | Unique Local Unicast | | fe80::/10 | Link-Scoped Unicast | | ff00::/8 | Multicast | **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:ipv6_net_to_type; https://www.iana.org/assignments/iana-ipv6-special-registry; https://www.iana.org/assignments/ipv6-address-space **Acceptance:** `ipcalc -i ` for an address in each row → the listed `Address space`; `ipcalc -i 100::1` → `Discard-Only Address Block`; `ipcalc -i 1000::1` → `Reserved`; `ipcalc -i 100:0:0:1::5`, `ipcalc -i 2001:1::3`, `ipcalc -i 2001:30::1`, `ipcalc -i 3fff::1`, `ipcalc -i 5f00::1` → their new names; `ipcalc --addrspace 2001:db8::/16` → `"Global Unicast"`; `ipcalc --addrspace 2002::/15` → `"Global Unicast"` — positive, negative ; test: TestHumanReadable* (IPv6 rows), TestHumanReadableDiscardOnly, AddrspaceNotDiscardOnly, TestHumanReadableDummyIPv6Prefix, TestHumanReadableDNSSDSRPAnycast, TestHumanReadableDRIPDET, TestHumanReadableDocumentation3fff, TestHumanReadableSRv6SIDs, AddrspaceIPv6LargerThanBlock, AllocateAddressSpacePrefix48, AllocateAddressSpacePrefix64 **Links:** REQ-INFO-CALC-006, REQ-INFO-COMPAT-001 ### REQ-INFO-COMPAT-001 **Requirement:** ipcalc MUST NOT change the `ADDRSPACE` string it prints for a block when the IANA registry renames that block; a block newly added to a registry MUST be reported with its registry name, so that scripts matching existing `ADDRSPACE` values keep working. **Strength:** MUST NOT **Status:** DERIVED **Source:** maintainer decision (2026-10-03) when refreshing REQ-INFO-CALC-006/007 — the registry now names `Private-Use`, `Deprecated (6to4 Relay Anycast)`, `Unique-Local`, and `Link-Local Unicast`, which ipcalc keeps as `Private Use`, `6 to 4 Relay Anycast (Deprecated)`, `Unique Local Unicast`, and `Link-Scoped Unicast` **Acceptance:** `ipcalc --addrspace 10.0.0.1` → `ADDRSPACE="Private Use"`; `ipcalc -i fc00:0:a001::bcdf:4` → `Address space: Unique Local Unicast` — positive ; test: TestHumanReadablePrivateUse1, TestHumanReadableUniqueLocalUnicast, TestHumanReadableLinkScopedUnicast, TestHumanReadableDeprecated6to4RelayAnycast ### REQ-INFO-CALC-008 **Requirement:** For IPv4, ipcalc MUST report the address class (`ADDRCLASS`) of the network address as `Class A` (first octet 0–127), `Class B` (128–191), `Class C` (192–223), `Class D` (224–239), or `Class E` (240–255), and MUST NOT report a class for IPv6. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:ipv4_net_to_class **Acceptance:** `ipcalc --all-info 192.168.2.7/24` → `Address class: Class C`; `ipcalc --all-info 224.0.0.1` and `ipcalc --all-info 239.1.1.1` → `Address class: Class D`; `ipcalc --all-info 240.0.0.1` → `Address class: Class E` — positive ; test: AllInfo, AllInfoClassDLowest, AllInfoClassDHighestOctet, AllInfoClassE ### REQ-INFO-CALC-009 **Requirement:** For IPv4, ipcalc MUST compute one reverse DNS domain (`REVERSEDNS`) for the network: `d.c.b.a.in-addr.arpa.` for /32; `c.b.a.in-addr.arpa.`, `b.a.in-addr.arpa.`, `a.in-addr.arpa.` for /24, /16, /8; `in-addr.arpa.` for /0; and for any other prefix, `-.` followed by the labels of the enclosing octet boundary, where ``/`` are the values of the first partial octet in the network's first and last address. **Strength:** MUST **Status:** REVIEW **Source:** ipcalc-reverse.c:calc_reverse_dns4 (`USE_RFC2317_STYLE` undefined; "draft-ietf-dnsop-rfc2317bis-00") **Acceptance:** `ipcalc --reverse-dns 193.92.150.3/32` → `REVERSEDNS=3.150.92.193.in-addr.arpa.`; `/26` → `0-63.150.92.193.in-addr.arpa.`; `/16` → `92.193.in-addr.arpa.`; `/12` → `80-95.193.in-addr.arpa.`; `/4` → `192-207.in-addr.arpa.`; `/0` → `in-addr.arpa.`; `ipcalc --reverse-dns 192.168.1.4/31` → `4-5.1.168.192.in-addr.arpa.` — positive ; test: LookupReverseDNSFromPrefix32IPv4, LookupReverseDNSFromPrefix26IPv4, LookupReverseDNSFromPrefix16IPv4, LookupReverseDNSFromPrefix12IPv4, LookupReverseDNSFromPrefix4IPv4, LookupReverseDNSFromPrefix0IPv4 (no /31 test) **Links:** REQ-INFO-CALC-002 > [REVIEW: defect] For /31 the last value is taken from the broadcast > address, which is `255.255.255.255` for /31 (REQ-INFO-CALC-002), so > `192.168.1.4/31` gives `4-255.1.168.192.in-addr.arpa.`. ### REQ-INFO-CALC-010 **Requirement:** For IPv6, ipcalc MUST compute the reverse DNS domains (`REVERSEDNS`) in the RFC 3596 nibble format: one domain when the prefix is a multiple of 4 (`ip6.arpa.` for /0), and otherwise the 2^(4 − prefix mod 4) domains at the next nibble boundary that cover the network, in ascending order. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc-reverse.c:calc_reverse_dns6; ipcalc.h:MAX_REVERSE_DNS; ipcalc.1.md#Options (`--reverse-dns`) **Acceptance:** `ipcalc --reverse-dns 1234::4321/124` → one domain; `ipcalc --reverse-dns 2001:db8::/31` → 2 domains; `…/33` → 8; `…/34` → 4; `ipcalc --reverse-dns ::/0` → `REVERSEDNS=ip6.arpa.`; `ipcalc --reverse-dns 2001:db8:3fff::1/35` → domains of the network, not the address — positive ; test: LookupReverseDNSFromPrefix124IPv6, LookupReverseDNSFromPrefix31IPv6, LookupReverseDNSFromPrefix33IPv6, LookupReverseDNSFromPrefix34IPv6, LookupReverseDNSFromPrefix127IPv6, LookupReverseDNSFromPrefix0IPv6, LookupReverseDNSUnmaskedPrefix35IPv6, LookupReverseDNS4321IPv6 ### REQ-INFO-CALC-011 **Requirement:** With `-h`/`--hostname`, ipcalc MUST look up the name of the input address with `getnameinfo()` and print it as `HOSTNAME`; a network is rejected without a lookup (REQ-INFO-ERR-001). **Strength:** MUST **Status:** REVIEW **Source:** ipcalc.c:get_hostname, ipcalc.c:get_ipv4_info, ipcalc.c:get_ipv6_info; ipcalc.1.md#Options (`--hostname`) **Acceptance:** `ipcalc -h 127.0.0.1` → `HOSTNAME=localhost`; `ipcalc -h ::1` → tests/ip-localhost-ipv6 — positive ; test: IPIPv4Localhost, IPIPv6Localhost, IPIPv4LocalhostJson **Links:** REQ-INFO-ERR-001 > [REVIEW] `getnameinfo()` is called without `NI_NAMEREQD`, so an > address with no name succeeds and prints the numeric address > (`ipcalc -h 192.0.2.1` → `HOSTNAME=192.0.2.1`, exit 0). The error path > `ipcalc: cannot find hostname for ` (exit 1) is only reached when > the lookup itself fails. Decide whether "no name" is an error. ### REQ-INFO-ERR-001 **Requirement:** ipcalc MUST reject `-h`/`--hostname` when the input is a network rather than a single address — an IPv4 prefix shorter than 32 or an IPv6 prefix shorter than 128, whether given, implied by `--class-prefix`, or generated by `-r` — by printing `ipcalc: -h requires a single address, not a network:

/` to stderr (subject to `-s`, REQ-CLI-ERR-006) and exiting with status 1 without other output, in every output format, so that a name is never reported for a whole network. The name MUST NOT be looked up first, so that a network is rejected without a DNS query and with this message even when the lookup would fail. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`ATTR_REQUIRES_SINGLE_ADDRESS` check); ipcalc.c:get_ipv4_info, ipcalc.c:get_ipv6_info (prefix check before `get_hostname()`); ipcalc.1.md#Options (`--hostname`) **Acceptance:** `ipcalc -h 127.0.0.1/32` → `HOSTNAME=localhost` — positive; `ipcalc -h 127.0.0.1/8` → `ipcalc: -h requires a single address, not a network: 127.0.0.1/8`, exit 1; `ipcalc -j -h 127.0.0.1/8`, `ipcalc -h ::1/64` → exit 1, no stdout; `ipcalc -s -h 127.0.0.1/8` → no output, exit 1; `ipcalc --format=json -h 127.0.0.1/8` → the message, exit 1; `ipcalc -h 127.0.0.1/8` with every `getnameinfo()` call failing → the message above, exit 1 — negative ; test: HostnameHostPrefix, HostnameNetwork, HostnameNetworkJson, HostnameNetworkIPv6, HostnameNetworkSilent, HostnameNetworkNoLookup, HostnameNetworkFormatJson **Links:** REQ-INFO-CALC-011, REQ-INFO-OUTPUT-005, REQ-CLI-ERR-006 ### REQ-INFO-CALC-012 **Requirement:** With `-o`/`--lookup-host `, ipcalc MUST resolve the name with `getaddrinfo()` — restricted to IPv4 with `-4`, to IPv6 with `-6`, otherwise any family — and use the first returned address as the input address; if resolution fails it MUST print `ipcalc: could not resolve ` and exit with status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:get_ip_address, ipcalc.c:main (`if (hostname)`); ipcalc.1.md#Options (`--lookup-host`) **Acceptance:** `ipcalc -4 -o localhost` → `ADDRESS=127.0.0.1`; `ipcalc -6 -o localhost` → tests/hostname-localhost-ipv6; `ipcalc -o no-such-host.invalid` → exit 1 — positive, negative ; test: HostnameIPv4Localhost, HostnameIPv6Localhost, HostnameIPv4LocalhostJson (no negative test) ### REQ-INFO-CALC-013 **Requirement:** For an IPv6 input address whose first three bits are not `000`, whose first octet is not `ff`, and whose low 64 bits are not all zero, ipcalc MUST take those low 64 bits as the interface identifier. When octets 3 and 4 of the interface identifier are `ff` and `fe`, ipcalc MUST treat it as a Modified EUI-64 (RFC 4291 Appendix A) and derive the EUI-64 by inverting bit `0x02` of its first octet, and the MAC address from octets 0–2 and 5–7 of that EUI-64. It MUST then report the MAC as universally administered when bit `0x02` of its first octet is clear and locally administered otherwise, and as individual when bit `0x01` of its first octet is clear and group otherwise. Interface identifiers without the `ff:fe` octets MUST NOT have an EUI-64, MAC address, or flags derived (RFC 7136). IPv4 inputs have no interface identifier. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:get_ipv6_iid_info, ipcalc.c:get_ipv6_info; GitLab issue #29 **Acceptance:** `ipcalc --all-info fe80::21b:21ff:fe3a:5c7d/64` → tests/all-info-fe80::21b:21ff:fe3a:5c7d-64 (MAC `00:1b:21:3a:5c:7d`, universal, individual); `ipcalc --all-info fe80::ff:fe00:1` → MAC `02:00:00:00:00:01`, local; `ipcalc --all-info 2001:db8::300:ff:fe00:1` → MAC `01:00:00:00:00:01`, group; `ipcalc --all-info 2001:db8::f00d:1234:5678:9abc/64` → interface identifier only; `ipcalc --all-info fe80::/64`, `ipcalc --all-info ::ffff:192.0.2.1`, `ipcalc --all-info ff02::21b:21ff:fe3a:5c7d`, `ipcalc --all-info 192.168.2.7/24` → no interface identifier — positive, negative ; test: AllInfoIIDLinkLocalUniversal, AllInfoIIDLinkLocalLocal, AllInfoIIDGroup, AllInfoIIDNotEUI64, AllInfoIIDNetwork, AllInfoIIDMapped, AllInfoIIDMulticast, AllInfo, JsonAllInfoIIDLinkLocalUniversal, NoDecorateAllInfoIIDLinkLocalUniversal **Links:** REQ-INFO-OUTPUT-006 ## Network comparison These requirements define the comparisons of REQ-CLI-INPUT-006. Both networks are compared by network address and prefix; host bits of the input address and of NET are ignored. ### REQ-INFO-CALC-014 **Requirement:** `--equals=NET` MUST be true exactly when the input network and NET are of the same family, have the same prefix, and have the same network address, for both IPv4 and IPv6. **Strength:** MUST **Status:** DERIVED **Source:** netcompare.c:comparison_holds, netcompare.c:network_contains, netcompare.c:same_leading_bits, netcompare.c:to_binary_network; ipcalc.1.md#Options (`--equals`) **Acceptance:** `ipcalc 192.168.1.15 --equals=192.168.1.15/32`, `ipcalc 192.168.7.15/24 --equals=192.168.7.5/24`, `ipcalc 2001:db8::1/64 --equals=2001:db8::ffff/64`, `ipcalc 1.2.3.4/0 --equals=0.0.0.0/0` → exit 0; `ipcalc 192.168.0.0/24 --equals=192.168.0.0/23`, `ipcalc 192.168.1.15/24 --equals=192.168.7.1/24`, `ipcalc 2001:db8::/64 --equals=2001:db8::/65` → exit 1 — positive, negative ; test: EqualsHost32, EqualsHostBits, EqualsHostBitsIPv6, EqualsPrefix0, EqualsDifferentPrefix, EqualsDisjoint, EqualsDifferentPrefixIPv6 **Links:** REQ-CLI-INPUT-006, REQ-CLI-OUTPUT-009 ### REQ-INFO-CALC-015 **Requirement:** `--subnet-of=NET` MUST be true exactly when the input network and NET are of the same family and every address of the input network is an address of NET — that is, the prefix of NET is less than or equal to the input prefix and the input network address with its last width−(NET prefix) bits cleared equals the network address of NET — for both IPv4 and IPv6. Equal networks MUST compare true; a /0 NET MUST contain every network of its family. **Strength:** MUST **Status:** DERIVED **Source:** netcompare.c:comparison_holds, netcompare.c:network_contains, netcompare.c:same_leading_bits, netcompare.c:to_binary_network; ipcalc.1.md#Options (`--equals`) **Acceptance:** `ipcalc 192.168.0.1/24 --subnet-of=192.168.1.15/23`, `ipcalc 10.0.0.0/8 --subnet-of=10.0.0.0/8`, `ipcalc 10.1.2.3 --subnet-of=0.0.0.0/0`, `ipcalc 10.64.0.0/10 --subnet-of=10.0.0.0/9`, `ipcalc 2001:db8:1::/48 --subnet-of=2001:db8::/32`, `ipcalc ::1 --subnet-of=::/0` → exit 0; `ipcalc 192.168.1.15/23 --subnet-of=192.168.0.1/24`, `ipcalc 10.128.0.0/10 --subnet-of=10.0.0.0/9`, `ipcalc 0.0.0.0/0 --subnet-of=0.0.0.0/1`, `ipcalc 2001:db8::/32 --subnet-of=2001:db8:1::/48` → exit 1 — positive, negative ; test: SubnetOf, SubnetOfEqual, SubnetOfPrefix0, SubnetOfPartialByte, SubnetOfIPv6, SubnetOfPrefix0IPv6, SubnetOfSupernet, SubnetOfSiblingPartialByte, SubnetOfPrefix0Supernet, SubnetOfSupernetIPv6 **Links:** REQ-INFO-CALC-016, REQ-CLI-OUTPUT-009 ### REQ-INFO-CALC-016 **Requirement:** `--overlaps=NET` MUST be true exactly when the input network and NET are of the same family and share at least one address, for both IPv4 and IPv6. For two networks given by address and prefix this holds exactly when one is a subnet of the other (REQ-INFO-CALC-015), so the result MUST equal `--subnet-of=NET` or, with the operands swapped, `--subnet-of`. **Strength:** MUST **Status:** DERIVED **Source:** netcompare.c:comparison_holds, netcompare.c:network_contains, netcompare.c:same_leading_bits, netcompare.c:to_binary_network; ipcalc.1.md#Options (`--equals`) **Acceptance:** `ipcalc 192.168.1.15/23 --overlaps=192.168.0.1/24`, `ipcalc 192.168.0.1/24 --overlaps=192.168.1.15/23`, `ipcalc 10.0.0.1 --overlaps=10.0.0.1`, `ipcalc ::/0 --overlaps=2001:db8::1` → exit 0; `ipcalc 192.168.1.15/24 --overlaps=192.168.7.1/24`, `ipcalc 192.168.0.0/24 --overlaps=192.168.1.0/24`, `ipcalc 2001:db8::/33 --overlaps=2001:db8:8000::/33` → exit 1 — positive, negative ; test: OverlapsSupernet, OverlapsSubnet, OverlapsHost, OverlapsPrefix0IPv6, OverlapsDisjoint, OverlapsAdjacent, OverlapsAdjacentIPv6 **Links:** REQ-INFO-CALC-015, REQ-CLI-OUTPUT-009 ### REQ-INFO-CALC-017 **Requirement:** When the input network and NET are of different families, `--equals`, `--subnet-of`, and `--overlaps` MUST be false (exit status 1, REQ-CLI-OUTPUT-009) rather than an error, including for an IPv4-mapped IPv6 address compared with the IPv4 address it maps, so that lists that mix IPv4 and IPv6 networks can be processed without errors. **Strength:** MUST **Status:** DERIVED **Source:** netcompare.c:comparison_holds, netcompare.c:network_contains, netcompare.c:same_leading_bits, netcompare.c:to_binary_network; ipcalc.1.md#Options (`--equals`) **Acceptance:** `ipcalc 10.0.0.0/8 --overlaps=::/0`, `ipcalc ::ffff:10.0.0.1 --equals=10.0.0.1` → `The networks do not overlap`, `The networks are not equal`, exit 1 — negative ; test: OverlapsMixedFamily, EqualsMappedIPv4 **Links:** REQ-CLI-INPUT-006, REQ-CLI-ERR-007 ## Summary output ### REQ-INFO-OUTPUT-001 **Requirement:** The decorated and `--no-decorate` summary output MUST print these lines, in this order, each only when its condition holds: `Full Address` (IPv6) and `Address` — when the network is a single host or the input address differs from the network address, and not for `-r` unless single host; `Hostname` — `-h` (REQ-INFO-ERR-001); `Full Network` (IPv6), `Network: /`, `Netmask: = `, `Wildcard` (IPv4, `--all-info` or `--wildcard`, REQ-INFO-OUTPUT-008), `Broadcast` (IPv4) — not for a single host; `Reverse DNS` — `--all-info` or `--reverse-dns`, one line per domain; a blank line (not for a single host); `Address space`; `Address class` — `--all-info` and IPv4 only; `Interface ID`, `EUI-64`, `MAC address`, `MAC scope`, `MAC type` — `--all-info` only (REQ-INFO-OUTPUT-006); `HostMin`, `HostMax`, `Hosts/Net` — not for a single host; then, when geo information was found, a blank line and `Country code`, `Country`, `City`, `Coordinates`. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`fields[]`, `field_selected()`, `field_in_summary()`) **Acceptance:** `ipcalc 192.168.2.0/24` → tests/standard-192.168.2.0-24 (no `Address`); `ipcalc -i --reverse-dns 192.168.2.7/24` → tests/info-reverse-dns-192.168.2.7-24; `ipcalc -i 192.168.2.7/24` → tests/info-192.168.2.7; `ipcalc --all-info 192.168.2.7/24` → tests/all-info-192.168.2.7; `ipcalc -i 127.0.0.1` → tests/i-127.0.0.1 (single host) — positive ; test: StandardInfo, Info, AllInfo, NoDecorateAllInfo, TestHumanReadableLoopback, AllInfoReverseDNSPrefix31IPv6, InfoReverseDNS **Links:** REQ-CLI-OUTPUT-002, REQ-INFO-OUTPUT-002, REQ-INFO-OUTPUT-006, REQ-GEO-OUTPUT-001 ### REQ-INFO-OUTPUT-002 **Requirement:** In the decorated summary, the IPv6 `Hosts/Net` line MUST be printed as `2^(<128 − prefix>) = ` when the prefix is below 112, and as `` otherwise; IPv4 MUST always print ``. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`info->prefix < 112`) **Acceptance:** `ipcalc -i 2001:db8::/64` → `Hosts/Net: 2^(64) = 18446744073709551616`; `ipcalc -i fd0b:a336:4e7d::/48` → tests/i-fd0b:a336:4e7d::-48 — positive ; test: TestHumanReadableGenericInfoPrefix48 **Links:** REQ-INFO-CALC-004 ### REQ-INFO-OUTPUT-003 **Requirement:** The JSON summary MUST contain these keys, in this order, each only when its condition holds: `FULLADDRESS` (IPv6) and `ADDRESS` (same condition as REQ-INFO-OUTPUT-001), `HOSTNAME` (`-h`, REQ-INFO-ERR-001), `FULLNETWORK` (IPv6), `NETWORK`, `NETMASK`, `WILDCARD` (IPv4, `--all-info` or `--wildcard`, REQ-INFO-OUTPUT-008), `PREFIX`, `CIDR` (REQ-INFO-OUTPUT-007), `BROADCAST` (IPv4), `REVERSEDNS` (`--all-info` or `--reverse-dns`), `ADDRSPACE`, `ADDRCLASS` (`--all-info`, IPv4), `INTERFACEID`, `EUI64`, `MACADDR`, `MACSCOPE`, `MACTYPE` (`--all-info`, REQ-INFO-OUTPUT-006), `MINADDR`, `MAXADDR`, `ADDRESSES`, then `COUNTRYCODE`, `COUNTRY`, `CITY`, `COORDINATES` when found. `NETWORK` and `FULLNETWORK` MUST NOT include the prefix, and the network keys MUST be present for single hosts too. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`fields[]`, `field_selected()`, `field_in_summary()`) **Acceptance:** `ipcalc -j -i 2a03:2880:20:4f06:face:b00c:0:1/56` → tests/json-i-2a03:2880:20:4f06:face:b00c:0:1-56; `ipcalc -j --reverse-dns 192.168.2.7/24` → tests/json-reverse-dns-192.168.2.7-24 (`REVERSEDNS` array); `ipcalc -j 192.168.2.7/24` → no `REVERSEDNS`; `ipcalc -j -h 127.0.0.1` → tests/ip-localhost-ipv4-json — positive ; test: JsonTestHumanReadableGenericInfoPrefix56, JsonAllInfoReverseDNSPrefix24IPv4, IPIPv4LocalhostJson, HostnameIPv4LocalhostJson, JsonReverseDNS **Links:** REQ-CLI-OUTPUT-008, REQ-CLI-OUTPUT-012, REQ-INFO-OUTPUT-004, REQ-INFO-OUTPUT-006, REQ-INFO-OUTPUT-008 ### REQ-INFO-OUTPUT-004 **Requirement:** In JSON output, `REVERSEDNS` MUST always be an array of strings, even when there is a single domain, so that its type does not depend on the prefix. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_json_field ("always an array"); ipcalc.1.md#Options (`--reverse-dns`); NEWS **Acceptance:** `ipcalc --all-info --json 2001:db8::/32` → `"REVERSEDNS":["8.b.d.0.1.0.0.2.ip6.arpa."]`; `…/31` → two-element array — positive ; test: JsonAllInfoReverseDNSPrefix32IPv6, JsonAllInfoReverseDNSPrefix31IPv6, JsonAllInfoReverseDNSPrefix24IPv4 ### REQ-INFO-OUTPUT-005 **Requirement:** When `-h` is combined with `-i` or `-j`, ipcalc MUST include the resolved name as `Hostname` in the summary and as `HOSTNAME` in the JSON object; since `-h` accepts only a single address (REQ-INFO-ERR-001), the name is never dropped for a network. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`HOSTNAME_NAME` row) **Acceptance:** `ipcalc -j -h 127.0.0.1` → tests/ip-localhost-ipv4-json; `ipcalc -j -h 127.0.0.1/8` → exit 1 (REQ-INFO-ERR-001) — positive, negative ; test: IPIPv4LocalhostJson, HostnameNetworkJson **Links:** REQ-INFO-ERR-001 ### REQ-INFO-OUTPUT-006 **Requirement:** With `--all-info`, when the input address has an interface identifier (REQ-INFO-CALC-013), the summary MUST print `Interface ID` (`INTERFACEID`) as four colon-separated groups of four lowercase hex digits; when it is a Modified EUI-64 it MUST also print `EUI-64` (`EUI64`) and `MAC address` (`MACADDR`) as colon-separated lowercase hex octets, `MAC scope` (`MACSCOPE`) as `universal` or `local`, and `MAC type` (`MACTYPE`) as `individual` or `group`. The fields MUST be printed for single hosts as well as networks, MUST be JSON strings, and MUST NOT be printed without `--all-info` or in `NAME=value` output. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`INTERFACEID_NAME` … `MACTYPE_NAME` rows, `ATTR_SUMMARY_WITH_ALL_INFO`); ipcalc.1.md#Options (`--all-info`); GitLab issue #29 **Acceptance:** `ipcalc --all-info fe80::21b:21ff:fe3a:5c7d/64` → tests/all-info-fe80::21b:21ff:fe3a:5c7d-64; `ipcalc --all-info --json fe80::21b:21ff:fe3a:5c7d/64` → tests/json-all-info-fe80::21b:21ff:fe3a:5c7d-64; `ipcalc --all-info --no-decorate fe80::21b:21ff:fe3a:5c7d/64` → tests/no-decorate-all-info-fe80::21b:21ff:fe3a:5c7d-64; `ipcalc -i fe80::21b:21ff:fe3a:5c7d/64` → no interface identifier lines — positive, negative ; test: AllInfoIIDLinkLocalUniversal, JsonAllInfoIIDLinkLocalUniversal, NoDecorateAllInfoIIDLinkLocalUniversal, InfoIIDLinkLocal **Links:** REQ-INFO-CALC-013, REQ-INFO-OUTPUT-001, REQ-INFO-OUTPUT-003 ### REQ-INFO-OUTPUT-007 **Requirement:** `--cidr` MUST select the `CIDR` field, which is the network address (REQ-INFO-CALC-001) and the prefix in CIDR notation, `/`, for both IPv4 and IPv6, with the network address written as `NETWORK` is (REQ-INFO-OUTPUT-003). The prefix MUST be included for single hosts too (/32, /128, or no prefix given), so that scripts get one form for every input. In `NAME=value` output it MUST be printed as `CIDR=/`, with `--no-decorate` as `/`, and in the JSON summary as the string key `CIDR`; the decorated summary MUST NOT change, as its `Network` line already shows the same value. It applies to generated networks (`-r`) as to given ones. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`OPT_CIDR`, `FLAG_SHOW_CIDR`); ipcalc.c:show_info_fields (`CIDR_NAME` row); ipcalc.c:long_options, ipcalc.c:usage; ipcalc.1.md#Options (`--cidr`) **Acceptance:** `ipcalc --cidr 192.168.123.7/24` → `CIDR=192.168.123.0/24`; `ipcalc --cidr --no-decorate 2001:db8::1/64` → `2001:db8::/64`; `ipcalc --cidr 192.168.1.1` → `CIDR=192.168.1.1/32`; `ipcalc --cidr ::1` → `CIDR=::1/128`; `ipcalc -n --cidr -p 10.1.2.3/8` → `NETWORK=10.0.0.0`, `PREFIX=8`, `CIDR=10.0.0.0/8`; `ipcalc -j 192.168.2.7/24` → `"CIDR":"192.168.2.0/24"`; `ipcalc -r 24 --cidr --no-decorate` → exit 0 — positive ; test: CidrIPv4, CidrNoDecorateIPv6, CidrSingleHost, CidrSingleHostIPv6, CidrFieldOrder, JsonAllInfoReverseDNSPrefix24IPv4, RandomCidr **Links:** REQ-INFO-OUTPUT-003, REQ-CLI-OUTPUT-004, REQ-CLI-OUTPUT-006 ### REQ-INFO-OUTPUT-008 **Requirement:** `--wildcard` MUST select the `WILDCARD` field, the wildcard (inverse) mask used by Cisco ACLs and OSPF: the bitwise complement of the IPv4 netmask, in dotted-quad notation (e.g. `0.0.0.255` for /24, `0.0.0.0` for /32 and `255.255.255.255` for /0). For IPv6, where wildcard masks are not used, ipcalc MUST NOT print the field in any output format, and `--wildcard` MUST NOT make it fail, as with `BROADCAST` (REQ-INFO-CALC-002). In `NAME=value` output it MUST be printed as `WILDCARD=`, with `--no-decorate` as ``. The decorated and `--no-decorate` summary MUST print it as a `Wildcard:` line, and the JSON summary as the string key `WILDCARD`, only with `--all-info` or `--wildcard` and not with `-i` alone or by default, so that the default and `-i` output of every format is unchanged. It applies to generated networks (`-r`) as to given ones. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`OPT_WILDCARD`, `FLAG_SHOW_WILDCARD`); ipcalc.c:show_info_fields (`WILDCARD_NAME` row); ipcalc.c:get_ipv4_info (`info->wildcard`); ipcalc.h (`wildcard; /* ipv4 only */`); ipcalc.c:long_options, ipcalc.c:usage; ipcalc.1.md#Options (`--wildcard`) **Acceptance:** `ipcalc --wildcard 192.168.123.7/24` → `WILDCARD=0.0.0.255`; `ipcalc --wildcard 192.168.1.1` → `WILDCARD=0.0.0.0`; `ipcalc --wildcard 0.0.0.0/0` → `WILDCARD=255.255.255.255`; `ipcalc --wildcard 10.0.0.1/1` → `WILDCARD=127.255.255.255`; `ipcalc --wildcard 10.0.0.1/8` → `WILDCARD=0.255.255.255`; `ipcalc --wildcard 172.16.5.4/12` → `WILDCARD=0.15.255.255`; `ipcalc --wildcard 172.16.5.4/16` → `WILDCARD=0.0.255.255`; `ipcalc --wildcard 192.168.1.130/25` → `WILDCARD=0.0.0.127`; `ipcalc --wildcard 192.168.1.130/27` → `WILDCARD=0.0.0.31`; `ipcalc --wildcard 192.168.1.130/31` → `WILDCARD=0.0.0.1`; `ipcalc --wildcard 10.1.2.3/255.255.255.252` → `WILDCARD=0.0.0.3`; `ipcalc --wildcard --no-decorate 172.16.5.4/12` → `0.15.255.255`; `ipcalc --wildcard -m -n 10.1.2.3/255.255.240.0` → `NETWORK=10.1.0.0`, `NETMASK=255.255.240.0`, `WILDCARD=0.0.15.255`; `ipcalc -i --wildcard 192.168.2.7/24` → tests/info-wildcard-192.168.2.7-24; `ipcalc -j --wildcard 192.168.2.7/24` → tests/json-wildcard-192.168.2.7-24; `ipcalc --all-info 192.168.2.7/24` → tests/all-info-192.168.2.7; `ipcalc --all-info --json 192.168.2.7/24` → tests/json-all-info-192.168.2.7-24; `ipcalc -r 24 --wildcard --no-decorate` → exit 0 — positive; `ipcalc -j 192.168.2.7/24` → no `WILDCARD` key; `ipcalc -i 192.168.2.7/24` → no `Wildcard` line; `ipcalc --wildcard 2001:db8::1/64`, `ipcalc --wildcard ::/0` → no output, exit 0; `ipcalc -i --wildcard 2001:db8::/32` → no `Wildcard` line; `ipcalc --all-info --json 2001:db8::/32` → no `WILDCARD` key — negative ; test: WildcardIPv4, WildcardSingleHost, WildcardPrefix0, WildcardPrefix1, WildcardPrefix8, WildcardPrefix12, WildcardPrefix16, WildcardPrefix25, WildcardPrefix27, WildcardPrefix31, WildcardNetmask, WildcardNoDecorate, WildcardFieldOrder, InfoWildcard, JsonWildcard, RandomWildcard, AllInfo, JsonAllInfoReverseDNSPrefix24IPv4, JsonTestHumanReadableGenericInfoPrefix56, Info, WildcardIPv6, WildcardPrefix0IPv6, InfoWildcardIPv6, JsonAllInfoReverseDNSPrefix32IPv6 **Links:** REQ-INFO-OUTPUT-001, REQ-INFO-OUTPUT-003, REQ-CLI-OUTPUT-004, REQ-CLI-OUTPUT-006 ### REQ-INFO-OUTPUT-009 **Requirement:** The summary output of `-i`, or of info mode with no mode option (REQ-CLI-INPUT-001), MUST show a small, basic set of information about the input: without field-selecting options it MUST print at most 15 lines, each at most 80 columns with tabs expanded to 8-column stops, for any IPv4 or IPv6 input, decorated or with `--no-decorate`. Each field-selecting option given with `-i` MUST add its field to the summary (e.g. `--reverse-dns`, `--wildcard`, `-h`), and those fields do not count toward the limit. An information item that would take the summary past the limit MUST NOT be added to it; it belongs to `--all-info` (REQ-INFO-OUTPUT-010) or to its own option, so that the default output stays readable at a glance. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`ATTR_SUMMARY_ALWAYS` rows, `field_in_summary()`); ipcalc.1.md#Options (`--info`) **Acceptance:** `ipcalc -i ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/1` → 10 lines, at most 65 columns; `ipcalc -i 255.255.255.255/1` → 9 lines; `ipcalc -i --reverse-dns 192.168.2.7/24` → tests/info-reverse-dns-192.168.2.7-24; `ipcalc -i --wildcard 192.168.2.7/24` → tests/info-wildcard-192.168.2.7-24 — positive ; `ipcalc -i 192.168.2.7/24` → no `Wildcard`, `Reverse DNS`, or `Address class` line; `ipcalc -i fe80::21b:21ff:fe3a:5c7d/64` → no interface identifier lines — negative ; test: InfoSummarySizeIPv6, InfoSummarySizeIPv4, InfoReverseDNS, InfoWildcard, Info, InfoIIDLinkLocal **Links:** REQ-INFO-OUTPUT-001, REQ-INFO-OUTPUT-010, REQ-CLI-OUTPUT-002, REQ-CLI-COMPAT-006 ### REQ-INFO-OUTPUT-010 **Requirement:** With `--all-info` ipcalc MUST show every information item it can determine for the input without a network query, in the summary and JSON outputs: the fields of every field-selecting option except `-h` and `-o`, for both IPv4 and IPv6 — including `-g` when a geo backend and database are available (REQ-GEO-CALC-001) — and every field shown only with `--all-info` (`Address class`, the interface identifier fields of REQ-INFO-OUTPUT-006). The output length is not limited. An information item that ipcalc learns to compute MUST be added to `--all-info`. `--all-info` MUST NOT resolve a hostname or perform any other DNS query, which only `-h` and `-o` request, so that it shows everything available without blocking on the network. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`ATTR_SUMMARY_WITH_ALL_INFO` rows, `field_in_summary()`); ipcalc.c:main (`geo_setup() == 0 && FLAG_SHOW_ALL_INFO`); ipcalc.c:field_selecting_options; ipcalc.1.md#Options (`--all-info`) **Acceptance:** `ipcalc --all-info -j 192.168.2.7/24` and `ipcalc --all-info -j fe80::21b:21ff:fe3a:5c7d/64` → contain every key that `-j` with `-a -b -m -n -p --cidr --wildcard --reverse-dns --addrspace --minaddr --maxaddr --addresses` prints for the same input; `ipcalc --all-info 192.168.2.7/24` → tests/all-info-192.168.2.7 — positive ; `ipcalc --all-info -j 127.0.0.1` with a reverse lookup that would return a name → exit 0 and no `HOSTNAME` key — negative ; test: AllInfoJsonKeysIPv4, AllInfoJsonKeysIPv6, AllInfo, AllInfoIIDLinkLocalUniversal, AllInfoNoLookup (Linux only, lookups faked with an `LD_PRELOAD` shim, tests/fake-getnameinfo.c) **Links:** REQ-INFO-OUTPUT-001, REQ-INFO-OUTPUT-003, REQ-INFO-OUTPUT-006, REQ-INFO-OUTPUT-009, REQ-GEO-CALC-001, REQ-CLI-COMPAT-006 ## Open items `REVIEW`: REQ-INFO-INPUT-004 (prefix plus netmask message), REQ-INFO-INPUT-005 (man page on default IPv4 prefix), REQ-INFO-CALC-009 (/31 reverse DNS), REQ-INFO-CALC-011 (`-h` never fails for unnamed addresses). `AMBIGUOUS`: hex/octal prefixes (REQ-INFO-INPUT-003). `UNDOCUMENTED`: REQ-INFO-INPUT-006 (`172/8` padding). Missing tests: IPv4 /31, /32 host counts; IPv6 broadcast omission; /31 reverse DNS; `-o` resolution failure. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/random.md000066400000000000000000000075741526405142400253650ustar00rootroot00000000000000--- title: Random private network generation (-r/--random-private) id-prefix: REQ-RANDOM sources: - ipcalc.c (generate_ip_network, randomize, str_to_prefix, main) - ipcalc.1.md - tests/meson.build --- # Random private network generation (`-r/--random-private`) Generated with `contrib/ai/protocols/requirements-from-implementation.md`. The generated network is then processed like an input network in info mode (`info.md`); its address is random, so requirements fix the format and the address space, not the value. ### REQ-RANDOM-INPUT-001 **Requirement:** `-r ` MUST accept a prefix as an integer or an IPv4 dotted-decimal netmask; it MUST generate an IPv6 network when `-6` is given or the prefix is greater than 32, and an IPv4 network otherwise; and it MUST reject a prefix that is invalid for the family with `ipcalc: bad IPv4 prefix: ` / `ipcalc: bad IPv6 prefix: ` and exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`FLAG_RANDOM`, `str_to_prefix(&flags, randomStr, 1)`) **Acceptance:** `ipcalc -r 112` → IPv6; `ipcalc -6 -r 24` → IPv6 /24; `ipcalc -r 255.255.0.0 -n` → an IPv4 /16; `ipcalc -r 129` → exit 1 — positive, negative ; test: RandomIPv6Implicit, RandomIPv6Explicit (no invalid-prefix test) ### REQ-RANDOM-ERR-001 **Requirement:** ipcalc MUST reject an address argument given together with `-r` with `ipcalc: provided superfluous parameter ''` and exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`if (flags & FLAG_RANDOM) { if (ipStr) …`) **Acceptance:** `ipcalc -r 24 -i 127.0.0.1` → exit 1 — negative ; test: Random-Info ### REQ-RANDOM-CALC-001 **Requirement:** The generated network MUST lie entirely within private address space — for IPv4 within 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16, choosing among those whose length does not exceed the requested prefix; for IPv6 within the locally assigned ULA block fd00::/8 — and MUST draw its random bits from `/dev/urandom`. **Strength:** MUST **Status:** REVIEW **Source:** ipcalc.c:generate_ip_network, ipcalc.c:randomize; ipcalc.1.md#Options (`--random-private`) **Acceptance:** `ipcalc -r 24 --addrspace` → `ADDRSPACE="Private Use"`; `ipcalc -6 -r 48 -a` → `ADDRESS=fd…`; `ipcalc -r 4 -n` → rejected or private — positive, negative ; test: RandomIPv6PrefixIsValidULA, Random, RandomAddress > [REVIEW: defect] For prefixes shorter than the private block, the > network is not private: `ipcalc -r 4 -n --addrspace` → `0.0.0.0`, > `"This host on this network"`, and `ipcalc -r 6 -n` → `8.0.0.0`, > which is public `Internet` space (any IPv4 prefix below 8); > `ipcalc -6 -r 4 -n` → `f000::` (`Reserved`; any IPv6 prefix below 8, > and /7 gives `fc00::/7`, which is not locally assigned). Either reject > such prefixes or document the behavior. > IPv4 prefixes 12–15 always use 10.0.0.0/8 (172.16.0.0/12 is chosen > only for prefixes ≥ 16); the choice between blocks uses the low bits > of the process CPU-time clock, which is incidental. ### REQ-RANDOM-OUTPUT-001 **Requirement:** With `-r` and no field-selecting option, ipcalc MUST print the summary output of the generated network (REQ-INFO-OUTPUT-001) without the `Address` line, except that for /32 and /128 it MUST print the `Address` line; with field-selecting options (e.g. `-a`, `-n`) it MUST print `NAME=value` output. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:show_info_fields (`input_is_network`, `ATTR_SUMMARY_HIDE_FOR_NETWORK_ADDRESS`); ipcalc.1.md#Options (`--random-private`) **Acceptance:** `ipcalc -r 24` → contains `Network:`, no `Address:`; `ipcalc -r 32` → contains `Address:`; `ipcalc -r 24 -a` → `ADDRESS=…` — positive ; test: Random, RandomAddress, RandomIPv6Implicit, RandomIPv6Explicit ## Open items `REVIEW`: REQ-RANDOM-CALC-001 (non-private networks for short prefixes). Missing tests: invalid `-r` prefix; netmask-form `-r`; short prefixes. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/doc/requirements/split.md000066400000000000000000000446271526405142400252400ustar00rootroot00000000000000--- title: Network splitting (-S/--split, --split-hosts) id-prefix: REQ-SPLIT sources: - netsplit.c (show_split_networks) - ipcalc.c (main, parse_split_req, parse_split_hosts, str_to_prefix) - ipcalc.1.md - tests/meson.build --- # Network splitting (`-S/--split`, `--split-hosts`) Generated with `contrib/ai/protocols/requirements-from-implementation.md`. The base network is parsed as in `info.md` (REQ-INFO-INPUT-001 to REQ-INFO-INPUT-005). Terms used below: a **request** is one `-S` argument, `[COUNT:]PREFIX`, asking for COUNT subnets of /PREFIX; a **counted request** has a COUNT; the **fill request** has none and takes the space that remains; an **equal split** is a split with a single fill request (e.g. `-S 26`); a **VLSM split** is any other split, i.e. one with counted requests; a **host-sized request** is one item of `--split-hosts`, asking for one subnet that holds a number of hosts, and is allocated as a counted request with a COUNT of 1; **unused space** is the part of the base network that no request is allocated. ### REQ-SPLIT-INPUT-001 **Requirement:** `-S` MUST take an argument of the form `[COUNT:]PREFIX` and MAY be repeated, each occurrence being one request. PREFIX MUST be accepted as an integer, or for IPv4 as a dotted-decimal netmask, and a PREFIX that is invalid for the family (REQ-INFO-INPUT-003) MUST be rejected with `ipcalc: bad IPv4 prefix: ` / `ipcalc: bad IPv6 prefix: `, where `` is the whole `-S` argument, and exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case 'S'` collects every argument, `case APP_SPLIT`), ipcalc.c:parse_split_req (`str_to_prefix(flags, prefixStr, 1)`); ipcalc.1.md#Options (`--split`) **Acceptance:** `ipcalc -S 26 192.168.5.45/24` → tests/split-192.168.5.45-24-26; `ipcalc -S 255.255.255.192 192.168.5.0/24` → four /26 networks; `ipcalc -S 2:255.255.255.192 192.168.1.0/24` → two /26 networks; `ipcalc -S 1:abc 192.168.0.0/24` → `ipcalc: bad IPv4 prefix: 1:abc`, exit 1; `ipcalc -S 129 2001:db8::/64` → exit 1 — positive, negative ; test: SplitPrefix26, SplitVLSMNetmask, SplitVLSMBadPrefix (no test of the netmask form without a count or of an out-of-range prefix) **Links:** REQ-SPLIT-INPUT-003 ### REQ-SPLIT-INPUT-002 **Requirement:** ipcalc MUST reject a split prefix greater than 32 for an IPv4 network with a message stating that the prefix is invalid for IPv4, and exit with status 1. **Strength:** MUST **Status:** REVIEW **Source:** ipcalc.c:str_to_prefix (`fix` sets `FLAG_IPV6` when the prefix exceeds 32), netsplit.c:show_split_networks (then parses the IPv4 network as IPv6) **Acceptance:** `ipcalc -S 33 192.168.1.0/24` → `ipcalc: bad IPv4 prefix: 33`, exit 1 — negative ; test: none **Links:** REQ-CLI-INPUT-005 > [REVIEW: defect] The input is rejected (exit 1), but via the IPv6 code > path, with the misleading `ipcalc: bad IPv6 address: 192.168.1.0`. ### REQ-SPLIT-INPUT-003 **Requirement:** The COUNT of a `-S` request MUST be a decimal integer from 1 to 2^64−1 made of digits only; ipcalc MUST reject a COUNT of 0, one that is empty or has a non-digit character, or one that does not fit in 64 bits, with `ipcalc: bad split count: ` and exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:parse_split_req (`isdigit`, `strtoull`, `end != sep`, `errno`, `count == 0`) **Acceptance:** `ipcalc -S 1:28 -S 2:27 192.168.0.0/24` → accepted; `ipcalc -S 0:26 192.168.0.0/24`, `ipcalc -S x:26 192.168.0.0/24`, `ipcalc -S 99999999999999999999:26 192.168.0.0/24` → `ipcalc: bad split count: `, exit 1 — positive, negative ; test: SplitVLSMUnused, SplitVLSMZeroCount, SplitVLSMBadCount, SplitVLSMCountOverflow **Links:** REQ-SPLIT-INPUT-001 ### REQ-SPLIT-INPUT-004 **Requirement:** `--split-hosts` MUST take a comma-separated list of host counts and MAY be repeated, the lists being concatenated in the order given; each count is one host-sized request for the smallest subnet with at least that many usable hosts — for IPv4 2^n ≥ count + 2 (network and broadcast addresses included, so the subnet is at most a /30), for IPv6 2^n ≥ count. Each count MUST be a decimal integer of digits only from 1 to 2^64−1; ipcalc MUST reject a count of 0, an empty item, a non-digit character, or a value that does not fit in 64 bits with `ipcalc: bad host count: `, where `` is the whole argument, and an IPv4 count above 4294967294 with `ipcalc: too many hosts requested: `; both with exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case OPT_SPLIT_HOSTS`), ipcalc.c:parse_split_hosts; ipcalc.1.md#Options (`--split-hosts`) **Acceptance:** `ipcalc --split-hosts=10,20,30 192.168.0.0/24` → a /28 and two /27; `ipcalc --split-hosts=1,2,62,63 192.168.0.0/24` → /30, /30, /26, /25; `ipcalc --split-hosts=1,2 --split-hosts=62,63 192.168.0.0/24` → same; `ipcalc --split-hosts=1,2,3,256 2001:db8::/112` → /128, /127, /126, /120; `ipcalc -j --split-hosts=4294967294 0.0.0.0/0` → `0.0.0.0/0`; `ipcalc --split-hosts=0 …`, `--split-hosts=1,,2 …`, `--split-hosts=18446744073709551616 2001:db8::/64` → `ipcalc: bad host count: `, exit 1; `ipcalc --split-hosts=4294967295 0.0.0.0/0` → `ipcalc: too many hosts requested: 4294967295`, exit 1 — positive, negative ; test: SplitHosts, SplitHostsSmallest, SplitHostsRepeated, SplitHostsIPv6, JsonSplitHostsWholeIPv4, SplitHostsZero, SplitHostsEmptyItem, SplitHostsOverflow, SplitHostsTooManyHosts **Links:** REQ-SPLIT-CALC-002, REQ-SPLIT-OUTPUT-004 > A host-sized IPv6 request is at most a /64, since counts are limited > to 2^64−1. ### REQ-SPLIT-ERR-001 **Requirement:** ipcalc MUST reject a request whose prefix is shorter than the base network's prefix with `Cannot subnet to / with this base network, use a prefix > /` and exit status 1, and MUST accept a prefix equal to the base prefix (producing the base network itself). **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks (`reqs[i].prefix < info->prefix`) **Acceptance:** `ipcalc -S 23 192.168.1.0/24`, `ipcalc -S 1:23 192.168.1.0/24` → exit 1; `ipcalc -S 24 192.168.1.0/24`, `ipcalc -S 1:24 192.168.1.0/24` → one network, exit 0 — negative, positive ; test: none > [REVIEW] The message says "use a prefix > /N" but a prefix equal to N > is accepted; it should say ">=". ### REQ-SPLIT-ERR-002 **Requirement:** ipcalc MUST reject more than one request without a COUNT with `ipcalc: only one split prefix may be given without a count` and exit status 1, so that the space left after the counted requests has a single, unambiguous prefix. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case APP_SPLIT`, `nfill > 1`) **Acceptance:** `ipcalc -S 26 -S 27 192.168.0.0/24` → exit 1 — negative ; test: SplitVLSMTwoFills ### REQ-SPLIT-ERR-003 **Requirement:** When the requests do not fit in the base network — the counted or host-sized requests need more addresses than it has (including a single host-sized request larger than the network), or a fill request is given and no aligned subnet of its prefix remains after the counted requests — ipcalc MUST print nothing to stdout, print `ipcalc: / is too small for the requested subnets` to stderr, and exit with status 1. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks (`too_small()`, called before any output; for host-sized requests also when `reqs[i].prefix < info->prefix`) **Acceptance:** `ipcalc -S 1:25 -S 1:25 -S 1:26 192.168.0.0/24`, `ipcalc -S 2:25 -S 26 192.168.0.0/24`, `ipcalc --split-hosts=200,100 192.168.0.0/24`, `ipcalc --split-hosts=300 192.168.0.0/24` → exit 1, only the message — negative ; test: SplitVLSMTooSmall, SplitVLSMNoSpaceForFill, SplitHostsTooSmall, SplitHostsLargerThanNetwork **Links:** REQ-SPLIT-CALC-002, REQ-SPLIT-CALC-003 ### REQ-SPLIT-ERR-004 **Requirement:** ipcalc MUST reject `--split-hosts` together with `-S` with `ipcalc: --split-hosts cannot be combined with --split` and exit status 1. **Strength:** MUST **Status:** DERIVED **Source:** ipcalc.c:main (`case APP_SPLIT`, `nsplits && nsplitHosts`) **Acceptance:** `ipcalc --split-hosts=10 -S 26 192.168.0.0/24` → exit 1 — negative ; test: SplitHostsWithSplit **Links:** REQ-CLI-ERR-001 ### REQ-SPLIT-CALC-001 **Requirement:** In an equal split, ipcalc MUST list, in ascending address order, every subnet of the given prefix contained in the base network — exactly 2^(split − base) subnets, starting at the base network address — for both IPv4 and IPv6, including networks at either end of the address space. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks **Acceptance:** `ipcalc -S 18 10.10.10.10/16` → tests/split-10.10.10.0-16-18 (4 networks from 10.10.0.0); `ipcalc -S 120 fcfa:b4ca:f1d8:125b:dc00::/112` → 256 networks; `ipcalc -S 2 ::/0` → `::/2`, `4000::/2`, `8000::/2`, `c000::/2`; `ipcalc -S 124 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/120` → 16 networks from `ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/124` — positive ; test: SplitPrefix18, SplitPrefix24, SplitPrefix26, SplitPrefix29, SplitPrefix31, SplitPrefix32, SplitPrefix64, SplitPrefix120, SplitPrefix128, SplitPrefix0IPv4, SplitPrefix3Of1, SplitPrefix2Of0IPv6, SplitPrefix124EndOfSpace, SplitLinesByNetworkIPv4, SplitLinesByNetworkIPv6 **Links:** REQ-SPLIT-OUTPUT-001 ### REQ-SPLIT-CALC-002 **Requirement:** ipcalc MUST allocate the counted (or host-sized) requests back to back from the base network address, largest subnets first and, among requests of the same prefix, in the order given, so that every subnet is aligned to its size and no space is lost between them. This is the layout of the split of the Debian ipcalc. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks (`order[]` insertion sort by prefix, `cursor`) **Acceptance:** `ipcalc -S 1:28 -S 2:27 192.168.0.0/24` → `192.168.0.64/28`, `192.168.0.0/27`, `192.168.0.32/27`; `ipcalc -S 1:26 -S 1:25 -S 27 192.168.0.0/24` → the /25 at `192.168.0.0`, the /26 at `192.168.0.128` — positive ; test: SplitVLSMUnused, SplitVLSMPrefix58And64, SplitVLSMWholeSpace, SplitHosts, SplitHostsExactFit **Links:** REQ-SPLIT-OUTPUT-001, REQ-SPLIT-ERR-003 ### REQ-SPLIT-CALC-003 **Requirement:** ipcalc MUST allocate the fill request as all subnets of its prefix from the first address after the counted requests that is aligned to that prefix up to the end of the base network; the space skipped to reach that alignment is unused space. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks (fill request after the counted ones, `gap`) **Acceptance:** `ipcalc -S 1:58 -S 64 2001:db8:1c88:6000::/56` → one /58 and 192 /64 networks; `ipcalc -S 3:64 -S 60 2001:db8::/56` → three /64, then fifteen /60 from `2001:db8:0:10::/60`, unused `2001:db8:0:3::/64`, `2001:db8:0:4::/62`, `2001:db8:0:8::/61`; `ipcalc -S 2:26 -S 26 192.168.1.0/24` → four /26 networks — positive ; test: SplitVLSMPrefix58And64, SplitVLSMFillAligned, SplitVLSMSamePrefix, SplitVLSMWholeSpace **Links:** REQ-SPLIT-OUTPUT-003, REQ-SPLIT-ERR-003 ### REQ-SPLIT-OUTPUT-001 **Requirement:** Except for the decorated output of host-sized requests (REQ-SPLIT-OUTPUT-004), the split output MUST list the subnets of each request in the order the requests are given, each request's subnets in ascending address order, as: decorated — a `[Split networks]` header, one `Network:\t/` line per subnet, a blank line, `Total: \t` with the number of subnets of all requests, and, only when every request has the same prefix, `Hosts/Net:\t`; with `--no-decorate` — only one `/` line per subnet; with `-j` — an object with `SPLITNETWORK` (array of `/` strings), `NETS`, and, under the same condition as `Hosts/Net`, `ADDRESSES`. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks (`array_start(…, "Split networks", "SPLITNETWORK")`, `default_printf`, `dist_printf(… "NETS" …)`, `same_prefix`, `dist_printf(… "ADDRESSES" …)`) **Acceptance:** `ipcalc -S 26 192.168.5.45/24`, `ipcalc --no-decorate -S 26 192.168.5.45/24`, `ipcalc -j -S 26 192.168.5.45/24` → tests/split-…, tests/nsplit-…, tests/json-split-192.168.5.45-24-26; `ipcalc -S 1:28 -S 2:27 192.168.0.0/24` → `Total: 3` and no `Hosts/Net`; `ipcalc -S 2:26 -S 26 192.168.1.0/24` → `Hosts/Net: 62` — positive ; test: SplitPrefix26, NoDecorateSplitPrefix26, JsonSplitPrefix26, JsonNoDecorateSplitPrefix26, the other Split/NoDecorateSplit/JsonSplit tests, SplitVLSMUnused, JsonSplitVLSMUnused, SplitVLSMSamePrefix **Links:** REQ-CLI-OUTPUT-006, REQ-CLI-OUTPUT-008 ### REQ-SPLIT-OUTPUT-002 **Requirement:** The split `Hosts/Net`/`ADDRESSES` value MUST be the host count of one subnet of the split prefix, as defined by REQ-INFO-CALC-004, printed in full for every prefix. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks (`ipv4_prefix_to_hosts`, `ipv6_prefix_to_hosts`) **Acceptance:** `ipcalc -S 26 192.168.5.45/24` → `Hosts/Net: 62`; `ipcalc -S 0 0.0.0.0/0` → `Hosts/Net: 4294967294`; `ipcalc -S 3 10.0.0.0/1` → `Hosts/Net: 536870910`; `ipcalc -S 2 ::/0` → `Hosts/Net: 85070591730234615865843651857942052864` — positive ; test: SplitPrefix26, SplitPrefix0IPv4, SplitPrefix3Of1, SplitPrefix2Of0IPv6 **Links:** REQ-INFO-CALC-004 ### REQ-SPLIT-OUTPUT-003 **Requirement:** When part of the base network is unused space, ipcalc MUST print it after the split networks as the minimal list of CIDR networks that covers it, in ascending address order: decorated — a blank line, an `[Unused networks]` header, and one `Network:\t/` line per network; with `-j` — an `UNUSED` array of `/` strings. ipcalc MUST NOT print unused space with `--no-decorate` (without `-j`), nor print the section or key when there is no unused space. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:show_split_networks (`has_gap`, `array_start(…, "Unused networks", "UNUSED")`), netsplit.c:print_range **Acceptance:** `ipcalc -S 1:28 -S 2:27 192.168.0.0/24` → unused `192.168.0.80/28`, `192.168.0.96/27`, `192.168.0.128/25`; same with `-j` → `"UNUSED"` array; same with `--no-decorate` → only the three split networks; `ipcalc -S 26 192.168.0.0/24` → no unused section — positive, negative ; test: SplitVLSMUnused, JsonSplitVLSMUnused, NoDecorateSplitVLSMUnused, SplitVLSMFillAligned, SplitPrefix26 **Links:** REQ-SPLIT-CALC-003, REQ-CLI-OUTPUT-008 ### REQ-SPLIT-OUTPUT-004 **Requirement:** For `--split-hosts`, the decorated output MUST replace each subnet's `Network:` line with a block per request, in request order and separated by blank lines: `. Requested size: hosts`, `Network:\t/`, `Netmask:\t = `, for IPv4 only `Broadcast:\t`, `HostMin:\t`, `HostMax:\t`, and `Hosts/Net:\t` — with the host range and count as for info mode (REQ-INFO-CALC-003, REQ-INFO-CALC-004) for IPv4, and the first address, last address and address count for IPv6. After `Total:` (and `Hosts/Net:` per REQ-SPLIT-OUTPUT-001) it MUST print `Needed size:\t`, the number of addresses from the base network address to the end of the last allocated subnet, and `Used network:\t/`, the smallest network starting at the base network address that contains all the subnets, followed by the unused networks (REQ-SPLIT-OUTPUT-003). With `-j` the output MUST be that of REQ-SPLIT-OUTPUT-001 with `NEEDED` and `USEDNETWORK` added before `UNUSED`; with `--no-decorate` (without `-j`) only one `/` line per subnet. **Strength:** MUST **Status:** DERIVED **Source:** netsplit.c:print_host_sized_subnet, netsplit.c:show_split_networks (`host_sized`, `details`, `dist_printf(… "NEEDED" …)`, `dist_printf(… "USEDNETWORK" …)`) **Acceptance:** `ipcalc --split-hosts=10,20,30 192.168.0.0/24` → tests/split-hosts-192.168.0.0-24-10,20,30 (`Needed size: 80`, `Used network: 192.168.0.0/25`); same with `-j` → `"NEEDED":"80"`, `"USEDNETWORK":"192.168.0.0/25"`; same with `--no-decorate` → three lines; `ipcalc --split-hosts=1,2,3,256 2001:db8::/112` → no `Broadcast:`, `Needed size: 263`, `Used network: 2001:db8::/119` — positive ; test: SplitHosts, JsonSplitHosts, NoDecorateSplitHosts, SplitHostsSmallest, SplitHostsIPv6, JsonSplitHostsWholeIPv4 **Links:** REQ-SPLIT-OUTPUT-001, REQ-SPLIT-OUTPUT-003, REQ-CLI-OUTPUT-008 ### REQ-SPLIT-COMPAT-001 **Requirement:** For an IPv4 network that holds the requests and host counts of 1 or more, `--split-hosts=N1,N2,…` SHOULD produce the same values as `ipcalc -s N1 N2 …` of the Debian ipcalc (0.51) — the same subnets in the same request order, with the same netmask, broadcast, `HostMin`, `HostMax`, and `Hosts/Net`, and the same needed size, used network, and unused networks — so that users of that tool can switch. The layout MAY differ: ipcalc prints the fields in its own split format (REQ-SPLIT-OUTPUT-004), without the Debian tool's leading block for the base network and its class column. Where the Debian ipcalc accepts input that ipcalc does not, ipcalc MUST follow its own requirements: a host count of 0 (Debian: a /31) is rejected per REQ-SPLIT-INPUT-004, and requests that do not fit (Debian: prints `Network is too small` and subnets beyond the network) fail per REQ-SPLIT-ERR-003. **Strength:** SHOULD **Status:** DERIVED **Source:** netsplit.c (header comment, print_host_sized_subnet); ipcalc.1.md#Options (`--split-hosts`); Debian ipcalc 0.51-1 `split_network()` (https://sources.debian.org/src/ipcalc/0.51-1/ipcalc) **Acceptance:** with the Debian script (tests/debian-ipcalc/ipcalc) run as `ipcalc -n -b -s `, the values above match for `192.168.0.0/24` with `10,20,30`, `1,2,62,63`, `126,62,62`, `5,5,5`, `30,30,30,30,30,30,30,30`; `192.168.5.45/24` with `10,20`; `192.168.1.0/24` with `254`; `10.0.0.0/30` with `2`; `172.16.0.0/12` with `1`; `10.0.0.0/8` with `1000,5,5,70000,300,2`; `10.0.0.0/16` with `2000,1000,500,250,120,60,30,14,6,2,1`; `10.20.30.0/23` with `100,100,50,3,3,1` — positive ; test: DebianSplitHosts-- (one per case, registered in the git tree, where the Debian script is present; they need perl and its bignum module and fail without them, per REQ-GEN-TEST-007); SplitHosts, SplitHostsSmallest, SplitHostsExactFit pin the matching values **Links:** REQ-SPLIT-OUTPUT-004, REQ-SPLIT-INPUT-004, REQ-SPLIT-ERR-003 ## Open items `REVIEW`: REQ-SPLIT-INPUT-002 (IPv4 split prefix > 32 goes through the IPv6 path), REQ-SPLIT-ERR-001 (message says ">"). Missing tests: netmask-form split prefix without a count, invalid split prefix, split prefix shorter than or equal to the base. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipcalc-maxmind.c000066400000000000000000000210571526405142400233150ustar00rootroot00000000000000/* * 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 . * * Authors: * Martin Sehnoutka */ #define _GNU_SOURCE #include #include #include #include #include #include #include "ipcalc.h" #ifdef USE_MAXMIND #include #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 #ifndef MAXMINDDB_LOCATION_ASN #define MAXMINDDB_LOCATION_ASN "/usr/share/GeoIP/GeoLite2-ASN.mmdb" #endif #ifdef USE_RUNTIME_LINKING # include # 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_aget_value_fn)(MMDB_entry_s *const start, MMDB_entry_data_s *const entry_data, const char *const *const path); static MMDB_close_fn pMMDB_close; static MMDB_aget_value_fn pMMDB_aget_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[512] = {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; geographic information requires libmaxminddb and the GeoLite2 databases, install them if they are missing\n", LIBNAME); ret = -1; return ret; } pMMDB_close = dlsym(ld, "MMDB_close"); pMMDB_aget_value = dlsym(ld, "MMDB_aget_value"); pMMDB_lookup_string = dlsym(ld, "MMDB_lookup_string"); pMMDB_open = dlsym(ld, "MMDB_open"); if (pMMDB_close == NULL || pMMDB_aget_value == NULL || pMMDB_lookup_string == NULL || pMMDB_open == NULL) { snprintf(err, sizeof(err), "ipcalc: could not find symbols in libmaxmind\n"); ret = -1; } return ret; } #else #define pMMDB_close MMDB_close #define pMMDB_aget_value MMDB_aget_value #define pMMDB_lookup_string MMDB_lookup_string #define pMMDB_open MMDB_open #endif /* USE_RUNTIME_LINKING */ static int get_entry_data(MMDB_entry_s *entry, const char *const *path, uint32_t type, MMDB_entry_data_s *data) { return pMMDB_aget_value(entry, data, path) == MMDB_SUCCESS && data->has_data && data->type == type; } /* NULL when the record has no string at path */ static char *get_string(MMDB_entry_s *entry, const char *const *path) { MMDB_entry_data_s data; char *str = NULL; /* MaxMind DB strings are not NUL-terminated */ if (get_entry_data(entry, path, MMDB_DATA_TYPE_UTF8_STRING, &data)) safe_asprintf(&str, "%.*s", (int)data.data_size, data.utf8_string); return str; } /* NULL when the record has no unsigned integer at path */ static char *get_unsigned(MMDB_entry_s *entry, const char *const *path) { MMDB_entry_data_s data; char *str = NULL; if (get_entry_data(entry, path, MMDB_DATA_TYPE_UINT16, &data)) safe_asprintf(&str, "%u", (unsigned)data.uint16); else if (get_entry_data(entry, path, MMDB_DATA_TYPE_UINT32, &data)) safe_asprintf(&str, "%u", (unsigned)data.uint32); return str; } /* Finds the record of ip, when it covers the whole network ip/prefix, and * the prefix of its network; on success the caller must close mmdb */ static int lookup(const char *file, const char *ip, unsigned prefix, MMDB_s *mmdb, MMDB_lookup_result_s *result, unsigned *record_prefix) { int gai_error, mmdb_error; if (pMMDB_open(file, MMDB_MODE_MMAP, mmdb) != MMDB_SUCCESS) return -1; /* mmdb_error is not set when gai_error is */ *result = pMMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error); if (gai_error != 0 || mmdb_error != MMDB_SUCCESS || !result->found_entry) { pMMDB_close(mmdb); return -1; } *record_prefix = result->netmask; /* IPv4 records are in the ::/96 subtree of an IPv6 database */ if (strchr(ip, ':') == NULL && mmdb->metadata.ip_version == 6) *record_prefix = *record_prefix > 96 ? *record_prefix - 96 : 0; if (prefix < *record_prefix) { pMMDB_close(mmdb); return -1; } return 0; } /* The network ip/prefix in CIDR notation */ static char *record_network(const char *ip, unsigned prefix) { unsigned char addr[sizeof(struct in6_addr)]; char str[INET6_ADDRSTRLEN]; int family = strchr(ip, ':') ? AF_INET6 : AF_INET; unsigned i, len = family == AF_INET6 ? 16 : 4; char *network = NULL; if (inet_pton(family, ip, addr) != 1) return NULL; for (i = 0; i < len; i++) { if (prefix <= i * 8) addr[i] = 0; else if (prefix < (i + 1) * 8) addr[i] &= 0xff << (8 - (prefix - i * 8)); } if (inet_ntop(family, addr, str, sizeof(str)) == NULL) return NULL; safe_asprintf(&network, "%s/%u", str, prefix); return network; } /* A missing database or record is not an error: the values it would * provide are left NULL */ void geo_ip_lookup(const char *ip, unsigned prefix, struct geo_info_st *geo) { static const char *const country_keys[] = { "country", "represented_country", "registered_country" }; static const char *const continent_path[] = { "continent", "names", "en", NULL }; static const char *const city_path[] = { "city", "names", "en", NULL }; static const char *const postal_path[] = { "postal", "code", NULL }; static const char *const latitude_path[] = { "location", "latitude", NULL }; static const char *const longitude_path[] = { "location", "longitude", NULL }; static const char *const radius_path[] = { "location", "accuracy_radius", NULL }; static const char *const time_zone_path[] = { "location", "time_zone", NULL }; static const char *const asn_path[] = { "autonomous_system_number", NULL }; static const char *const as_org_path[] = { "autonomous_system_organization", NULL }; MMDB_s mmdb; MMDB_lookup_result_s result; MMDB_entry_data_s latitude, longitude; unsigned i, record_prefix, network_prefix = 0; int found = 0; if (geo_setup() != 0) return; if (lookup(MAXMINDDB_LOCATION_COUNTRY, ip, prefix, &mmdb, &result, &record_prefix) == 0) { found = 1; network_prefix = record_prefix; geo->continent = get_string(&result.entry, continent_path); for (i = 0; i < sizeof(country_keys) / sizeof(country_keys[0]) && !geo->country && !geo->ccode; i++) { const char *const name_path[] = { country_keys[i], "names", "en", NULL }; const char *const code_path[] = { country_keys[i], "iso_code", NULL }; geo->country = get_string(&result.entry, name_path); geo->ccode = get_string(&result.entry, code_path); } pMMDB_close(&mmdb); } if (lookup(MAXMINDDB_LOCATION_CITY, ip, prefix, &mmdb, &result, &record_prefix) == 0) { found = 1; /* the smallest network is the one where all records hold */ if (record_prefix > network_prefix) network_prefix = record_prefix; geo->city = get_string(&result.entry, city_path); geo->postal_code = get_string(&result.entry, postal_path); if (get_entry_data(&result.entry, latitude_path, MMDB_DATA_TYPE_DOUBLE, &latitude) && get_entry_data(&result.entry, longitude_path, MMDB_DATA_TYPE_DOUBLE, &longitude)) safe_asprintf(&geo->coord, "%f,%f", latitude.double_value, longitude.double_value); geo->accuracy_radius = get_unsigned(&result.entry, radius_path); geo->time_zone = get_string(&result.entry, time_zone_path); pMMDB_close(&mmdb); } if (lookup(MAXMINDDB_LOCATION_ASN, ip, prefix, &mmdb, &result, &record_prefix) == 0) { found = 1; if (record_prefix > network_prefix) network_prefix = record_prefix; geo->asn = get_unsigned(&result.entry, asn_path); geo->as_org = get_string(&result.entry, as_org_path); geo->as_network = record_network(ip, record_prefix); pMMDB_close(&mmdb); } if (found) geo->network = record_network(ip, network_prefix); } #endif /* USE_MAXMIND */ ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipcalc-reverse.c000066400000000000000000000116031526405142400233270ustar00rootroot00000000000000/* * 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 . * * Authors: * Nikos Mavrogiannopoulos */ #define _GNU_SOURCE /* asprintf */ #include #include #include #include #include #include #include #include #include #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); } else if (prefix > 0) { unsigned min = (ntohl(network.s_addr) >> 24) & 0xff; unsigned max = (ntohl(broadcast.s_addr) >> 24) & 0xff; ret = asprintf(&str, "%u-%u.in-addr.arpa.", min, max); } else { ret = asprintf(&str, "in-addr.arpa."); } #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(); } /* Returns the value of the idx-th nibble of ip, counting from the most * significant one. */ static unsigned nibble(const struct in6_addr *ip, unsigned idx) { unsigned byte = ip->s6_addr[idx / 2]; return (idx % 2 == 0) ? (byte >> 4) : (byte & 0xf); } /* Stores in names the ip6.arpa. domains covering the network ip/prefix and * returns their number. The caller owns the returned strings. * * The nibble format of RFC 3596 can only express prefixes that are a multiple * of 4 (the bit-string labels of RFC 2673 that could do otherwise are no * longer in use, see RFC 3363). A network with any other prefix is covered by * the 2^(4 - prefix % 4) domains at the next nibble boundary, which are * returned in ascending order. */ unsigned calc_reverse_dns6(struct in6_addr *ip, unsigned prefix, char *names[MAX_REVERSE_DNS]) { /* 32 nibbles of "x." followed by "ip6.arpa." */ char str[32 * 2 + sizeof("ip6.arpa.")]; unsigned nibbles = (prefix + 3) / 4; unsigned host_bits = nibbles * 4 - prefix; unsigned count = 1u << host_bits; unsigned i, k, j; for (k = 0; k < count; k++) { j = 0; for (i = nibbles; i > 0; i--) { unsigned val = nibble(ip, i - 1); if (i == nibbles) val = (val & ~(count - 1)) + k; str[j++] = hexchar(val); str[j++] = '.'; } strcpy(&str[j], "ip6.arpa."); names[k] = safe_strdup(str); } return count; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipcalc-utils.c000066400000000000000000000037311526405142400230170ustar00rootroot00000000000000/* * 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 . * * Authors: * Martin Sehnoutka */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "ipcalc.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(exit_failure); } 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(exit_failure); } return ret; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipcalc.1.md000066400000000000000000000521341526405142400221770ustar00rootroot00000000000000# ipcalc(1) - Perform simple operations on IP addresses and networks ## SYNOPSIS **ipcalc** [OPTION]... [/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. The options select what **ipcalc** prints: by default, or with **--info** or **--all-info**, a summary of the network; with specific info options (e.g., **--prefix**), only those values. The **--format** option selects how it is printed, as described in the Output format section. Multiple options may be specified. It is required to specify an IP address; several operations require a netmask or a CIDR prefix as well. ## Output format The **--format**=_FORMAT_ option selects one of these formats: * **human** Titled lines, as in the summary. Colors are used only when the output is a terminal and the NO_COLOR environment variable is not set. This is the default for the summary and for **--split**, **--split-hosts**, **--deaggregate** and **--binary**. * **shell** **VAR=VALUE** lines that can be passed to the shell's eval; a value that contains characters special to the shell, such as a space, is quoted and escaped. This is the default for the specific info options. * **json** A JSON object, whose values are all strings or arrays of strings. * **value** The values only, one per line; a value that would be quoted in the **shell** format keeps its quotes. Each format applies to whatever is selected: the summary, or exactly the values of the specific info options, e.g., "ipcalc --format=json -n -m 192.168.1.5/24" prints only NETWORK and NETMASK. The specific info options accept all four formats; the formats each operation accepts are given in its description. Scripts should always pass **--format**, so that their output does not depend on the defaults. ## Options * **-c**, **--check** Checks whether this is a valid IP address. When an IP family is specified only the addresses of that family are accepted. A zero exit status indicates a well formed address and a non-zero exit status indicates a malformed address. **--format** is ignored. * **--equals**=NET, **--subnet-of**=NET, **--overlaps**=NET Compare the provided network with NET and print the result, such as "The networks overlap" or "192.168.0.0/24 is a subnet of 192.168.0.0/23"; nothing is printed with **--silent**. **--equals** holds if both have the same network address and prefix, **--subnet-of** if every address of the network is in NET (equal networks included), and **--overlaps** if the two share at least one address; for CIDR networks the latter holds exactly when one is a subnet of the other. Host bits are ignored, and NET is given in the same form as the provided address, with an optional prefix or netmask after a slash. Networks of different families never compare true. The exit status is 0 when the comparison holds, 1 when it does not, and 2 on any error, such as a malformed address. Only one comparison may be given, and not together with **--check**. The only format accepted is **human**. Example "ipcalc 192.168.0.1/24 --subnet-of=192.168.0.0/23". * **-i**, **--info** Display basic information on the provided network in human readable format, in a short summary, plus the fields of any specific info options given (e.g., **--reverse-dns**). This is the default option if no other options are provided. The formats accepted are **human**, **shell** and **json**; with **--format**, the specific info options other than **--lookup-host** cannot be given. * **--all-info** Display all the information ipcalc can determine on the provided network and addresses in human readable format, which may be long. That includes geographic information, but not the hostname, which requires a DNS lookup (see **--hostname**). The formats accepted are as for **--info**. For an IPv6 unicast address it also prints the interface identifier, i.e., the low 64 bits of the address, unless they are all zero or the address lies in ::/3. When the interface identifier is a Modified EUI-64 (it contains ff:fe in its middle octets), it prints the EUI-64, the MAC address it was derived from, whether that MAC address is universally (UAA) or locally (LAA) administered (MAC scope: universal or local), and whether it is an individual or group address (MAC type). These fields are not derived from other interface identifiers, such as stable privacy or temporary addresses, whose bits carry no such meaning (RFC 7136). * **-S**, **--split**=[COUNT:]PREFIX Split the provided network using the specified prefix or netmask. That is, split up the network into smaller chunks of a specified prefix. The formats accepted are **human**, **json** and **value**; with **value**, only the split networks are printed, one per line. Example "ipcalc -S 26 192.168.1.0/24". The option can be repeated to split the network into subnets of different sizes, also known as a VLSM (variable-length subnet mask) split. Each request of the form COUNT:PREFIX asks for COUNT subnets of the given prefix or netmask, and at most one request without a count takes all the space that remains. Requests are allocated from the start of the network, the largest subnets first, while the subnets are printed in the order of the requests. Space that is not allocated to any request is printed as unused networks, except with **--format=value**. If the network is too small for the requests, nothing is printed and the exit status is 1. Example "ipcalc -S 1:58 -S 64 2001:db8:1c88:6000::/56". * **--split-hosts**=N1,N2,... Split the provided network into subnets that hold N1, N2, ... hosts, one subnet for each count. Each subnet is the smallest that holds the hosts; for IPv4 that includes the network and broadcast addresses (e.g., 10 hosts need a /28). The subnets are allocated as with **--split** and printed with their details, followed by the needed size, the used network and the unused networks. The values are those of the split of the Debian ipcalc (its **-s** option), except that IPv6 networks are supported, a host count of 0 is rejected, and if the network is too small for the requests, nothing is printed and the exit status is 1. It cannot be combined with **--split**. The formats accepted are as for **--split**. Example "ipcalc --split-hosts=10,20,30 192.168.0.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". The formats accepted are **human**, **json** and **value**; with **value**, only the networks are printed, one per line. * **--binary** Displays the bits of the provided address or, when a prefix is given, the bits of the network part of the network; any host bits set in the address are ignored. By default it prints each octet of an IPv4 address, or each 16-bit group of an IPv6 address, above its bits, marks the host bits with 'x', and brackets the network and host parts with UTF-8 box-drawing characters. An IPv6 address is printed in two halves, or on a single line when the output is at least 135 columns wide (see **COLUMNS**). All four formats are accepted; with **value**, only the bits of the network are printed, as in NETWORK, e.g., "11000000101010000000000000000000" for 192.168.0.0/16. The variables exposed are the addresses of the output, each as all of its bits: ADDRESS when no prefix shorter than the address is given; otherwise PREFIX followed, for IPv4, by ADDRESS, NETMASK, NETWORK, HOSTMIN, HOSTMAX and BROADCAST (for a /31, without NETWORK and BROADCAST), and for IPv6 by NETWORK. The bits are not part of the summary, and the option cannot be combined with other operations or with the specific info options. * **-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 address must be a single address; a network (e.g., "127.0.0.1/8") is rejected. The variable exposed is HOSTNAME. * **-o**, **--lookup-host**=_NAME_ Display the IP address for the given hostname. With **--info** or **--all-info**, display the summary of that address instead. 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 libmaxminddb to be available, and is not accepted when ipcalc is built without it. The variables exposed are CONTINENT, COUNTRYCODE, COUNTRY, CITY, POSTALCODE, COORDINATES (latitude,longitude), ACCURACYRADIUS, TIMEZONE (e.g., Europe/Athens), ASN, ASORG, ASNETWORK and GEONETWORK (when available). ASN is the number of the autonomous system that routes the address on the Internet, i.e., the network of a single operator such as an ISP, a hosting provider or a company, and ASORG is the name of the organization that operates it (e.g., ASN=1241 and ASORG=Forthnet; "Routed by AS" and "Operated by" in the summary). They come from the GeoLite2 ASN database, when it is installed. ASNETWORK is the network, in CIDR notation, for which that database holds them; as the database is built from routing data, it approximates the network the autonomous system announces, e.g., the allocation of the ISP to which the address belongs. GEONETWORK is the network, in CIDR notation, for which the database holds the printed values. When the database has no country for the address, COUNTRY and COUNTRYCODE are the country its users represent (e.g., for a military base) or, without one, the country in which the network is registered. ACCURACYRADIUS is the accuracy of COORDINATES, as a radius in **kilometers** around them within which the address is likely to be. The summary output prints it with its unit, e.g., "Accuracy: 200 km". For a network, a value is printed only when the database knows it for the whole network, not just for the given address. * **-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. * **--wildcard** Display the wildcard mask, the inverse of the netmask that Cisco ACLs and OSPF use, e.g., "0.0.0.255" for a /24 network. It applies to IPv4 only; nothing is printed for IPv6. The variable exposed is WILDCARD. The summary shows it with **--all-info**. * **-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. * **--cidr** Display the network address and the prefix in CIDR notation, e.g., "192.168.123.0/24". The prefix is included for a single address too. The variable exposed is CIDR. For example, "ipcalc -r 24 --cidr --format=value" prints a random private network. * **--reverse-dns** Display the reverse DNS for the given IP address and netmask. Reverse DNS domains for IPv6 (RFC 3596) can only be delegated at 4-bit boundaries, so for an IPv6 prefix that is not a multiple of 4 the network is covered by up to 8 domains, which are all printed. In that case the REVERSEDNS variable holds a quoted, space-separated list, and with **--format=value** each domain is printed on its own line. The summary shows it with **--all-info**, and in JSON REVERSEDNS is always an array. 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. * **--format**=_FORMAT_ Print the output as **human**, **shell**, **json** or **value**; see the Output format section. * **-s**, **--silent** Don't ever display error messages, nor the result of a comparison. ## Deprecated options These options are kept for compatibility with earlier versions. On a terminal, ipcalc prints a hint that names the replacement. * **-j**, **--json** Print the summary as a JSON object, even when specific info options are given, which only add their values to it; with **--split**, **--split-hosts**, **--deaggregate** and **--binary** print JSON, and with the comparison options print nothing. Use **--format=json**, which prints only the selected values. * **--no-decorate** Print the values of the specific info options, or the networks of **--split**, **--split-hosts** and **--deaggregate**, without titles; print the summary without colors; and with the comparison options print nothing. It is ignored when **-j** is given, and cannot be used with **--binary**. Use **--format=value**, or for the summary **--format=human** with the NO_COLOR environment variable set. ## Environment * **NO_COLOR** When set, to any value, the **human** format is printed without colors, even on a terminal. * **COLUMNS** The width of the output in columns. With **--binary**, an IPv6 address is printed on a single line when it is 135 or more, and in two halves otherwise, e.g., "COLUMNS=135 ipcalc --binary 2001:db8::/48". When unset, the width of the terminal is used, or 80 when the output is not a terminal. ## 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 Wildcard: 0.0.0.255 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 --format=shell -pnmb --minaddr --maxaddr --geoinfo --addrspace 193.92.150.2/255.255.255.224 NETWORK=193.92.150.0 NETMASK=255.255.255.224 PREFIX=27 BROADCAST=193.92.150.31 ADDRSPACE=Internet MINADDR=193.92.150.1 MAXADDR=193.92.150.30 COUNTRYCODE=GR 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 Interface ID: face:b00c:0000:0014 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 the MAC address behind an IPv6 link-local address $ ipcalc --all-info fe80::21b:21ff:fe3a:5c7d/64 Full Address: fe80:0000:0000:0000:021b:21ff:fe3a:5c7d Address: fe80::21b:21ff:fe3a:5c7d Full Network: fe80:0000:0000:0000:0000:0000:0000:0000/64 Network: fe80::/64 Netmask: ffff:ffff:ffff:ffff:: = 64 Reverse DNS: 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. Address space: Link-Scoped Unicast Interface ID: 021b:21ff:fe3a:5c7d EUI-64: 00:1b:21:ff:fe:3a:5c:7d MAC address: 00:1b:21:3a:5c:7d MAC scope: universal MAC type: individual HostMin: fe80:: HostMax: fe80::ffff:ffff:ffff:ffff Hosts/Net: 2^(64) = 18446744073709551616 ### Display JSON output $ ipcalc --all-info --format=json 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", "CIDR":"2a03:2880:20:4f06::/64", "REVERSEDNS":[ "6.0.f.4.0.2.0.0.0.8.8.2.3.0.a.2.ip6.arpa."], "ADDRSPACE":"Global Unicast", "INTERFACEID":"face:b00c:0000:0014", "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" } ### Split a network into subnets of different sizes $ ipcalc -S 1:28 -S 2:27 192.168.0.0/24 [Split networks] Network: 192.168.0.64/28 Network: 192.168.0.0/27 Network: 192.168.0.32/27 Total: 3 [Unused networks] Network: 192.168.0.80/28 Network: 192.168.0.96/27 Network: 192.168.0.128/25 ### Split a network into subnets for a number of hosts $ ipcalc --split-hosts=10,20 192.168.0.0/24 [Split networks] 1. Requested size: 10 hosts Network: 192.168.0.32/28 Netmask: 255.255.255.240 = 28 Broadcast: 192.168.0.47 HostMin: 192.168.0.33 HostMax: 192.168.0.46 Hosts/Net: 14 2. Requested size: 20 hosts Network: 192.168.0.0/27 Netmask: 255.255.255.224 = 27 Broadcast: 192.168.0.31 HostMin: 192.168.0.1 HostMax: 192.168.0.30 Hosts/Net: 30 Total: 2 Needed size: 48 Used network: 192.168.0.0/26 [Unused networks] Network: 192.168.0.48/28 Network: 192.168.0.64/26 Network: 192.168.0.128/25 ### Split an IPv6 prefix into one /58 and /64 networks in the remaining space $ ipcalc --format=value -S 1:58 -S 64 2001:db8:1c88:6000::/56 2001:db8:1c88:6000::/58 2001:db8:1c88:6040::/64 2001:db8:1c88:6041::/64 ... 2001:db8:1c88:60ff::/64 ### Display the bits of a network $ ipcalc --binary 192.168.92.6/22 Network: 192.168.92.0/22 192. 168. 92-95. 0-255 11000000.10101000.010111xx.xxxxxxxx └──── network /22 ─────┘└ host 10 ┘ Address: 192.168.92.6 11000000.10101000.01011100.00000110 Netmask: 255.255.252.0 11111111.11111111.11111100.00000000 Network: 192.168.92.0 11000000.10101000.01011100.00000000 HostMin: 192.168.92.1 11000000.10101000.01011100.00000001 HostMax: 192.168.95.254 11000000.10101000.01011111.11111110 Broadcast: 192.168.95.255 11000000.10101000.01011111.11111111 ### Check whether a network is a subnet of another $ ipcalc 192.168.0.1/24 --subnet-of=192.168.1.15/23 192.168.0.0/24 is a subnet of 192.168.0.0/23 ### Check whether a network overlaps any network in a list $ while read net; do > ipcalc -s 10.20.0.0/16 --overlaps="$net" > case $? in 0) echo "conflict: $net" ;; 2) echo "bad entry: $net" ;; esac > done < networks.txt ### Lookup of a hostname $ ipcalc --format=value --lookup-host localhost ::1 ### IPv4 lookup of a hostname $ ipcalc --format=value --lookup-host localhost -4 127.0.0.1 ### Reverse lookup of a hostname $ ipcalc --format=value -h 127.0.0.1 localhost ### Use the values in a shell script $ eval "$(ipcalc --format=shell -n -p 192.168.1.5/24)" $ echo "$NETWORK/$PREFIX" 192.168.1.0/24 ## Authors * Nikos Mavrogiannopoulos * Erik Troan * Preston Brown * David Cantrell ## Reporting Bugs Report bugs at https://gitlab.com/ipcalc/ipcalc/issues ## Copyright Copyright © 1997-2024 Red Hat, Inc. Copyright © 2020-2024 Nikos Mavrogiannopoulos This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipcalc.c000066400000000000000000002131211526405142400216550ustar00rootroot00000000000000/* * Copyright (c) 1997-2015 Red Hat, Inc. All rights reserved. * Copyright (c) 2026 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 . * * Authors: * Nikos Mavrogiannopoulos * Erik Troan * Preston Brown * David Cantrell */ #define _GNU_SOURCE /* asprintf */ #include #include #include #include #include #include #include #include #include #include #include /* open */ #include /* open */ #include /* read */ #include #include #include #include /* clock_gettime */ #include "ipcalc.h" int beSilent = 0; int exit_failure = 1; 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(~((1U << (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", "340282366920938463463374607431768211456", }; if (pow <= 128) return pow2[pow]; return ""; } struct addr_block { const char *net; unsigned prefix; const char *name; }; /* Based on IANA's iana-ipv4-special-registry (updated 2025-10-09) and * ipv4-address-space. The most specific block that contains the whole * network wins, so the order of the rows does not matter. Blocks keep the * name ipcalc has always printed when IANA renames them. */ static const struct addr_block ipv4_blocks[] = { {"0.0.0.0", 32, "This host on this network"}, {"0.0.0.0", 8, "This network"}, {"10.0.0.0", 8, "Private Use"}, {"100.64.0.0", 10, "Shared Address Space"}, {"127.0.0.0", 8, "Loopback"}, {"169.254.0.0", 16, "Link Local"}, {"172.16.0.0", 12, "Private Use"}, {"192.0.0.0", 29, "IPv4 Service Continuity Prefix"}, {"192.0.0.8", 32, "IPv4 dummy address"}, {"192.0.0.9", 32, "Port Control Protocol Anycast"}, {"192.0.0.10", 32, "Traversal Using Relays around NAT Anycast"}, {"192.0.0.170", 32, "NAT64/DNS64 Discovery"}, {"192.0.0.171", 32, "NAT64/DNS64 Discovery"}, {"192.0.0.0", 24, "IETF Protocol Assignments"}, {"192.0.2.0", 24, "Documentation (TEST-NET-1)"}, {"192.31.196.0", 24, "AS112-v4"}, {"192.52.193.0", 24, "AMT"}, {"192.88.99.2", 32, "6a44-relay anycast address"}, {"192.88.99.0", 24, "6 to 4 Relay Anycast (Deprecated)"}, {"192.168.0.0", 16, "Private Use"}, {"192.175.48.0", 24, "Direct Delegation AS112 Service"}, {"198.18.0.0", 15, "Benchmarking"}, {"198.51.100.0", 24, "Documentation (TEST-NET-2)"}, {"203.0.113.0", 24, "Documentation (TEST-NET-3)"}, {"224.0.0.0", 4, "Multicast"}, {"255.255.255.255", 32, "Limited Broadcast"}, {"240.0.0.0", 4, "Reserved"}, }; static const char *ipv4_net_to_type(struct in_addr net, unsigned prefix) { const struct addr_block *best = NULL; struct in_addr block; unsigned i; for (i = 0; i < sizeof(ipv4_blocks) / sizeof(ipv4_blocks[0]); i++) { if (prefix < ipv4_blocks[i].prefix) continue; if (best && best->prefix >= ipv4_blocks[i].prefix) continue; if (inet_pton(AF_INET, ipv4_blocks[i].net, &block) != 1) abort(); if ((net.s_addr & prefix2mask(ipv4_blocks[i].prefix)) == block.s_addr) best = &ipv4_blocks[i]; } return best ? best->name : "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 < 240) { 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 { uint64_t tmp = (UINT64_C(1) << (32 - prefix)) - 2; snprintf(hosts, hosts_size, "%" PRIu64, 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; } int get_ipv4_info(const char *ipStr, int prefix, ip_info_st * info, unsigned flags) { struct in_addr ip, netmask, wildcard, 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__); exit(exit_failure); } 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(exit_failure); } info->netmask = safe_strdup(namebuf); info->prefix = prefix; wildcard.s_addr = ~netmask.s_addr; if (inet_ntop(AF_INET, &wildcard, namebuf, INET_ADDRSTRLEN) == NULL) { fprintf(stderr, "inet_ntop failure at line %d\n", __LINE__); exit(exit_failure); } info->wildcard = safe_strdup(namebuf); 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(exit_failure); } info->broadcast = safe_strdup(namebuf); network = calc_network(ip, prefix); info->reverse_dns[0] = calc_reverse_dns4(network, prefix, network, broadcast); info->reverse_dns_count = info->reverse_dns[0] ? 1 : 0; 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(exit_failure); } info->network = safe_strdup(namebuf); info->type = ipv4_net_to_type(network, prefix); 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(exit_failure); } 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 (flags & FLAG_GET_GEOIP) geo_ip_lookup(ipStr, prefix, &info->geo); /* show_info_fields() rejects a network without the lookup */ if ((flags & FLAG_RESOLVE_HOST) && prefix == 32) { 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); } /* Based on IANA's iana-ipv6-special-registry (updated 2025-10-09) * followed by the unicast and multicast blocks of ipv6-address-space. * As for IPv4, the most specific matching block wins and renamed blocks * keep the name ipcalc has always printed. */ static const struct addr_block ipv6_blocks[] = { {"::1", 128, "Loopback Address"}, {"::", 128, "Unspecified Address"}, {"::ffff:0:0", 96, "IPv4-mapped Address"}, {"64:ff9b::", 96, "IPv4-IPv6 Translat."}, {"64:ff9b:1::", 48, "IPv4-IPv6 Translat."}, {"100::", 64, "Discard-Only Address Block"}, {"100:0:0:1::", 64, "Dummy IPv6 Prefix"}, {"2001::", 32, "TEREDO"}, {"2001:1::1", 128, "Port Control Protocol Anycast"}, {"2001:1::2", 128, "Traversal Using Relays around NAT Anycast"}, {"2001:1::3", 128, "DNS-SD Service Registration Protocol Anycast"}, {"2001:2::", 48, "Benchmarking"}, {"2001:3::", 32, "AMT"}, {"2001:4:112::", 48, "AS112-v6"}, {"2001:10::", 28, "Deprecated (previously ORCHID)"}, {"2001:20::", 28, "ORCHIDv2"}, {"2001:30::", 28, "Drone Remote ID Protocol Entity Tags (DETs) Prefix"}, {"2001::", 23, "IETF Protocol Assignments"}, {"2001:db8::", 32, "Documentation"}, {"2002::", 16, "6to4"}, {"2620:4f:8000::", 48, "Direct Delegation AS112 Service"}, {"3fff::", 20, "Documentation"}, {"5f00::", 16, "Segment Routing (SRv6) SIDs"}, {"2000::", 3, "Global Unicast"}, {"fc00::", 7, "Unique Local Unicast"}, {"fe80::", 10, "Link-Scoped Unicast"}, {"ff00::", 8, "Multicast"}, }; static const char *ipv6_net_to_type(struct in6_addr *net, int prefix) { const struct addr_block *best = NULL; struct in6_addr block, mask; unsigned i, j; for (i = 0; i < sizeof(ipv6_blocks) / sizeof(ipv6_blocks[0]); i++) { if ((unsigned)prefix < ipv6_blocks[i].prefix) continue; if (best && best->prefix >= ipv6_blocks[i].prefix) continue; if (inet_pton(AF_INET6, ipv6_blocks[i].net, &block) != 1 || ipv6_prefix_to_mask(ipv6_blocks[i].prefix, &mask) < 0) abort(); for (j = 0; j < 16; j++) if ((net->s6_addr[j] & mask.s6_addr[j]) != block.s6_addr[j]) break; if (j == 16) best = &ipv6_blocks[i]; } return best ? best->name : "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 iid_is_zero(const unsigned char *iid) { unsigned i; for (i = 0; i < 8; i++) if (iid[i] != 0) return 0; return 1; } /* RFC 4291 Appendix A: a Modified EUI-64 built from a 48-bit MAC has * ff:fe inserted between the OUI and the NIC-specific octets. */ static int iid_is_mac_derived(const unsigned char *iid) { return iid[3] == 0xff && iid[4] == 0xfe; } /* RFC 4291 section 2.5.1: unicast addresses outside ::/3 have a 64-bit * interface identifier. The u/g bits only carry meaning when the * identifier was derived from an IEEE MAC (RFC 7136). */ static void get_ipv6_iid_info(const struct in6_addr *ip6, ip_info_st *info) { const unsigned char *iid = &ip6->s6_addr[8]; unsigned char mac0; if ((ip6->s6_addr[0] & 0xe0) == 0 || ip6->s6_addr[0] == 0xff) return; /* The all-zero identifier is the Subnet-Router anycast address * (RFC 4291 section 2.6.1), not a host's identifier. */ if (iid_is_zero(iid)) return; safe_asprintf(&info->iid, "%02x%02x:%02x%02x:%02x%02x:%02x%02x", iid[0], iid[1], iid[2], iid[3], iid[4], iid[5], iid[6], iid[7]); if (!iid_is_mac_derived(iid)) return; /* Modified EUI-64 inverts the universal/local bit */ mac0 = iid[0] ^ 0x02; safe_asprintf(&info->eui64, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", mac0, iid[1], iid[2], iid[3], iid[4], iid[5], iid[6], iid[7]); safe_asprintf(&info->mac, "%02x:%02x:%02x:%02x:%02x:%02x", mac0, iid[1], iid[2], iid[5], iid[6], iid[7]); info->mac_scope = (mac0 & 0x02) ? "local" : "universal"; info->mac_type = (mac0 & 0x01) ? "group" : "individual"; } 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_count = calc_reverse_dns6(&network, prefix, info->reverse_dns); get_ipv6_iid_info(&ip6, info); 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 (flags & FLAG_GET_GEOIP) geo_ip_lookup(ipStr, prefix, &info->geo); /* show_info_fields() rejects a network without the lookup */ if ((flags & FLAG_RESOLVE_HOST) && prefix == 128) { 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; } 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; } /* [COUNT:]PREFIX, where PREFIX may also be a netmask */ static int parse_split_req(unsigned *flags, const char *str, struct split_req *req) { const char *prefixStr = str; const char *sep = strchr(str, ':'); int prefix; req->count = 0; if (sep) { char *end; errno = 0; /* strtoull() accepts leading spaces and a sign, and wraps * "-1" to UINT64_MAX */ if (!isdigit((unsigned char)str[0])) goto bad_count; req->count = strtoull(str, &end, 10); if (end != sep || errno != 0 || req->count == 0) { bad_count: if (!beSilent) fprintf(stderr, "ipcalc: bad split count: %s\n", str); return -1; } prefixStr = sep + 1; } prefix = str_to_prefix(flags, prefixStr, 1); if (prefix < 0) { if (!beSilent) fprintf(stderr, "ipcalc: bad %s prefix: %s\n", ((*flags) & FLAG_IPV6)?"IPv6":"IPv4", str); return -1; } req->prefix = prefix; return 0; } static int parse_split_hosts(unsigned flags, const char *str, struct split_req **reqs, unsigned *nreqs) { unsigned width = (flags & FLAG_IPV6) ? 128 : 32; const char *p = str; while (1) { struct split_req *req; uint64_t hosts, size; unsigned bits = 0; char *end = NULL; errno = 0; /* see parse_split_req() */ if (!isdigit((unsigned char)*p)) goto bad_count; hosts = strtoull(p, &end, 10); if (errno != 0 || hosts == 0 || (*end != ',' && *end != 0)) { bad_count: if (!beSilent) fprintf(stderr, "ipcalc: bad host count: %s\n", str); return -1; } /* IPv4 subnets also need the network and broadcast addresses */ size = hosts; if (!(flags & FLAG_IPV6)) { if (hosts > UINT32_MAX - 1) { if (!beSilent) fprintf(stderr, "ipcalc: too many hosts requested: %" PRIu64 "\n", hosts); return -1; } size += 2; } while (bits < 64 && (UINT64_C(1) << bits) < size) bits++; *reqs = realloc(*reqs, (*nreqs + 1) * sizeof((*reqs)[0])); if (*reqs == NULL) exit(exit_failure); req = &(*reqs)[(*nreqs)++]; req->prefix = width - bits; req->count = 1; req->hosts = hosts; if (*end == 0) break; p = end + 1; } return 0; } #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 #define OPT_HELP 10 #define OPT_SPLIT_HOSTS 11 #define OPT_EQUALS 12 #define OPT_SUBNET_OF 13 #define OPT_OVERLAPS 14 #define OPT_CIDR 15 #define OPT_WILDCARD 16 #define OPT_FORMAT 17 #define OPT_BINARY 18 #define IS_COMPARE_OPT(c) ((c) == OPT_EQUALS || (c) == OPT_SUBNET_OF || (c) == OPT_OVERLAPS) #ifdef USE_MAXMIND # define GEO_SHORT_OPTION "g" #else # define GEO_SHORT_OPTION "" #endif static const struct option long_options[] = { {"check", 0, 0, 'c'}, {"equals", 1, 0, OPT_EQUALS}, {"subnet-of", 1, 0, OPT_SUBNET_OF}, {"overlaps", 1, 0, OPT_OVERLAPS}, {"random-private", 1, 0, 'r'}, {"split", 1, 0, 'S'}, {"split-hosts", 1, 0, OPT_SPLIT_HOSTS}, {"deaggregate", 1, 0, 'd'}, {"binary", 0, 0, OPT_BINARY}, {"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}, #ifdef USE_MAXMIND {"geoinfo", 0, 0, 'g'}, #endif {"netmask", 0, 0, 'm'}, {"network", 0, 0, 'n'}, {"cidr", 0, 0, OPT_CIDR}, {"wildcard", 0, 0, OPT_WILDCARD}, {"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'}, {"format", 1, 0, OPT_FORMAT}, {"version", 0, 0, 'v'}, {"help", 0, 0, OPT_HELP}, {"usage", 0, 0, OPT_USAGE}, {NULL, 0, 0, 0} }; /* Options that select a field to print */ static const struct { int option; enum ipcalc_flag field_flag; } field_selecting_options[] = { {'a', FLAG_SHOW_ADDRESS}, {'o', FLAG_RESOLVE_IP}, {'b', FLAG_SHOW_BROADCAST}, {'h', FLAG_RESOLVE_HOST}, {'m', FLAG_SHOW_NETMASK}, {'n', FLAG_SHOW_NETWORK}, {'p', FLAG_SHOW_PREFIX}, #ifdef USE_MAXMIND {'g', FLAG_SHOW_GEOIP}, #endif {OPT_REVERSE, FLAG_SHOW_REVERSE}, {OPT_CIDR, FLAG_SHOW_CIDR}, {OPT_WILDCARD, FLAG_SHOW_WILDCARD}, {OPT_MINADDR, FLAG_SHOW_MINADDR}, {OPT_MAXADDR, FLAG_SHOW_MAXADDR}, {OPT_ADDRESSES, FLAG_SHOW_ADDRESSES}, {OPT_ADDRSPACE, FLAG_SHOW_ADDRSPACE}, }; /* 0 for an option that selects no field */ static unsigned field_flag_of_option(int option) { const unsigned n = sizeof(field_selecting_options) / sizeof(field_selecting_options[0]); unsigned i; for (i = 0; i < n; i++) { if (field_selecting_options[i].option == option) return field_selecting_options[i].field_flag; } return 0; } static void usage(unsigned verbose) { if (verbose) { fprintf(stderr, "Usage: ipcalc [OPTION...]\n"); fprintf(stderr, " -c, --check Validate IP address\n"); fprintf(stderr, " --equals=NET Succeed if the network equals NET\n"); fprintf(stderr, " --subnet-of=NET Succeed if the network is within NET\n"); fprintf(stderr, " --overlaps=NET Succeed if the network shares an address\n"); fprintf(stderr, " with NET\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=[COUNT:]PREFIX Split the provided network using the\n"); fprintf(stderr, " provided prefix/netmask; repeat with\n"); fprintf(stderr, " COUNT for subnets of different sizes\n"); fprintf(stderr, " --split-hosts=N1,N2,... Split the provided network into subnets\n"); fprintf(stderr, " that hold N1, N2, ... hosts\n"); fprintf(stderr, " -d, --deaggregate=IP1-IP2 Deaggregate the provided address range\n"); fprintf(stderr, " --binary Print the bits of the provided address\n"); fprintf(stderr, " or of the network part of a network\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, " --wildcard Display wildcard (inverse) mask for IP\n"); fprintf(stderr, " -n, --network Display network address\n"); fprintf(stderr, " --cidr Display network address and prefix in\n"); fprintf(stderr, " CIDR notation\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"); #ifdef USE_MAXMIND fprintf(stderr, " -g, --geoinfo Show Geographic information about the\n"); fprintf(stderr, " provided IP\n"); #endif fprintf(stderr, "\n"); fprintf(stderr, "Output format:\n"); fprintf(stderr, " --format=FORMAT Print the output as human (default for the\n"); fprintf(stderr, " summary), shell (NAME=value, default for\n"); fprintf(stderr, " specific info options), json, or value\n"); 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, " -s, --silent Don't ever display error messages, nor\n"); fprintf(stderr, " the result of a comparison\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] [--equals=NET] [--subnet-of=NET]\n"); fprintf(stderr, " [--overlaps=NET] [-r|--random-private=STRING] [-i|--info]\n"); fprintf(stderr, " [--all-info] [-4|--ipv4] [-6|--ipv6] [-a|--address] [-b|--broadcast]\n"); #ifdef USE_MAXMIND fprintf(stderr, " [-h|--hostname] [-o|--lookup-host=STRING] [-g|--geoinfo]\n"); #else fprintf(stderr, " [-h|--hostname] [-o|--lookup-host=STRING]\n"); #endif fprintf(stderr, " [-m|--netmask] [--wildcard] [-n|--network] [--cidr] [-p|--prefix]\n"); fprintf(stderr, " [--minaddr] [--maxaddr] [--addresses] [--addrspace]\n"); fprintf(stderr, " [--format=FORMAT]\n"); fprintf(stderr, " [-s|--silent] [-v|--version] [--reverse-dns] [--class-prefix]\n"); fprintf(stderr, " [--binary] [-?|--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; } /* Prints str without a newline; the color is skipped when color is NULL * or colors are disabled */ void color_fputs(const char *color, const char *str) { if (colors && color) fputs(color, stdout); fputs(str, stdout); if (colors && color) fputs(KRESET, stdout); } 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; } /* Host names and geo values come from outside ipcalc and may contain * characters that are not allowed unescaped in a JSON string (RFC 8259). */ static void json_print_string(const char *str) { const unsigned char *p; putchar('"'); for (p = (const unsigned char *)str; *p; p++) { if (*p == '"' || *p == '\\') printf("\\%c", *p); else if (*p < 0x20) printf("\\u%04x", *p); else putchar(*p); } putchar('"'); } 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\":", jsontitle); json_print_string(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, 2, 3))) pretty_printf(const char *title, const char *fmt, ...) { va_list args; va_start(args, fmt); 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, 2, 3))) pretty_dist_printf(const char *title, const char *fmt, ...) { va_list args; va_start(args, fmt); 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 WILDCARD_NAME "WILDCARD" #define PREFIX_NAME "PREFIX" #define CIDR_NAME "CIDR" #define BROADCAST_NAME "BROADCAST" #define REVERSEDNS_NAME "REVERSEDNS" #define ADDRSPACE_NAME "ADDRSPACE" #define ADDRCLASS_NAME "ADDRCLASS" #define INTERFACEID_NAME "INTERFACEID" #define EUI64_NAME "EUI64" #define MACADDR_NAME "MACADDR" #define MACSCOPE_NAME "MACSCOPE" #define MACTYPE_NAME "MACTYPE" #define MINADDR_NAME "MINADDR" #define MAXADDR_NAME "MAXADDR" #define ADDRESSES_NAME "ADDRESSES" #define CONTINENT_NAME "CONTINENT" #define COUNTRYCODE_NAME "COUNTRYCODE" #define COUNTRY_NAME "COUNTRY" #define CITY_NAME "CITY" #define POSTALCODE_NAME "POSTALCODE" #define COORDINATES_NAME "COORDINATES" #define ACCURACYRADIUS_NAME "ACCURACYRADIUS" #define TIMEZONE_NAME "TIMEZONE" #define ASN_NAME "ASN" #define ASORG_NAME "ASORG" #define ASNETWORK_NAME "ASNETWORK" #define GEONETWORK_NAME "GEONETWORK" static const char * const format_names[] = { [FORMAT_HUMAN] = "human", [FORMAT_SHELL] = "shell", [FORMAT_JSON] = "json", [FORMAT_VALUE] = "value", }; /* -1, after reporting it, for an unknown format name */ static int parse_format(const char *name) { unsigned i; for (i = 0; i < sizeof(format_names) / sizeof(format_names[0]); i++) { if (strcmp(name, format_names[i]) == 0) return i; } if (!beSilent) fprintf(stderr, "ipcalc: unknown output format: %s; use human, shell, json or value\n", name); return -1; } /* How show_info_fields() prints a field; the option that selects a field is * a FLAG_SHOW_* (or FLAG_RESOLVE_*) of enum ipcalc_flag */ enum field_attr { /* Without an ATTR_SUMMARY_* attribute a field is in the summary only when its option is given */ ATTR_SUMMARY_ALWAYS=1<<0, ATTR_SUMMARY_WITH_ALL_INFO=1<<1, /* the text summary already shows it as part of another field */ ATTR_SUMMARY_JSON_ONLY=1<<2, /* the input address is meaningless for a network or a random network */ ATTR_SUMMARY_HIDE_FOR_NETWORK_ADDRESS=1<<3, /* hidden in the text summary only, where it would repeat the single address */ ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS=1<<4, /* printed in a different color than other values */ ATTR_SUMMARY_HIGHLIGHT=1<<5, ATTR_VAR_QUOTE_ALWAYS=1<<6, /* values-only output quotes as released, since scripts read it verbatim */ ATTR_VALUE_QUOTE_IF_SPACE=1<<7, ATTR_REQUIRES_SINGLE_ADDRESS=1<<8 }; enum summary_section { SECTION_NETWORK, SECTION_RANGE, SECTION_GEO }; /* A field without a value for the input's address family is left NULL by * get_ipv4_info() or get_ipv6_info(), so it is never printed */ struct output_field { const char *title; const char *name; enum ipcalc_flag option; const char *option_name; /* named in diagnostics */ enum field_attr attrs; enum summary_section section; const char *value; const char *text_value; /* the value in the text summary, when it differs */ char * const *values; /* instead of value, for a field with several values */ unsigned nvalues; }; static unsigned field_has_value(const struct output_field *f) { return f->value != NULL || f->nvalues > 0; } static unsigned field_in_summary(const struct output_field *f, enum output_format format, unsigned single_address, unsigned input_is_network) { if (!field_has_value(f)) return 0; if ((f->attrs & ATTR_SUMMARY_HIDE_FOR_NETWORK_ADDRESS) && input_is_network) return 0; if (format == FORMAT_HUMAN && (((f->attrs & ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS) && single_address) || (f->attrs & ATTR_SUMMARY_JSON_ONLY))) return 0; if (flags & f->option) return 1; if (f->attrs & (ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_JSON_ONLY)) return 1; return (f->attrs & ATTR_SUMMARY_WITH_ALL_INFO) && (flags & FLAG_SHOW_ALL_INFO); } static void show_json_field(unsigned * const jsonchain, const struct output_field *f) { unsigned i; if (!f->values) { json_printf(jsonchain, f->name, "%s", f->value); return; } /* always an array, so that its type does not depend on the number of values */ array_start(jsonchain, f->title, f->name); for (i = 0; i < f->nvalues; i++) json_printf(jsonchain, NULL, "%s", f->values[i]); array_stop(jsonchain); } static void show_text_field(const struct output_field *f) { const char *value = f->text_value ? f->text_value : f->value; unsigned i; if (f->values) { for (i = 0; i < f->nvalues; i++) pretty_printf(f->title, "%s", f->values[i]); } else if (f->attrs & ATTR_SUMMARY_HIGHLIGHT) { pretty_dist_printf(f->title, "%s", value); } else { pretty_printf(f->title, "%s", value); } } /* Characters that the shell takes literally in an unquoted word; bytes of * UTF-8 sequences are among them */ static unsigned shell_safe(const char *value) { const unsigned char *c; for (c = (const unsigned char *)value; *c; c++) { if (*c >= 0x80 || (*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9')) continue; if (strchr("._:/-,+@%", *c) == NULL) return 0; } return 1; } /* Inside double quotes the shell interprets only these characters */ static void print_shell_escaped(const char *value) { for (; *value; value++) { if (strchr("\"\\$`", *value) != NULL) putchar('\\'); putchar(*value); } } /* NAME=value output must be usable with eval, whatever the value holds */ static void print_shell_value(const char *value, unsigned quote) { if (!quote && shell_safe(value)) { fputs(value, stdout); return; } putchar('"'); print_shell_escaped(value); putchar('"'); } static void show_var_field(const struct output_field *f, unsigned bare) { unsigned i; if (f->values) { if (bare) { /* one value per line, as with --deaggregate */ for (i = 0; i < f->nvalues; i++) printf("%s\n", f->values[i]); } else if (f->nvalues == 1) { printf("%s=", f->name); print_shell_value(f->values[0], 0); putchar('\n'); } else { /* a quoted, space-separated list */ printf("%s=\"", f->name); for (i = 0; i < f->nvalues; i++) { if (i > 0) putchar(' '); print_shell_escaped(f->values[i]); } printf("\"\n"); } return; } if (bare) { if ((f->attrs & ATTR_VAR_QUOTE_ALWAYS) || ((f->attrs & ATTR_VALUE_QUOTE_IF_SPACE) && strchr(f->value, ' ') != NULL)) printf("\"%s\"\n", f->value); else printf("%s\n", f->value); return; } printf("%s=", f->name); print_shell_value(f->value, f->attrs & ATTR_VAR_QUOTE_ALWAYS); putchar('\n'); } static unsigned field_selected(const struct output_field *f, enum output_format format, unsigned single_address, unsigned input_is_network) { if (flags & FLAG_SHOW_MODERN_INFO) return field_in_summary(f, format, single_address, input_is_network); return field_has_value(f) && (flags & f->option); } static void show_field(unsigned * const jsonchain, const struct output_field *f, enum output_format format) { switch (format) { case FORMAT_HUMAN: show_text_field(f); break; case FORMAT_SHELL: show_var_field(f, 0); break; case FORMAT_JSON: show_json_field(jsonchain, f); break; case FORMAT_VALUE: show_var_field(f, 1); break; } } /* Prints the summary or, when specific fields are selected, those fields; * both in the order of fields[] and in the given format. */ static void show_info_fields(const ip_info_st *info, enum output_format format, unsigned randomized) { unsigned human_summary = (flags & FLAG_SHOW_MODERN_INFO) && format == FORMAT_HUMAN; unsigned single_address = info->prefix == ((flags & FLAG_IPV6) ? 128 : 32); unsigned input_is_network = !single_address && (randomized || strcmp(info->network, info->ip) == 0); char prefix[8]; char *cidr = NULL, *full_network = NULL, *netmask = NULL, *hosts = NULL; char *radius = NULL; unsigned jsonchain = JSON_FIRST; enum summary_section section = SECTION_NETWORK; unsigned i; snprintf(prefix, sizeof(prefix), "%u", info->prefix); safe_asprintf(&cidr, "%s/%u", info->network, info->prefix); safe_asprintf(&netmask, "%s = %u", info->netmask, info->prefix); if (info->expanded_network) safe_asprintf(&full_network, "%s/%u", info->expanded_network, info->prefix); if ((flags & FLAG_IPV6) && info->prefix < 112) safe_asprintf(&hosts, "2^(%u) = %s", 128 - info->prefix, info->hosts); if (info->geo.accuracy_radius) safe_asprintf(&radius, "%s km", info->geo.accuracy_radius); const struct output_field fields[] = { { .title = "Full Address:\t", .name = FULL_ADDRESS_NAME, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_NETWORK_ADDRESS, .value = info->expanded_ip }, { .title = "Address:\t", .name = ADDRESS_NAME, .option = FLAG_SHOW_ADDRESS|FLAG_RESOLVE_IP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_NETWORK_ADDRESS, .value = info->ip }, { .title = "Hostname:\t", .name = HOSTNAME_NAME, .option = FLAG_RESOLVE_HOST, .option_name = "-h", .attrs = ATTR_SUMMARY_ALWAYS|ATTR_REQUIRES_SINGLE_ADDRESS, .value = info->hostname }, { .title = "Full Network:\t", .name = FULL_NETWORK_NAME, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS, .value = info->expanded_network, .text_value = full_network }, { .title = "Network:\t", .name = NETWORK_NAME, .option = FLAG_SHOW_NETWORK, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS, .value = info->network, .text_value = cidr }, { .title = "Netmask:\t", .name = NETMASK_NAME, .option = FLAG_SHOW_NETMASK, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS, .value = info->netmask, .text_value = netmask }, { .title = "Wildcard:\t", .name = WILDCARD_NAME, .option = FLAG_SHOW_WILDCARD, .attrs = ATTR_SUMMARY_WITH_ALL_INFO|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS, .value = info->wildcard }, { .title = "Prefix:\t", .name = PREFIX_NAME, .option = FLAG_SHOW_PREFIX, .attrs = ATTR_SUMMARY_JSON_ONLY, .value = prefix }, { .title = "CIDR:\t", .name = CIDR_NAME, .option = FLAG_SHOW_CIDR, .attrs = ATTR_SUMMARY_JSON_ONLY, .value = cidr }, { .title = "Broadcast:\t", .name = BROADCAST_NAME, .option = FLAG_SHOW_BROADCAST, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS, .value = info->broadcast }, { .title = "Reverse DNS:\t", .name = REVERSEDNS_NAME, .option = FLAG_SHOW_REVERSE, .attrs = ATTR_SUMMARY_WITH_ALL_INFO, .values = info->reverse_dns, .nvalues = info->reverse_dns_count }, { .title = "Address space:\t", .name = ADDRSPACE_NAME, .option = FLAG_SHOW_ADDRSPACE, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT|ATTR_VALUE_QUOTE_IF_SPACE, .section = SECTION_RANGE, .value = info->type }, { .title = "Address class:\t", .name = ADDRCLASS_NAME, .attrs = ATTR_SUMMARY_WITH_ALL_INFO|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_RANGE, .value = info->class }, { .title = "Interface ID:\t", .name = INTERFACEID_NAME, .attrs = ATTR_SUMMARY_WITH_ALL_INFO|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_RANGE, .value = info->iid }, { .title = "EUI-64:\t\t", .name = EUI64_NAME, .attrs = ATTR_SUMMARY_WITH_ALL_INFO|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_RANGE, .value = info->eui64 }, { .title = "MAC address:\t", .name = MACADDR_NAME, .attrs = ATTR_SUMMARY_WITH_ALL_INFO|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_RANGE, .value = info->mac }, { .title = "MAC scope:\t", .name = MACSCOPE_NAME, .attrs = ATTR_SUMMARY_WITH_ALL_INFO|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_RANGE, .value = info->mac_scope }, { .title = "MAC type:\t", .name = MACTYPE_NAME, .attrs = ATTR_SUMMARY_WITH_ALL_INFO|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_RANGE, .value = info->mac_type }, { .title = "HostMin:\t", .name = MINADDR_NAME, .option = FLAG_SHOW_MINADDR, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS, .section = SECTION_RANGE, .value = info->hostmin }, { .title = "HostMax:\t", .name = MAXADDR_NAME, .option = FLAG_SHOW_MAXADDR, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS, .section = SECTION_RANGE, .value = info->hostmax }, { .title = "Hosts/Net:\t", .name = ADDRESSES_NAME, .option = FLAG_SHOW_ADDRESSES, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIDE_FOR_SINGLE_ADDRESS|ATTR_VALUE_QUOTE_IF_SPACE, .section = SECTION_RANGE, .value = info->hosts[0] ? info->hosts : NULL, .text_value = hosts }, /* geo values exist only when looked up, with -g or --all-info */ { .title = "Continent:\t", .name = CONTINENT_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT|ATTR_VALUE_QUOTE_IF_SPACE, .section = SECTION_GEO, .value = info->geo.continent }, { .title = "Country code:\t", .name = COUNTRYCODE_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_GEO, .value = info->geo.ccode }, { .title = "Country:\t", .name = COUNTRY_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT|ATTR_VALUE_QUOTE_IF_SPACE, .section = SECTION_GEO, .value = info->geo.country }, { .title = "City:\t\t", .name = CITY_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT|ATTR_VALUE_QUOTE_IF_SPACE, .section = SECTION_GEO, .value = info->geo.city }, { .title = "Postal code:\t", .name = POSTALCODE_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT|ATTR_VALUE_QUOTE_IF_SPACE, .section = SECTION_GEO, .value = info->geo.postal_code }, { .title = "Coordinates:\t", .name = COORDINATES_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT|ATTR_VAR_QUOTE_ALWAYS, .section = SECTION_GEO, .value = info->geo.coord }, { .title = "Accuracy:\t", .name = ACCURACYRADIUS_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_GEO, .value = info->geo.accuracy_radius, .text_value = radius }, { .title = "Time zone:\t", .name = TIMEZONE_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_GEO, .value = info->geo.time_zone }, { .title = "Routed by AS:\t", .name = ASN_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_GEO, .value = info->geo.asn }, { .title = "Operated by:\t", .name = ASORG_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT|ATTR_VALUE_QUOTE_IF_SPACE, .section = SECTION_GEO, .value = info->geo.as_org }, { .title = "AS network:\t", .name = ASNETWORK_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_GEO, .value = info->geo.as_network }, { .title = "Geo network:\t", .name = GEONETWORK_NAME, .option = FLAG_SHOW_GEOIP, .attrs = ATTR_SUMMARY_ALWAYS|ATTR_SUMMARY_HIGHLIGHT, .section = SECTION_GEO, .value = info->geo.network }, }; const unsigned nfields = sizeof(fields) / sizeof(fields[0]); const struct output_field *f; for (i = 0; i < nfields; i++) { f = &fields[i]; if ((f->attrs & ATTR_REQUIRES_SINGLE_ADDRESS) && (flags & f->option) && !single_address) { if (!beSilent) fprintf(stderr, "ipcalc: %s requires a single address, not a network: %s/%u\n", f->option_name, info->ip, info->prefix); exit(exit_failure); } } output_start(&jsonchain); for (i = 0; i < nfields; i++) { f = &fields[i]; if (!field_selected(f, format, single_address, input_is_network)) continue; if (human_summary && f->section != section) { /* a single address has no network fields to separate * from its range fields */ if (f->section == SECTION_GEO || !single_address) output_separate(&jsonchain); section = f->section; } show_field(&jsonchain, f, format); } output_stop(&jsonchain); free(cidr); free(full_network); free(netmask); free(hosts); free(radius); } /* The format implied by -j, --no-decorate and the selection, when no * --format is given */ static enum output_format legacy_format(void) { if (flags & FLAG_JSON) return FORMAT_JSON; if (flags & FLAG_SHOW_MODERN_INFO) return FORMAT_HUMAN; /* uncolored with --no-decorate */ if (flags & FLAG_NO_DECORATE) return FORMAT_VALUE; return FORMAT_SHELL; } static int format_conflict(const char *option, enum output_format format) { if (!beSilent) fprintf(stderr, "ipcalc: conflicting output formats: %s and --format=%s\n", option, format_names[format]); return -1; } /* Applies --format=name, given again as other_name when that differs, and * makes the flags that the other modes read agree with it */ static int select_format(const char *name, const char *other_name, unsigned *selected_fields, enum output_format *format) { int f = parse_format(name); if (f < 0) return -1; if (other_name) { if (parse_format(other_name) < 0) return -1; if (!beSilent) fprintf(stderr, "ipcalc: conflicting output formats: --format=%s and --format=%s\n", name, other_name); return -1; } if ((flags & FLAG_JSON) && f != FORMAT_JSON) return format_conflict("-j", f); if ((flags & FLAG_NO_DECORATE) && f != FORMAT_VALUE) return format_conflict("--no-decorate", f); if (flags & FLAG_SHOW_MODERN_INFO) { /* with -i or --all-info, -o only supplies the address */ *selected_fields &= ~FLAG_RESOLVE_IP; if (*selected_fields) { if (!beSilent) fprintf(stderr, "ipcalc: -i and --all-info cannot be combined with specific field options\n"); return -1; } } if (f == FORMAT_JSON) flags |= FLAG_JSON; else if (f == FORMAT_VALUE) flags |= FLAG_NO_DECORATE; *format = f; return 0; } static int check_format_for_app(enum output_format format, enum app_t app) { const char *unsupported = NULL; if ((app & (APP_SPLIT | APP_DEAGGREGATE)) && format == FORMAT_SHELL) unsupported = "--split, --split-hosts or --deaggregate; use --format=value"; else if ((app & APP_COMPARE) && format != FORMAT_HUMAN) unsupported = "--equals, --subnet-of or --overlaps"; if (unsupported) { if (!beSilent) fprintf(stderr, "ipcalc: --format=%s is not supported with %s\n", format_names[format], unsupported); return -1; } /* info mode is the default, so app may have no bit set */ if ((app & ~APP_SHOW_INFO) == 0 && format == FORMAT_VALUE && (flags & FLAG_SHOW_MODERN_INFO)) { if (!beSilent) fprintf(stderr, "ipcalc: --format=value needs specific field options; use --format=shell or --format=json\n"); return -1; } return 0; } /* Only on a terminal, so that the output of scripts does not change */ static void suggest_format(enum app_t app, unsigned selected_fields) { const char *option, *replacement; if (beSilent || !isatty(STDERR_FILENO)) return; if (flags & FLAG_JSON) { option = "-j"; if (app & APP_COMPARE) replacement = "-s to print no result"; else if (selected_fields) replacement = "--format=json, which prints only the selected fields"; else replacement = "--format=json"; } else if (flags & FLAG_NO_DECORATE) { option = "--no-decorate"; if (app & APP_COMPARE) replacement = "-s to print no result"; else if (selected_fields || (app & (APP_SPLIT | APP_DEAGGREGATE))) replacement = "--format=value"; else replacement = "--format=human"; } else { return; } fprintf(stderr, "ipcalc: hint: %s is deprecated; use %s\n", option, replacement); } /*! \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 **splitStrs = NULL; unsigned nsplits = 0; char **splitHostsStrs = NULL; unsigned nsplitHosts = 0; char *ipStr = NULL, *prefixStr = NULL, *chptr = NULL; int prefix = -1; ip_info_st info; int r = 0; enum app_t app = 0; char *cmpStr = NULL; enum net_comparison cmpOp = CMP_EQUALS; unsigned ncmps = 0; unsigned userFlags; unsigned selected_fields = 0; enum output_format format; const char *formatStr = NULL, *otherFormatStr = NULL; int badOption = 0; int noDecorate = 0; while (1) { int c = getopt_long(argc, argv, "S:cr:i46abho:" GEO_SHORT_OPTION "mnpjsvd:", long_options, NULL); if (c == -1) break; switch(c) { case 'c': app |= APP_CHECK_ADDRESS; break; case OPT_EQUALS: case OPT_SUBNET_OF: case OPT_OVERLAPS: app |= APP_COMPARE; cmpOp = c == OPT_EQUALS ? CMP_EQUALS : c == OPT_SUBNET_OF ? CMP_SUBNET_OF : CMP_OVERLAPS; ncmps++; exit_failure = 2; cmpStr = safe_strdup(optarg); if (cmpStr == NULL) exit(exit_failure); break; case 'S': app |= APP_SPLIT; splitStrs = realloc(splitStrs, (nsplits + 1) * sizeof(splitStrs[0])); if (splitStrs == NULL) exit(exit_failure); splitStrs[nsplits] = safe_strdup(optarg); if (splitStrs[nsplits] == NULL) exit(exit_failure); nsplits++; break; case OPT_SPLIT_HOSTS: app |= APP_SPLIT; splitHostsStrs = realloc(splitHostsStrs, (nsplitHosts + 1) * sizeof(splitHostsStrs[0])); if (splitHostsStrs == NULL) exit(exit_failure); splitHostsStrs[nsplitHosts] = safe_strdup(optarg); if (splitHostsStrs[nsplitHosts] == NULL) exit(exit_failure); nsplitHosts++; break; case OPT_BINARY: app |= APP_SHOW_BITS; break; case 'd': app |= APP_DEAGGREGATE; ipStr = safe_strdup(optarg); if (ipStr == NULL) exit(exit_failure); break; case 'r': app |= APP_SHOW_INFO; flags |= FLAG_RANDOM; randomStr = safe_strdup(optarg); if (randomStr == NULL) exit(exit_failure); 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 '4': flags |= FLAG_IPV4; break; case '6': flags |= FLAG_IPV6; break; case 'o': selected_fields |= field_flag_of_option(c); hostname = safe_strdup(optarg); if (hostname == NULL) exit(exit_failure); break; case OPT_NO_DECORATE: flags |= FLAG_NO_DECORATE; noDecorate = 1; break; case 'j': flags |= FLAG_JSON; break; case OPT_FORMAT: if (formatStr == NULL) formatStr = optarg; else if (strcmp(formatStr, optarg) != 0 && otherFormatStr == NULL) otherFormatStr = optarg; break; case 's': beSilent = 1; break; case 'v': app |= APP_VERSION; break; /* after an invalid option, help must not turn the * error into a success */ case OPT_USAGE: if (badOption) break; usage(0); exit(0); case OPT_HELP: if (badOption) break; usage(1); exit(0); case '?': /* -? is not in the short options, so getopt reports * it like an unknown option */ if (optopt == '?' && !badOption) { usage(1); exit(0); } if (IS_COMPARE_OPT(optopt)) exit_failure = 2; /* keep parsing, since a later comparison option * changes the exit status; report only this error */ badOption = 1; opterr = 0; break; default: selected_fields |= field_flag_of_option(c); break; } } if (selected_fields) app |= APP_SHOW_INFO; if (badOption) { usage(1); exit(exit_failure); } if (optind < argc) { if (ipStr != NULL) { if (!beSilent) fprintf(stderr, "ipcalc: superfluous option given\n"); exit(exit_failure); } ipStr = argv[optind++]; if (optind < argc) chptr = argv[optind++]; } if (formatStr) { if (select_format(formatStr, otherFormatStr, &selected_fields, &format) < 0) return exit_failure; } else if ((flags & FLAG_JSON) && (flags & FLAG_NO_DECORATE)) { flags &= ~FLAG_NO_DECORATE; } /* without --format, JSON output is always the summary, to which * selected fields are added */ if (!selected_fields || (!formatStr && (flags & FLAG_JSON))) flags |= FLAG_SHOW_MODERN_INFO; flags |= selected_fields; if (!formatStr) format = legacy_format(); if (geo_setup() == 0 && (flags & FLAG_SHOW_ALL_INFO)) flags |= FLAG_GET_GEOIP; if (bit_count(app) > 1 || ncmps > 1) { if (!beSilent) fprintf(stderr, "ipcalc: you cannot mix these options\n"); return exit_failure; } /* FLAG_NO_DECORATE is also set by --format=value and cleared by -j */ if (noDecorate && (app & APP_SHOW_BITS)) { if (!beSilent) fprintf(stderr, "ipcalc: --no-decorate is not supported with --binary; use --format=value\n"); return exit_failure; } if (formatStr && check_format_for_app(format, app) < 0) return exit_failure; if (!formatStr) suggest_format(app, selected_fields); if ((flags & FLAG_IPV6) && (flags & FLAG_IPV4)) { if (!beSilent) fprintf(stderr, "ipcalc: you cannot specify both IPv4 and IPv6\n"); return exit_failure; } userFlags = flags; /* 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_COMPARE: case APP_SHOW_INFO: case APP_SHOW_BITS: /* 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 exit_failure; } 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 exit_failure; } ipStr = generate_ip_network(prefix, flags); if (ipStr == NULL) { if (!beSilent) fprintf(stderr, "ipcalc: cannot generate network with prefix: %u\n", prefix); return exit_failure; } } if (hostname == NULL && ipStr == NULL) { if (!beSilent) { fprintf(stderr, "ipcalc: ip address expected\n"); usage(1); } return exit_failure; } /* 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 exit_failure; } 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 exit_failure; } } 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 exit_failure; } } if (flags & FLAG_IPV6) r = get_ipv6_info(ipStr, prefix, &info, flags); else r = get_ipv4_info(ipStr, prefix, &info, flags); if (r < 0) { return exit_failure; } switch (app) { case APP_SPLIT: { struct split_req *reqs = NULL; unsigned i, nfill = 0, nreqs = 0; if (nsplits && nsplitHosts) { if (!beSilent) fprintf(stderr, "ipcalc: --split-hosts cannot be combined with --split\n"); return exit_failure; } for (i = 0; i < nsplitHosts; i++) { if (parse_split_hosts(flags, splitHostsStrs[i], &reqs, &nreqs) < 0) return exit_failure; } if (nsplits) { reqs = calloc(nsplits, sizeof(reqs[0])); if (reqs == NULL) exit(exit_failure); nreqs = nsplits; } for (i = 0; i < nsplits; i++) { if (parse_split_req(&flags, splitStrs[i], &reqs[i]) < 0) return exit_failure; if (reqs[i].count == 0 && ++nfill > 1) { if (!beSilent) fprintf(stderr, "ipcalc: only one split prefix may be given without a count\n"); return exit_failure; } } show_split_networks(reqs, nreqs, &info, flags); } return 0; case APP_CHECK_ADDRESS: return 0; case APP_COMPARE: return compare_networks(cmpOp, &info, flags, cmpStr, userFlags); default: break; } if ((isatty(STDOUT_FILENO) != 0) && (getenv("NO_COLOR") == 0)) colors = 1; if (app == APP_SHOW_BITS) show_binary(&info, flags, format); else show_info_fields(&info, format, randomStr != NULL); return 0; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipcalc.h000066400000000000000000000144431526405142400216700ustar00rootroot00000000000000/* * 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 . * * Authors: * Nikos Mavrogiannopoulos */ #ifndef _IPCALC_H #define _IPCALC_H #include /* for va_list */ struct geo_info_st { char *continent; char *country; char *ccode; char *city; char *postal_code; char *coord; char *accuracy_radius; /* of coord, in km */ char *time_zone; char *asn; char *as_org; char *as_network; /* of the ASN record */ char *network; /* of the records the values come from */ }; #ifdef USE_MAXMIND void geo_ip_lookup(const char *ip, unsigned prefix, struct geo_info_st *geo); int geo_setup(void); # ifndef USE_RUNTIME_LINKING # define geo_setup() 0 # endif #else # define geo_ip_lookup(ip, prefix, geo) # define geo_setup() -1 #endif /* USE_MAXMIND */ 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); /* An IPv6 prefix not on a nibble boundary needs up to 2^3 ip6.arpa. zones */ #define MAX_REVERSE_DNS 8 unsigned calc_reverse_dns6(struct in6_addr *ip, unsigned prefix, char *names[MAX_REVERSE_DNS]); 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[MAX_REVERSE_DNS]; unsigned reverse_dns_count; char *network; char *broadcast; /* ipv4 only */ char *netmask; char *wildcard; /* ipv4 only */ char *hostname; struct geo_info_st geo; char hosts[64]; /* number of hosts in text */ unsigned prefix; char *hostmin; char *hostmax; const char *type; const char *class; /* ipv6 only */ char *iid; char *eui64; char *mac; const char *mac_scope; const char *mac_type; } 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, APP_COMPARE=1<<5, APP_SHOW_BITS=1<<6 }; /* Bits of the global flags: options to show a field (FLAG_SHOW_*, FLAG_RESOLVE_*) * and modifiers of the output or input */ enum ipcalc_flag { FLAG_IPV6=1<<1, FLAG_IPV4=1<<2, FLAG_SHOW_MODERN_INFO=1<<3, FLAG_RESOLVE_IP=1<<4, FLAG_RESOLVE_HOST=1<<5, FLAG_SHOW_BROADCAST=1<<6, FLAG_SHOW_NETMASK=1<<7, FLAG_SHOW_NETWORK=1<<8, FLAG_SHOW_PREFIX=1<<9, FLAG_SHOW_MINADDR=1<<10, FLAG_SHOW_MAXADDR=1<<11, FLAG_SHOW_ADDRESSES=1<<12, FLAG_SHOW_ADDRSPACE=1<<13, FLAG_GET_GEOIP=1<<14, FLAG_SHOW_GEOIP=(1<<15)|FLAG_GET_GEOIP, FLAG_SHOW_ALL_INFO=1<<16, FLAG_SHOW_REVERSE=1<<17, FLAG_ASSUME_CLASS_PREFIX=1<<18, FLAG_SHOW_CIDR=1<<19, FLAG_NO_DECORATE=1<<20, FLAG_SHOW_ADDRESS=1<<21, FLAG_JSON=1<<22, FLAG_RANDOM=1<<23, FLAG_SHOW_WILDCARD=1<<24, }; enum output_format { FORMAT_HUMAN, /* titled lines, colored on a terminal */ FORMAT_SHELL, /* NAME=value */ FORMAT_JSON, FORMAT_VALUE /* values only */ }; /* A split request: count subnets of size /prefix. A count of zero makes it * the fill request, which takes all the remaining space. When hosts is * non-zero, the request is for one subnet of that many hosts; the requests * of a split are either all host-sized or none is. */ struct split_req { unsigned prefix; uint64_t count; uint64_t hosts; }; void show_split_networks(const struct split_req *reqs, unsigned nreqs, const struct ip_info_st *info, unsigned flags); void output_separate(unsigned * const jsonfirst); void deaggregate(char *str, unsigned flags); void show_binary(const ip_info_st *info, unsigned flags, enum output_format format); int get_ipv4_info(const char *ipStr, int prefix, ip_info_st * info, unsigned flags); int get_ipv6_info(const char *ipStr, int prefix, ip_info_st * info, unsigned flags); int str_to_prefix(unsigned *flags, const char *prefixStr, unsigned fix); enum net_comparison { CMP_EQUALS, CMP_SUBNET_OF, CMP_OVERLAPS }; /* userFlags are the flags before the input address set its family, so that * otherStr gets its family on its own. Returns the exit status, as cmp(1). */ int compare_networks(enum net_comparison op, const ip_info_st *network, unsigned flags, char *otherStr, unsigned userFlags); #define KBLUE "\x1B[34m" #define KMAG "\x1B[35m" #define KDIM "\x1B[2m" #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 color_fputs(const char *color, const char *str); 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; /* 2 when comparing networks, as cmp(1) */ extern int exit_failure; #endif ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipv6.c000066400000000000000000000037621526405142400213160ustar00rootroot00000000000000/* * 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 . */ #include #include #include #include #include #include /* 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; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/ipv6.h000066400000000000000000000016571526405142400213240ustar00rootroot00000000000000/* * 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 . * */ #ifndef IPV6_H #define IPV6_H #include #include 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/meson.build000066400000000000000000000025341526405142400224240ustar00rootroot00000000000000project('ipcalc', 'c', license : 'GPLv2', version : '1.2.0' ) src = files( 'ipcalc.h', 'ipcalc.c', 'ipcalc-reverse.c', 'ipcalc-utils.c', 'netsplit.c', 'netcompare.c', 'binary.c', 'ipv6.h', 'ipv6.c', 'deaggregate.c' ) args = [ '-DVERSION="' + meson.project_version() + '"' ] deps = [] have_geo = false use_maxminddb = get_option('use_maxminddb') 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 += files('ipcalc-maxmind.c') args += ['-DUSE_MAXMIND'] have_geo = true 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 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') ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/meson_options.txt000066400000000000000000000006011526405142400237100ustar00rootroot00000000000000option('use_geoip', type : 'feature', value : 'auto', description : 'Ignored; libGeoIP is no longer supported' ) 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 maxminddb library at runtime if available' ) ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/netcompare.c000066400000000000000000000101251526405142400225560ustar00rootroot00000000000000/* * Copyright (c) 2026 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 . */ #include #include #include #include #include #include #include "ipcalc.h" struct binary_network { unsigned char addr[16]; unsigned prefix; int family; }; /* Bytewise, so that no shift reaches the width of an integer */ static int same_leading_bits(const unsigned char *a, const unsigned char *b, unsigned nbits) { unsigned bytes = nbits / 8, bits = nbits % 8; if (memcmp(a, b, bytes) != 0) return 0; if (bits == 0) return 1; return ((a[bytes] ^ b[bytes]) & (0xff << (8 - bits)) & 0xff) == 0; } static int network_contains(const struct binary_network *outer, const struct binary_network *inner) { return outer->family == inner->family && outer->prefix <= inner->prefix && same_leading_bits(outer->addr, inner->addr, outer->prefix); } /* ip_info_st keeps the network address only as text */ static int to_binary_network(const ip_info_st *info, unsigned flags, struct binary_network *net) { net->family = (flags & FLAG_IPV6) ? AF_INET6 : AF_INET; net->prefix = info->prefix; memset(net->addr, 0, sizeof(net->addr)); return inet_pton(net->family, info->network, net->addr) == 1 ? 0 : -1; } static int comparison_holds(enum net_comparison op, const struct binary_network *a, const struct binary_network *b) { switch (op) { case CMP_EQUALS: return a->family == b->family && a->prefix == b->prefix && memcmp(a->addr, b->addr, sizeof(a->addr)) == 0; case CMP_SUBNET_OF: return network_contains(b, a); case CMP_OVERLAPS: default: /* CIDR networks are either nested or disjoint */ return network_contains(a, b) || network_contains(b, a); } } static int parse_network(char *str, unsigned *flags, ip_info_st *info) { char *prefixStr; int prefix = -1; if ((*flags & FLAG_IPV4) == 0 && strchr(str, ':') != NULL) *flags |= FLAG_IPV6; prefixStr = strchr(str, '/'); if (prefixStr != NULL) { *prefixStr++ = '\0'; 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) return get_ipv6_info(str, prefix, info, *flags); return get_ipv4_info(str, prefix, info, *flags); } static void print_comparison(enum net_comparison op, int holds, const ip_info_st *network, const ip_info_st *other) { unsigned jsonchain = JSON_FIRST; if (op == CMP_SUBNET_OF) default_printf(&jsonchain, "", NULL, "%s/%u is %sa subnet of %s/%u", network->network, network->prefix, holds ? "" : "not ", other->network, other->prefix); else if (op == CMP_EQUALS) default_printf(&jsonchain, "", NULL, "The networks are %sequal", holds ? "" : "not "); else default_printf(&jsonchain, "", NULL, "The networks %s", holds ? "overlap" : "do not overlap"); } int compare_networks(enum net_comparison op, const ip_info_st *network, unsigned flags, char *otherStr, unsigned userFlags) { ip_info_st other; struct binary_network a, b; int holds; if (parse_network(otherStr, &userFlags, &other) < 0) return exit_failure; if (to_binary_network(network, flags, &a) < 0 || to_binary_network(&other, userFlags, &b) < 0) return exit_failure; holds = comparison_holds(op, &a, &b); /* the result has no JSON or undecorated form; the exit status carries it */ if (!beSilent && !(flags & (FLAG_JSON | FLAG_NO_DECORATE))) print_comparison(op, holds, network, &other); return holds ? 0 : 1; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/netsplit.c000066400000000000000000000355171526405142400222770ustar00rootroot00000000000000/* * 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 #include #include #include #include #include #include #include "ipcalc.h" /* Splitting of a network into subnets. * * Terminology: * - request: a [COUNT:]PREFIX item, i.e., COUNT subnets of size /PREFIX. * - fill request: a request without a count (count is zero); it takes all * the space that remains after the counted requests are allocated. * - equal split: a split with a single fill request (e.g., -S 26). * - VLSM split: any other split, i.e., one with counted requests. * - unused: the space of the network that no request was allocated. * - host-sized request: a request for a single subnet that holds a number * of hosts (--split-hosts); its subnets are printed with their details, * as in the Debian ipcalc's split. * * Counted requests are allocated largest first (equal sizes keep the request * order), back to back from the start of the network, which is the layout * the Debian ipcalc uses. Since every block allocated before a request is at * least as large as it, the allocation cursor is always aligned to the size * of the request and no space is lost. The fill request is aligned to its * own size and extends to the end of the network. An equal split's fill * request starts at the network address, so only a VLSM split can leave * unused space. * * Addresses of both families are handled as 128-bit numbers, with IPv4 * using the low 32 bits. */ typedef struct { uint64_t hi, lo; } u128_t; /* last is inclusive: the last address of the last subnet */ struct split_run { u128_t start; u128_t last; unsigned prefix; }; static u128_t u128_from64(uint64_t v) { u128_t r; r.hi = 0; r.lo = v; return r; } static u128_t u128_add(u128_t a, u128_t b) { u128_t r; r.lo = a.lo + b.lo; r.hi = a.hi + b.hi + (r.lo < a.lo); return r; } static u128_t u128_sub(u128_t a, u128_t b) { u128_t r; r.lo = a.lo - b.lo; r.hi = a.hi - b.hi - (a.lo < b.lo); return r; } static int u128_cmp(u128_t a, u128_t b) { if (a.hi != b.hi) return (a.hi < b.hi) ? -1 : 1; if (a.lo != b.lo) return (a.lo < b.lo) ? -1 : 1; return 0; } static int u128_is_zero(u128_t a) { return (a.hi == 0 && a.lo == 0); } static u128_t u128_and(u128_t a, u128_t b) { a.hi &= b.hi; a.lo &= b.lo; return a; } static u128_t u128_or(u128_t a, u128_t b) { a.hi |= b.hi; a.lo |= b.lo; return a; } static u128_t u128_shl(u128_t a, unsigned n) { u128_t r; if (n == 0) { r = a; } else if (n < 64) { r.hi = (a.hi << n) | (a.lo >> (64 - n)); r.lo = a.lo << n; } else if (n < 128) { r.hi = a.lo << (n - 64); r.lo = 0; } else { r.hi = r.lo = 0; } return r; } static u128_t u128_shr(u128_t a, unsigned n) { u128_t r; if (n == 0) { r = a; } else if (n < 64) { r.lo = (a.lo >> n) | (a.hi << (64 - n)); r.hi = a.hi >> n; } else if (n < 128) { r.lo = a.hi >> (n - 64); r.hi = 0; } else { r.hi = r.lo = 0; } return r; } /* Returns a value with the n low bits set */ static u128_t u128_low_mask(unsigned n) { u128_t r; if (n >= 128) { r.hi = r.lo = UINT64_MAX; return r; } return u128_sub(u128_shl(u128_from64(1), n), u128_from64(1)); } /* Divides v by 10 in place and returns the remainder */ static unsigned u128_divmod10(u128_t *v) { uint64_t r, mid, low, mid_q, low_q; r = v->hi % 10; v->hi /= 10; mid = (r << 32) | (v->lo >> 32); mid_q = mid / 10; r = mid % 10; low = (r << 32) | (v->lo & 0xffffffff); low_q = low / 10; r = low % 10; v->lo = (mid_q << 32) | low_q; return r; } /* Prints v + 1 in decimal; the addition is done on the digits so that * 2^128 can be printed. */ static const char *u128_plus1_to_dec(u128_t v, char *buf, size_t size) { char digits[48]; unsigned n = 0, i, carry = 1; do { digits[n++] = u128_divmod10(&v); } while (!u128_is_zero(v)); for (i = 0; i < n && carry; i++) { digits[i] += carry; carry = (digits[i] == 10); if (carry) digits[i] = 0; } if (carry) digits[n++] = 1; if (size < n + 1) { buf[0] = 0; return buf; } for (i = 0; i < n; i++) buf[i] = '0' + digits[n - 1 - i]; buf[n] = 0; return buf; } static int str_to_u128(const char *str, unsigned flags, u128_t *v) { unsigned i; if (flags & FLAG_IPV6) { struct in6_addr a; if (inet_pton(AF_INET6, str, &a) <= 0) return -1; v->hi = v->lo = 0; for (i = 0; i < 8; i++) v->hi = (v->hi << 8) | a.s6_addr[i]; for (i = 8; i < 16; i++) v->lo = (v->lo << 8) | a.s6_addr[i]; } else { struct in_addr a; if (inet_pton(AF_INET, str, &a) <= 0) return -1; v->hi = 0; v->lo = ntohl(a.s_addr); } return 0; } static const char *u128_to_str(u128_t v, unsigned flags, char *buf, size_t size) { int i; if (flags & FLAG_IPV6) { struct in6_addr a; for (i = 15; i >= 8; i--) { a.s6_addr[i] = v.lo & 0xff; v.lo >>= 8; } for (i = 7; i >= 0; i--) { a.s6_addr[i] = v.hi & 0xff; v.hi >>= 8; } return inet_ntop(AF_INET6, &a, buf, size); } else { struct in_addr a; a.s_addr = htonl((uint32_t)v.lo); return inet_ntop(AF_INET, &a, buf, size); } } static void print_network(unsigned *jsonchain, u128_t addr, unsigned prefix, unsigned flags) { char str[INET6_ADDRSTRLEN]; u128_to_str(addr, flags, str, sizeof(str)); if (!(flags & FLAG_NO_DECORATE) || (flags & FLAG_JSON)) { default_printf(jsonchain, "Network:\t", NULL, "%s/%u", str, prefix); } else { printf("%s/%u\n", str, prefix); } } /* Returns the host bits of the largest network that starts at start and * ends at or before last */ static unsigned largest_aligned_block(u128_t start, u128_t last, unsigned width) { const u128_t one = u128_from64(1); unsigned hb = 0; while (hb < width && u128_is_zero(u128_and(start, u128_shl(one, hb)))) { if (u128_cmp(u128_or(start, u128_low_mask(hb + 1)), last) > 0) break; hb++; } return hb; } /* last is inclusive */ static void print_range(unsigned *jsonchain, u128_t start, u128_t last, unsigned width, unsigned flags) { const u128_t one = u128_from64(1); unsigned hb; while (1) { hb = largest_aligned_block(start, last, width); print_network(jsonchain, start, width - hb, flags); start = u128_or(start, u128_low_mask(hb)); if (u128_cmp(start, last) >= 0) break; start = u128_add(start, one); } } static void print_host_sized_subnet(unsigned *jsonchain, unsigned idx, const struct split_req *req, const struct split_run *run, unsigned width, unsigned flags) { unsigned hb = width - run->prefix; const u128_t one = u128_from64(1); u128_t mask = u128_sub(u128_low_mask(width), u128_low_mask(hb)); char str[INET6_ADDRSTRLEN], buf[64]; char *title; if (idx) output_separate(jsonchain); safe_asprintf(&title, "%u. Requested size: ", idx + 1); default_printf(jsonchain, title, NULL, "%" PRIu64 " hosts", req->hosts); free(title); print_network(jsonchain, run->start, run->prefix, flags); default_printf(jsonchain, "Netmask:\t", NULL, "%s = %u", u128_to_str(mask, flags, str, sizeof(str)), run->prefix); if (flags & FLAG_IPV6) { default_printf(jsonchain, "HostMin:\t", NULL, "%s", u128_to_str(run->start, flags, str, sizeof(str))); default_printf(jsonchain, "HostMax:\t", NULL, "%s", u128_to_str(run->last, flags, str, sizeof(str))); ipv6_prefix_to_hosts(buf, sizeof(buf), run->prefix); } else { /* host-sized IPv4 requests are at least /30, so start + 1 * and last - 1 are host addresses */ default_printf(jsonchain, "Broadcast:\t", NULL, "%s", u128_to_str(run->last, flags, str, sizeof(str))); default_printf(jsonchain, "HostMin:\t", NULL, "%s", u128_to_str(u128_add(run->start, one), flags, str, sizeof(str))); default_printf(jsonchain, "HostMax:\t", NULL, "%s", u128_to_str(u128_sub(run->last, one), flags, str, sizeof(str))); ipv4_prefix_to_hosts(buf, sizeof(buf), run->prefix); } default_printf(jsonchain, "Hosts/Net:\t", NULL, "%s", buf); } static void too_small(const struct ip_info_st *info) { if (!beSilent) fprintf(stderr, "ipcalc: %s/%u is too small for the requested subnets\n", info->network, info->prefix); exit(1); } void show_split_networks(const struct split_req *reqs, unsigned nreqs, const struct ip_info_st *info, unsigned flags) { unsigned width = (flags & FLAG_IPV6) ? 128 : 32; unsigned i, j, hb, ncounted = 0, fill = nreqs; unsigned has_space = 1, has_gap = 0, same_prefix = 1; /* main() rejects combining --split-hosts with --split, so the first * request decides */ unsigned host_sized = (reqs[0].hosts != 0); unsigned details = host_sized && !(flags & (FLAG_JSON | FLAG_NO_DECORATE)); unsigned jsonchain = JSON_FIRST; const u128_t one = u128_from64(1); u128_t net, last, cursor, gap_last, nets_m1, needed_m1; struct split_run *runs; unsigned *order; char buf[64]; if (str_to_u128(info->network, flags, &net) < 0) { if (!beSilent) fprintf(stderr, "ipcalc: bad %s address: %s\n", (flags & FLAG_IPV6) ? "IPv6" : "IPv4", info->network); exit(1); } last = u128_or(net, u128_low_mask(width - info->prefix)); runs = calloc(nreqs, sizeof(runs[0])); order = calloc(nreqs, sizeof(order[0])); if (runs == NULL || order == NULL) { fprintf(stderr, "ipcalc: memory error\n"); exit(1); } for (i = 0; i < nreqs; i++) { /* a host-sized request has no user-given prefix for the * "Cannot subnet to /N" error to name */ if (host_sized && reqs[i].prefix < info->prefix) too_small(info); if (reqs[i].prefix < info->prefix || reqs[i].prefix > width) { if (!beSilent) fprintf(stderr, "Cannot subnet to /%u with this base network, use a prefix > /%u\n", reqs[i].prefix, info->prefix); exit(1); } if (reqs[i].prefix != reqs[0].prefix) same_prefix = 0; if (reqs[i].count == 0) { fill = i; continue; } /* stable: equal prefixes keep the request order, as in the * Debian ipcalc */ for (j = ncounted; j > 0 && reqs[order[j - 1]].prefix > reqs[i].prefix; j--) order[j] = order[j - 1]; order[j] = i; ncounted++; } cursor = net; for (j = 0; j < ncounted; j++) { const struct split_req *req = &reqs[order[j]]; struct split_run *run = &runs[order[j]]; hb = width - req->prefix; /* the cursor is aligned to the request, so (last - cursor) >> hb * is the number of available subnets minus one */ if (!has_space || u128_cmp(u128_from64(req->count - 1), u128_shr(u128_sub(last, cursor), hb)) > 0) too_small(info); run->start = cursor; run->last = u128_add(cursor, u128_sub(u128_shl(u128_from64(req->count), hb), one)); run->prefix = req->prefix; /* the cursor is not advanced past the end, as last + 1 wraps * when the network ends at the top of the IPv6 space */ if (u128_cmp(run->last, last) == 0) has_space = 0; else cursor = u128_add(run->last, one); } if (fill < nreqs) { u128_t low_mask, rem, start = cursor; hb = width - reqs[fill].prefix; low_mask = u128_low_mask(hb); rem = u128_and(cursor, low_mask); /* the space skipped to align the fill request is unused */ if (has_space && !u128_is_zero(rem)) { u128_t gap = u128_add(u128_sub(low_mask, rem), one); if (u128_cmp(u128_sub(last, cursor), gap) < 0) { has_space = 0; } else { start = u128_add(cursor, gap); gap_last = u128_sub(start, one); has_gap = 1; } } if (!has_space) too_small(info); runs[fill].start = start; runs[fill].last = last; runs[fill].prefix = reqs[fill].prefix; } else if (has_space) { gap_last = last; has_gap = 1; } output_start(&jsonchain); array_start(&jsonchain, "Split networks", "SPLITNETWORK"); nets_m1 = u128_from64(0); for (i = 0; i < nreqs; i++) { u128_t addr, low_mask, step; hb = width - runs[i].prefix; low_mask = u128_low_mask(hb); step = u128_shl(one, hb); /* the total is kept minus one, as 2^128 subnets do not fit */ if (i > 0) nets_m1 = u128_add(nets_m1, one); nets_m1 = u128_add(nets_m1, u128_shr(u128_sub(runs[i].last, runs[i].start), hb)); if (details) { print_host_sized_subnet(&jsonchain, i, &reqs[i], &runs[i], width, flags); continue; } for (addr = runs[i].start;; addr = u128_add(addr, step)) { print_network(&jsonchain, addr, runs[i].prefix, flags); if (u128_cmp(u128_add(addr, low_mask), runs[i].last) == 0) break; } } array_stop(&jsonchain); if ((!(flags & FLAG_NO_DECORATE)) || (flags & FLAG_JSON)) { dist_printf(&jsonchain, "\nTotal: \t", "NETS", "%s", u128_plus1_to_dec(nets_m1, buf, sizeof(buf))); /* Hosts/Net is per subnet, so it is printed only when all * subnets have one size, as in every equal split */ if (same_prefix) { if (flags & FLAG_IPV6) ipv6_prefix_to_hosts(buf, sizeof(buf), reqs[0].prefix); else ipv4_prefix_to_hosts(buf, sizeof(buf), reqs[0].prefix); dist_printf(&jsonchain, "Hosts/Net:\t", "ADDRESSES", "%s", buf); } if (host_sized) { char str[INET6_ADDRSTRLEN]; if (has_space) needed_m1 = u128_sub(u128_sub(cursor, net), one); else needed_m1 = u128_sub(last, net); for (hb = 0; hb < width && u128_cmp(u128_low_mask(hb), needed_m1) < 0; hb++) ; dist_printf(&jsonchain, "Needed size:\t", "NEEDED", "%s", u128_plus1_to_dec(needed_m1, buf, sizeof(buf))); dist_printf(&jsonchain, "Used network:\t", "USEDNETWORK", "%s/%u", u128_to_str(net, flags, str, sizeof(str)), width - hb); } if (has_gap) { output_separate(&jsonchain); array_start(&jsonchain, "Unused networks", "UNUSED"); print_range(&jsonchain, cursor, gap_last, width, flags); array_stop(&jsonchain); } } output_stop(&jsonchain); free(order); free(runs); } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/release.sh000077500000000000000000000046301526405142400222400ustar00rootroot00000000000000#!/bin/bash echo "This script will make a new release and create tags at gitlab" echo "It will use your ssh keys, gpg key, glab, and gitlab token as placed in ~/.gitlab-token" echo "Press enter to continue..." read if test -z "$1";then echo "usage: $0 [VERSION]" echo "No version was specified" exit 1 fi if ! test -f ~/.gitlab-token;then echo "Cannot find ~/.gitlab-token" exit 1 fi PROJECT=7517683 REPO=ipcalc/ipcalc TOKEN=$(cat ~/.gitlab-token) version=$1 meson_version=$(sed -n "s/^[[:space:]]*version[[:space:]]*:[[:space:]]*'\([^']*\)'.*/\1/p" meson.build|head -1) if test "$meson_version" != "$version";then echo "Version in meson.build ($meson_version) does not match $version" exit 1 fi echo "Creating tag $version and gitlab release" echo "Press enter to continue or type skip to skip..." read s if test "$s" != "s" && test "$s" != "skip";then git tag -s ${version} -m "Released ${version}" git push origin ${version} fi tarball=ipcalc-${version}.tar.xz echo "Creating and signing $tarball" echo "Press enter to continue or type skip to skip..." read s if test "$s" != "s" && test "$s" != "skip";then if test "$(git rev-parse HEAD)" != "$(git rev-parse ${version}^{commit})";then echo "HEAD is not at tag $version; check it out first" exit 1 fi set -e builddir=$(mktemp -d) trap 'rm -rf "$builddir"' EXIT meson setup "$builddir" meson dist -C "$builddir" --formats xztar cp "$builddir/meson-dist/$tarball" . gpg --detach-sign "$tarball" set +e fi echo "Creating gitlab $version release with $tarball and $tarball.sig" echo "Press enter to continue or type skip to skip..." read s if test "$s" != "s" && test "$s" != "skip";then line=$(grep -n "Version ${version}" NEWS|cut -d ':' -f 1) test -z "$line" && exit 1 stopline="$(head -n 100 NEWS|tail -n $((100-$line))|grep -n Version|head -1|cut -d ':' -f 1)" test -z "$stopline" && exit 1 set -e notes=$(mktemp) head -n 100 NEWS|tail -n +$((1+$line))|head -n $(($stopline-1)) >"$notes" export GITLAB_TOKEN="$TOKEN" milestone_opt="" if test "$(glab api "projects/${PROJECT}/milestones?title=${version}&include_ancestors=true")" != "[]";then milestone_opt="--milestone=${version}" fi glab release create "$version" -R "$REPO" --name "$version" --notes-file "$notes" \ $milestone_opt --use-package-registry --package-name ipcalc \ "$tarball#Tarball#package" "$tarball.sig#PGP signature#other" rm -f "$notes" fi echo "" echo Done exit 0 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/000077500000000000000000000000001526405142400214205ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/12.15.1.5000066400000000000000000000001271526405142400223130ustar00rootroot00000000000000ADDRESS=12.15.1.5 NETWORK=12.0.0.0 NETMASK=255.0.0.0 PREFIX=8 BROADCAST=12.255.255.255 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/129.15.31.5000066400000000000000000000001361526405142400224670ustar00rootroot00000000000000ADDRESS=129.15.31.5 NETWORK=129.15.0.0 NETMASK=255.255.0.0 PREFIX=16 BROADCAST=129.15.255.255 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/192.168.1.5-16000066400000000000000000000001351526405142400227200ustar00rootroot00000000000000ADDRESS=10.100.4.1 NETWORK=10.100.0.0 NETMASK=255.255.0.0 PREFIX=16 BROADCAST=10.100.255.255 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/192.168.1.5-24000066400000000000000000000001351526405142400227170ustar00rootroot00000000000000ADDRESS=10.10.10.5 NETWORK=10.10.10.0 NETMASK=255.255.255.0 PREFIX=24 BROADCAST=10.10.10.255 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/192.168.1.5-30000066400000000000000000000001351526405142400227140ustar00rootroot00000000000000ADDRESS=10.100.4.1 NETWORK=10.100.4.0 NETMASK=255.255.255.252 PREFIX=30 BROADCAST=10.100.4.3 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/192.168.1.5-31000066400000000000000000000001441526405142400227150ustar00rootroot00000000000000ADDRESS=192.168.1.5 NETWORK=192.168.1.4 NETMASK=255.255.255.254 PREFIX=31 BROADCAST=255.255.255.255 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/192.168.1.5-8000066400000000000000000000001311526405142400226350ustar00rootroot00000000000000ADDRESS=10.10.10.10 NETWORK=10.0.0.0 NETMASK=255.0.0.0 PREFIX=8 BROADCAST=10.255.255.255 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/192.168.2.6000066400000000000000000000002301526405142400224720ustar00rootroot00000000000000ADDRESS=192.168.2.6 NETWORK=192.168.2.0 NETMASK=255.255.255.0 PREFIX=24 BROADCAST=192.168.2.255 MINADDR=192.168.2.1 MAXADDR=192.168.2.254 ADDRESSES=254 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/192.168.2.7000066400000000000000000000001251526405142400224760ustar00rootroot00000000000000192.168.2.7 192.168.2.0 255.255.255.0 24 192.168.2.255 192.168.2.1 192.168.2.254 254 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/193.92.150.3-24000066400000000000000000000001661526405142400230030ustar00rootroot00000000000000ADDRESS=193.92.150.3 NETWORK=193.92.150.0 NETMASK=255.255.255.0 PREFIX=24 BROADCAST=193.92.150.255 ADDRSPACE=Internet ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/193.92.31.0000066400000000000000000000001401526405142400224630ustar00rootroot00000000000000ADDRESS=193.92.31.0 NETWORK=193.92.31.0 NETMASK=255.255.255.0 PREFIX=24 BROADCAST=193.92.31.255 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-192.168.2.7000066400000000000000000000004111526405142400241730ustar00rootroot00000000000000Address: 192.168.2.7 Network: 192.168.2.0/24 Netmask: 255.255.255.0 = 24 Wildcard: 0.0.0.255 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-2001:db8::-31000066400000000000000000000005161526405142400245230ustar00rootroot00000000000000Full Network: 2001:0db8:0000:0000:0000:0000:0000:0000/31 Network: 2001:db8::/31 Netmask: ffff:fffe:: = 31 Reverse DNS: 8.b.d.0.1.0.0.2.ip6.arpa. Reverse DNS: 9.b.d.0.1.0.0.2.ip6.arpa. Address space: Global Unicast HostMin: 2001:db8:: HostMax: 2001:db9:ffff:ffff:ffff:ffff:ffff:ffff Hosts/Net: 2^(97) = 158456325028528675187087900672 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-2001:db8::300:ff:fe00:1000066400000000000000000000005221526405142400260500ustar00rootroot00000000000000Full Address: 2001:0db8:0000:0000:0300:00ff:fe00:0001 Address: 2001:db8::300:ff:fe00:1 Reverse DNS: 1.0.0.0.0.0.e.f.f.f.0.0.0.0.3.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. Address space: Documentation Interface ID: 0300:00ff:fe00:0001 EUI-64: 01:00:00:ff:fe:00:00:01 MAC address: 01:00:00:00:00:01 MAC scope: universal MAC type: group all-info-2001:db8::f00d:1234:5678:9abc-64000066400000000000000000000006541526405142400270100ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/testsFull Address: 2001:0db8:0000:0000:f00d:1234:5678:9abc Address: 2001:db8::f00d:1234:5678:9abc Full Network: 2001:0db8:0000:0000:0000:0000:0000:0000/64 Network: 2001:db8::/64 Netmask: ffff:ffff:ffff:ffff:: = 64 Reverse DNS: 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. Address space: Documentation Interface ID: f00d:1234:5678:9abc HostMin: 2001:db8:: HostMax: 2001:db8::ffff:ffff:ffff:ffff Hosts/Net: 2^(64) = 18446744073709551616 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-224.0.0.1000066400000000000000000000001501526405142400240000ustar00rootroot00000000000000Address: 224.0.0.1 Reverse DNS: 1.0.0.224.in-addr.arpa. Address space: Multicast Address class: Class D ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-239.1.1.1000066400000000000000000000001501526405142400240100ustar00rootroot00000000000000Address: 239.1.1.1 Reverse DNS: 1.1.1.239.in-addr.arpa. Address space: Multicast Address class: Class D ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-240.0.0.1000066400000000000000000000001471526405142400240040ustar00rootroot00000000000000Address: 240.0.0.1 Reverse DNS: 1.0.0.240.in-addr.arpa. Address space: Reserved Address class: Class E ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-::ffff:192.0.2.1000066400000000000000000000003121526405142400251140ustar00rootroot00000000000000Full Address: 0000:0000:0000:0000:0000:ffff:c000:0201 Address: ::ffff:192.0.2.1 Reverse DNS: 1.0.2.0.0.0.0.c.f.f.f.f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. Address space: IPv4-mapped Address ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-fe80::-64000066400000000000000000000004471526405142400242240ustar00rootroot00000000000000Full Network: fe80:0000:0000:0000:0000:0000:0000:0000/64 Network: fe80::/64 Netmask: ffff:ffff:ffff:ffff:: = 64 Reverse DNS: 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. Address space: Link-Scoped Unicast HostMin: fe80:: HostMax: fe80::ffff:ffff:ffff:ffff Hosts/Net: 2^(64) = 18446744073709551616 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-fe80::21b:21ff:fe3a:5c7d-64000066400000000000000000000010131526405142400266760ustar00rootroot00000000000000Full Address: fe80:0000:0000:0000:021b:21ff:fe3a:5c7d Address: fe80::21b:21ff:fe3a:5c7d Full Network: fe80:0000:0000:0000:0000:0000:0000:0000/64 Network: fe80::/64 Netmask: ffff:ffff:ffff:ffff:: = 64 Reverse DNS: 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. Address space: Link-Scoped Unicast Interface ID: 021b:21ff:fe3a:5c7d EUI-64: 00:1b:21:ff:fe:3a:5c:7d MAC address: 00:1b:21:3a:5c:7d MAC scope: universal MAC type: individual HostMin: fe80:: HostMax: fe80::ffff:ffff:ffff:ffff Hosts/Net: 2^(64) = 18446744073709551616 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-fe80::ff:fe00:1000066400000000000000000000005211526405142400252220ustar00rootroot00000000000000Full Address: fe80:0000:0000:0000:0000:00ff:fe00:0001 Address: fe80::ff:fe00:1 Reverse DNS: 1.0.0.0.0.0.e.f.f.f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. Address space: Link-Scoped Unicast Interface ID: 0000:00ff:fe00:0001 EUI-64: 02:00:00:ff:fe:00:00:01 MAC address: 02:00:00:00:00:01 MAC scope: local MAC type: individual ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/all-info-ff02::21b:21ff:fe3a:5c7d000066400000000000000000000003101526405142400264410ustar00rootroot00000000000000Full Address: ff02:0000:0000:0000:021b:21ff:fe3a:5c7d Address: ff02::21b:21ff:fe3a:5c7d Reverse DNS: d.7.c.5.a.3.e.f.f.f.1.2.b.1.2.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.f.f.ip6.arpa. Address space: Multicast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-0.0.0.0-0000066400000000000000000000011241526405142400232260ustar00rootroot00000000000000Network: 0.0.0.0/0 0-255. 0-255. 0-255. 0-255 xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx └──────────── host 32 ────────────┘ Netmask: 0.0.0.0 00000000.00000000.00000000.00000000 Network: 0.0.0.0 00000000.00000000.00000000.00000000 HostMin: 0.0.0.1 00000000.00000000.00000000.00000001 HostMax: 255.255.255.254 11111111.11111111.11111111.11111110 Broadcast: 255.255.255.255 11111111.11111111.11111111.11111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-10.0.0.0-8000066400000000000000000000011131526405142400233150ustar00rootroot00000000000000Network: 10.0.0.0/8 10. 0-255. 0-255. 0-255 00001010.xxxxxxxx.xxxxxxxx.xxxxxxxx └─ /8 ─┘ └─────── host 24 ────────┘ Netmask: 255.0.0.0 11111111.00000000.00000000.00000000 Network: 10.0.0.0 00001010.00000000.00000000.00000000 HostMin: 10.0.0.1 00001010.00000000.00000000.00000001 HostMax: 10.255.255.254 00001010.11111111.11111111.11111110 Broadcast: 10.255.255.255 00001010.11111111.11111111.11111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-128.0.0.0-1000066400000000000000000000011241526405142400234020ustar00rootroot00000000000000Network: 128.0.0.0/1 128-255. 0-255. 0-255. 0-255 1xxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx 1└─────────── host 31 ────────────┘ Netmask: 128.0.0.0 10000000.00000000.00000000.00000000 Network: 128.0.0.0 10000000.00000000.00000000.00000000 HostMin: 128.0.0.1 10000000.00000000.00000000.00000001 HostMax: 255.255.255.254 11111111.11111111.11111111.11111110 Broadcast: 255.255.255.255 11111111.11111111.11111111.11111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-192.168.1.4-31000066400000000000000000000007151526405142400236570ustar00rootroot00000000000000Network: 192.168.1.4/31 192. 168. 1. 4-5 11000000.10101000.00000001.0000010x └───────── network /31 ──────────┘1 Netmask: 255.255.255.254 11111111.11111111.11111111.11111110 HostMin: 192.168.1.4 11000000.10101000.00000001.00000100 HostMax: 192.168.1.5 11000000.10101000.00000001.00000101 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-192.168.1.5-31000066400000000000000000000010161526405142400236530ustar00rootroot00000000000000Network: 192.168.1.4/31 192. 168. 1. 4-5 11000000.10101000.00000001.0000010x └───────── network /31 ──────────┘1 Address: 192.168.1.5 11000000.10101000.00000001.00000101 Netmask: 255.255.255.254 11111111.11111111.11111111.11111110 HostMin: 192.168.1.4 11000000.10101000.00000001.00000100 HostMax: 192.168.1.5 11000000.10101000.00000001.00000101 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-192.168.92.1-24000066400000000000000000000012051526405142400237430ustar00rootroot00000000000000Network: 192.168.92.0/24 192. 168. 92. 0-255 11000000.10101000.01011100.xxxxxxxx └───── network /24 ──────┘ └host 8┘ Address: 192.168.92.1 11000000.10101000.01011100.00000001 Netmask: 255.255.255.0 11111111.11111111.11111111.00000000 Network: 192.168.92.0 11000000.10101000.01011100.00000000 HostMin: 192.168.92.1 11000000.10101000.01011100.00000001 HostMax: 192.168.92.254 11000000.10101000.01011100.11111110 Broadcast: 192.168.92.255 11000000.10101000.01011100.11111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-192.168.92.255-24000066400000000000000000000012051526405142400241160ustar00rootroot00000000000000Network: 192.168.92.0/24 192. 168. 92. 0-255 11000000.10101000.01011100.xxxxxxxx └───── network /24 ──────┘ └host 8┘ Address: 192.168.92.255 11000000.10101000.01011100.11111111 Netmask: 255.255.255.0 11111111.11111111.11111111.00000000 Network: 192.168.92.0 11000000.10101000.01011100.00000000 HostMin: 192.168.92.1 11000000.10101000.01011100.00000001 HostMax: 192.168.92.254 11000000.10101000.01011100.11111110 Broadcast: 192.168.92.255 11000000.10101000.01011100.11111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-192.168.92.6000066400000000000000000000001421526405142400235240ustar00rootroot00000000000000Address: 192.168.92.6 192. 168. 92. 6 11000000.10101000.01011100.00000110 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-192.168.92.6-22000066400000000000000000000012011526405142400237420ustar00rootroot00000000000000Network: 192.168.92.0/22 192. 168. 92-95. 0-255 11000000.10101000.010111xx.xxxxxxxx └──── network /22 ─────┘└ host 10 ┘ Address: 192.168.92.6 11000000.10101000.01011100.00000110 Netmask: 255.255.252.0 11111111.11111111.11111100.00000000 Network: 192.168.92.0 11000000.10101000.01011100.00000000 HostMin: 192.168.92.1 11000000.10101000.01011100.00000001 HostMax: 192.168.95.254 11000000.10101000.01011111.11111110 Broadcast: 192.168.95.255 11000000.10101000.01011111.11111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-192.168.92.6-24000066400000000000000000000012051526405142400237500ustar00rootroot00000000000000Network: 192.168.92.0/24 192. 168. 92. 0-255 11000000.10101000.01011100.xxxxxxxx └───── network /24 ──────┘ └host 8┘ Address: 192.168.92.6 11000000.10101000.01011100.00000110 Netmask: 255.255.255.0 11111111.11111111.11111111.00000000 Network: 192.168.92.0 11000000.10101000.01011100.00000000 HostMin: 192.168.92.1 11000000.10101000.01011100.00000001 HostMax: 192.168.92.254 11000000.10101000.01011100.11111110 Broadcast: 192.168.92.255 11000000.10101000.01011100.11111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-2001:db8::-127000066400000000000000000000007301526405142400240470ustar00rootroot00000000000000Network: 2001:db8::/127 2001: 0db8: 0000: 0000 0010000000000001:0000110110111000:0000000000000000:0000000000000000 0000: 0000: 0000: 0000-0001 0000000000000000:0000000000000000:0000000000000000:000000000000000x ───────────────────────── network /127 ──────────────────────────┘1 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-2001:db8::-64000066400000000000000000000005501526405142400237670ustar00rootroot00000000000000Network: 2001:db8::/64 2001: 0db8: 0000: 0000 0010000000000001:0000110110111000:0000000000000000:0000000000000000 └─────────────────────── subnet prefix /64 ───────────────────────┘ bits 64-127: interface ID, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-2001:db8::-65000066400000000000000000000007431526405142400237740ustar00rootroot00000000000000Network: 2001:db8::/65 2001: 0db8: 0000: 0000 0010000000000001:0000110110111000:0000000000000000:0000000000000000 0000-7fff: 0000-ffff: 0000-ffff: 0000-ffff 0xxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx ┘└─────────────────────────── host 63 ────────────────────────────┘ ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-2001:db8::-96000066400000000000000000000007071526405142400240000ustar00rootroot00000000000000Network: 2001:db8::/96 2001: 0db8: 0000: 0000 0010000000000001:0000110110111000:0000000000000000:0000000000000000 0000: 0000: 0000-ffff: 0000-ffff 0000000000000000:0000000000000000:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx ───────── network /96 ──────────┘ └─────────── host 32 ───────────┘ ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-2001:db8::1000066400000000000000000000004511526405142400236210ustar00rootroot00000000000000Address: 2001:db8::1 2001: 0db8: 0000: 0000 0010000000000001:0000110110111000:0000000000000000:0000000000000000 0000: 0000: 0000: 0001 0000000000000000:0000000000000000:0000000000000000:0000000000000001 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-2001:db8:abcd:10::-62000066400000000000000000000005511526405142400251250ustar00rootroot00000000000000Network: 2001:db8:abcd:10::/62 2001: 0db8: abcd: 0010-0013 0010000000000001:0000110110111000:1010101111001101:00000000000100xx └───────────────────── routing prefix /62 ──────────────────────┘2 bits 64-127: interface ID, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-2001:db8:abcd:12::1-56000066400000000000000000000005451526405142400252160ustar00rootroot00000000000000Network: 2001:db8:abcd::/56 2001: 0db8: abcd: 0000-00ff 0010000000000001:0000110110111000:1010101111001101:00000000xxxxxxxx └────────────────── routing prefix /56 ───────────────────┘└─ 8 ──┘ bits 64-127: interface ID, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-::-0000066400000000000000000000005511526405142400227030ustar00rootroot00000000000000Network: ::/0 0000-ffff: 0000-ffff: 0000-ffff: 0000-ffff xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx └──────────────────────────── host 128 ──────────────────────────── bits 64-127: host, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-fd10:da05:b5ac::-48000066400000000000000000000005161526405142400250440ustar00rootroot00000000000000Network: fd10:da05:b5ac::/48 fd10: da05: b5ac: 0000-ffff 1111110100010000:1101101000000101:1011010110101100:xxxxxxxxxxxxxxxx └────────────── routing prefix /48 ──────────────┘ └ subnet ID 16 ┘ bits 64-127: interface ID, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-fe80::-10000066400000000000000000000005441526405142400234510ustar00rootroot00000000000000Network: fe80::/10 fe80-febf: 0000-ffff: 0000-ffff: 0000-ffff 1111111010xxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx └─ /10 ──┘└─────────────────────── host 118 ─────────────────────── bits 64-127: host, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-fe80::-64000066400000000000000000000005501526405142400234570ustar00rootroot00000000000000Network: fe80::/64 fe80: 0000: 0000: 0000 1111111010000000:0000000000000000:0000000000000000:0000000000000000 └────────────────────────── network /64 ──────────────────────────┘ bits 64-127: host, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-ff02::-16000066400000000000000000000005221526405142400234460ustar00rootroot00000000000000Network: ff02::/16 ff02: 0000-ffff: 0000-ffff: 0000-ffff 1111111100000010:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx └ network /16 ─┘ └─────────────────── host 112 ──────────────────── bits 64-127: host, all x ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-json-192.168.92.0-22000066400000000000000000000004661526405142400247170ustar00rootroot00000000000000{ "PREFIX":"22", "ADDRESS":"11000000101010000101110000000000", "NETMASK":"11111111111111111111110000000000", "NETWORK":"11000000101010000101110000000000", "HOSTMIN":"11000000101010000101110000000001", "HOSTMAX":"11000000101010000101111111111110", "BROADCAST":"11000000101010000101111111111111" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-json-2001:db8::1000066400000000000000000000002231526405142400245650ustar00rootroot00000000000000{ "ADDRESS":"00100000000000010000110110111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-json-2001:db8:abcd:12::1-56000066400000000000000000000002441526405142400261610ustar00rootroot00000000000000{ "PREFIX":"56", "NETWORK":"00100000000000010000110110111000101010111100110100000000000000000000000000000000000000000000000000000000000000000000000000000000" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-shell-10.0.0.0-8000066400000000000000000000004011526405142400244210ustar00rootroot00000000000000PREFIX=8 ADDRESS=00001010000000000000000000000000 NETMASK=11111111000000000000000000000000 NETWORK=00001010000000000000000000000000 HOSTMIN=00001010000000000000000000000001 HOSTMAX=00001010111111111111111111111110 BROADCAST=00001010111111111111111111111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-shell-192.168.1.5-31000066400000000000000000000002561526405142400247650ustar00rootroot00000000000000PREFIX=31 ADDRESS=11000000101010000000000100000101 NETMASK=11111111111111111111111111111110 HOSTMIN=11000000101010000000000100000100 HOSTMAX=11000000101010000000000100000101 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-shell-192.168.92.6000066400000000000000000000000511526405142400246300ustar00rootroot00000000000000ADDRESS=11000000101010000101110000000110 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-shell-192.168.92.6-22000066400000000000000000000004021526405142400250510ustar00rootroot00000000000000PREFIX=22 ADDRESS=11000000101010000101110000000110 NETMASK=11111111111111111111110000000000 NETWORK=11000000101010000101110000000000 HOSTMIN=11000000101010000101110000000001 HOSTMAX=11000000101010000101111111111110 BROADCAST=11000000101010000101111111111111 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-shell-2001:db8::1000066400000000000000000000002111526405142400247200ustar00rootroot00000000000000ADDRESS=00100000000000010000110110111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-shell-2001:db8:abcd:12::1-56000066400000000000000000000002231526405142400263140ustar00rootroot00000000000000PREFIX=56 NETWORK=00100000000000010000110110111000101010111100110100000000000000000000000000000000000000000000000000000000000000000000000000000000 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-shell-::-0000066400000000000000000000002221526405142400240030ustar00rootroot00000000000000PREFIX=0 NETWORK=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-wide-2001:db8::-96000066400000000000000000000012231526405142400247200ustar00rootroot00000000000000Network: 2001:db8::/96 2001: 0db8: 0000: 0000: 0000: 0000: 0000-ffff: 0000-ffff 0010000000000001:0000110110111000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx └─────────────────────────────────────────── network /96 ───────────────────────────────────────────┘ └─────────── host 32 ───────────┘ ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-wide-2001:db8::1000066400000000000000000000004511526405142400245470ustar00rootroot00000000000000Address: 2001:db8::1 2001: 0db8: 0000: 0000: 0000: 0000: 0000: 0001 0010000000000001:0000110110111000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:0000000000000001 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-wide-2001:db8:abcd:12::1-56000066400000000000000000000011641526405142400261420ustar00rootroot00000000000000Network: 2001:db8:abcd::/56 2001: 0db8: abcd: 0000-00ff: 0000-ffff: 0000-ffff: 0000-ffff: 0000-ffff 0010000000000001:0000110110111000:1010101111001101:00000000xxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx └────────────────── routing prefix /56 ───────────────────┘└─ 8 ──┘ └──────────────────────── interface ID 64 ────────────────────────┘ ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/bits-wide-::-0000066400000000000000000000012441526405142400236310ustar00rootroot00000000000000Network: ::/0 0000-ffff: 0000-ffff: 0000-ffff: 0000-ffff: 0000-ffff: 0000-ffff: 0000-ffff: 0000-ffff xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxx └───────────────────────────────────────────────────────────── host 128 ──────────────────────────────────────────────────────────────┘ ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/deaggregate-0.0.0.0-255.255.255.255000066400000000000000000000000531526405142400260360ustar00rootroot00000000000000[Deaggregated networks] Network: 0.0.0.0/0 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/deaggregate-127.0.0.0-255.255.255.255000066400000000000000000000001021526405142400262030ustar00rootroot00000000000000[Deaggregated networks] Network: 127.0.0.0/8 Network: 128.0.0.0/1 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/deaggregate-192.168.2.0-192.168.3.255000066400000000000000000000000601526405142400262230ustar00rootroot00000000000000[Deaggregated networks] Network: 192.168.2.0/23 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/deaggregate-192.168.2.33-192.168.3.2000066400000000000000000000003541526405142400261450ustar00rootroot00000000000000{ "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"] } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/deaggregate-192.168.2.7-192.168.2.13000066400000000000000000000000561526405142400261460ustar00rootroot00000000000000192.168.2.7/32 192.168.2.8/30 192.168.2.12/31 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/deaggregate-240.0.0.0-255.255.255.255000066400000000000000000000000551526405142400262060ustar00rootroot00000000000000[Deaggregated networks] Network: 240.0.0.0/4 deaggregate-2a03:2880:20:4f06:face::0-2a03:2880:20:4f06:face::fffe000066400000000000000000000010141526405142400326320ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests2a03: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 deaggregate-8000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff000066400000000000000000000000521526405142400334740ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests[Deaggregated networks] Network: 8000::/1 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/deaggregate-::-8000::000066400000000000000000000000721526405142400246130ustar00rootroot00000000000000[Deaggregated networks] Network: ::/1 Network: 8000::/128 deaggregate-::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff000066400000000000000000000000461526405142400331670ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests[Deaggregated networks] Network: ::/0 deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:0-fcd3:57d1:733:c18f:b498:25e1:788:ffff000066400000000000000000000001101526405142400351170ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests[Deaggregated networks] Network: fcd3:57d1:733:c18f:b498:25e1:788:0/112 deaggregate-fcd3:57d1:733:c18f:b498:25e1:788:f-fcd3:57d1:733:c18f:b498:25e1:789:ffa9000066400000000000000000000023251526405142400351360ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests{ "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"] } deaggregate-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff000066400000000000000000000001151526405142400421260ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests[Deaggregated networks] Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/fail-getnameinfo.c000066400000000000000000000006701526405142400247740ustar00rootroot00000000000000/* * LD_PRELOAD shim for the -h network test: every reverse lookup fails, * so that the test can tell whether ipcalc attempted one. */ #include #include int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) { (void)sa; (void)salen; (void)host; (void)hostlen; (void)serv; (void)servlen; (void)flags; return EAI_FAIL; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/fake-getnameinfo.c000066400000000000000000000012361526405142400247660ustar00rootroot00000000000000/* * LD_PRELOAD shim for the JSON escaping test: every reverse lookup * resolves to a name containing characters that JSON requires to be * escaped, which no real resolver configuration available to the test * suite can provide. */ #include #include #include int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) { static const char name[] = "a\"b\\c\td"; (void)sa; (void)salen; (void)serv; (void)servlen; (void)flags; if (host == NULL || hostlen < sizeof(name)) return EAI_OVERFLOW; memcpy(host, name, sizeof(name)); return 0; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/fake-isatty.c000066400000000000000000000004241526405142400240050ustar00rootroot00000000000000/* * LD_PRELOAD shim for the deprecation hint tests: stderr is reported as * a terminal, which the test suite cannot otherwise provide, while * stdout is not, so that the output stays uncolored. */ #include int isatty(int fd) { return fd == STDERR_FILENO; } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/fd0b:a336:4e7d::-48000066400000000000000000000001661526405142400240430ustar00rootroot00000000000000ADDRESS=fd0b:a336:4e7d:: NETWORK=fd0b:a336:4e7d:: NETMASK=ffff:ffff:ffff:: PREFIX=48 ADDRSPACE="Unique Local Unicast" ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/fd95:6be5:0ae0:84a5::-64000066400000000000000000000002031526405142400245300ustar00rootroot00000000000000ADDRESS=fd95:6be5:ae0:84a5:: NETWORK=fd95:6be5:ae0:84a5:: NETMASK=ffff:ffff:ffff:ffff:: PREFIX=64 ADDRSPACE="Unique Local Unicast" ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-192.0.2.0-24000066400000000000000000000003501526405142400233030ustar00rootroot00000000000000CONTINENT=Europe COUNTRYCODE=GR COUNTRY=Greece CITY=Athens POSTALCODE="105 52" COORDINATES="37.984200,23.735300" ACCURACYRADIUS=200 TIMEZONE=Europe/Athens ASN=64496 ASORG="Example Net" ASNETWORK=192.0.2.0/24 GEONETWORK=192.0.2.0/24 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-192.0.2.5000066400000000000000000000003501526405142400230650ustar00rootroot00000000000000CONTINENT=Europe COUNTRYCODE=GR COUNTRY=Greece CITY=Athens POSTALCODE="105 52" COORDINATES="37.984200,23.735300" ACCURACYRADIUS=200 TIMEZONE=Europe/Athens ASN=64496 ASORG="Example Net" ASNETWORK=192.0.2.0/24 GEONETWORK=192.0.2.0/24 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-192.0.2.77-23000066400000000000000000000001071526405142400234000ustar00rootroot00000000000000CONTINENT=Europe COUNTRYCODE=GR COUNTRY=Greece GEONETWORK=192.0.0.0/22 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-198.51.100.130000066400000000000000000000002561526405142400234640ustar00rootroot00000000000000CONTINENT="North America" COUNTRYCODE=US COUNTRY="United States" COORDINATES="37.751000,-97.822000" ACCURACYRADIUS=1000 TIMEZONE=America/Chicago GEONETWORK=198.51.100.128/26 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-198.51.100.200000066400000000000000000000002071526405142400234560ustar00rootroot00000000000000CONTINENT="North America" COORDINATES="37.751000,-97.822000" ACCURACYRADIUS=1000 TIMEZONE=America/Chicago GEONETWORK=198.51.100.192/26 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-198.51.100.5000066400000000000000000000003501526405142400233200ustar00rootroot00000000000000CONTINENT="North America" COUNTRYCODE=US COUNTRY="United States" COORDINATES="37.751000,-97.822000" ACCURACYRADIUS=1000 TIMEZONE=America/Chicago ASN=64497 ASORG="Example Transit" ASNETWORK=198.51.100.0/27 GEONETWORK=198.51.100.0/27 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-2001:db8::-32000066400000000000000000000001771526405142400236000ustar00rootroot00000000000000CONTINENT=Europe COUNTRYCODE=DE COUNTRY=Germany ASN=64499 ASORG="Example Six" ASNETWORK=2001:db8::/32 GEONETWORK=2001:db8::/32 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-2001:db8::1000066400000000000000000000003471526405142400234360ustar00rootroot00000000000000CONTINENT=Europe COUNTRYCODE=DE COUNTRY=Germany CITY=Berlin POSTALCODE=10115 COORDINATES="52.519600,13.406900" ACCURACYRADIUS=50 TIMEZONE=Europe/Berlin ASN=64499 ASORG="Example Six" ASNETWORK=2001:db8::/32 GEONETWORK=2001:db8::/48 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-203.0.113.1000066400000000000000000000001251526405142400232150ustar00rootroot00000000000000ASN=64498 ASORG="Example Anycast" ASNETWORK=203.0.113.0/24 GEONETWORK=203.0.113.0/24 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-all-info-10.0.0.1000066400000000000000000000001501526405142400244610ustar00rootroot00000000000000Address: 10.0.0.1 Reverse DNS: 1.0.0.10.in-addr.arpa. Address space: Private Use Address class: Class A ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-all-info-192.0.0.0-16000066400000000000000000000003531526405142400250040ustar00rootroot00000000000000Network: 192.0.0.0/16 Netmask: 255.255.0.0 = 16 Wildcard: 0.0.255.255 Broadcast: 192.0.255.255 Reverse DNS: 0.192.in-addr.arpa. Address space: Internet Address class: Class C HostMin: 192.0.0.1 HostMax: 192.0.255.254 Hosts/Net: 65534 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-all-info-192.0.2.5000066400000000000000000000005721526405142400245720ustar00rootroot00000000000000Address: 192.0.2.5 Reverse DNS: 5.2.0.192.in-addr.arpa. Address space: Documentation (TEST-NET-1) Address class: Class C Continent: Europe Country code: GR Country: Greece City: Athens Postal code: 105 52 Coordinates: 37.984200,23.735300 Accuracy: 200 km Time zone: Europe/Athens Routed by AS: 64496 Operated by: Example Net AS network: 192.0.2.0/24 Geo network: 192.0.2.0/24 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-asn.json000066400000000000000000000007551526405142400236530ustar00rootroot00000000000000{ "database_type": "GeoLite2-ASN", "networks": { "192.0.2.0/24": { "autonomous_system_number": 64496, "autonomous_system_organization": "Example Net" }, "198.51.100.0/27": { "autonomous_system_number": 64497, "autonomous_system_organization": "Example Transit" }, "203.0.113.0/24": { "autonomous_system_number": 64498, "autonomous_system_organization": "Example Anycast" }, "2001:db8::/32": { "autonomous_system_number": 64499, "autonomous_system_organization": "Example Six" } } } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-city.json000066400000000000000000000022611526405142400240340ustar00rootroot00000000000000{ "database_type": "GeoLite2-City", "networks": { "192.0.2.0/24": { "city": { "names": { "en": "Athens" } }, "continent": { "code": "EU", "names": { "en": "Europe" } }, "country": { "iso_code": "GR", "names": { "en": "Greece" } }, "location": { "accuracy_radius": 200, "latitude": 37.9842, "longitude": 23.7353, "time_zone": "Europe/Athens" }, "postal": { "code": "105 52" }, "registered_country": { "iso_code": "GR", "names": { "en": "Greece" } } }, "198.51.100.0/24": { "continent": { "code": "NA", "names": { "en": "North America" } }, "location": { "accuracy_radius": 1000, "latitude": 37.751, "longitude": -97.822, "time_zone": "America/Chicago" }, "registered_country": { "iso_code": "US", "names": { "en": "United States" } } }, "2001:db8::/48": { "city": { "names": { "en": "Berlin" } }, "continent": { "code": "EU", "names": { "en": "Europe" } }, "country": { "iso_code": "DE", "names": { "en": "Germany" } }, "location": { "accuracy_radius": 50, "latitude": 52.5196, "longitude": 13.4069, "time_zone": "Europe/Berlin" }, "postal": { "code": "10115" }, "registered_country": { "iso_code": "DE", "names": { "en": "Germany" } } } } } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-country.json000066400000000000000000000020651526405142400245710ustar00rootroot00000000000000{ "database_type": "GeoLite2-Country", "networks": { "192.0.0.0/22": { "continent": { "code": "EU", "names": { "en": "Europe" } }, "country": { "iso_code": "GR", "names": { "en": "Greece" } }, "registered_country": { "iso_code": "GR", "names": { "en": "Greece" } } }, "198.51.100.0/25": { "continent": { "code": "NA", "names": { "en": "North America" } }, "registered_country": { "iso_code": "US", "names": { "en": "United States" } } }, "198.51.100.128/26": { "continent": { "code": "NA", "names": { "en": "North America" } }, "represented_country": { "iso_code": "US", "names": { "en": "United States" }, "type": "military" }, "registered_country": { "iso_code": "DE", "names": { "en": "Germany" } } }, "198.51.100.192/26": { "continent": { "code": "NA", "names": { "en": "North America" } } }, "2001:db8::/32": { "continent": { "code": "EU", "names": { "en": "Europe" } }, "country": { "iso_code": "DE", "names": { "en": "Germany" } }, "registered_country": { "iso_code": "DE", "names": { "en": "Germany" } } } } } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-json-2001:db8::1000066400000000000000000000004721526405142400244040ustar00rootroot00000000000000{ "CONTINENT":"Europe", "COUNTRYCODE":"DE", "COUNTRY":"Germany", "CITY":"Berlin", "POSTALCODE":"10115", "COORDINATES":"52.519600,13.406900", "ACCURACYRADIUS":"50", "TIMEZONE":"Europe/Berlin", "ASN":"64499", "ASORG":"Example Six", "ASNETWORK":"2001:db8::/32", "GEONETWORK":"2001:db8::/48" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-nolib-192.0.2.5000066400000000000000000000002411526405142400241650ustar00rootroot00000000000000ipcalc: could not open /nonexistent/libmaxminddb.so.0; geographic information requires libmaxminddb and the GeoLite2 databases, install them if they are missing ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/geo-nolib-all-info-192.0.2.5000066400000000000000000000001711526405142400256660ustar00rootroot00000000000000Address: 192.0.2.5 Reverse DNS: 5.2.0.192.in-addr.arpa. Address space: Documentation (TEST-NET-1) Address class: Class C ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/hostname-localhost-ipv4000066400000000000000000000000221526405142400260210ustar00rootroot00000000000000ADDRESS=127.0.0.1 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/hostname-localhost-ipv4-json000066400000000000000000000003701526405142400267760ustar00rootroot00000000000000{ "ADDRESS":"127.0.0.1", "NETWORK":"127.0.0.1", "NETMASK":"255.255.255.255", "PREFIX":"32", "CIDR":"127.0.0.1/32", "BROADCAST":"127.0.0.1", "ADDRSPACE":"Loopback", "MINADDR":"127.0.0.1", "MAXADDR":"127.0.0.1", "ADDRESSES":"1" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/hostname-localhost-ipv6000066400000000000000000000000141526405142400260240ustar00rootroot00000000000000ADDRESS=::1 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-0.0.0.0000066400000000000000000000000721526405142400223610ustar00rootroot00000000000000Address: 0.0.0.0 Address space: This host on this network ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-0.0.0.1000066400000000000000000000000551526405142400223630ustar00rootroot00000000000000Address: 0.0.0.1 Address space: This network ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-10.0.0.1000066400000000000000000000000551526405142400224440ustar00rootroot00000000000000Address: 10.0.0.1 Address space: Private Use ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-100.64.0.1000066400000000000000000000000701526405142400226130ustar00rootroot00000000000000Address: 100.64.0.1 Address space: Shared Address Space ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-100:0:0:1::5000066400000000000000000000001551526405142400230420ustar00rootroot00000000000000Full Address: 0100:0000:0000:0001:0000:0000:0000:0005 Address: 100:0:0:1::5 Address space: Dummy IPv6 Prefix ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-100::1000066400000000000000000000001601526405142400223330ustar00rootroot00000000000000Full Address: 0100:0000:0000:0000:0000:0000:0000:0001 Address: 100::1 Address space: Discard-Only Address Block ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-127.0.0.1000066400000000000000000000000531526405142400225330ustar00rootroot00000000000000Address: 127.0.0.1 Address space: Loopback ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-127.0.1.1000066400000000000000000000000531526405142400225340ustar00rootroot00000000000000Address: 127.0.1.1 Address space: Loopback ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-169.254.0.1000066400000000000000000000000571526405142400227200ustar00rootroot00000000000000Address: 169.254.0.1 Address space: Link Local ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-172.16.0.1000066400000000000000000000000571526405142400226260ustar00rootroot00000000000000Address: 172.16.0.1 Address space: Private Use ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-172.31.255.254000066400000000000000000000000631526405142400231460ustar00rootroot00000000000000Address: 172.31.255.254 Address space: Private Use ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.1000066400000000000000000000000741526405142400225400ustar00rootroot00000000000000Address: 192.0.0.1 Address space: IETF Protocol Assignments ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.10000066400000000000000000000001151526405142400226140ustar00rootroot00000000000000Address: 192.0.0.10 Address space: Traversal Using Relays around NAT Anycast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.170000066400000000000000000000000721526405142400227050ustar00rootroot00000000000000Address: 192.0.0.170 Address space: NAT64/DNS64 Discovery ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.171000066400000000000000000000000721526405142400227060ustar00rootroot00000000000000Address: 192.0.0.171 Address space: NAT64/DNS64 Discovery ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.254000066400000000000000000000000761526405142400227140ustar00rootroot00000000000000Address: 192.0.0.254 Address space: IETF Protocol Assignments ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.6000066400000000000000000000001011526405142400225340ustar00rootroot00000000000000Address: 192.0.0.6 Address space: IPv4 Service Continuity Prefix ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.8000066400000000000000000000000651526405142400225470ustar00rootroot00000000000000Address: 192.0.0.8 Address space: IPv4 dummy address ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.0.9000066400000000000000000000001001526405142400225360ustar00rootroot00000000000000Address: 192.0.0.9 Address space: Port Control Protocol Anycast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.0.2.1000066400000000000000000000000751526405142400225430ustar00rootroot00000000000000Address: 192.0.2.1 Address space: Documentation (TEST-NET-1) ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.168.0.1000066400000000000000000000000601526405142400227120ustar00rootroot00000000000000Address: 192.168.0.1 Address space: Private Use ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.175.48.12000066400000000000000000000001061526405142400230670ustar00rootroot00000000000000Address: 192.175.48.12 Address space: Direct Delegation AS112 Service ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.31.196.1000066400000000000000000000000561526405142400230040ustar00rootroot00000000000000Address: 192.31.196.1 Address space: AS112-v4 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.52.193.5000066400000000000000000000000511526405142400230030ustar00rootroot00000000000000Address: 192.52.193.5 Address space: AMT ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.88.99.1000066400000000000000000000001061526405142400227360ustar00rootroot00000000000000Address: 192.88.99.1 Address space: 6 to 4 Relay Anycast (Deprecated) ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-192.88.99.2000066400000000000000000000000771526405142400227460ustar00rootroot00000000000000Address: 192.88.99.2 Address space: 6a44-relay anycast address ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-198.18.0.1000066400000000000000000000000601526405142400226320ustar00rootroot00000000000000Address: 198.18.0.1 Address space: Benchmarking ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-198.19.201.71000066400000000000000000000000631526405142400230700ustar00rootroot00000000000000Address: 198.19.201.71 Address space: Benchmarking ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-198.19.255.254000066400000000000000000000000641526405142400231650ustar00rootroot00000000000000Address: 198.19.255.254 Address space: Benchmarking ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-198.51.100.1000066400000000000000000000001001526405142400227630ustar00rootroot00000000000000Address: 198.51.100.1 Address space: Documentation (TEST-NET-2) ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:0:50::d78a:0:c000066400000000000000000000001511526405142400240400ustar00rootroot00000000000000Full Address: 2001:0000:0050:0000:0000:d78a:0000:000c Address: 2001:0:50::d78a:0:c Address space: TEREDO ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:190:70::e86a:0:b000066400000000000000000000001761526405142400242220ustar00rootroot00000000000000Full Address: 2001:0190:0070:0000:0000:e86a:0000:000b Address: 2001:190:70::e86a:0:b Address space: IETF Protocol Assignments ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:1::1000066400000000000000000000001661526405142400225760ustar00rootroot00000000000000Full Address: 2001:0001:0000:0000:0000:0000:0000:0001 Address: 2001:1::1 Address space: Port Control Protocol Anycast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:1::2000066400000000000000000000002021526405142400225660ustar00rootroot00000000000000Full Address: 2001:0001:0000:0000:0000:0000:0000:0002 Address: 2001:1::2 Address space: Traversal Using Relays around NAT Anycast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:1::3000066400000000000000000000002051526405142400225720ustar00rootroot00000000000000Full Address: 2001:0001:0000:0000:0000:0000:0000:0003 Address: 2001:1::3 Address space: DNS-SD Service Registration Protocol Anycast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:1e:ab:7::000066400000000000000000000001741526405142400234370ustar00rootroot00000000000000Full Address: 2001:001e:00ab:0007:0000:0000:0000:0000 Address: 2001:1e:ab:7:: Address space: Deprecated (previously ORCHID) ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:2:0:a::5:b7f000066400000000000000000000001551526405142400236770ustar00rootroot00000000000000Full Address: 2001:0002:0000:000a:0000:0000:0005:0b7f Address: 2001:2:0:a::5:b7f Address space: Benchmarking ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:2c:ab:7::000066400000000000000000000001461526405142400234350ustar00rootroot00000000000000Full Address: 2001:002c:00ab:0007:0000:0000:0000:0000 Address: 2001:2c:ab:7:: Address space: ORCHIDv2 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:30::1000066400000000000000000000002141526405142400226520ustar00rootroot00000000000000Full Address: 2001:0030:0000:0000:0000:0000:0000:0001 Address: 2001:30::1 Address space: Drone Remote ID Protocol Entity Tags (DETs) Prefix ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:3:89:71::ab:1000066400000000000000000000001451526405142400237070ustar00rootroot00000000000000Full Address: 2001:0003:0089:0071:0000:0000:00ab:0001 Address: 2001:3:89:71::ab:1 Address space: AMT ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:4:112::6483:bd12:9010000066400000000000000000000001621526405142400245260ustar00rootroot00000000000000Full Address: 2001:0004:0112:0000:0000:6483:bd12:9010 Address: 2001:4:112::6483:bd12:9010 Address space: AS112-v6 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2001:db8:329::4a000066400000000000000000000001551526405142400236050ustar00rootroot00000000000000Full Address: 2001:0db8:0329:0000:0000:0000:0000:004a Address: 2001:db8:329::4a Address space: Documentation ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2002::34000066400000000000000000000001341526405142400225050ustar00rootroot00000000000000Full Address: 2002:0000:0000:0000:0000:0000:0000:0034 Address: 2002::34 Address space: 6to4 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-203.0.113.1000066400000000000000000000000771526405142400227010ustar00rootroot00000000000000Address: 203.0.113.1 Address space: Documentation (TEST-NET-3) ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-224.0.0.1000066400000000000000000000000541526405142400225320ustar00rootroot00000000000000Address: 224.0.0.1 Address space: Multicast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-240.0.0.1000066400000000000000000000000531526405142400225270ustar00rootroot00000000000000Address: 240.0.0.1 Address space: Reserved ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-250.7.93.1000066400000000000000000000000541526405142400226340ustar00rootroot00000000000000Address: 250.7.93.1 Address space: Reserved ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-255.255.255.254000066400000000000000000000000611526405142400232360ustar00rootroot00000000000000Address: 255.255.255.254 Address space: Reserved ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-255.255.255.255000066400000000000000000000000721526405142400232410ustar00rootroot00000000000000Address: 255.255.255.255 Address space: Limited Broadcast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2620:4f:8000::7372:ad1000066400000000000000000000002051526405142400242740ustar00rootroot00000000000000Full Address: 2620:004f:8000:0000:0000:0000:7372:0ad1 Address: 2620:4f:8000::7372:ad1 Address space: Direct Delegation AS112 Service ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-2a03:2880:20:4f06:face:b00c:0:1000066400000000000000000000001751526405142400256000ustar00rootroot00000000000000Full Address: 2a03:2880:0020:4f06:face:b00c:0000:0001 Address: 2a03:2880:20:4f06:face:b00c:0:1 Address space: Global Unicast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-3.130.45.15000066400000000000000000000000551526405142400227100ustar00rootroot00000000000000Address: 3.130.45.15 Address space: Internet ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-3fff::1000066400000000000000000000001441526405142400226610ustar00rootroot00000000000000Full Address: 3fff:0000:0000:0000:0000:0000:0000:0001 Address: 3fff::1 Address space: Documentation ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-5f00::1000066400000000000000000000001621526405142400225070ustar00rootroot00000000000000Full Address: 5f00:0000:0000:0000:0000:0000:0000:0001 Address: 5f00::1 Address space: Segment Routing (SRv6) SIDs ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-64:ff9b:1:ea21:4316:55::1000066400000000000000000000001751526405142400247250ustar00rootroot00000000000000Full Address: 0064:ff9b:0001:ea21:4316:0055:0000:0001 Address: 64:ff9b:1:ea21:4316:55:0:1 Address space: IPv4-IPv6 Translat. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-64:ff9b::2100:951a000066400000000000000000000001651526405142400240460ustar00rootroot00000000000000Full Address: 0064:ff9b:0000:0000:0000:0000:2100:951a Address: 64:ff9b::2100:951a Address space: IPv4-IPv6 Translat. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-fc00:0:a001::bcdf:4000066400000000000000000000001671526405142400243340ustar00rootroot00000000000000Full Address: fc00:0000:a001:0000:0000:0000:bcdf:0004 Address: fc00:0:a001::bcdf:4 Address space: Unique Local Unicast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-fd0b:a336:4e7d::-48000066400000000000000000000004231526405142400242650ustar00rootroot00000000000000Full 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-fe80::21b:21ff:fe3a:5c7d-64000066400000000000000000000005101526405142400254260ustar00rootroot00000000000000Full Address: fe80:0000:0000:0000:021b:21ff:fe3a:5c7d Address: fe80::21b:21ff:fe3a:5c7d Full Network: fe80:0000:0000:0000:0000:0000:0000:0000/64 Network: fe80::/64 Netmask: ffff:ffff:ffff:ffff:: = 64 Address space: Link-Scoped Unicast HostMin: fe80:: HostMax: fe80::ffff:ffff:ffff:ffff Hosts/Net: 2^(64) = 18446744073709551616 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/i-fe80::b:0:7acd:0:5000066400000000000000000000001651526405142400242170ustar00rootroot00000000000000Full Address: fe80:0000:0000:000b:0000:7acd:0000:0005 Address: fe80::b:0:7acd:0:5 Address space: Link-Scoped Unicast ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/info-192.168.2.7000066400000000000000000000002711526405142400234310ustar00rootroot00000000000000Address: 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/info-reverse-dns-192.168.2.7-24000066400000000000000000000003361526405142400261110ustar00rootroot00000000000000Address: 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 HostMin: 192.168.2.1 HostMax: 192.168.2.254 Hosts/Net: 254 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/info-wildcard-192.168.2.7-24000066400000000000000000000003151526405142400254420ustar00rootroot00000000000000Address: 192.168.2.7 Network: 192.168.2.0/24 Netmask: 255.255.255.0 = 24 Wildcard: 0.0.0.255 Broadcast: 192.168.2.255 Address space: Private Use HostMin: 192.168.2.1 HostMax: 192.168.2.254 Hosts/Net: 254 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/info-wildcard-2001:db8::-32000066400000000000000000000003761526405142400255510ustar00rootroot00000000000000Full Network: 2001:0db8:0000:0000:0000:0000:0000:0000/32 Network: 2001:db8::/32 Netmask: ffff:ffff:: = 32 Address space: Documentation HostMin: 2001:db8:: HostMax: 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff Hosts/Net: 2^(96) = 79228162514264337593543950336 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ip-localhost-ipv4000066400000000000000000000000231526405142400246140ustar00rootroot00000000000000HOSTNAME=localhost ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ip-localhost-ipv4-json000066400000000000000000000004221526405142400255660ustar00rootroot00000000000000{ "ADDRESS":"127.0.0.1", "HOSTNAME":"localhost", "NETWORK":"127.0.0.1", "NETMASK":"255.255.255.255", "PREFIX":"32", "CIDR":"127.0.0.1/32", "BROADCAST":"127.0.0.1", "ADDRSPACE":"Loopback", "MINADDR":"127.0.0.1", "MAXADDR":"127.0.0.1", "ADDRESSES":"1" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ip-localhost-ipv6000066400000000000000000000000231526405142400246160ustar00rootroot00000000000000HOSTNAME=localhost ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ipcalc-debian-split-hosts.sh000077500000000000000000000045671526405142400267350ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2026 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 # Usage: ipcalc-debian-split-hosts.sh NETWORK COUNT[,COUNT...] # # Checks that "ipcalc --split-hosts=COUNTS NETWORK" prints the same values # as "ipcalc -s COUNT..." of the Debian ipcalc (REQ-SPLIT-COMPAT-001). # Both outputs are reduced to " " lines, since # the two tools lay out the fields differently. IPCALC="${IPCALC:-build/ipcalc}" DEBIAN_IPCALC="${DEBIAN_IPCALC:-tests/debian-ipcalc/ipcalc}" NETWORK="$1" COUNTS="$2" command -v perl >/dev/null || { echo "perl: not found"; exit 1; } perl -Mbignum -e 1 2>/dev/null || { echo "perl: bignum module not found"; exit 1; } # Fields of the requested subnets; the Debian tool prints a block for the # base network before them, and ipcalc a Hosts/Net after "Total:". normalize() { awk ' /^[0-9]+\. Requested size:/ { req++; print req, "Requested", $4; next } /^(Total|Needed size):/ && req { req = 0 } req && /^(Network|Broadcast|HostMin|HostMax|Hosts\/Net):/ { print req, $1, $2; next } req && /^Netmask:/ { print req, $1, $2, $4; next } /^Needed size:/ { print "Needed", $3 } /^Used network:/ { print "Used", $3 } /^(Unused:|\[Unused networks\])/ { unused = 1; next } unused && /^Network:/ { print "Unused", ++n, $2; next } unused && /^[0-9]/ { print "Unused", ++n, $1 } ' | sort } OURS=$(${IPCALC} --split-hosts="${COUNTS}" "${NETWORK}") || { echo "ipcalc failed"; exit 1; } OURS=$(echo "${OURS}" | normalize) THEIRS=$(perl "${DEBIAN_IPCALC}" -n -b "${NETWORK}" -s $(echo "${COUNTS}" | tr ',' ' ') | normalize) if test -z "${OURS}" || test "${OURS}" != "${THEIRS}"; then echo "Values differ from the Debian ipcalc for ${NETWORK} with ${COUNTS}" echo "ipcalc:" echo "${OURS}" echo "Debian ipcalc:" echo "${THEIRS}" exit 1 fi exit 0 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ipcalc-delegate-ipv6-random.sh000077500000000000000000000017031526405142400271230ustar00rootroot00000000000000#!/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 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ipcalc-delegate-split-ipv4.sh000077500000000000000000000023671526405142400270030ustar00rootroot00000000000000#!/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 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ipcalc-delegate-split-ipv6.sh000077500000000000000000000024051526405142400267760ustar00rootroot00000000000000#!/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 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/ipcalc-testrunner.sh000077500000000000000000000050401526405142400254200ustar00rootroot00000000000000#!/bin/bash # # This shell script is a simple test runner for ipcalc tests. # # Adapted from: Matej Susta # # 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 } TestStatus() { echo -n "Checking $2 exits with $1... " output=$(sh -c "$2" 2>&1) rc=$? [ $rc -eq $1 ] && ok || fail "exit status $rc: $output" } 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" # a changed exit status breaks callers as much as changed output [ $rc -eq 0 ] || fail "exit status $rc" } 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-status) TestStatus "$2" "$3"; shift; 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-all-info-192.168.2.7-24000066400000000000000000000005571526405142400254000ustar00rootroot00000000000000{ "ADDRESS":"192.168.2.7", "NETWORK":"192.168.2.0", "NETMASK":"255.255.255.0", "WILDCARD":"0.0.0.255", "PREFIX":"24", "CIDR":"192.168.2.0/24", "BROADCAST":"192.168.2.255", "REVERSEDNS":[ "2.168.192.in-addr.arpa."], "ADDRSPACE":"Private Use", "ADDRCLASS":"Class C", "MINADDR":"192.168.2.1", "MAXADDR":"192.168.2.254", "ADDRESSES":"254" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-all-info-2001:db8::-31000066400000000000000000000006221526405142400254700ustar00rootroot00000000000000{ "FULLNETWORK":"2001:0db8:0000:0000:0000:0000:0000:0000", "NETWORK":"2001:db8::", "NETMASK":"ffff:fffe::", "PREFIX":"31", "CIDR":"2001:db8::/31", "REVERSEDNS":[ "8.b.d.0.1.0.0.2.ip6.arpa.", "9.b.d.0.1.0.0.2.ip6.arpa."], "ADDRSPACE":"Global Unicast", "MINADDR":"2001:db8::", "MAXADDR":"2001:db9:ffff:ffff:ffff:ffff:ffff:ffff", "ADDRESSES":"158456325028528675187087900672" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-all-info-2001:db8::-32000066400000000000000000000005571526405142400255000ustar00rootroot00000000000000{ "FULLNETWORK":"2001:0db8:0000:0000:0000:0000:0000:0000", "NETWORK":"2001:db8::", "NETMASK":"ffff:ffff::", "PREFIX":"32", "CIDR":"2001:db8::/32", "REVERSEDNS":[ "8.b.d.0.1.0.0.2.ip6.arpa."], "ADDRSPACE":"Documentation", "MINADDR":"2001:db8::", "MAXADDR":"2001:db8:ffff:ffff:ffff:ffff:ffff:ffff", "ADDRESSES":"79228162514264337593543950336" } json-all-info-fe80::21b:21ff:fe3a:5c7d-64000066400000000000000000000011611526405142400275720ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests{ "FULLADDRESS":"fe80:0000:0000:0000:021b:21ff:fe3a:5c7d", "ADDRESS":"fe80::21b:21ff:fe3a:5c7d", "FULLNETWORK":"fe80:0000:0000:0000:0000:0000:0000:0000", "NETWORK":"fe80::", "NETMASK":"ffff:ffff:ffff:ffff::", "PREFIX":"64", "CIDR":"fe80::/64", "REVERSEDNS":[ "0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa."], "ADDRSPACE":"Link-Scoped Unicast", "INTERFACEID":"021b:21ff:fe3a:5c7d", "EUI64":"00:1b:21:ff:fe:3a:5c:7d", "MACADDR":"00:1b:21:3a:5c:7d", "MACSCOPE":"universal", "MACTYPE":"individual", "MINADDR":"fe80::", "MAXADDR":"fe80::ffff:ffff:ffff:ffff", "ADDRESSES":"18446744073709551616" } json-i-2a03:2880:20:4f06:face:b00c:0:1-56000066400000000000000000000007041526405142400267160ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests{ "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", "CIDR":"2a03:2880:20:4f00::/56", "ADDRSPACE":"Global Unicast", "MINADDR":"2a03:2880:20:4f00::", "MAXADDR":"2a03:2880:20:4fff:ffff:ffff:ffff:ffff", "ADDRESSES":"4722366482869645213696" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-nsplit-10.10.10.0-16-24000066400000000000000000000127161526405142400253130ustar00rootroot00000000000000{ "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" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-nsplit-192.168.5.45-24-26000066400000000000000000000002261526405142400255130ustar00rootroot00000000000000{ "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" } json-nsplit-2a03:2880:20:4f06:face::-56-64000066400000000000000000000171151526405142400273320ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests{ "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" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-reverse-dns-192.168.2.7-24000066400000000000000000000004741526405142400261320ustar00rootroot00000000000000{ "ADDRESS":"192.168.2.7", "NETWORK":"192.168.2.0", "NETMASK":"255.255.255.0", "PREFIX":"24", "CIDR":"192.168.2.0/24", "BROADCAST":"192.168.2.255", "REVERSEDNS":[ "2.168.192.in-addr.arpa."], "ADDRSPACE":"Private Use", "MINADDR":"192.168.2.1", "MAXADDR":"192.168.2.254", "ADDRESSES":"254" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-split-10.10.10.0-16-24000066400000000000000000000127161526405142400251350ustar00rootroot00000000000000{ "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" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-split-192.168.0.0-24-1:28-2:27000066400000000000000000000002751526405142400260220ustar00rootroot00000000000000{ "SPLITNETWORK":[ "192.168.0.64/28", "192.168.0.0/27", "192.168.0.32/27"], "NETS":"3", "UNUSED":[ "192.168.0.80/28", "192.168.0.96/27", "192.168.0.128/25"] } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-split-192.168.5.45-24-26000066400000000000000000000002261526405142400253350ustar00rootroot00000000000000{ "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" } json-split-2001:db8:1c88:6000::-56-1:58-64000066400000000000000000000136061526405142400270120ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests{ "SPLITNETWORK":[ "2001:db8:1c88:6000::/58", "2001:db8:1c88:6040::/64", "2001:db8:1c88:6041::/64", "2001:db8:1c88:6042::/64", "2001:db8:1c88:6043::/64", "2001:db8:1c88:6044::/64", "2001:db8:1c88:6045::/64", "2001:db8:1c88:6046::/64", "2001:db8:1c88:6047::/64", "2001:db8:1c88:6048::/64", "2001:db8:1c88:6049::/64", "2001:db8:1c88:604a::/64", "2001:db8:1c88:604b::/64", "2001:db8:1c88:604c::/64", "2001:db8:1c88:604d::/64", "2001:db8:1c88:604e::/64", "2001:db8:1c88:604f::/64", "2001:db8:1c88:6050::/64", "2001:db8:1c88:6051::/64", "2001:db8:1c88:6052::/64", "2001:db8:1c88:6053::/64", "2001:db8:1c88:6054::/64", "2001:db8:1c88:6055::/64", "2001:db8:1c88:6056::/64", "2001:db8:1c88:6057::/64", "2001:db8:1c88:6058::/64", "2001:db8:1c88:6059::/64", "2001:db8:1c88:605a::/64", "2001:db8:1c88:605b::/64", "2001:db8:1c88:605c::/64", "2001:db8:1c88:605d::/64", "2001:db8:1c88:605e::/64", "2001:db8:1c88:605f::/64", "2001:db8:1c88:6060::/64", "2001:db8:1c88:6061::/64", "2001:db8:1c88:6062::/64", "2001:db8:1c88:6063::/64", "2001:db8:1c88:6064::/64", "2001:db8:1c88:6065::/64", "2001:db8:1c88:6066::/64", "2001:db8:1c88:6067::/64", "2001:db8:1c88:6068::/64", "2001:db8:1c88:6069::/64", "2001:db8:1c88:606a::/64", "2001:db8:1c88:606b::/64", "2001:db8:1c88:606c::/64", "2001:db8:1c88:606d::/64", "2001:db8:1c88:606e::/64", "2001:db8:1c88:606f::/64", "2001:db8:1c88:6070::/64", "2001:db8:1c88:6071::/64", "2001:db8:1c88:6072::/64", "2001:db8:1c88:6073::/64", "2001:db8:1c88:6074::/64", "2001:db8:1c88:6075::/64", "2001:db8:1c88:6076::/64", "2001:db8:1c88:6077::/64", "2001:db8:1c88:6078::/64", "2001:db8:1c88:6079::/64", "2001:db8:1c88:607a::/64", "2001:db8:1c88:607b::/64", "2001:db8:1c88:607c::/64", "2001:db8:1c88:607d::/64", "2001:db8:1c88:607e::/64", "2001:db8:1c88:607f::/64", "2001:db8:1c88:6080::/64", "2001:db8:1c88:6081::/64", "2001:db8:1c88:6082::/64", "2001:db8:1c88:6083::/64", "2001:db8:1c88:6084::/64", "2001:db8:1c88:6085::/64", "2001:db8:1c88:6086::/64", "2001:db8:1c88:6087::/64", "2001:db8:1c88:6088::/64", "2001:db8:1c88:6089::/64", "2001:db8:1c88:608a::/64", "2001:db8:1c88:608b::/64", "2001:db8:1c88:608c::/64", "2001:db8:1c88:608d::/64", "2001:db8:1c88:608e::/64", "2001:db8:1c88:608f::/64", "2001:db8:1c88:6090::/64", "2001:db8:1c88:6091::/64", "2001:db8:1c88:6092::/64", "2001:db8:1c88:6093::/64", "2001:db8:1c88:6094::/64", "2001:db8:1c88:6095::/64", "2001:db8:1c88:6096::/64", "2001:db8:1c88:6097::/64", "2001:db8:1c88:6098::/64", "2001:db8:1c88:6099::/64", "2001:db8:1c88:609a::/64", "2001:db8:1c88:609b::/64", "2001:db8:1c88:609c::/64", "2001:db8:1c88:609d::/64", "2001:db8:1c88:609e::/64", "2001:db8:1c88:609f::/64", "2001:db8:1c88:60a0::/64", "2001:db8:1c88:60a1::/64", "2001:db8:1c88:60a2::/64", "2001:db8:1c88:60a3::/64", "2001:db8:1c88:60a4::/64", "2001:db8:1c88:60a5::/64", "2001:db8:1c88:60a6::/64", "2001:db8:1c88:60a7::/64", "2001:db8:1c88:60a8::/64", "2001:db8:1c88:60a9::/64", "2001:db8:1c88:60aa::/64", "2001:db8:1c88:60ab::/64", "2001:db8:1c88:60ac::/64", "2001:db8:1c88:60ad::/64", "2001:db8:1c88:60ae::/64", "2001:db8:1c88:60af::/64", "2001:db8:1c88:60b0::/64", "2001:db8:1c88:60b1::/64", "2001:db8:1c88:60b2::/64", "2001:db8:1c88:60b3::/64", "2001:db8:1c88:60b4::/64", "2001:db8:1c88:60b5::/64", "2001:db8:1c88:60b6::/64", "2001:db8:1c88:60b7::/64", "2001:db8:1c88:60b8::/64", "2001:db8:1c88:60b9::/64", "2001:db8:1c88:60ba::/64", "2001:db8:1c88:60bb::/64", "2001:db8:1c88:60bc::/64", "2001:db8:1c88:60bd::/64", "2001:db8:1c88:60be::/64", "2001:db8:1c88:60bf::/64", "2001:db8:1c88:60c0::/64", "2001:db8:1c88:60c1::/64", "2001:db8:1c88:60c2::/64", "2001:db8:1c88:60c3::/64", "2001:db8:1c88:60c4::/64", "2001:db8:1c88:60c5::/64", "2001:db8:1c88:60c6::/64", "2001:db8:1c88:60c7::/64", "2001:db8:1c88:60c8::/64", "2001:db8:1c88:60c9::/64", "2001:db8:1c88:60ca::/64", "2001:db8:1c88:60cb::/64", "2001:db8:1c88:60cc::/64", "2001:db8:1c88:60cd::/64", "2001:db8:1c88:60ce::/64", "2001:db8:1c88:60cf::/64", "2001:db8:1c88:60d0::/64", "2001:db8:1c88:60d1::/64", "2001:db8:1c88:60d2::/64", "2001:db8:1c88:60d3::/64", "2001:db8:1c88:60d4::/64", "2001:db8:1c88:60d5::/64", "2001:db8:1c88:60d6::/64", "2001:db8:1c88:60d7::/64", "2001:db8:1c88:60d8::/64", "2001:db8:1c88:60d9::/64", "2001:db8:1c88:60da::/64", "2001:db8:1c88:60db::/64", "2001:db8:1c88:60dc::/64", "2001:db8:1c88:60dd::/64", "2001:db8:1c88:60de::/64", "2001:db8:1c88:60df::/64", "2001:db8:1c88:60e0::/64", "2001:db8:1c88:60e1::/64", "2001:db8:1c88:60e2::/64", "2001:db8:1c88:60e3::/64", "2001:db8:1c88:60e4::/64", "2001:db8:1c88:60e5::/64", "2001:db8:1c88:60e6::/64", "2001:db8:1c88:60e7::/64", "2001:db8:1c88:60e8::/64", "2001:db8:1c88:60e9::/64", "2001:db8:1c88:60ea::/64", "2001:db8:1c88:60eb::/64", "2001:db8:1c88:60ec::/64", "2001:db8:1c88:60ed::/64", "2001:db8:1c88:60ee::/64", "2001:db8:1c88:60ef::/64", "2001:db8:1c88:60f0::/64", "2001:db8:1c88:60f1::/64", "2001:db8:1c88:60f2::/64", "2001:db8:1c88:60f3::/64", "2001:db8:1c88:60f4::/64", "2001:db8:1c88:60f5::/64", "2001:db8:1c88:60f6::/64", "2001:db8:1c88:60f7::/64", "2001:db8:1c88:60f8::/64", "2001:db8:1c88:60f9::/64", "2001:db8:1c88:60fa::/64", "2001:db8:1c88:60fb::/64", "2001:db8:1c88:60fc::/64", "2001:db8:1c88:60fd::/64", "2001:db8:1c88:60fe::/64", "2001:db8:1c88:60ff::/64"], "NETS":"193" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-split-hosts-0.0.0.0-0-4294967294000066400000000000000000000002101526405142400266250ustar00rootroot00000000000000{ "SPLITNETWORK":[ "0.0.0.0/0"], "NETS":"1", "ADDRESSES":"4294967294", "NEEDED":"4294967296", "USEDNETWORK":"0.0.0.0/0" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-split-hosts-192.168.0.0-24-10,20,30000066400000000000000000000003601526405142400270220ustar00rootroot00000000000000{ "SPLITNETWORK":[ "192.168.0.64/28", "192.168.0.0/27", "192.168.0.32/27"], "NETS":"3", "NEEDED":"80", "USEDNETWORK":"192.168.0.0/25", "UNUSED":[ "192.168.0.80/28", "192.168.0.96/27", "192.168.0.128/25"] } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/json-wildcard-192.168.2.7-24000066400000000000000000000004451526405142400254640ustar00rootroot00000000000000{ "ADDRESS":"192.168.2.7", "NETWORK":"192.168.2.0", "NETMASK":"255.255.255.0", "WILDCARD":"0.0.0.255", "PREFIX":"24", "CIDR":"192.168.2.0/24", "BROADCAST":"192.168.2.255", "ADDRSPACE":"Private Use", "MINADDR":"192.168.2.1", "MAXADDR":"192.168.2.254", "ADDRESSES":"254" } ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/meson.build000066400000000000000000002243331526405142400235710ustar00rootroot00000000000000testrunner = 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('SplitHosts-Info', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -n --split-hosts=10 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', 'out=$(' + ipcalc.full_path() + ' -r 24) && echo "$out" | grep -Eq \'^Network:[[:space:]]+(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)\' && ! echo "$out" | grep -q \'^Address:\'' ] ) test('RandomAddress', testrunner, args : [ '--test-success', ipcalc.full_path() + ' -r 24 -a' + '|grep ADDRESS' ] ) test('RandomIPv6Implicit', testrunner, args : [ '--test-success', 'out=$(' + ipcalc.full_path() + ' -r 112) && echo "$out" | grep -Eq \'^Network:[[:space:]]+fd\' && ! echo "$out" | grep -q \'^Address:\'' ] ) test('RandomIPv6PrefixIsValidULA', testrunner, args : [ '--test-success', ipcalc.full_path() + ' -6 -r 48 -a' + '|grep ^ADDRESS=fd' ] ) test('RandomIPv6Explicit', testrunner, args : [ '--test-success', 'out=$(' + ipcalc.full_path() + ' -6 -r 24) && echo "$out" | grep -Eq \'^Network:[[:space:]]+fd\' && ! echo "$out" | grep -q \'^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') ] ) # Values that reach the JSON output from outside ipcalc (here a host # name) must be escaped. The test needs jq, and fails when it is missing # rather than being skipped (REQ-GEN-TEST-007). if host_machine.system() == 'linux' fake_getnameinfo = shared_module('fake-getnameinfo', 'fake-getnameinfo.c') test('JsonEscapeHostname', testrunner, args : [ '--test-success', '{ command -v jq >/dev/null || { echo "jq: not found"; exit 1; }; } && ASAN_OPTIONS="$ASAN_OPTIONS:verify_asan_link_order=0" LD_PRELOAD=' + fake_getnameinfo.full_path() + ' ' + ipcalc.full_path() + ' -j -h 127.0.0.1 | jq -e \'.HOSTNAME == "a\\"b\\\\c\\td"\'' ], depends : fake_getnameinfo ) # NAME=value output must stay usable with eval for a name from DNS foreach c : [ ['ShellEscapeHostname', '--format=shell -h 127.0.0.1'], ['ShellEscapeHostnameDefault', '-h 127.0.0.1'], ] test(c[0], testrunner, args : [ '--test-success', 'out=$(ASAN_OPTIONS="$ASAN_OPTIONS:verify_asan_link_order=0" LD_PRELOAD=' + fake_getnameinfo.full_path() + ' ' + ipcalc.full_path() + ' ' + c[1] + ') && eval "$out" && [ "$HOSTNAME" = "$(printf \'a"b\\\\c\\td\')" ]' ], depends : fake_getnameinfo ) endforeach # values-only output prints the name verbatim, as released foreach c : [ ['NoDecorateHostnameVerbatim', '--no-decorate -h 127.0.0.1'], ['FormatValueHostnameVerbatim', '--format=value -h 127.0.0.1'], ] cmd = 'ASAN_OPTIONS="$ASAN_OPTIONS:verify_asan_link_order=0" LD_PRELOAD=' + fake_getnameinfo.full_path() + ' ' + ipcalc.full_path() + ' ' + c[1] test(c[0], testrunner, args : ['--test-status', '0', cmd, '--test-output', cmd, 'a"b\\c\td'], depends : fake_getnameinfo ) endforeach # deprecated options suggest --format on a terminal: [name, arguments, hint] fake_isatty = shared_module('fake-isatty', 'fake-isatty.c') foreach c : [ ['HintJson', '-j 10.0.0.1/24', 'ipcalc: hint: -j is deprecated; use --format=json'], ['HintJsonFields', '-j -m 10.0.0.1/24', 'ipcalc: hint: -j is deprecated; use --format=json, which prints only the selected fields'], ['HintJsonEquals', '-j 10.0.0.0/8 --equals=10.0.0.0/8', 'ipcalc: hint: -j is deprecated; use -s to print no result'], ['HintNoDecorateFields', '--no-decorate -m 10.0.0.1/24', 'ipcalc: hint: --no-decorate is deprecated; use --format=value'], ['HintNoDecorateSplit', '--no-decorate -S 26 10.0.0.0/24', 'ipcalc: hint: --no-decorate is deprecated; use --format=value'], ['HintNoDecorateSummary', '--no-decorate 10.0.0.1/24', 'ipcalc: hint: --no-decorate is deprecated; use --format=human'], ['NoHintFormat', '--format=json -m 10.0.0.1/24', ''], ['NoHintFields', '-m -n 10.0.0.1/24', ''], ['NoHintFormatValueSplit', '--format=value -S 26 10.0.0.0/24', ''], ['NoHintSilent', '-s -j 10.0.0.1/24', ''], ] cmd = 'ASAN_OPTIONS="$ASAN_OPTIONS:verify_asan_link_order=0" LD_PRELOAD=' + fake_isatty.full_path() + ' ' + ipcalc.full_path() + ' ' + c[1] + ' >/dev/null' test(c[0], testrunner, args : ['--test-status', '0', cmd, '--test-output', cmd, c[2]], depends : fake_isatty ) endforeach # -h rejects a network before looking up its name fail_getnameinfo = shared_module('fail-getnameinfo', 'fail-getnameinfo.c') cmd = 'ASAN_OPTIONS="$ASAN_OPTIONS:verify_asan_link_order=0" LD_PRELOAD=' + fail_getnameinfo.full_path() + ' ' + ipcalc.full_path() + ' -h 127.0.0.1/8' test('HostnameNetworkNoLookup', testrunner, args : ['--test-status', '1', cmd, '--test-output', cmd, 'ipcalc: -h requires a single address, not a network: 127.0.0.1/8'], depends : fail_getnameinfo ) # --all-info does not look up the hostname test('AllInfoNoLookup', testrunner, args : ['--test-success', 'out=$(ASAN_OPTIONS="$ASAN_OPTIONS:verify_asan_link_order=0" LD_PRELOAD=' + fake_getnameinfo.full_path() + ' ' + ipcalc.full_path() + ' -j --all-info 127.0.0.1) && ! echo "$out" | grep -q HOSTNAME'], depends : fake_getnameinfo ) endif 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') ] ) test('SplitPrefix0IPv4', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 0 0.0.0.0/0', files('split-0.0.0.0-0-0') ] ) test('SplitPrefix3Of1', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 3 10.0.0.0/1', files('split-10.0.0.0-1-3') ] ) test('SplitPrefix2Of0IPv6', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 2 ::/0', files('split-::-0-2') ] ) test('SplitPrefix124EndOfSpace', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 124 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/120', files('split-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-120-124') ] ) # --split tests with subnets of different sizes (VLSM) test('SplitVLSMPrefix58And64', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 1:58 -S 64 2001:db8:1c88:6000::/56', files('split-2001:db8:1c88:6000::-56-1:58-64') ] ) test('NoDecorateSplitVLSMPrefix58And64', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --no-decorate -S 1:58 -S 64 2001:db8:1c88:6000::/56', files('nsplit-2001:db8:1c88:6000::-56-1:58-64') ] ) test('JsonSplitVLSMPrefix58And64', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -j -S 1:58 -S 64 2001:db8:1c88:6000::/56', files('json-split-2001:db8:1c88:6000::-56-1:58-64') ] ) test('SplitVLSMUnused', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 1:28 -S 2:27 192.168.0.0/24', files('split-192.168.0.0-24-1:28-2:27') ] ) test('NoDecorateSplitVLSMUnused', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --no-decorate -S 1:28 -S 2:27 192.168.0.0/24', files('nsplit-192.168.0.0-24-1:28-2:27') ] ) test('JsonSplitVLSMUnused', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -j -S 1:28 -S 2:27 192.168.0.0/24', files('json-split-192.168.0.0-24-1:28-2:27') ] ) test('SplitVLSMFillAligned', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 3:64 -S 60 2001:db8::/56', files('split-2001:db8::-56-3:64-60') ] ) test('SplitVLSMSamePrefix', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 2:26 -S 26 192.168.1.0/24', files('split-192.168.1.0-24-2:26-26') ] ) test('SplitVLSMNetmask', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 2:255.255.255.192 192.168.1.0/24', files('split-192.168.1.0-24-2:255.255.255.192') ] ) test('SplitVLSMWholeSpace', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -S 2 -S 1:1 ::/0', files('split-::-0-2-1:1') ] ) test('SplitVLSMTooSmall', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S 1:25 -S 1:25 -S 1:26 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' -S 1:25 -S 1:25 -S 1:26 192.168.0.0/24', 'ipcalc: 192.168.0.0/24 is too small for the requested subnets' ] ) test('SplitVLSMNoSpaceForFill', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S 2:25 -S 26 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' -S 2:25 -S 26 192.168.0.0/24', 'ipcalc: 192.168.0.0/24 is too small for the requested subnets' ] ) test('SplitVLSMTwoFills', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S 26 -S 27 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' -S 26 -S 27 192.168.0.0/24', 'ipcalc: only one split prefix may be given without a count' ] ) test('SplitVLSMZeroCount', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S 0:26 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' -S 0:26 192.168.0.0/24', 'ipcalc: bad split count: 0:26' ] ) test('SplitVLSMBadCount', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S x:26 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' -S x:26 192.168.0.0/24', 'ipcalc: bad split count: x:26' ] ) test('SplitVLSMCountOverflow', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S 99999999999999999999:26 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' -S 99999999999999999999:26 192.168.0.0/24', 'ipcalc: bad split count: 99999999999999999999:26' ] ) test('SplitVLSMBadPrefix', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S 1:abc 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' -S 1:abc 192.168.0.0/24', 'ipcalc: bad IPv4 prefix: 1:abc' ] ) # --split-hosts tests test('SplitHosts', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --split-hosts=10,20,30 192.168.0.0/24', files('split-hosts-192.168.0.0-24-10,20,30') ] ) test('NoDecorateSplitHosts', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --no-decorate --split-hosts=10,20,30 192.168.0.0/24', files('nsplit-hosts-192.168.0.0-24-10,20,30') ] ) test('JsonSplitHosts', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -j --split-hosts=10,20,30 192.168.0.0/24', files('json-split-hosts-192.168.0.0-24-10,20,30') ] ) test('SplitHostsSmallest', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --split-hosts=1,2,62,63 192.168.0.0/24', files('split-hosts-192.168.0.0-24-1,2,62,63') ] ) test('SplitHostsRepeated', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --split-hosts=1,2 --split-hosts=62,63 192.168.0.0/24', files('split-hosts-192.168.0.0-24-1,2,62,63') ] ) test('SplitHostsExactFit', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --no-decorate --split-hosts=126,62,62 192.168.0.0/24', files('nsplit-hosts-192.168.0.0-24-126,62,62') ] ) test('SplitHostsIPv6', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --split-hosts=1,2,3,256 2001:db8::/112', files('split-hosts-2001:db8::-112-1,2,3,256') ] ) test('JsonSplitHostsWholeIPv4', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -j --split-hosts=4294967294 0.0.0.0/0', files('json-split-hosts-0.0.0.0-0-4294967294') ] ) test('SplitHostsTooSmall', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --split-hosts=200,100 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' --split-hosts=200,100 192.168.0.0/24', 'ipcalc: 192.168.0.0/24 is too small for the requested subnets' ] ) test('SplitHostsLargerThanNetwork', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --split-hosts=300 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' --split-hosts=300 192.168.0.0/24', 'ipcalc: 192.168.0.0/24 is too small for the requested subnets' ] ) test('SplitHostsTooManyHosts', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --split-hosts=4294967295 0.0.0.0/0', '--test-output', ipcalc.full_path() + ' --split-hosts=4294967295 0.0.0.0/0', 'ipcalc: too many hosts requested: 4294967295' ] ) test('SplitHostsWithSplit', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --split-hosts=10 -S 26 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' --split-hosts=10 -S 26 192.168.0.0/24', 'ipcalc: --split-hosts cannot be combined with --split' ] ) test('SplitHostsZero', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --split-hosts=0 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' --split-hosts=0 192.168.0.0/24', 'ipcalc: bad host count: 0' ] ) test('SplitHostsEmptyItem', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --split-hosts=1,,2 192.168.0.0/24', '--test-output', ipcalc.full_path() + ' --split-hosts=1,,2 192.168.0.0/24', 'ipcalc: bad host count: 1,,2' ] ) test('SplitHostsOverflow', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --split-hosts=18446744073709551616 2001:db8::/64', '--test-output', ipcalc.full_path() + ' --split-hosts=18446744073709551616 2001:db8::/64', 'ipcalc: bad host count: 18446744073709551616' ] ) # --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('TestHumanReadableThisNetwork', 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('TestHumanReadableThisHostOnThisNetwork', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 0.0.0.0', files('i-0.0.0.0') ] ) test('TestHumanReadable6a44Relay', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 192.88.99.2', files('i-192.88.99.2') ] ) test('AddrspaceIPv4LargerThanBlock', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addrspace 192.168.0.0/8', 'ADDRSPACE=Internet' ] ) test('AddrspaceIPv4LargerThanPrivateBlock', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addrspace 10.0.0.0/7', 'ADDRSPACE=Internet' ] ) test('AddrspaceIPv4LargerThanThisNetwork', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addrspace 0.0.0.0/7', 'ADDRSPACE=Internet' ] ) test('TestHumanReadableDiscardOnly', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 100::1', files('i-100::1') ] ) test('AddrspaceNotDiscardOnly', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addrspace 1000::1', 'ADDRSPACE=Reserved' ] ) test('TestHumanReadableDummyIPv6Prefix', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 100:0:0:1::5', files('i-100:0:0:1::5') ] ) test('TestHumanReadableDNSSDSRPAnycast', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 2001:1::3', files('i-2001:1::3') ] ) test('TestHumanReadableDRIPDET', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 2001:30::1', files('i-2001:30::1') ] ) test('TestHumanReadableDocumentation3fff', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 3fff::1', files('i-3fff::1') ] ) test('TestHumanReadableSRv6SIDs', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i 5f00::1', files('i-5f00::1') ] ) test('AddrspaceIPv6LargerThanBlock', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addrspace 2002::/15', 'ADDRSPACE="Global Unicast"' ] ) 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' ] ) # -g/--geoinfo exist only with a geo backend if have_geo test('GeoInfoAccepted', testrunner, args : [ '--test-success', ipcalc.full_path() + ' -g 127.0.0.1' ] ) # ipcalc-geo reads databases generated from geo-*.json instead of the # system ones, whose contents vary python = import('python').find_installation() geo_dbs = [] foreach db : ['country', 'city', 'asn'] geo_dbs += custom_target('geo-' + db + '.mmdb', input : ['mkmmdb.py', 'geo-' + db + '.json'], output : 'geo-' + db + '.mmdb', command : [python, '@INPUT@', '@OUTPUT@'], build_by_default : true ) endforeach ipcalc_geo = executable('ipcalc-geo', sources : src, c_args : args + [ '-DMAXMINDDB_LOCATION_COUNTRY="' + geo_dbs[0].full_path() + '"', '-DMAXMINDDB_LOCATION_CITY="' + geo_dbs[1].full_path() + '"', '-DMAXMINDDB_LOCATION_ASN="' + geo_dbs[2].full_path() + '"' ], dependencies : deps ) # [name, arguments, expected output] foreach c : [ ['GeoInfoIPv4', '-g 192.0.2.5', 'geo-192.0.2.5'], ['GeoInfoIPv6', '-g 2001:db8::1', 'geo-2001:db8::1'], ['GeoInfoNoCountry', '-g 198.51.100.200', 'geo-198.51.100.200'], ['GeoInfoRegisteredCountry', '-g 198.51.100.5', 'geo-198.51.100.5'], ['GeoInfoRepresentedCountry', '-g 198.51.100.130', 'geo-198.51.100.130'], ['GeoInfoASNOnly', '-g 203.0.113.1', 'geo-203.0.113.1'], ['GeoInfoAllInfo', '--all-info 192.0.2.5', 'geo-all-info-192.0.2.5'], ['GeoInfoNotFound', '--all-info 10.0.0.1', 'geo-all-info-10.0.0.1'], ['GeoInfoJson', '--format=json -g 2001:db8::1', 'geo-json-2001:db8::1'], ['GeoInfoNetworkWithinRecords', '-g 192.0.2.0/24', 'geo-192.0.2.0-24'], ['GeoInfoNetworkLargerThanCity', '-g 192.0.2.77/23', 'geo-192.0.2.77-23'], ['GeoInfoNetworkLargerThanCityIPv6', '-g 2001:db8::/32', 'geo-2001:db8::-32'], ['GeoInfoNetworkLargerThanRecords', '--all-info 192.0.0.0/16', 'geo-all-info-192.0.0.0-16'], ] test(c[0], testrunner, args : ['--test-outfile', ipcalc_geo.full_path() + ' ' + c[1], files(c[2])], depends : geo_dbs ) endforeach # ipcalc-nolib cannot load libmaxminddb at run time if dl.found() nolib_args = ['-DLIBPATH="/nonexistent"'] foreach a : args if not a.startswith('-DLIBPATH=') nolib_args += a endif endforeach ipcalc_nolib = executable('ipcalc-nolib', sources : src, c_args : nolib_args, dependencies : deps ) test('GeoLibraryMissing', testrunner, args : ['--test-outfile', ipcalc_nolib.full_path() + ' -g 192.0.2.5', files('geo-nolib-192.0.2.5')]) test('GeoLibraryMissingAllInfo', testrunner, args : ['--test-outfile', ipcalc_nolib.full_path() + ' --all-info 192.0.2.5', files('geo-nolib-all-info-192.0.2.5')]) test('GeoLibraryMissingSilent', testrunner, args : ['--test-success', '[ -z "$(' + ipcalc_nolib.full_path() + ' -s -g 192.0.2.5 2>&1)" ]']) endif else test('GeoInfoShortUnavailable', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -g 127.0.0.1' ] ) test('GeoInfoLongUnavailable', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --geoinfo 127.0.0.1' ] ) test('GeoInfoNotInUsage', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --usage 2>&1 | grep -e -g -e geoinfo' ] ) endif test('TestShortHelpCommand', testrunner, args : [ '--test-success', ipcalc.full_path() + ' -?' ] ) test('UnknownLongOption', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' --bogus 1.2.3.4' ] ) test('UnknownShortOption', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -y 1.2.3.4' ] ) test('MissingOptionArgument', testrunner, args : [ '--test-failure', ipcalc.full_path() + ' -S' ] ) # --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('CalculateNetmaskPrefix1', testrunner, args : [ '--test-output', ipcalc.full_path() + ' -m 10.0.0.0/1', 'NETMASK=128.0.0.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' ] ) test('AddressesPrefix0IPv4', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addresses 0.0.0.0/0', 'ADDRESSES=4294967294' ] ) test('AddressesPrefix1IPv4', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addresses 10.0.0.0/1', 'ADDRESSES=2147483646' ] ) test('AddressesPrefix0IPv6', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addresses ::/0', 'ADDRESSES=340282366920938463463374607431768211456' ] ) # --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('LookupReverseDNSFromPrefix4IPv4', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns 193.92.150.3/4', 'REVERSEDNS=192-207.in-addr.arpa.' ] ) test('LookupReverseDNSFromPrefix0IPv4', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns 193.92.150.3/0', 'REVERSEDNS=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.' ] ) test('LookupReverseDNSFromPrefix0IPv6', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns ::/0', 'REVERSEDNS=ip6.arpa.' ] ) test('LookupReverseDNSFromPrefix31IPv6', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns 2001:db8::/31', 'REVERSEDNS="8.b.d.0.1.0.0.2.ip6.arpa. 9.b.d.0.1.0.0.2.ip6.arpa."' ] ) test('LookupReverseDNSFromPrefix33IPv6', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns 2001:db8:8000::/33', 'REVERSEDNS="8.8.b.d.0.1.0.0.2.ip6.arpa. 9.8.b.d.0.1.0.0.2.ip6.arpa. a.8.b.d.0.1.0.0.2.ip6.arpa. b.8.b.d.0.1.0.0.2.ip6.arpa. c.8.b.d.0.1.0.0.2.ip6.arpa. d.8.b.d.0.1.0.0.2.ip6.arpa. e.8.b.d.0.1.0.0.2.ip6.arpa. f.8.b.d.0.1.0.0.2.ip6.arpa."' ] ) test('LookupReverseDNSFromPrefix34IPv6', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns 2001:db8:4000::/34', 'REVERSEDNS="4.8.b.d.0.1.0.0.2.ip6.arpa. 5.8.b.d.0.1.0.0.2.ip6.arpa. 6.8.b.d.0.1.0.0.2.ip6.arpa. 7.8.b.d.0.1.0.0.2.ip6.arpa."' ] ) test('LookupReverseDNSFromPrefix127IPv6', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns 1234::4321/127', 'REVERSEDNS="0.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. 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('LookupReverseDNSUnmaskedPrefix35IPv6', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --reverse-dns 2001:db8:3fff::1/35', 'REVERSEDNS="2.8.b.d.0.1.0.0.2.ip6.arpa. 3.8.b.d.0.1.0.0.2.ip6.arpa."' ] ) test('LookupReverseDNSNoDecoratePrefix37IPv6', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --reverse-dns --no-decorate 2001:db8:abcd::/37', files('reverse-dns-no-decorate-2001:db8:abcd::-37') ] ) test('AllInfoReverseDNSPrefix31IPv6', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info 2001:db8::/31', files('all-info-2001:db8::-31') ] ) test('JsonAllInfoReverseDNSPrefix31IPv6', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info --json 2001:db8::/31', files('json-all-info-2001:db8::-31') ] ) test('JsonAllInfoReverseDNSPrefix32IPv6', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info --json 2001:db8::/32', files('json-all-info-2001:db8::-32') ] ) test('JsonAllInfoReverseDNSPrefix24IPv4', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info --json 192.168.2.7/24', files('json-all-info-192.168.2.7-24') ] ) # 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') ] ) test('SpecificInfoOutputNoDecorateQuotedAddrspace', testrunner, args : [ '--test-output', ipcalc.full_path() + ' --addrspace --no-decorate 10.0.0.1', '"Private Use"' ] ) # --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('AllInfoClassDLowest', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info 224.0.0.1', files('all-info-224.0.0.1') ] ) test('AllInfoClassDHighestOctet', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info 239.1.1.1', files('all-info-239.1.1.1') ] ) test('AllInfoClassE', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info 240.0.0.1', files('all-info-240.0.0.1') ] ) test('AllInfoIIDLinkLocalUniversal', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info fe80::21b:21ff:fe3a:5c7d/64', files('all-info-fe80::21b:21ff:fe3a:5c7d-64') ] ) test('JsonAllInfoIIDLinkLocalUniversal', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info --json fe80::21b:21ff:fe3a:5c7d/64', files('json-all-info-fe80::21b:21ff:fe3a:5c7d-64') ] ) test('NoDecorateAllInfoIIDLinkLocalUniversal', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info --no-decorate fe80::21b:21ff:fe3a:5c7d/64', files('no-decorate-all-info-fe80::21b:21ff:fe3a:5c7d-64') ] ) test('AllInfoIIDLinkLocalLocal', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info fe80::ff:fe00:1', files('all-info-fe80::ff:fe00:1') ] ) test('AllInfoIIDGroup', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info 2001:db8::300:ff:fe00:1', files('all-info-2001:db8::300:ff:fe00:1') ] ) test('AllInfoIIDNotEUI64', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info 2001:db8::f00d:1234:5678:9abc/64', files('all-info-2001:db8::f00d:1234:5678:9abc-64') ] ) test('AllInfoIIDNetwork', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info fe80::/64', files('all-info-fe80::-64') ] ) test('AllInfoIIDMapped', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info ::ffff:192.0.2.1', files('all-info-::ffff:192.0.2.1') ] ) test('AllInfoIIDMulticast', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' --all-info ff02::21b:21ff:fe3a:5c7d', files('all-info-ff02::21b:21ff:fe3a:5c7d') ] ) test('InfoIIDLinkLocal', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -i fe80::21b:21ff:fe3a:5c7d/64', files('i-fe80::21b:21ff:fe3a:5c7d-64') ] ) 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('DeaggregateLargeNum', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -d 240.0.0.0-255.255.255.255', files('deaggregate-240.0.0.0-255.255.255.255') ] ) test('DeaggregateLargeNum2', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -d 127.0.0.0-255.255.255.255', files('deaggregate-127.0.0.0-255.255.255.255') ] ) test('DeaggregateLargeNum3', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -d 0.0.0.0-255.255.255.255', files('deaggregate-0.0.0.0-255.255.255.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('DeaggregateIPv6All', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -d ::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', files('deaggregate-::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff') ] ) test('DeaggregateIPv6UpperHalf', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -d 8000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', files('deaggregate-8000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff') ] ) test('DeaggregateIPv6LastAddress', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -d ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', files('deaggregate-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff') ] ) test('DeaggregateIPv6LowerHalf', testrunner, args : [ '--test-outfile', ipcalc.full_path() + ' -d ::-8000::', files('deaggregate-::-8000::') ] ) 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()] ) # Compare --split-hosts with the Debian ipcalc (REQ-SPLIT-COMPAT-001); the # Debian script is only in the git tree, not in release tarballs. The tests # need perl and fail when it is missing (REQ-GEN-TEST-007). if import('fs').exists('debian-ipcalc/ipcalc') debian_split_hosts = find_program('ipcalc-debian-split-hosts.sh') foreach c : [ ['192.168.0.0/24', '10,20,30'], ['192.168.0.0/24', '1,2,62,63'], ['192.168.0.0/24', '126,62,62'], ['192.168.0.0/24', '5,5,5'], ['192.168.0.0/24', '30,30,30,30,30,30,30,30'], ['192.168.5.45/24', '10,20'], ['192.168.1.0/24', '254'], ['10.0.0.0/30', '2'], ['172.16.0.0/12', '1'], ['10.0.0.0/8', '1000,5,5,70000,300,2'], ['10.0.0.0/16', '2000,1000,500,250,120,60,30,14,6,2,1'], ['10.20.30.0/23', '100,100,50,3,3,1'], ] test('DebianSplitHosts-' + c[0].replace('/', '-') + '-' + c[1], debian_split_hosts, args : c, env : ['IPCALC=' + ipcalc.full_path(), 'DEBIAN_IPCALC=' + meson.current_source_dir() / 'debian-ipcalc' / 'ipcalc'] ) endforeach endif # Network comparison: [name, expected exit status, arguments, expected # output]. The output of errors (status 2) is not compared. foreach c : [ ['EqualsHostBits', '0', '192.168.7.15/24 --equals=192.168.7.5/24', 'The networks are equal'], ['EqualsNetmask', '0', '192.168.7.15 255.255.255.0 --equals=192.168.7.5/255.255.255.0', 'The networks are equal'], ['EqualsClassPrefix', '0', '--class-prefix 10.0.0.0/8 --equals=10.9.9.9', 'The networks are equal'], ['EqualsJson', '0', '-j 192.168.7.15/24 --equals=192.168.7.5/24', ''], ['EqualsNoDecorate', '1', '--no-decorate 192.168.7.15/24 --equals=192.168.7.5/25', ''], ['SubnetOfNoDecorate', '0', '--no-decorate 192.168.0.1/24 --subnet-of=192.168.1.15/23', ''], ['OverlapsSilent', '1', '-s 10.0.0.0/8 --overlaps=::/0', ''], ['EqualsHost32', '0', '192.168.1.15 --equals=192.168.1.15/32', 'The networks are equal'], ['EqualsHostBitsIPv6', '0', '2001:db8::1/64 --equals=2001:db8::ffff/64', 'The networks are equal'], ['EqualsPrefix0', '0', '1.2.3.4/0 --equals=0.0.0.0/0', 'The networks are equal'], ['EqualsDifferentPrefix', '1', '192.168.0.0/24 --equals=192.168.0.0/23', 'The networks are not equal'], ['EqualsDisjoint', '1', '192.168.1.15/24 --equals=192.168.7.1/24', 'The networks are not equal'], ['EqualsDifferentPrefixIPv6', '1', '2001:db8::/64 --equals=2001:db8::/65', 'The networks are not equal'], ['SubnetOf', '0', '192.168.0.1/24 --subnet-of=192.168.1.15/23', '192.168.0.0/24 is a subnet of 192.168.0.0/23'], ['SubnetOfEqual', '0', '10.0.0.0/8 --subnet-of=10.0.0.0/8', '10.0.0.0/8 is a subnet of 10.0.0.0/8'], ['SubnetOfPartialByte', '0', '10.64.0.0/10 --subnet-of=10.0.0.0/9', '10.64.0.0/10 is a subnet of 10.0.0.0/9'], ['SubnetOfPrefix0', '0', '10.1.2.3 --subnet-of=0.0.0.0/0', '10.1.2.3/32 is a subnet of 0.0.0.0/0'], ['SubnetOfIPv6', '0', '2001:db8:1::/48 --subnet-of=2001:db8::/32', '2001:db8:1::/48 is a subnet of 2001:db8::/32'], ['SubnetOfPrefix0IPv6', '0', '::1 --subnet-of=::/0', '::1/128 is a subnet of ::/0'], ['SubnetOfSupernet', '1', '192.168.1.15/23 --subnet-of=192.168.0.1/24', '192.168.0.0/23 is not a subnet of 192.168.0.0/24'], ['SubnetOfSiblingPartialByte', '1', '10.128.0.0/10 --subnet-of=10.0.0.0/9', '10.128.0.0/10 is not a subnet of 10.0.0.0/9'], ['SubnetOfPrefix0Supernet', '1', '0.0.0.0/0 --subnet-of=0.0.0.0/1', '0.0.0.0/0 is not a subnet of 0.0.0.0/1'], ['SubnetOfSupernetIPv6', '1', '2001:db8::/32 --subnet-of=2001:db8:1::/48', '2001:db8::/32 is not a subnet of 2001:db8:1::/48'], ['OverlapsSupernet', '0', '192.168.1.15/23 --overlaps=192.168.0.1/24', 'The networks overlap'], ['OverlapsSubnet', '0', '192.168.0.1/24 --overlaps=192.168.1.15/23', 'The networks overlap'], ['OverlapsHost', '0', '10.0.0.1 --overlaps=10.0.0.1', 'The networks overlap'], ['OverlapsPrefix0IPv6', '0', '::/0 --overlaps=2001:db8::1', 'The networks overlap'], ['OverlapsDisjoint', '1', '192.168.1.15/24 --overlaps=192.168.7.1/24', 'The networks do not overlap'], ['OverlapsAdjacent', '1', '192.168.0.0/24 --overlaps=192.168.1.0/24', 'The networks do not overlap'], ['OverlapsAdjacentIPv6', '1', '2001:db8::/33 --overlaps=2001:db8:8000::/33', 'The networks do not overlap'], ['OverlapsMixedFamily', '1', '10.0.0.0/8 --overlaps=::/0', 'The networks do not overlap'], ['EqualsMappedIPv4', '1', '::ffff:10.0.0.1 --equals=10.0.0.1', 'The networks are not equal'], ['EqualsBadAddress', '2', '10.0.0.0/8 --equals=1.2.3', ''], ['SubnetOfBadPrefixIPv6', '2', '::/0 --subnet-of=::/129', ''], ['OverlapsBadNetmask', '2', '10.0.0.0/8 --overlaps=10.0.0.0/255.0.255.0', ''], ['OverlapsForcedFamily', '2', '-4 10.0.0.0/8 --overlaps=::/0', ''], ['EqualsBadInputAddress', '2', '1.2.3 --equals=1.2.3.0/24', ''], ['Equals-Overlaps', '2', '10.0.0.0/8 --equals=10.0.0.0/8 --overlaps=10.0.0.0/8', ''], ['Equals-Equals', '2', '10.0.0.0/8 --equals=10.0.0.0/8 --equals=10.0.0.0/8', ''], ['Equals-Info', '2', '--equals=10.0.0.0/8 -n 10.0.0.0/8', ''], ['Check-Equals', '2', '-c 10.0.0.0/8 --equals=10.0.0.0/8', ''], ['Equals-IPv4-IPv6', '2', '-4 -6 10.0.0.0/8 --equals=10.0.0.0/8', ''], ['Overlaps-UnknownOption', '2', '10.0.0.0/8 --overlaps=10.0.0.0/8 --bogus', ''], ['UnknownOption-Overlaps', '2', '--bogus 10.0.0.0/8 --overlaps=10.0.0.0/8', ''], ['EqualsMissingArgument', '2', '10.0.0.0/8 --equals', ''], ['SubnetOfNoAddress', '2', '--subnet-of=10.0.0.0/8', ''], ] cmd = ipcalc.full_path() + ' ' + c[2] args = ['--test-status', c[1], cmd] if c[1] != '2' args += ['--test-output', cmd, c[3]] endif test(c[0], testrunner, args : args) endforeach # Without a comparison option, errors keep exit status 1 test('UnknownOptionStatus', testrunner, args : [ '--test-status', '1', ipcalc.full_path() + ' --bogus 1.2.3.4' ] ) # --cidr: [name, arguments, expected output] foreach c : [ ['CidrIPv4', '--cidr 192.168.123.7/24', 'CIDR=192.168.123.0/24'], ['CidrNoDecorateIPv6', '--cidr --no-decorate 2001:db8::1/64', '2001:db8::/64'], ['CidrSingleHost', '--cidr 192.168.1.1', 'CIDR=192.168.1.1/32'], ['CidrSingleHostIPv6', '--cidr ::1', 'CIDR=::1/128'], ['CidrFieldOrder', '-n --cidr -p 10.1.2.3/8', 'NETWORK=10.0.0.0\nPREFIX=8\nCIDR=10.0.0.0/8'], ] cmd = ipcalc.full_path() + ' ' + c[1] test(c[0], testrunner, args : ['--test-status', '0', cmd, '--test-output', cmd, c[2]]) endforeach test('RandomCidr', testrunner, args : ['--test-success', ipcalc.full_path() + ' -r 24 --cidr --no-decorate']) # --wildcard: [name, arguments, expected output] foreach c : [ ['WildcardIPv4', '--wildcard 192.168.123.7/24', 'WILDCARD=0.0.0.255'], ['WildcardSingleHost', '--wildcard 192.168.1.1', 'WILDCARD=0.0.0.0'], ['WildcardPrefix0', '--wildcard 0.0.0.0/0', 'WILDCARD=255.255.255.255'], ['WildcardPrefix1', '--wildcard 10.0.0.1/1', 'WILDCARD=127.255.255.255'], ['WildcardPrefix8', '--wildcard 10.0.0.1/8', 'WILDCARD=0.255.255.255'], ['WildcardPrefix12', '--wildcard 172.16.5.4/12', 'WILDCARD=0.15.255.255'], ['WildcardPrefix16', '--wildcard 172.16.5.4/16', 'WILDCARD=0.0.255.255'], ['WildcardPrefix25', '--wildcard 192.168.1.130/25', 'WILDCARD=0.0.0.127'], ['WildcardPrefix27', '--wildcard 192.168.1.130/27', 'WILDCARD=0.0.0.31'], ['WildcardPrefix31', '--wildcard 192.168.1.130/31', 'WILDCARD=0.0.0.1'], ['WildcardNetmask', '--wildcard 10.1.2.3/255.255.255.252', 'WILDCARD=0.0.0.3'], ['WildcardNoDecorate', '--wildcard --no-decorate 172.16.5.4/12', '0.15.255.255'], ['WildcardIPv6', '--wildcard 2001:db8::1/64', ''], ['WildcardPrefix0IPv6', '--wildcard ::/0', ''], ['WildcardFieldOrder', '--wildcard -m -n 10.1.2.3/255.255.240.0', 'NETWORK=10.1.0.0\nNETMASK=255.255.240.0\nWILDCARD=0.0.15.255'], ] cmd = ipcalc.full_path() + ' ' + c[1] test(c[0], testrunner, args : ['--test-status', '0', cmd, '--test-output', cmd, c[2]]) endforeach test('InfoWildcard', testrunner, args : ['--test-outfile', ipcalc.full_path() + ' -i --wildcard 192.168.2.7/24', files('info-wildcard-192.168.2.7-24')]) test('JsonWildcard', testrunner, args : ['--test-outfile', ipcalc.full_path() + ' -j --wildcard 192.168.2.7/24', files('json-wildcard-192.168.2.7-24')]) test('InfoWildcardIPv6', testrunner, args : ['--test-outfile', ipcalc.full_path() + ' -i --wildcard 2001:db8::/32', files('info-wildcard-2001:db8::-32')]) test('RandomWildcard', testrunner, args : ['--test-success', ipcalc.full_path() + ' -r 24 --wildcard --no-decorate']) # one field order for the summary and NAME=value output foreach c : [ ['FieldOrderNetworkNetmask', '-m -n 10.1.2.3/8', 'NETWORK=10.0.0.0\nNETMASK=255.0.0.0'], ['AddressAndLookupHost', '-a -o localhost -4', 'ADDRESS=127.0.0.1'], ['HostnameHostPrefix', '-h 127.0.0.1/32', 'HOSTNAME=localhost'], ] cmd = ipcalc.full_path() + ' ' + c[1] test(c[0], testrunner, args : ['--test-status', '0', cmd, '--test-output', cmd, c[2]]) endforeach test('InfoReverseDNS', testrunner, args : ['--test-outfile', ipcalc.full_path() + ' -i --reverse-dns 192.168.2.7/24', files('info-reverse-dns-192.168.2.7-24')]) test('JsonReverseDNS', testrunner, args : ['--test-outfile', ipcalc.full_path() + ' -j --reverse-dns 192.168.2.7/24', files('json-reverse-dns-192.168.2.7-24')]) # -h rejects a network: [name, arguments, expected output] foreach c : [ ['HostnameNetwork', '-h 127.0.0.1/8', 'ipcalc: -h requires a single address, not a network: 127.0.0.1/8'], ['HostnameNetworkJson', '-j -h 127.0.0.1/8', 'ipcalc: -h requires a single address, not a network: 127.0.0.1/8'], ['HostnameNetworkIPv6', '-h ::1/64', 'ipcalc: -h requires a single address, not a network: ::1/64'], ['HostnameNetworkSilent', '-s -h 127.0.0.1/8', ''], ['HostnameNetworkFormatJson', '--format=json -h 127.0.0.1/8', 'ipcalc: -h requires a single address, not a network: 127.0.0.1/8'], ] cmd = ipcalc.full_path() + ' ' + c[1] test(c[0], testrunner, args : ['--test-status', '1', cmd, '--test-output', cmd, c[2]]) endforeach # -i stays within 15 lines of at most 80 columns: [name, input] foreach c : [ ['InfoSummarySizeIPv6', 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/1'], ['InfoSummarySizeIPv4', '255.255.255.255/1'], ] test(c[0], testrunner, args : ['--test-success', 'out=$(' + ipcalc.full_path() + ' -i ' + c[1] + ') && [ "$(echo "$out" | wc -l)" -le 15 ] && ! echo "$out" | expand | grep -q \'.\{81\}\'']) endforeach # --all-info has every key the field-selecting options add, except # -h and -o, which need DNS, and -g, which needs a geo database all_fields = ' -j -a -b -m -n -p --cidr --wildcard --reverse-dns --addrspace --minaddr --maxaddr --addresses ' foreach c : [ ['AllInfoJsonKeysIPv4', '192.168.2.7/24'], ['AllInfoJsonKeysIPv6', 'fe80::21b:21ff:fe3a:5c7d/64'], ] test(c[0], testrunner, args : ['--test-success', 'all=$(' + ipcalc.full_path() + ' -j --all-info ' + c[1] + ' | grep -o \'"[A-Z0-9]*":\') && ' + 'sel=$(' + ipcalc.full_path() + all_fields + c[1] + ' | grep -o \'"[A-Z0-9]*":\') && ' + 'for k in $sel; do echo "$all" | grep -qxF "$k" || { echo "missing $k"; exit 1; }; done']) endforeach # --format selects the output format: [name, arguments, expected output] foreach c : [ ['FormatJsonFields', '--format=json -m -n 192.168.2.7/24', '{\n "NETWORK":"192.168.2.0",\n "NETMASK":"255.255.255.0"\n}'], ['FormatHumanFields', '--format=human -m -n 192.168.2.7/24', 'Network:\t192.168.2.0/24\nNetmask:\t255.255.255.0 = 24'], ['FormatJsonReverseDNS', '--format=json --reverse-dns 2001:db8::/31', '{\n "REVERSEDNS":[\n "8.b.d.0.1.0.0.2.ip6.arpa.",\n "9.b.d.0.1.0.0.2.ip6.arpa."]\n}'], ['FormatJsonHostname', '--format=json -h 127.0.0.1', '{\n "HOSTNAME":"localhost"\n}'], ['FormatJsonLookupHost', '--format=json -4 -o localhost', '{\n "ADDRESS":"127.0.0.1"\n}'], ['FormatJsonWithJ', '-j --format=json -n 10.1.2.3/8', '{\n "NETWORK":"10.0.0.0"\n}'], ['FormatValueWithNoDecorate', '--no-decorate --format=value -n 10.1.2.3/8', '10.0.0.0'], ['FormatHumanEquals', '--format=human 192.168.7.15/24 --equals=192.168.7.5/24', 'The networks are equal'], ['FormatCheck', '-c --format=shell 127.0.0.1', ''], ] cmd = ipcalc.full_path() + ' ' + c[1] test(c[0], testrunner, args : ['--test-status', '0', cmd, '--test-output', cmd, c[2]]) endforeach # --format with the output of existing tests: [name, arguments, file] foreach c : [ ['FormatHumanSummary', '--format=human 192.168.2.0/24', 'standard-192.168.2.0-24'], ['FormatJsonAllInfo', '--format=json --all-info 192.168.2.7/24', 'json-all-info-192.168.2.7-24'], ['FormatShellSummary', '--format=shell 192.168.2.7/24', 'shell-192.168.2.7-24'], ['FormatJsonInfoLookupHost', '--format=json -i -4 -o localhost', 'hostname-localhost-ipv4-json'], ['FormatValueSplit', '--format=value -S 26 192.168.5.45/24', 'nsplit-192.168.5.45-24-26'], ['FormatJsonSplit', '--format=json -S 26 192.168.5.45/24', 'json-split-192.168.5.45-24-26'], ['FormatHumanSplit', '--format=human -S 26 192.168.5.45/24', 'split-192.168.5.45-24-26'], ['FormatValueDeaggregate', '--format=value -d 192.168.2.7-192.168.2.13', 'deaggregate-192.168.2.7-192.168.2.13'], ] test(c[0], testrunner, args : ['--test-outfile', ipcalc.full_path() + ' ' + c[1], files(c[2])]) endforeach # --format prints what the legacy options print: [name, arguments, legacy arguments] foreach c : [ ['FormatShellFields', '--format=shell -m -n 10.1.2.3/8', '-m -n 10.1.2.3/8'], ['FormatValueFields', '--format=value -m -n 10.1.2.3/8', '--no-decorate -m -n 10.1.2.3/8'], ] test(c[0], testrunner, args : ['--test-equal', ipcalc.full_path() + ' ' + c[1], ipcalc.full_path() + ' ' + c[2]]) endforeach # --format rejects ambiguous combinations: [name, status, arguments, expected output] foreach c : [ ['FormatUnknown', '1', '--format=xml 10.0.0.1', 'ipcalc: unknown output format: xml; use human, shell, json or value'], ['FormatUnknownSilent', '1', '-s --format=xml 10.0.0.1', ''], ['FormatTwice', '1', '--format=json --format=shell 10.0.0.1', 'ipcalc: conflicting output formats: --format=json and --format=shell'], ['FormatConflictJson', '1', '-j --format=shell 10.0.0.1', 'ipcalc: conflicting output formats: -j and --format=shell'], ['FormatConflictNoDecorate', '1', '--no-decorate --format=json -m 10.0.0.1', 'ipcalc: conflicting output formats: --no-decorate and --format=json'], ['FormatInfoWithField', '1', '--format=json -i -m 10.0.0.1', 'ipcalc: -i and --all-info cannot be combined with specific field options'], ['FormatAllInfoWithField', '1', '--format=human --all-info -n 10.0.0.1/24', 'ipcalc: -i and --all-info cannot be combined with specific field options'], ['FormatValueSummary', '1', '--format=value 10.0.0.1/24', 'ipcalc: --format=value needs specific field options; use --format=shell or --format=json'], ['FormatShellSplit', '1', '--format=shell -S 26 10.0.0.0/24', 'ipcalc: --format=shell is not supported with --split, --split-hosts or --deaggregate; use --format=value'], ['FormatShellDeaggregate', '1', '--format=shell -d 10.0.0.1-10.0.0.9', 'ipcalc: --format=shell is not supported with --split, --split-hosts or --deaggregate; use --format=value'], ['FormatJsonEquals', '2', '--format=json 10.0.0.0/8 --equals=10.0.0.0/8', 'ipcalc: --format=json is not supported with --equals, --subnet-of or --overlaps'], ['FormatValueSubnetOf', '2', '--format=value 10.0.0.0/8 --subnet-of=10.0.0.0/7', 'ipcalc: --format=value is not supported with --equals, --subnet-of or --overlaps'], ['FormatShellOverlaps', '2', '--format=shell 10.0.0.0/8 --overlaps=10.0.0.0/7', 'ipcalc: --format=shell is not supported with --equals, --subnet-of or --overlaps'], ] cmd = ipcalc.full_path() + ' ' + c[2] test(c[0], testrunner, args : ['--test-status', c[1], cmd, '--test-output', cmd, c[3]]) endforeach # --binary diagram and JSON output: [name, arguments, expected-output file] foreach c : [ ['BitsAddress', '192.168.92.6', 'bits-192.168.92.6'], ['BitsHostBits', '192.168.92.6/22', 'bits-192.168.92.6-22'], ['BitsPrefix8', '10.0.0.0/8', 'bits-10.0.0.0-8'], ['BitsPrefix31', '192.168.1.4/31', 'bits-192.168.1.4-31'], ['BitsPrefix1', '128.0.0.0/1', 'bits-128.0.0.0-1'], ['BitsPrefix0', '0.0.0.0/0', 'bits-0.0.0.0-0'], ['BitsDetails', '192.168.92.6/24', 'bits-192.168.92.6-24'], ['BitsAddressHostMin', '192.168.92.1/24', 'bits-192.168.92.1-24'], ['BitsAddressBroadcast', '192.168.92.255/24', 'bits-192.168.92.255-24'], ['BitsAddressPrefix31', '192.168.1.5/31', 'bits-192.168.1.5-31'], ['BitsAddressIPv6', '2001:db8::1', 'bits-2001:db8::1'], ['BitsHostBitsIPv6', '2001:db8:abcd:12::1/56', 'bits-2001:db8:abcd:12::1-56'], ['BitsPrefix64IPv6', '2001:db8::/64', 'bits-2001:db8::-64'], ['BitsPrefix62IPv6', '2001:db8:abcd:10::/62', 'bits-2001:db8:abcd:10::-62'], ['BitsPrefix96IPv6', '2001:db8::/96', 'bits-2001:db8::-96'], ['BitsPrefix65IPv6', '2001:db8::/65', 'bits-2001:db8::-65'], ['BitsPrefix0IPv6', '::/0', 'bits-::-0'], ['BitsPrefix127IPv6', '2001:db8::/127', 'bits-2001:db8::-127'], ['BitsUniqueLocalIPv6', 'fd10:da05:b5ac::/48', 'bits-fd10:da05:b5ac::-48'], ['BitsLinkLocalIPv6', 'fe80::/64', 'bits-fe80::-64'], ['BitsLinkLocalPrefix10IPv6', 'fe80::/10', 'bits-fe80::-10'], ['BitsMulticastIPv6', 'ff02::/16', 'bits-ff02::-16'], ['BitsFormatHuman', '--format=human 192.168.92.6/22', 'bits-192.168.92.6-22'], ['BitsJson', '--format=json 192.168.92.0/22', 'bits-json-192.168.92.0-22'], ['BitsJsonIPv6', '--format=json 2001:db8::1', 'bits-json-2001:db8::1'], ['BitsJsonNetworkIPv6', '--format=json 2001:db8:abcd:12::1/56', 'bits-json-2001:db8:abcd:12::1-56'], ['BitsShell', '--format=shell 192.168.92.6/22', 'bits-shell-192.168.92.6-22'], ['BitsShellPrefix8', '--format=shell 10.0.0.0/8', 'bits-shell-10.0.0.0-8'], ['BitsShellPrefix31', '--format=shell 192.168.1.5/31', 'bits-shell-192.168.1.5-31'], ['BitsShellAddress', '--format=shell 192.168.92.6', 'bits-shell-192.168.92.6'], ['BitsShellIPv6', '--format=shell 2001:db8:abcd:12::1/56', 'bits-shell-2001:db8:abcd:12::1-56'], ['BitsShellAddressIPv6', '--format=shell 2001:db8::1', 'bits-shell-2001:db8::1'], ] test(c[0], testrunner, args : ['--test-outfile', ipcalc.full_path() + ' --binary ' + c[1], files(c[2])], env : ['COLUMNS=80']) endforeach # --binary diagram with the given COLUMNS: [name, COLUMNS, arguments, expected-output file] foreach c : [ ['BitsWideAddressIPv6', '135', '2001:db8::1', 'bits-wide-2001:db8::1'], ['BitsWideHostBitsIPv6', '135', '2001:db8:abcd:12::1/56', 'bits-wide-2001:db8:abcd:12::1-56'], ['BitsWidePrefix96IPv6', '200', '2001:db8::/96', 'bits-wide-2001:db8::-96'], ['BitsWidePrefix0IPv6', '135', '::/0', 'bits-wide-::-0'], ['BitsNarrowIPv6', '134', '2001:db8:abcd:12::1/56', 'bits-2001:db8:abcd:12::1-56'], ['BitsColumnsInvalid', 'abc', '2001:db8:abcd:12::1/56', 'bits-2001:db8:abcd:12::1-56'], ['BitsColumnsZero', '0', '2001:db8:abcd:12::1/56', 'bits-2001:db8:abcd:12::1-56'], ['BitsWideIPv4', '200', '192.168.92.6/22', 'bits-192.168.92.6-22'], ['BitsShellPrefix0IPv6', '200', '--format=shell ::/0', 'bits-shell-::-0'], ] test(c[0], testrunner, args : ['--test-outfile', 'COLUMNS=' + c[1] + ' ' + ipcalc.full_path() + ' --binary ' + c[2], files(c[3])]) endforeach # --binary value output: [name, arguments, expected output] foreach c : [ ['BitsAddressValue', '--format=value 192.168.92.6', '11000000101010000101110000000110'], ['BitsNetworkValue', '--format=value 192.168.92.6/22', '11000000101010000101110000000000'], ['BitsNetmaskValue', '--format=value 192.168.92.6 255.255.252.0', '11000000101010000101110000000000'], ['BitsClassPrefixValue', '--format=value --class-prefix 10.1.2.3', '00001010000000000000000000000000'], ['BitsPrefix0Value', '--format=value 0.0.0.0/0', '00000000000000000000000000000000'], ['BitsNetworkIPv6Value', '--format=value 2001:db8::/32', '00100000000000010000110110111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'], ['BitsAddressIPv6Value', '--format=value 2001:db8::1', '00100000000000010000110110111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'], ['BitsPrefix0IPv6Value', '--format=value ::/0', '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'], ] cmd = ipcalc.full_path() + ' --binary ' + c[1] test(c[0], testrunner, args : ['--test-status', '0', cmd, '--test-output', cmd, c[2]], env : ['COLUMNS=200']) endforeach # --binary invocations with the same output: [name, arguments, same output as] foreach c : [ ['BitsPrefix32Value', '--format=value 192.168.92.6/32', '--format=value 192.168.92.6'], ['BitsPrefix32', '192.168.92.6/32', '192.168.92.6'], ['BitsJsonLegacy', '-j 192.168.92.0/22', '--format=json 192.168.92.0/22'], ] test(c[0], testrunner, args : ['--test-equal', ipcalc.full_path() + ' --binary ' + c[1], ipcalc.full_path() + ' --binary ' + c[2]]) endforeach # --binary rejects --no-decorate: [name, arguments, expected output] foreach c : [ ['BitsNoDecorate', '--no-decorate 192.168.92.6/22', 'ipcalc: --no-decorate is not supported with --binary; use --format=value'], ['BitsJsonNoDecorate', '-j --no-decorate 192.168.92.0/22', 'ipcalc: --no-decorate is not supported with --binary; use --format=value'], ['BitsNoDecorateFormatValue', '--no-decorate --format=value 192.168.92.6/22', 'ipcalc: --no-decorate is not supported with --binary; use --format=value'], ['BitsNoDecorateSilent', '-s --no-decorate 192.168.92.6/22', ''], ] cmd = ipcalc.full_path() + ' --binary ' + c[1] test(c[0], testrunner, args : ['--test-status', '1', cmd, '--test-output', cmd, c[2]]) endforeach # --binary rejected inputs and combinations: [name, expected exit status, arguments] foreach c : [ ['BitsBadAddress', '1', '1.2.3.400'], ['BitsBadPrefixIPv4', '1', '1.2.3.4/33'], ['BitsBadPrefixIPv6', '1', '2001:db8::/129'], ['BitsForcedFamily', '1', '-6 1.2.3.4'], ['Bits-Info', '1', '-i 10.0.0.0/8'], ['Bits-AllInfo', '1', '--all-info 10.0.0.0/8'], ['Bits-Network', '1', '-n 10.0.0.0/8'], ['Bits-Cidr', '1', '--cidr 10.0.0.0/8'], ['Bits-Check', '1', '-c 10.0.0.0/8'], ['Bits-Split', '1', '-S 24 10.0.0.0/8'], ['Bits-SplitHosts', '1', '--split-hosts=10 10.0.0.0/8'], ['Bits-Deaggregate', '1', '-d 10.0.0.0-10.0.0.255'], ['Bits-Random', '1', '-r 24'], ['Bits-Equals', '2', '10.0.0.0/8 --equals=10.0.0.0/8'], ['BitsFormatConflict', '1', '-j --format=shell 10.0.0.0/8'], ] test(c[0], testrunner, args : ['--test-status', c[1], ipcalc.full_path() + ' --binary ' + c[2]]) endforeach # --all-info does not show the bits foreach c : [ ['AllInfoNoBits', '--all-info 192.168.92.6/22'], ['AllInfoNoBitsJson', '--all-info --format=json 192.168.92.6/22'], ['AllInfoNoBitsShell', '--all-info --format=shell 2001:db8::1/56'], ] test(c[0], testrunner, args : ['--test-success', 'out=$(' + ipcalc.full_path() + ' ' + c[1] + ') && ! echo "$out" | grep -qi bits']) endforeach ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/mkmmdb.py000066400000000000000000000111561526405142400232450ustar00rootroot00000000000000#!/usr/bin/env python3 # # Writes a MaxMind DB file (https://maxmind.github.io/MaxMind-DB/) from a # JSON description, so that the geo tests do not depend on the databases # installed on the system: # # {"database_type": "...", "networks": {"192.0.2.0/24": {...}, ...}} # # Integers are written as the smallest unsigned type that holds them, as # MaxMind does (e.g. accuracy_radius as uint16). # # Usage: mkmmdb.py INPUT.json OUTPUT.mmdb import ipaddress import json import struct import sys TYPE_UTF8 = 2 TYPE_DOUBLE = 3 TYPE_UINT16 = 5 TYPE_UINT32 = 6 TYPE_MAP = 7 TYPE_UINT64 = 9 TYPE_ARRAY = 11 TYPE_BOOLEAN = 14 RECORD_SIZE = 24 class Uint: """An unsigned integer of a fixed type, as the metadata requires""" def __init__(self, type_, value): self.type = type_ self.value = value def control(type_, size): if size < 29: out, ext = size, b'' elif size < 29 + 256: out, ext = 29, bytes([size - 29]) elif size < 285 + 65536: out, ext = 30, struct.pack('>H', size - 285) else: out, ext = 31, (size - 65821).to_bytes(3, 'big') if type_ <= 7: return bytes([(type_ << 5) | out]) + ext return bytes([out, type_ - 7]) + ext def encode_uint(type_, value): data = value.to_bytes((value.bit_length() + 7) // 8, 'big') return control(type_, len(data)) + data def encode(value): if isinstance(value, Uint): return encode_uint(value.type, value.value) if isinstance(value, bool): return control(TYPE_BOOLEAN, int(value)) if isinstance(value, int): if value < 1 << 16: return encode_uint(TYPE_UINT16, value) if value < 1 << 32: return encode_uint(TYPE_UINT32, value) return encode_uint(TYPE_UINT64, value) if isinstance(value, float): return control(TYPE_DOUBLE, 8) + struct.pack('>d', value) if isinstance(value, str): data = value.encode('utf-8') return control(TYPE_UTF8, len(data)) + data if isinstance(value, dict): return control(TYPE_MAP, len(value)) + b''.join( encode(k) + encode(v) for k, v in value.items()) if isinstance(value, list): return control(TYPE_ARRAY, len(value)) + b''.join( encode(v) for v in value) raise TypeError('cannot encode %r' % (value,)) class Data: def __init__(self, offset): self.offset = offset def insert(root, network, data): """Adds a leaf for network; IPv4 networks go under ::/96, where libmaxminddb looks them up in an IPv6 tree""" net = ipaddress.ip_network(network) bits = int(net.network_address) plen = net.prefixlen if net.version == 4: plen += 96 node = root for depth in range(plen): bit = (bits >> (127 - depth)) & 1 if depth == plen - 1: if node[bit] is not None: sys.exit('%s overlaps another network' % network) node[bit] = data else: if node[bit] is None: node[bit] = [None, None] elif isinstance(node[bit], Data): sys.exit('%s overlaps another network' % network) node = node[bit] def main(): with open(sys.argv[1], encoding='utf-8') as f: desc = json.load(f) root = [None, None] data_section = b'' for network, record in desc['networks'].items(): insert(root, network, Data(len(data_section))) data_section += encode(record) nodes = [root] i = 0 while i < len(nodes): for child in nodes[i]: if isinstance(child, list): nodes.append(child) i += 1 index = {id(n): i for i, n in enumerate(nodes)} node_count = len(nodes) def record(child): if child is None: return node_count if isinstance(child, Data): return node_count + 16 + child.offset return index[id(child)] tree = b''.join(record(n[0]).to_bytes(3, 'big') + record(n[1]).to_bytes(3, 'big') for n in nodes) metadata = { 'node_count': Uint(TYPE_UINT32, node_count), 'record_size': Uint(TYPE_UINT16, RECORD_SIZE), 'ip_version': Uint(TYPE_UINT16, 6), 'database_type': desc['database_type'], 'languages': ['en'], 'binary_format_major_version': Uint(TYPE_UINT16, 2), 'binary_format_minor_version': Uint(TYPE_UINT16, 0), 'build_epoch': Uint(TYPE_UINT64, 1), 'description': {'en': 'ipcalc test database'}, } with open(sys.argv[2], 'wb') as f: f.write(tree + bytes(16) + data_section + b'\xab\xcd\xefMaxMind.com' + encode(metadata)) if __name__ == '__main__': main() ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/no-decorate-192.168.2.0-24000066400000000000000000000002441526405142400251120ustar00rootroot00000000000000Network: 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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/no-decorate-all-info-192.168.2.0-24000066400000000000000000000003641526405142400266140ustar00rootroot00000000000000Network: 192.168.2.0/24 Netmask: 255.255.255.0 = 24 Wildcard: 0.0.0.255 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 no-decorate-all-info-fe80::21b:21ff:fe3a:5c7d-64000066400000000000000000000010131526405142400310150ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/testsFull Address: fe80:0000:0000:0000:021b:21ff:fe3a:5c7d Address: fe80::21b:21ff:fe3a:5c7d Full Network: fe80:0000:0000:0000:0000:0000:0000:0000/64 Network: fe80::/64 Netmask: ffff:ffff:ffff:ffff:: = 64 Reverse DNS: 0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. Address space: Link-Scoped Unicast Interface ID: 021b:21ff:fe3a:5c7d EUI-64: 00:1b:21:ff:fe:3a:5c:7d MAC address: 00:1b:21:3a:5c:7d MAC scope: universal MAC type: individual HostMin: fe80:: HostMax: fe80::ffff:ffff:ffff:ffff Hosts/Net: 2^(64) = 18446744073709551616 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-10.10.10.0-16-18000066400000000000000000000000711526405142400243360ustar00rootroot0000000000000010.10.0.0/18 10.10.64.0/18 10.10.128.0/18 10.10.192.0/18 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-10.10.10.0-16-24000066400000000000000000000072221526405142400243400ustar00rootroot0000000000000010.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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-192.168.0.0-24-1:28-2:27000066400000000000000000000000571526405142400252270ustar00rootroot00000000000000192.168.0.64/28 192.168.0.0/27 192.168.0.32/27 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-192.168.5.0-24-29000066400000000000000000000010211526405142400244500ustar00rootroot00000000000000192.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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-192.168.5.0-24-31000066400000000000000000000041111526405142400244440ustar00rootroot00000000000000192.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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-192.168.5.0-24-32000066400000000000000000000102221526405142400244450ustar00rootroot00000000000000192.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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-192.168.5.0-31-32000066400000000000000000000000361526405142400244450ustar00rootroot00000000000000192.168.5.0/32 192.168.5.1/32 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-192.168.5.45-24-26000066400000000000000000000001011526405142400245340ustar00rootroot00000000000000192.168.5.0/26 192.168.5.64/26 192.168.5.128/26 192.168.5.192/26 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-2001:db8:1c88:6000::-56-1:58-64000066400000000000000000000110301526405142400262650ustar00rootroot000000000000002001:db8:1c88:6000::/58 2001:db8:1c88:6040::/64 2001:db8:1c88:6041::/64 2001:db8:1c88:6042::/64 2001:db8:1c88:6043::/64 2001:db8:1c88:6044::/64 2001:db8:1c88:6045::/64 2001:db8:1c88:6046::/64 2001:db8:1c88:6047::/64 2001:db8:1c88:6048::/64 2001:db8:1c88:6049::/64 2001:db8:1c88:604a::/64 2001:db8:1c88:604b::/64 2001:db8:1c88:604c::/64 2001:db8:1c88:604d::/64 2001:db8:1c88:604e::/64 2001:db8:1c88:604f::/64 2001:db8:1c88:6050::/64 2001:db8:1c88:6051::/64 2001:db8:1c88:6052::/64 2001:db8:1c88:6053::/64 2001:db8:1c88:6054::/64 2001:db8:1c88:6055::/64 2001:db8:1c88:6056::/64 2001:db8:1c88:6057::/64 2001:db8:1c88:6058::/64 2001:db8:1c88:6059::/64 2001:db8:1c88:605a::/64 2001:db8:1c88:605b::/64 2001:db8:1c88:605c::/64 2001:db8:1c88:605d::/64 2001:db8:1c88:605e::/64 2001:db8:1c88:605f::/64 2001:db8:1c88:6060::/64 2001:db8:1c88:6061::/64 2001:db8:1c88:6062::/64 2001:db8:1c88:6063::/64 2001:db8:1c88:6064::/64 2001:db8:1c88:6065::/64 2001:db8:1c88:6066::/64 2001:db8:1c88:6067::/64 2001:db8:1c88:6068::/64 2001:db8:1c88:6069::/64 2001:db8:1c88:606a::/64 2001:db8:1c88:606b::/64 2001:db8:1c88:606c::/64 2001:db8:1c88:606d::/64 2001:db8:1c88:606e::/64 2001:db8:1c88:606f::/64 2001:db8:1c88:6070::/64 2001:db8:1c88:6071::/64 2001:db8:1c88:6072::/64 2001:db8:1c88:6073::/64 2001:db8:1c88:6074::/64 2001:db8:1c88:6075::/64 2001:db8:1c88:6076::/64 2001:db8:1c88:6077::/64 2001:db8:1c88:6078::/64 2001:db8:1c88:6079::/64 2001:db8:1c88:607a::/64 2001:db8:1c88:607b::/64 2001:db8:1c88:607c::/64 2001:db8:1c88:607d::/64 2001:db8:1c88:607e::/64 2001:db8:1c88:607f::/64 2001:db8:1c88:6080::/64 2001:db8:1c88:6081::/64 2001:db8:1c88:6082::/64 2001:db8:1c88:6083::/64 2001:db8:1c88:6084::/64 2001:db8:1c88:6085::/64 2001:db8:1c88:6086::/64 2001:db8:1c88:6087::/64 2001:db8:1c88:6088::/64 2001:db8:1c88:6089::/64 2001:db8:1c88:608a::/64 2001:db8:1c88:608b::/64 2001:db8:1c88:608c::/64 2001:db8:1c88:608d::/64 2001:db8:1c88:608e::/64 2001:db8:1c88:608f::/64 2001:db8:1c88:6090::/64 2001:db8:1c88:6091::/64 2001:db8:1c88:6092::/64 2001:db8:1c88:6093::/64 2001:db8:1c88:6094::/64 2001:db8:1c88:6095::/64 2001:db8:1c88:6096::/64 2001:db8:1c88:6097::/64 2001:db8:1c88:6098::/64 2001:db8:1c88:6099::/64 2001:db8:1c88:609a::/64 2001:db8:1c88:609b::/64 2001:db8:1c88:609c::/64 2001:db8:1c88:609d::/64 2001:db8:1c88:609e::/64 2001:db8:1c88:609f::/64 2001:db8:1c88:60a0::/64 2001:db8:1c88:60a1::/64 2001:db8:1c88:60a2::/64 2001:db8:1c88:60a3::/64 2001:db8:1c88:60a4::/64 2001:db8:1c88:60a5::/64 2001:db8:1c88:60a6::/64 2001:db8:1c88:60a7::/64 2001:db8:1c88:60a8::/64 2001:db8:1c88:60a9::/64 2001:db8:1c88:60aa::/64 2001:db8:1c88:60ab::/64 2001:db8:1c88:60ac::/64 2001:db8:1c88:60ad::/64 2001:db8:1c88:60ae::/64 2001:db8:1c88:60af::/64 2001:db8:1c88:60b0::/64 2001:db8:1c88:60b1::/64 2001:db8:1c88:60b2::/64 2001:db8:1c88:60b3::/64 2001:db8:1c88:60b4::/64 2001:db8:1c88:60b5::/64 2001:db8:1c88:60b6::/64 2001:db8:1c88:60b7::/64 2001:db8:1c88:60b8::/64 2001:db8:1c88:60b9::/64 2001:db8:1c88:60ba::/64 2001:db8:1c88:60bb::/64 2001:db8:1c88:60bc::/64 2001:db8:1c88:60bd::/64 2001:db8:1c88:60be::/64 2001:db8:1c88:60bf::/64 2001:db8:1c88:60c0::/64 2001:db8:1c88:60c1::/64 2001:db8:1c88:60c2::/64 2001:db8:1c88:60c3::/64 2001:db8:1c88:60c4::/64 2001:db8:1c88:60c5::/64 2001:db8:1c88:60c6::/64 2001:db8:1c88:60c7::/64 2001:db8:1c88:60c8::/64 2001:db8:1c88:60c9::/64 2001:db8:1c88:60ca::/64 2001:db8:1c88:60cb::/64 2001:db8:1c88:60cc::/64 2001:db8:1c88:60cd::/64 2001:db8:1c88:60ce::/64 2001:db8:1c88:60cf::/64 2001:db8:1c88:60d0::/64 2001:db8:1c88:60d1::/64 2001:db8:1c88:60d2::/64 2001:db8:1c88:60d3::/64 2001:db8:1c88:60d4::/64 2001:db8:1c88:60d5::/64 2001:db8:1c88:60d6::/64 2001:db8:1c88:60d7::/64 2001:db8:1c88:60d8::/64 2001:db8:1c88:60d9::/64 2001:db8:1c88:60da::/64 2001:db8:1c88:60db::/64 2001:db8:1c88:60dc::/64 2001:db8:1c88:60dd::/64 2001:db8:1c88:60de::/64 2001:db8:1c88:60df::/64 2001:db8:1c88:60e0::/64 2001:db8:1c88:60e1::/64 2001:db8:1c88:60e2::/64 2001:db8:1c88:60e3::/64 2001:db8:1c88:60e4::/64 2001:db8:1c88:60e5::/64 2001:db8:1c88:60e6::/64 2001:db8:1c88:60e7::/64 2001:db8:1c88:60e8::/64 2001:db8:1c88:60e9::/64 2001:db8:1c88:60ea::/64 2001:db8:1c88:60eb::/64 2001:db8:1c88:60ec::/64 2001:db8:1c88:60ed::/64 2001:db8:1c88:60ee::/64 2001:db8:1c88:60ef::/64 2001:db8:1c88:60f0::/64 2001:db8:1c88:60f1::/64 2001:db8:1c88:60f2::/64 2001:db8:1c88:60f3::/64 2001:db8:1c88:60f4::/64 2001:db8:1c88:60f5::/64 2001:db8:1c88:60f6::/64 2001:db8:1c88:60f7::/64 2001:db8:1c88:60f8::/64 2001:db8:1c88:60f9::/64 2001:db8:1c88:60fa::/64 2001:db8:1c88:60fb::/64 2001:db8:1c88:60fc::/64 2001:db8:1c88:60fd::/64 2001:db8:1c88:60fe::/64 2001:db8:1c88:60ff::/64 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-2a03:2880:20:4f06:face::-56-64000066400000000000000000000134001526405142400264330ustar00rootroot000000000000002a03: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 nsplit-fcfa:b4ca:f1d8:125b:dc00::-112-120000066400000000000000000000213551526405142400273130ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/testsfcfa: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 nsplit-fcfa:b4ca:f1d8:125b:dc00::-127-128000066400000000000000000000000771526405142400273270ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/testsfcfa:b4ca:f1d8:125b:dc00::/128 fcfa:b4ca:f1d8:125b:dc00::1/128 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-hosts-192.168.0.0-24-10,20,30000066400000000000000000000000571526405142400262340ustar00rootroot00000000000000192.168.0.64/28 192.168.0.0/27 192.168.0.32/27 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/nsplit-hosts-192.168.0.0-24-126,62,62000066400000000000000000000000611526405142400263320ustar00rootroot00000000000000192.168.0.0/25 192.168.0.128/26 192.168.0.192/26 reverse-dns-no-decorate-2001:db8:abcd::-37000066400000000000000000000003601526405142400303050ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests8.a.8.b.d.0.1.0.0.2.ip6.arpa. 9.a.8.b.d.0.1.0.0.2.ip6.arpa. a.a.8.b.d.0.1.0.0.2.ip6.arpa. b.a.8.b.d.0.1.0.0.2.ip6.arpa. c.a.8.b.d.0.1.0.0.2.ip6.arpa. d.a.8.b.d.0.1.0.0.2.ip6.arpa. e.a.8.b.d.0.1.0.0.2.ip6.arpa. f.a.8.b.d.0.1.0.0.2.ip6.arpa. ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/run-coverage.sh000077500000000000000000000002611526405142400243530ustar00rootroot00000000000000#! /bin/sh set -e entries=$(grep headerCovTableEntry public/index.html) echo "$entries"|grep "%"|head -1|sed 's/ //g'|sed 's/^.*>\([0-9\.\ %]*\)<.*$/coverage lines: \1/' ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/shell-192.168.2.7-24000066400000000000000000000003041526405142400240250ustar00rootroot00000000000000ADDRESS=192.168.2.7 NETWORK=192.168.2.0 NETMASK=255.255.255.0 PREFIX=24 CIDR=192.168.2.0/24 BROADCAST=192.168.2.255 ADDRSPACE="Private Use" MINADDR=192.168.2.1 MAXADDR=192.168.2.254 ADDRESSES=254 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-0.0.0.0-0-0000066400000000000000000000001061526405142400235540ustar00rootroot00000000000000[Split networks] Network: 0.0.0.0/0 Total: 1 Hosts/Net: 4294967294 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-10.0.0.0-1-3000066400000000000000000000002011526405142400236350ustar00rootroot00000000000000[Split networks] Network: 0.0.0.0/3 Network: 32.0.0.0/3 Network: 64.0.0.0/3 Network: 96.0.0.0/3 Total: 4 Hosts/Net: 536870910 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-10.10.10.0-16-18000066400000000000000000000002131526405142400241560ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-10.10.10.0-16-24000066400000000000000000000137001526405142400241600ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.0.0-24-1:28-2:27000066400000000000000000000003061526405142400250460ustar00rootroot00000000000000[Split networks] Network: 192.168.0.64/28 Network: 192.168.0.0/27 Network: 192.168.0.32/27 Total: 3 [Unused networks] Network: 192.168.0.80/28 Network: 192.168.0.96/27 Network: 192.168.0.128/25 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.1.0-24-2:255.255.255.192000066400000000000000000000002111526405142400256610ustar00rootroot00000000000000[Split networks] Network: 192.168.1.0/26 Network: 192.168.1.64/26 Total: 2 Hosts/Net: 62 [Unused networks] Network: 192.168.1.128/25 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.1.0-24-2:26-26000066400000000000000000000002201526405142400246640ustar00rootroot00000000000000[Split networks] Network: 192.168.1.0/26 Network: 192.168.1.64/26 Network: 192.168.1.128/26 Network: 192.168.1.192/26 Total: 4 Hosts/Net: 62 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.5.0-24-29000066400000000000000000000015341526405142400243030ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.5.0-24-31000066400000000000000000000063651526405142400243030ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.5.0-24-32000066400000000000000000000146761526405142400243100ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.5.0-31-32000066400000000000000000000001321526405142400242640ustar00rootroot00000000000000[Split networks] Network: 192.168.5.0/32 Network: 192.168.5.1/32 Total: 2 Hosts/Net: 1 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-192.168.5.45-24-26000066400000000000000000000002201526405142400243600ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-2001:db8:1c88:6000::-56-1:58-64000066400000000000000000000144001526405142400261130ustar00rootroot00000000000000[Split networks] Network: 2001:db8:1c88:6000::/58 Network: 2001:db8:1c88:6040::/64 Network: 2001:db8:1c88:6041::/64 Network: 2001:db8:1c88:6042::/64 Network: 2001:db8:1c88:6043::/64 Network: 2001:db8:1c88:6044::/64 Network: 2001:db8:1c88:6045::/64 Network: 2001:db8:1c88:6046::/64 Network: 2001:db8:1c88:6047::/64 Network: 2001:db8:1c88:6048::/64 Network: 2001:db8:1c88:6049::/64 Network: 2001:db8:1c88:604a::/64 Network: 2001:db8:1c88:604b::/64 Network: 2001:db8:1c88:604c::/64 Network: 2001:db8:1c88:604d::/64 Network: 2001:db8:1c88:604e::/64 Network: 2001:db8:1c88:604f::/64 Network: 2001:db8:1c88:6050::/64 Network: 2001:db8:1c88:6051::/64 Network: 2001:db8:1c88:6052::/64 Network: 2001:db8:1c88:6053::/64 Network: 2001:db8:1c88:6054::/64 Network: 2001:db8:1c88:6055::/64 Network: 2001:db8:1c88:6056::/64 Network: 2001:db8:1c88:6057::/64 Network: 2001:db8:1c88:6058::/64 Network: 2001:db8:1c88:6059::/64 Network: 2001:db8:1c88:605a::/64 Network: 2001:db8:1c88:605b::/64 Network: 2001:db8:1c88:605c::/64 Network: 2001:db8:1c88:605d::/64 Network: 2001:db8:1c88:605e::/64 Network: 2001:db8:1c88:605f::/64 Network: 2001:db8:1c88:6060::/64 Network: 2001:db8:1c88:6061::/64 Network: 2001:db8:1c88:6062::/64 Network: 2001:db8:1c88:6063::/64 Network: 2001:db8:1c88:6064::/64 Network: 2001:db8:1c88:6065::/64 Network: 2001:db8:1c88:6066::/64 Network: 2001:db8:1c88:6067::/64 Network: 2001:db8:1c88:6068::/64 Network: 2001:db8:1c88:6069::/64 Network: 2001:db8:1c88:606a::/64 Network: 2001:db8:1c88:606b::/64 Network: 2001:db8:1c88:606c::/64 Network: 2001:db8:1c88:606d::/64 Network: 2001:db8:1c88:606e::/64 Network: 2001:db8:1c88:606f::/64 Network: 2001:db8:1c88:6070::/64 Network: 2001:db8:1c88:6071::/64 Network: 2001:db8:1c88:6072::/64 Network: 2001:db8:1c88:6073::/64 Network: 2001:db8:1c88:6074::/64 Network: 2001:db8:1c88:6075::/64 Network: 2001:db8:1c88:6076::/64 Network: 2001:db8:1c88:6077::/64 Network: 2001:db8:1c88:6078::/64 Network: 2001:db8:1c88:6079::/64 Network: 2001:db8:1c88:607a::/64 Network: 2001:db8:1c88:607b::/64 Network: 2001:db8:1c88:607c::/64 Network: 2001:db8:1c88:607d::/64 Network: 2001:db8:1c88:607e::/64 Network: 2001:db8:1c88:607f::/64 Network: 2001:db8:1c88:6080::/64 Network: 2001:db8:1c88:6081::/64 Network: 2001:db8:1c88:6082::/64 Network: 2001:db8:1c88:6083::/64 Network: 2001:db8:1c88:6084::/64 Network: 2001:db8:1c88:6085::/64 Network: 2001:db8:1c88:6086::/64 Network: 2001:db8:1c88:6087::/64 Network: 2001:db8:1c88:6088::/64 Network: 2001:db8:1c88:6089::/64 Network: 2001:db8:1c88:608a::/64 Network: 2001:db8:1c88:608b::/64 Network: 2001:db8:1c88:608c::/64 Network: 2001:db8:1c88:608d::/64 Network: 2001:db8:1c88:608e::/64 Network: 2001:db8:1c88:608f::/64 Network: 2001:db8:1c88:6090::/64 Network: 2001:db8:1c88:6091::/64 Network: 2001:db8:1c88:6092::/64 Network: 2001:db8:1c88:6093::/64 Network: 2001:db8:1c88:6094::/64 Network: 2001:db8:1c88:6095::/64 Network: 2001:db8:1c88:6096::/64 Network: 2001:db8:1c88:6097::/64 Network: 2001:db8:1c88:6098::/64 Network: 2001:db8:1c88:6099::/64 Network: 2001:db8:1c88:609a::/64 Network: 2001:db8:1c88:609b::/64 Network: 2001:db8:1c88:609c::/64 Network: 2001:db8:1c88:609d::/64 Network: 2001:db8:1c88:609e::/64 Network: 2001:db8:1c88:609f::/64 Network: 2001:db8:1c88:60a0::/64 Network: 2001:db8:1c88:60a1::/64 Network: 2001:db8:1c88:60a2::/64 Network: 2001:db8:1c88:60a3::/64 Network: 2001:db8:1c88:60a4::/64 Network: 2001:db8:1c88:60a5::/64 Network: 2001:db8:1c88:60a6::/64 Network: 2001:db8:1c88:60a7::/64 Network: 2001:db8:1c88:60a8::/64 Network: 2001:db8:1c88:60a9::/64 Network: 2001:db8:1c88:60aa::/64 Network: 2001:db8:1c88:60ab::/64 Network: 2001:db8:1c88:60ac::/64 Network: 2001:db8:1c88:60ad::/64 Network: 2001:db8:1c88:60ae::/64 Network: 2001:db8:1c88:60af::/64 Network: 2001:db8:1c88:60b0::/64 Network: 2001:db8:1c88:60b1::/64 Network: 2001:db8:1c88:60b2::/64 Network: 2001:db8:1c88:60b3::/64 Network: 2001:db8:1c88:60b4::/64 Network: 2001:db8:1c88:60b5::/64 Network: 2001:db8:1c88:60b6::/64 Network: 2001:db8:1c88:60b7::/64 Network: 2001:db8:1c88:60b8::/64 Network: 2001:db8:1c88:60b9::/64 Network: 2001:db8:1c88:60ba::/64 Network: 2001:db8:1c88:60bb::/64 Network: 2001:db8:1c88:60bc::/64 Network: 2001:db8:1c88:60bd::/64 Network: 2001:db8:1c88:60be::/64 Network: 2001:db8:1c88:60bf::/64 Network: 2001:db8:1c88:60c0::/64 Network: 2001:db8:1c88:60c1::/64 Network: 2001:db8:1c88:60c2::/64 Network: 2001:db8:1c88:60c3::/64 Network: 2001:db8:1c88:60c4::/64 Network: 2001:db8:1c88:60c5::/64 Network: 2001:db8:1c88:60c6::/64 Network: 2001:db8:1c88:60c7::/64 Network: 2001:db8:1c88:60c8::/64 Network: 2001:db8:1c88:60c9::/64 Network: 2001:db8:1c88:60ca::/64 Network: 2001:db8:1c88:60cb::/64 Network: 2001:db8:1c88:60cc::/64 Network: 2001:db8:1c88:60cd::/64 Network: 2001:db8:1c88:60ce::/64 Network: 2001:db8:1c88:60cf::/64 Network: 2001:db8:1c88:60d0::/64 Network: 2001:db8:1c88:60d1::/64 Network: 2001:db8:1c88:60d2::/64 Network: 2001:db8:1c88:60d3::/64 Network: 2001:db8:1c88:60d4::/64 Network: 2001:db8:1c88:60d5::/64 Network: 2001:db8:1c88:60d6::/64 Network: 2001:db8:1c88:60d7::/64 Network: 2001:db8:1c88:60d8::/64 Network: 2001:db8:1c88:60d9::/64 Network: 2001:db8:1c88:60da::/64 Network: 2001:db8:1c88:60db::/64 Network: 2001:db8:1c88:60dc::/64 Network: 2001:db8:1c88:60dd::/64 Network: 2001:db8:1c88:60de::/64 Network: 2001:db8:1c88:60df::/64 Network: 2001:db8:1c88:60e0::/64 Network: 2001:db8:1c88:60e1::/64 Network: 2001:db8:1c88:60e2::/64 Network: 2001:db8:1c88:60e3::/64 Network: 2001:db8:1c88:60e4::/64 Network: 2001:db8:1c88:60e5::/64 Network: 2001:db8:1c88:60e6::/64 Network: 2001:db8:1c88:60e7::/64 Network: 2001:db8:1c88:60e8::/64 Network: 2001:db8:1c88:60e9::/64 Network: 2001:db8:1c88:60ea::/64 Network: 2001:db8:1c88:60eb::/64 Network: 2001:db8:1c88:60ec::/64 Network: 2001:db8:1c88:60ed::/64 Network: 2001:db8:1c88:60ee::/64 Network: 2001:db8:1c88:60ef::/64 Network: 2001:db8:1c88:60f0::/64 Network: 2001:db8:1c88:60f1::/64 Network: 2001:db8:1c88:60f2::/64 Network: 2001:db8:1c88:60f3::/64 Network: 2001:db8:1c88:60f4::/64 Network: 2001:db8:1c88:60f5::/64 Network: 2001:db8:1c88:60f6::/64 Network: 2001:db8:1c88:60f7::/64 Network: 2001:db8:1c88:60f8::/64 Network: 2001:db8:1c88:60f9::/64 Network: 2001:db8:1c88:60fa::/64 Network: 2001:db8:1c88:60fb::/64 Network: 2001:db8:1c88:60fc::/64 Network: 2001:db8:1c88:60fd::/64 Network: 2001:db8:1c88:60fe::/64 Network: 2001:db8:1c88:60ff::/64 Total: 193 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-2001:db8::-56-3:64-60000066400000000000000000000011631526405142400250120ustar00rootroot00000000000000[Split networks] Network: 2001:db8::/64 Network: 2001:db8:0:1::/64 Network: 2001:db8:0:2::/64 Network: 2001:db8:0:10::/60 Network: 2001:db8:0:20::/60 Network: 2001:db8:0:30::/60 Network: 2001:db8:0:40::/60 Network: 2001:db8:0:50::/60 Network: 2001:db8:0:60::/60 Network: 2001:db8:0:70::/60 Network: 2001:db8:0:80::/60 Network: 2001:db8:0:90::/60 Network: 2001:db8:0:a0::/60 Network: 2001:db8:0:b0::/60 Network: 2001:db8:0:c0::/60 Network: 2001:db8:0:d0::/60 Network: 2001:db8:0:e0::/60 Network: 2001:db8:0:f0::/60 Total: 18 [Unused networks] Network: 2001:db8:0:3::/64 Network: 2001:db8:0:4::/62 Network: 2001:db8:0:8::/61 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-2a03:2880:20:4f06:face::-56-64000066400000000000000000000200771526405142400262650ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-::-0-2000066400000000000000000000002231526405142400232300ustar00rootroot00000000000000[Split networks] Network: ::/2 Network: 4000::/2 Network: 8000::/2 Network: c000::/2 Total: 4 Hosts/Net: 85070591730234615865843651857942052864 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-::-0-2-1:1000066400000000000000000000001171526405142400235430ustar00rootroot00000000000000[Split networks] Network: 8000::/2 Network: c000::/2 Network: ::/1 Total: 3 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-fcfa:b4ca:f1d8:125b:dc00::-112-120000066400000000000000000000260331526405142400272120ustar00rootroot00000000000000[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 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-fcfa:b4ca:f1d8:125b:dc00::-127-128000066400000000000000000000001731526405142400272250ustar00rootroot00000000000000[Split networks] Network: fcfa:b4ca:f1d8:125b:dc00::/128 Network: fcfa:b4ca:f1d8:125b:dc00::1/128 Total: 2 Hosts/Net: 1 split-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff-120-124000066400000000000000000000015741526405142400324350ustar00rootroot00000000000000ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests[Split networks] Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff10/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff20/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff30/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff40/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff50/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff60/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff70/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff90/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffa0/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffb0/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffd0/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0/124 Network: ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0/124 Total: 16 Hosts/Net: 16 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-hosts-192.168.0.0-24-1,2,62,63000066400000000000000000000015141526405142400261470ustar00rootroot00000000000000[Split networks] 1. Requested size: 1 hosts Network: 192.168.0.192/30 Netmask: 255.255.255.252 = 30 Broadcast: 192.168.0.195 HostMin: 192.168.0.193 HostMax: 192.168.0.194 Hosts/Net: 2 2. Requested size: 2 hosts Network: 192.168.0.196/30 Netmask: 255.255.255.252 = 30 Broadcast: 192.168.0.199 HostMin: 192.168.0.197 HostMax: 192.168.0.198 Hosts/Net: 2 3. Requested size: 62 hosts Network: 192.168.0.128/26 Netmask: 255.255.255.192 = 26 Broadcast: 192.168.0.191 HostMin: 192.168.0.129 HostMax: 192.168.0.190 Hosts/Net: 62 4. Requested size: 63 hosts Network: 192.168.0.0/25 Netmask: 255.255.255.128 = 25 Broadcast: 192.168.0.127 HostMin: 192.168.0.1 HostMax: 192.168.0.126 Hosts/Net: 126 Total: 4 Needed size: 200 Used network: 192.168.0.0/24 [Unused networks] Network: 192.168.0.200/29 Network: 192.168.0.208/28 Network: 192.168.0.224/27 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-hosts-192.168.0.0-24-10,20,30000066400000000000000000000012301526405142400260500ustar00rootroot00000000000000[Split networks] 1. Requested size: 10 hosts Network: 192.168.0.64/28 Netmask: 255.255.255.240 = 28 Broadcast: 192.168.0.79 HostMin: 192.168.0.65 HostMax: 192.168.0.78 Hosts/Net: 14 2. Requested size: 20 hosts Network: 192.168.0.0/27 Netmask: 255.255.255.224 = 27 Broadcast: 192.168.0.31 HostMin: 192.168.0.1 HostMax: 192.168.0.30 Hosts/Net: 30 3. Requested size: 30 hosts Network: 192.168.0.32/27 Netmask: 255.255.255.224 = 27 Broadcast: 192.168.0.63 HostMin: 192.168.0.33 HostMax: 192.168.0.62 Hosts/Net: 30 Total: 3 Needed size: 80 Used network: 192.168.0.0/25 [Unused networks] Network: 192.168.0.80/28 Network: 192.168.0.96/27 Network: 192.168.0.128/25 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/split-hosts-2001:db8::-112-1,2,3,256000066400000000000000000000021411526405142400263330ustar00rootroot00000000000000[Split networks] 1. Requested size: 1 hosts Network: 2001:db8::106/128 Netmask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff = 128 HostMin: 2001:db8::106 HostMax: 2001:db8::106 Hosts/Net: 1 2. Requested size: 2 hosts Network: 2001:db8::104/127 Netmask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe = 127 HostMin: 2001:db8::104 HostMax: 2001:db8::105 Hosts/Net: 2 3. Requested size: 3 hosts Network: 2001:db8::100/126 Netmask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc = 126 HostMin: 2001:db8::100 HostMax: 2001:db8::103 Hosts/Net: 4 4. Requested size: 256 hosts Network: 2001:db8::/120 Netmask: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00 = 120 HostMin: 2001:db8:: HostMax: 2001:db8::ff Hosts/Net: 256 Total: 4 Needed size: 263 Used network: 2001:db8::/119 [Unused networks] Network: 2001:db8::107/128 Network: 2001:db8::108/125 Network: 2001:db8::110/124 Network: 2001:db8::120/123 Network: 2001:db8::140/122 Network: 2001:db8::180/121 Network: 2001:db8::200/119 Network: 2001:db8::400/118 Network: 2001:db8::800/117 Network: 2001:db8::1000/116 Network: 2001:db8::2000/115 Network: 2001:db8::4000/114 Network: 2001:db8::8000/113 ipcalc-1.2.0-e364dbbcfaf604b039649e941a7603615e674d91/tests/standard-192.168.2.0-24000066400000000000000000000002441526405142400245120ustar00rootroot00000000000000Network: 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