{"id":19863531,"url":"https://github.com/sandialabs/arcus","last_synced_at":"2025-06-19T07:04:34.675Z","repository":{"id":139856648,"uuid":"117757709","full_name":"sandialabs/Arcus","owner":"sandialabs","description":"Arcus, developed by Sandia National Laboratories, is a C# library for calculating, parsing, formatting, converting and comparing both IPv4 and IPv6 addresses and subnets. It accounts for 128-bit numbers on 32-bit platforms.","archived":false,"fork":false,"pushed_at":"2025-05-11T10:25:32.000Z","size":703,"stargazers_count":11,"open_issues_count":4,"forks_count":4,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-06-03T18:29:43.898Z","etag":null,"topics":["c-sharp","ip","ip-calculator","ipaddress","ipaddresses","ipv4","ipv4-address","ipv4-calculator","ipv4-network","ipv6","ipv6-address","ipv6-calulator","ipv6-network","networking","scr-2276","snl-other","subnet"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sandialabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-01-16T23:54:25.000Z","updated_at":"2025-04-29T16:53:04.000Z","dependencies_parsed_at":"2025-04-14T15:28:19.463Z","dependency_job_id":"4c1b2adf-1e52-4368-8ed8-6710a13b3636","html_url":"https://github.com/sandialabs/Arcus","commit_stats":{"total_commits":39,"total_committers":8,"mean_commits":4.875,"dds":0.641025641025641,"last_synced_commit":"2750d1d18552ab8e8a9f31df48e33b186ad562e4"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/sandialabs/Arcus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandialabs%2FArcus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandialabs%2FArcus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandialabs%2FArcus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandialabs%2FArcus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sandialabs","download_url":"https://codeload.github.com/sandialabs/Arcus/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandialabs%2FArcus/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260705803,"owners_count":23049487,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-sharp","ip","ip-calculator","ipaddress","ipaddresses","ipv4","ipv4-address","ipv4-calculator","ipv4-network","ipv6","ipv6-address","ipv6-calulator","ipv6-network","networking","scr-2276","snl-other","subnet"],"created_at":"2024-11-12T15:15:02.294Z","updated_at":"2025-06-19T07:04:29.637Z","avatar_url":"https://github.com/sandialabs.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ![Arcus](src/Arcus/icon.png) Arcus\n\n![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/sandialabs/Arcus/build.yml?branch=main)\n[![nuget Version](https://img.shields.io/nuget/v/Arcus)](https://www.nuget.org/packages/Arcus)\n[![GitHub Release](https://img.shields.io/github/v/release/sandialabs/Arcus)](https://github.com/sandialabs/Arcus/releases)\n[![GitHub Tag](https://img.shields.io/github/v/tag/sandialabs/Arcus)](https://github.com/sandialabs/Arcus/tags)\n![Targets](https://img.shields.io/badge/.NET%20Standard%202.0%20|%20.NET%208.0%20|%20.NET%209.0-blue?logo=.net)\n[![Apache 2.0 License](https://img.shields.io/github/license/sandialabs/Arcus?logo=apache)](https://github.com/sandialabs/Arcus/blob/main/LICENSE)\n\n## About the Project\n\nArcus is a C# manipulation library for calculating, parsing, formatting, converting, and comparing both IPv4 and IPv6 addresses and subnets. It accounts for 128-bit numbers on 32-bit platforms.\n\n## ❗Breaking Changes in Version 3+\n\n### IP Address Parsing based on .NET Targets\n\nIn .NET versions up to and including .NET 4.8 (which corresponds to .NET Standard 2.0), stricter parsing rules were enforced for `IPAddress` according to the IPv6 specification. Specifically, the presence of a terminal '%' character without a valid zone index is considered invalid in these versions. As a result, the input `abcd::%` fails to parse, leading to a null or failed address parsing depending on `Parse`/`TryParse`. This behavior represents a breaking change from Arcus's previous target of .NET Standard 1.3. and may provide confusion for .NET 4.8 / .NET Standard 2.0 versions.\n\nIn contrast, in newer versions of .NET, including .NET 8 and .NET 9, the parsing rules have been relaxed. The trailing '%' character is now ignored during parsing, allowing for inputs that would have previously failed.\n\nIt is important to note that this scenario appears to be an extreme edge case, and developers should ensure that their applications handle `IPAddress` parsing appropriately across different target frameworks as expected.\n\nIf in doubt it is suggested that IP Address based user input should be sanitized to meet your development needs.\n\n## Getting Started\n\nThe latest stable release of Arcus is [available on NuGet](https://www.nuget.org/packages/Arcus/).\n\nThe latest [Arcus documentation](https://arcus.readthedocs.io/en/latest/) may be found on [ReadTheDocs](https://arcus.readthedocs.io/en/latest/).\n\n### Usage\n\nAt its heart Arcus is split amongst five separate interdependent units. _Types_, _Comparers_, _Converters_, _Math_, and _Utilities_.\n\nThese units each work across Arcus's `IPAddressRange`, `Subnet` and .NET's `System.Net.IPAddress`. Arcus adds extra desired functionality where the standard C# libraries left off.\n\n#### Types\n\n##### `Subnet`\n\nAn IPv4 or IPv6 subnetwork representation - the work horse and original reason for the Arcus library. Outside the concept of the `Subnet` object, most everything else in Arcus is auxiliary and exists only in support of the `Subnet` object. That’s not to say that the remaining pieces of the Arcus library aren’t useful, on the contrary their utility can benefit a developer greatly.\n\nA `Subnet` may be instantiated in several ways:\n\nThe most common way to create a `Subnet` object is to construct it via a high and low `IPAddress` by calling the constructor `Subnet(IPAddress primary, IPAddress secondary)`. This constructs the smallest possible subnet that would contain both IP addresses. Typically the addresses specified are the Network and Broadcast addresses (lower and higher bounds of a subnet) but this is not necessary. Addresses _MUST_ be the same address family (either Internetwork or InternetworkV6).\n\nIt is also possible to create a `Subnet` from an `IPAddress` and an `integer` based _route prefix_. Eg: `Subnet(IPAddress ipAddress, int routingPrefix)`.\n\nLikewise it may be desired to statically parse a subnet string with `Subnet.Parse(string input)` or it’s safe equivalent of `bool Subnet.TryParse(string input, out Subnet subnet)`\n\nFor example, one could safely parse the `string` \"192.168.1.0/16\" via\n\n```c#\nSubnet subnet;\nvar success = Subnet.TryParse(\"192.168.1.0/16\", out subnet)\n```\n\n##### `IPAddressRange`\n\n`IPAddressRange` is a basic implementation of `IIPAddressRange` it is used to represent an inclusive range of arbitrary IP Addresses of the same address family. Unlike `Subnet`, `IPAddressRange` is not restricted to a power of two length, nor a valid broadcast address head.\n\n#### Comparers\n\nThe _Comparers_ package contains useful Comparer objects for comparing properties of IP Addresses and IP Address composite objects.\n\n- `DefaultAddressFamilyComparer` - A comparer that compares address families. Most frequently `Internetwork` (IPv4) and `InternetworkV6` (IPv6)\n- `DefaultIPAddressComparer` - A comparer for `IPAddress` objects\n- `DefaultIPAddressRangeComparer` - A comparer for `IIPAddressRange`. Compares such that lower order ranges are less that higher order ranges accounting for size at matching range starts\n\n#### Converters\n\nThe _Converters_ package is a package of static utility classes for converting one type into another type.\n\n##### `IPAddressConverters`\n\nStatic utility class containing conversion methods for converting `IPAddress` objects into something else.\n\n#### Math\n\nThe _Math_ package is a package of static utility classes for doing computational mathematics on objects.\n\n##### `IPAddressMath`\n\nIn some cases the C# `IPAddress` object doesn't go far enough with what you can do with it mathematically, this static utility class containing mathematical methods to fill in the gaps.\n\n###### Incrementing and Decrementing\n\nIncrementing and Decrementing an `IPAddress` is easy.\n\nIncrementing by one is a simple call to the extension method:\n\n```c#\nvar address = IPAddress.Parse(\"192.168.1.1\");\nvar result = address.Increment(); // result is 192.168.1.2\n```\n\nDecrementing is just as simple:\n\n```c#\nvar address = IPAddress.Parse(\"192.168.1.1\");\nvar result = address.Increment(-2); // result is 192.168.0.0\n```\n\n_Overflow_ and _Underflow_ conditions will result in an `InvalidOperationException`.\n\n###### Equality\n\nEquality may also be tested via a host of equality extension methods:\n\n- `bool IsEqualTo(this IPAddress alpha, IPAddress beta)`\n- `bool IsGreaterThan(this IPAddress alpha, IPAddress beta)`\n- `bool IsGreaterThanOrEqualTo(this IPAddress alpha, IPAddress beta)`\n- `bool IsLessThan(this IPAddress alpha, IPAddress beta)`\n- `bool IsLessThanOrEqualTo(this IPAddress alpha, IPAddress beta)`\n\n#### Utilities\n\nThe _Utilities_ package contains static classes for miscellaneous operations on specific types.\n\n##### `IPAddressUtilities`\n\nStatic utility class containing miscellaneous operations for `IPAddress` objects\n\n###### Address Family Detection\n\nA couple of extension methods were created to quickly determine the address family of an IP Address. To determine if an address is IPv4 use `bool IsIPv4(this IPAddress ipAddress)`, likewise `bool IsIPv6(this IPAddress ipAddress)` can be used to test for IPv6.\n\n###### Parsing\n\nIt is possible to parse an `IPAddress` from a hexadecimal string into either an IPv4 of IPv6 address using the `IPAddress ParseFromHexString(string input, AddressFamily addressFamily)` method. Likewise it can be done safely with `bool TryParseFromHexString(string input, AddressFamily addressFamily, out IPAddress address)`.\n\nSimilarly, conversion may be done from an octal string by using `bool TryParseIgnoreOctalInIPv4(string input, out IPAddress address)` or even a `BigInteger` by way of `bool TryParse(BigInteger input, AddressFamily addressFamily, out IPAddress address)`.\n\n##### `SubnetUtilities`\n\nStatic utility class containing miscellaneous operations for `Subnet` objects that didn't make sense to put on the object itself.\n\nGiven two arbitrary IP Addresses of the same family it may be desired to calculate the fewest consecutive subnets that would hold the inclusive range between them. For example\n\n```c#\nSubnetUtilities.FewestConsecutiveSubnetsFor(IPAddress.Parse(\"128.64.20.3\"), IPAddress.Parse(\"128.64.20.12\"))\n```\n\nwould return an `Enumerable` containing the subnets `128.64.20.3/32`, `128.64.20.4/30`, `128.64.20.8/30`, `128.64.20.12/32`.\n\n### Developer Notes\n\n## Built With\n\nThis project was built with the aid of:\n\n- [CSharpier](https://csharpier.com/)\n- [dotnet-outdated](https://github.com/dotnet-outdated/dotnet-outdated)\n- [Gulliver](https://github.com/sandialabs/gulliver) - A self created library that helped us keep our bits and bytes in order\n- [Husky.Net](https://alirezanet.github.io/Husky.Net/)\n- [Roslynator](https://josefpihrt.github.io/docs/roslynator/)\n- [SonarAnalyzer](https://www.sonarsource.com/products/sonarlint/features/visual-studio/)\n- [StyleCop.Analyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers)\n- [xUnit.net](https://xunit.net/)\n\n### Versioning\n\nThis project uses [Semantic Versioning](https://semver.org/)\n\n### Targeting\n\nThe project targets [.NET Standard 2.0](https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0), [.NET 8](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-8), and [.NET 9](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/overview). The test project similarly targets .NET 8, .NET 9, but targets [.NET Framework 4.8](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) for the .NET Standard 2.0 tests.\n\n### Commit Hook\n\nThe project itself has a configured pre-commit git hook, via [Husky.Net](https://alirezanet.github.io/Husky.Net/) that automatically lints and formats code via [dotnet format](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-format) and [csharpier](https://csharpier.com/).\n\n#### Disable husky in CI/CD pipelines\n\nPer the [Husky.Net instructions](https://alirezanet.github.io/Husky.Net/guide/automate.html#disable-husky-in-ci-cd-pipelines)\n\n\u003e You can set the `HUSKY` environment variable to `0` in order to disable husky in CI/CD pipelines.\n\n#### Manual Linting and Formatting\n\nOn occasion a manual run is desired it may be done so via the `src` directory and with the command\n\n```shell\ndotnet format style; dotnet format analyzers; dotnet csharpier format .\n```\n\nThese commands may be called independently, but order may matter.\n\n#### Testing\n\nAfter making changes tests should be run that include all targets\n\n## Acknowledgments\n\nThis project was built by the Production Tools Team at Sandia National Laboratories. Special thanks to all contributors and reviewers who helped shape and improve this library.\n\nIncluding, but not limited to:\n\n- **Robert H. Engelhardt** - _Primary Developer, Source of Ideas Good and Bad_ - [rheone](https://github.com/rheone)\n- **Andrew Steele** - _Review and Suggestions_ - [ahsteele](https://github.com/ahsteele)\n- **Nick Bachicha** - _Git Wrangler and DevOps Extraordinaire_ - [nicksterx](https://github.com/nicksterx)\n\n## Copyright\n\n\u003e Copyright 2025 National Technology \u0026 Engineering Solutions of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights in this software.\n\n## License\n\n\u003e Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at\n\u003e\n\u003e http://www.apache.org/licenses/LICENSE-2.0\n\u003e\n\u003e Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandialabs%2Farcus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsandialabs%2Farcus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandialabs%2Farcus/lists"}