Subnet¶
The Subnet
type, flavored in both IPv4 or IPv6, is a representation of a subnetwork within Arcus. It is the workhorse 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 making this one facet work. 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. But that said, once the dark and mysterious magic of the Subnet
is understood the rest of Arcus should be easy to understand.
Keep in mind that a Subnet
is not an arbitrary range of addresses, for that you want an IPAddress Range, but rather conforms to a range of length \(2^n\) starting a particular position, following the typical rules of Classless Inter-Domain Routing.
The Subnet
class extends AbstractIPAddressRange and implements IIPAddressRange, IEquatable<Subnet>
, IComparable<Subnet>
, IFormattable
, IEnumerable<IPAddress>
, and ISerializable
.
Note
Be aware that Subnet
does not extend IPAddress Range but does implement IIPAddressRange.
Creation¶
There are a number of ways to instantiate a Subnet
. Your most likely candidates are direct construction with a new
, the use of a static factory method on the Subnet
class, or the use of sub-set of static factory methods that handle parsing of strings. Most of the factory methods have a “try” style safe alternative that will return a bool
and out the constructed value.
Note
Unless otherwise specified each creation technique is valid for both IPv4 and IPv6 subnetworks.
constructor IPAddress lowAddress
, IPAddress highAddress
¶
The most common way to create a Subnet
is to construct it via a IPAddress lowAddress
and IPAddress highAddress
. This will construct the smallest possible Subnet
that would contain both IP addresses. Typically, the address specified are the Network and Broadcast addresses (lower and higher bounds) but this is not necessary.
Addresses MUST be the same address family (either InterNetwork
or InterNetworkV6
).
public Subnet(IPAddress lowAddress, IPAddress highAddress)
constructor IPAddress address
, int routingPrefix
¶
It is also possible to create a Subnet
from an IPAddress address
and an int routingPrefix
. This is equivalent of programmatically using a CIDR to define your Subnet
.
public Subnet(IPAddress address, int routingPrefix)
The following example shows that the IPAddress
and routingPrefix
constructor taking an input of 192.168.1.1
and 24
creates a Subnet
192.168.1.0/32
. Note that the Head
is 192.168.1.0
and not 192.168.1.1
, this is done as Arcus will autocorrect the input to a valid Subnet
. If this is not desired it is advised that you compare the Head
to the input in order to validate expectations.
[Fact]
public void Address_RoutePrefix_Subnet_Example()
{
// Arrange
var ipAddress = IPAddress.Parse("192.168.1.1");
const int routePrefix = 24;
// Act
var subnet = new Subnet(ipAddress, routePrefix);
// Assert
Assert.False(subnet.IsSingleIP);
Assert.Equal(256, subnet.Length);
Assert.Equal("192.168.1.0", subnet.Head.ToString());
Assert.Equal("192.168.1.255", subnet.Tail.ToString());
Assert.Equal(24, subnet.RoutingPrefix);
Assert.Equal("192.168.1.0/24", subnet.ToString());
}
constructor IPAddress address
¶
On the rare occasion it may be desired to make a Subnet
comprised of a single IPAddress
. This is possible with the following constructor.
public Subnet(IPAddress address)
The following example shows that the single IPAddress
constructor taking an input of 192.168.1.1
creates a Subnet
192.168.1.1/32
that is comprised of only the single input address.
[Fact]
public void Single_Address_Subnet_Example()
{
// Arrange
var ipAddress = IPAddress.Parse("192.168.1.1");
// Act
var subnet = new Subnet(ipAddress);
// Assert
Assert.Equal(1, subnet.Length);
Assert.Equal(ipAddress, subnet.Single());
Assert.True(subnet.IsSingleIP);
Assert.Equal("192.168.1.1/32", subnet.ToString());
}
factory IPAddress and NetMask¶
A once popular way to define a IPv4 subnetwork was to use a netmask, a specialized form of consecutive bitmasking, along side an IPAddress
.
The following factory methods may be used to create an IPv4 Subnet
where as the IPAddress address
is the address, and the IPAddress netmask
is the valid netmask.
public static Subnet FromNetMask(IPAddress address, IPAddress netmask)
public static bool TryFromNetMask(IPAddress address, IPAddress netmask, out Subnet subnet)
factory From Big-Endian Byte Arrays¶
IPAddress
objects may not always be handy, in some cases only a couple of big-endian byte arrays may be available. This will construct the smallest possible Subnet
that would contain both byte arrays as IP addresses. Typically, the address specified are the Network and Broadcast addresses (lower and upper bounds) but this is not necessary.
The given byte
arrays are interpreted as being in big-endian ordering are are functionally the equivalent construction an IPAddress
using its byte[]
constructor.
public static Subnet FromBytes(byte[] lowAddressBytes, byte[] highAddressBytes)
public static bool TryFromBytes(byte[] lowAddressBytes, byte[] highAddressBytes, out Subnet subnet)
parse string¶
It is pretty common to tote around a string
as a representation of a subnet, but you needn’t do such any longer. Assuming said string subnetString
represents something roughly similar to a CIDR Arcus will hand you a Subnet
.
If a representation of an IP Address string
is provided the resulting Subnet
will consist of only that address.
public static Subnet Parse(string subnetString)
public static bool TryParse(string subnetString, out Subnet subnet)
parse IPAddress string and RoutingPrefix int¶
It is also possible to build a Subnet
from an String address
and an int routingPrefix
.
public static Subnet Parse(string addressString, int routingPrefix)
public static bool TryParse(string addressString, int routingPrefix, out Subnet subnet)
parse IPAddress strings¶
A rather common way to to build a Subnet
is to provide a pair of string
objects, in this case a string lowAddress
and string highAddress
. This will construct the smallest possible Subnet
that would contain both IP addresses. Typically, the address specified are the Network and Broadcast addresses (lower and higher bounds) but this is not necessary.
public static Subnet Parse(string lowAddressString, string highAddressString)
public static bool TryParse(string lowAddressString, string highAddressString, out Subnet subnet)
Functionality¶
The Subnet
implements IIPAddressRange, IEquatable<Subnet>
, IComparable<Subnet>
, IFormattable
, and IEnumerable<IPAddress>
, and there by contains all the expected functionality it inherits.
Properties¶
In addition to the properties defined in IIPAddressRange Subnet
provides a few more additional options
IPAddress
BroadcastAddressAn alias to the
Tail
propertyIPAddress
NetmaskThe calculated netmask of the subnet, only valid for IPv4 based subnets. All others will be return a
null
valueIPAddress
NetworkPrefixAddressAn alias to the
Head
propertyint
RoutingPrefixThe routing prefix used to specify the subnet
BigInteger
UsableHostAddressCountThe number of usable addresses in the subnet ignoring both the Broadcast and Network addresses
Set Based Operations¶
Inherently a Subnet
is a range of IPAddress
objects, as such there is some set based operations available.
In addition to the set based operations promised by IIPAddressRange, the Subnet
type also has a few new options.
Contains¶
It is possible to easily check if a subnet is entirely encapsulates another subnet by using the Contains
method on the larger Subnet
.
public bool Subnet.Contains(Subnet subnet)
In the following example it is shown that 192.168.1.0/8
contains 192.168.0.0
, but as expected 192.168.1.0/8
does not contain 255.0.0.0/8
[Fact]
public void Contains_Example()
{
// Arrange
var subnetA = Subnet.Parse("192.168.1.0", 8); // 192.0.0.0 - 192.255.255.255
var subnetB = Subnet.Parse("192.168.0.0", 16); // 192.168.0.0 - 192.168.255.255
var subnetC = Subnet.Parse("255.0.0.0", 8); // 255.0.0.0 - 255.255.255.255
// Assert
Assert.True(subnetA.Contains(subnetB));
Assert.False(subnetA.Contains(subnetC));
}
Overlaps¶
It is possible determine if a subnet in any way overlaps another subnet, even if just by a single address, by using the Contains
between two subnets.
This is a transitive operation, so if Subnet A
overlaps Subnet B
then B overlaps A as well.
public bool Overlaps(Subnet subnet)
In the following example it is shown that 255.255.0.0/16
and 0.0.0.0/0
each overlap each other. However, due to their disparate address families, ::/0
and 0.0.0.0/0
do not overlap despite being equivalent ranges in the differing in integer spaces.
[Fact]
public void Overlaps_Example()
{
// Arrange
var ipv4SubnetA = Subnet.Parse("255.255.0.0", 16);
var ipv4SubnetB = Subnet.Parse("0.0.0.0", 0);
var ipv6SubnetA = Subnet.Parse("::", 0);
var ipv6SubnetB = Subnet.Parse("abcd:ef01::", 64);
// Act
Assert.True(ipv4SubnetA.Overlaps(ipv4SubnetB));
Assert.True(ipv4SubnetB.Overlaps(ipv4SubnetA));
Assert.True(ipv6SubnetA.Overlaps(ipv6SubnetB));
Assert.False(ipv6SubnetA.Overlaps(ipv4SubnetA));
}
IFormatable¶
Subnet
offers a number or preexisting formats that are accessible via the standard ToString
method provided by IFormattable
Format |
Name |
Description |
Example |
---|---|---|---|
null,
empty string,
|
Default / General format |
CIDR representation |
|
|
“friendly” format |
CIDR representaion for Subnets of size > 1 Single address representation for Subnetes of size 1 |
|
|
range format |
A range represented by NetworkPrefix - Brodcast |
|