glm_cidr/cidr
Types
The relationship between an IP Address, and an Subnet
pub type AddressSubnetRelationship {
AddressIsInsideSubnet(
next: IpAddress,
subnet_metadata: SubnetMetadata,
)
AddressIsOutsideSubnet(subnet_metadata: SubnetMetadata)
UnrelatedNetworkTypes
}
Constructors
-
AddressIsInsideSubnet( next: IpAddress, subnet_metadata: SubnetMetadata, )The IP Address lies inside the Subnet. At least one of the Subnet addresses resolves to the IP Address.
-
AddressIsOutsideSubnet(subnet_metadata: SubnetMetadata)The IP Address lies outside the Subnet. None of the Subnet addresses resolve to the IP Address.
-
UnrelatedNetworkTypesThe IP Address does not have a relationship with the Subnet because the IP Address is not the same network type as the Subnet. If the IP Address is IPV4 and the Subnet is IPV6, they are unrelated. Likewise if the IPAddress is IPV6 and the Subnet is IPV4, then the two are unrelated.
MODELS
IP Address
pub type IpAddress {
Ipv4(a: Int, b: Int, c: Int, d: Int)
Ipv6(
a: Int,
b: Int,
c: Int,
d: Int,
e: Int,
f: Int,
g: Int,
h: Int,
)
}
Constructors
-
Ipv4(a: Int, b: Int, c: Int, d: Int)The IPV4 representation of an IP Address (4 8 bit integers)
-
Ipv6( a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, h: Int, )The IPV6 representation of an IP Address (8 16 bit integers)
The number of bits in a network mask.
pub type NetworkMask {
NetworkMask(count: Int)
}
Constructors
-
NetworkMask(count: Int)For IPV4, valid values are from 0 to 32 For IPV6, valid values are from 0 to 128
Parse errors are any error encontered while trying to parse user input into a subnet.
pub type ParseError {
UnknownParseError
ParseErrors(errors: List(ParseError))
SplitAddressFromMaskParseError
MaskParseError(Nil)
MaskTooLargeParseError(value: Int)
MaskTooSmallParseError(value: Int)
AddressTooManyComponentsParseError(count: Int)
AddressTooFewComponentsParseError(count: Int)
AddressComponentStringToIntParseError(s: String)
AddressComponentValueTooSmallParseError(value: Int)
AddressComponentValueTooLargeParseError(value: Int)
InternallyInconsistentSubnetIpv6SubnetWithIpv4Netmask
InternallyInconsistentSubnetIpv4SubnetWithIpv6Netmask
SubnetBitSliceParseError(
subnet: Subnet,
bitarray: BitArray,
bitarray_length: Int,
)
TargetAddressSliceParseError(
subnet: Subnet,
bitarray: BitArray,
bitarray_length: Int,
)
MalformedBitArray
NetworkSizeParseError(Nil)
NetworkAddressParseError(Nil)
IncrementIpAddressParseError
}
Constructors
-
UnknownParseErrorUnknown (default) Parse Error when we don’t know what happened
-
ParseErrors(errors: List(ParseError))Parse failed and fallback(s) also failed
-
SplitAddressFromMaskParseErrorFailed to split the address from the mask, probably missing the “/” separator
-
MaskParseError(Nil)The net mask is probably not parsing to an integer
-
MaskTooLargeParseError(value: Int)The net mask can be <= 128 for ipv6, and <= 32 for ipv4
-
MaskTooSmallParseError(value: Int)The mask must be > 0
-
AddressTooManyComponentsParseError(count: Int)After splitting the address on “:” for ipv6 or “.” for ipv4, there are too many strings
-
AddressTooFewComponentsParseError(count: Int)After splitting the address on “:” for ipv6 or “.” for ipv4, there are too few strings
-
AddressComponentStringToIntParseError(s: String)Parsing the hex string failed, max length 4 characters
-
AddressComponentValueTooSmallParseError(value: Int)Addresses must be between 0 and 216 for ipv6 or 0 and 28 for ipv4
-
AddressComponentValueTooLargeParseError(value: Int)Addresses must be between 0 and 216 for ipv6 or 0 and 28 for ipv4
-
InternallyInconsistentSubnetIpv6SubnetWithIpv4NetmaskInternally inconsistent objects, should never occur
-
InternallyInconsistentSubnetIpv4SubnetWithIpv6Netmask -
SubnetBitSliceParseError( subnet: Subnet, bitarray: BitArray, bitarray_length: Int, )Bit Parsing Errors
-
TargetAddressSliceParseError( subnet: Subnet, bitarray: BitArray, bitarray_length: Int, ) -
MalformedBitArray -
NetworkSizeParseError(Nil) -
NetworkAddressParseError(Nil) -
IncrementIpAddressParseError
A subnet defines a network using an IP Address and a NetMask
pub type Subnet {
Subnet(address: IpAddress, netmask: NetworkMask)
}
Constructors
-
Subnet(address: IpAddress, netmask: NetworkMask)An IPV4 Subnet has 32 bits for the network and host address An IPV6 Subnet has 128 bits for the network and host address
SubnetMetadata
SubnetMetadata about the usable addresses. By usable addresses, we mean the addresses that are not already allocated by the networking system, e.g. the network address and the broadcast address.
Special cases:
Note that for both IPV4 and IPV6, this function follows the following convention:
IPV4 /32 -> single host -> 1 address IPV4 /31 -> point-to-point link -> 2 addresses IPV4 /30 -> traditional point-to-point link -> 2 addresses
Single Host Route (/32 | /128)
If the entire range is masked off, e.g. /32 or /128, then this is deemed to be a single host with no subnet, and the function returns one usable address for both the first and last addresses.
Point-To-Point Links (/31 /127)
With all but one bit masked off, e.g. /32 or /127, then 2 hosts are returned. This is commonly used for the creation of a point-to-point network with two usable addresses.
Traditional Point-To-Point Links (/30 /126)
With all but two bits masked off, e.g. /30 or /126, this defines a traditional point-to-point link. The first and last addresses are allocated as network and broadcast addresses. This method returns the two remaining addresses as first and last.
Standard Subnet (/29 /64)
With three or more bits available (IPV4) or 64 bits (IPV6), the first and last addresses are and last addresses are allocated as network and broadcast addresses. This method returns the two remaining addresses as first and last. The count for IPV4 returns the count of usable addresses, .e.g 2**(32-3) for a /29 IPV4 network and 2**(128-64) for a /64 IPV4 network.
Summary
To keep things consistent, the behaviour of these special cases follows the same convention for both IPV4 and IPV6. Even though IPV6 does not have a broadcast address, we are treating it as if it did.
Examples
metadata(subnet("10.0.0.1/32"))
-> Ok(SubnetMetadata(first: 10.0.0.1, last: 10.0.0.1, count: 1)
metadata(subnet("10.0.0.1/31"))
-> Ok(SubnetMetadata(first: 10.0.0.0, last: 10.0.0.1, count: 2)
metadata(subnet("10.0.0.1/30"))
-> Ok(SubnetMetadata(first: 10.0.0.1, last: 10.0.0.2, count: 2)
metadata(subnet("10.0.0.1/24"))
-> Ok(SubnetMetadata(first: 10.0.0.1, last: 10.0.0.254, count: 254)
metadata(subnet("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF/128"))
-> Ok(SubnetMetadata(first: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF, last: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF, count: 1)
metadata(subnet("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF/127"))
-> Ok(SubnetMetadata(first: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE, last: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF, count: 2)
metadata(subnet("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF/126"))
-> Ok(SubnetMetadata(first: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFD, last: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE, count: 2)
metadata(subnet("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF/112"))
-> Ok(SubnetMetadata(first: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:1, last: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE, count: 65534)
pub type SubnetMetadata {
SubnetMetadata(
first: IpAddress,
last: IpAddress,
count: Int,
network: BitArray,
)
}
Constructors
-
Arguments
- first
-
The first usable address in the subnet.
- last
-
The last usable address in the subnet.
- count
-
The count of the usable addresses in the subnet.
- network
-
The subnet network
Values
pub fn ip_address_to_string(address: IpAddress) -> String
Convert an IP Address the same string representation that the API consumes:
Examples
let assert(ipv4_address) = Ipv4(10, 0, 0, 1)
ip_address_to_string(ipv4_address)
-> "10.0.0.1"
Note: for IPV6, no smart collapsing is done.
pub fn relationship(
subnet: Subnet,
address: String,
) -> Result(AddressSubnetRelationship, ParseError)
Given a subnet and a string with an internet address, determine the relationship between the two.
Examples
let assert Ok(subnet) = subnet("10.0.0.1/24")
relationship(subnet, "10.0.0.66")
-> Ok(AddressIsInsideSubnet(prev: 10.0.0.65, next: 10.0.0.67, subnet_metadata: { first: 10.0.0.1, last: 10.0.0.255, count: 254 } )
relationship(subnet, "10.0.2.1")
-> Ok(AddressIsOutsideSubnet, subnet_metadata: { first: 10.0.0.1, last: 10.0.0.255, count: 254 } )
relationship(subnet, ":::::::1")
-> Ok(UnrelatedNetworkTypes, subnet_metadata: { first: 10.0.0.1, last: 10.0.0.255, count: 254 } )
relationship(subnet, "i:am:a:cat")
-> Error(ParseError(...))
pub fn subnet(s: String) -> Result(Subnet, ParseError)
PUBLIC API
Given a string with an internet address and network mask delimited with a slash “/”, return a subnet.
Examples
subnet("10.0.0.1/24")
-> Ok(IPV4 SUBNET)
subnet(":::::::1/128")
-> Ok(IPV6 SUBNET)
pub fn subnet_to_string(subnet: Subnet) -> String
Convert a network subnet to string.