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.

  • UnrelatedNetworkTypes

    The 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

  • UnknownParseError

    Unknown (default) Parse Error when we don’t know what happened

  • ParseErrors(errors: List(ParseError))

    Parse failed and fallback(s) also failed

  • SplitAddressFromMaskParseError

    Failed 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

  • InternallyInconsistentSubnetIpv6SubnetWithIpv4Netmask

    Internally 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

  • SubnetMetadata(
      first: IpAddress,
      last: IpAddress,
      count: Int,
      network: BitArray,
    )

    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.

Search Document