netx

package
v0.1.36 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 19, 2026 License: GPL-3.0 Imports: 5 Imported by: 0

README

netx

netx is a production-ready IPv4 and IPv6 network subnetting toolkit for Go, built exclusively on the standard library. It provides a clean, consistent API for CIDR parsing, subnet address calculation, FLSM (Fixed-Length Subnet Masking), VLSM (Variable-Length Subnet Masking), and general-purpose network utility functions.

Designed for backend infrastructure services, DevOps tooling, Kubernetes networking automation, and cloud infrastructure management.


Table of Contents


Overview

netx eliminates the boilerplate of writing subnet calculations from scratch. It addresses common pain points like:

  • CIDR parsing — parse any CIDR and get all addressing attributes in one call
  • Subnet splitting — divide a block into equal-sized sub-networks (FLSM)
  • Efficient allocation — allocate right-sized subnets per host requirement (VLSM)
  • Overlap detection — check whether two networks share any addresses
  • IPv6 support — the same API works identically for IPv6 with *big.Int host counts

Subnetting Concepts

CIDR Notation

A CIDR (Classless Inter-Domain Routing) address like 10.0.0.0/24 describes:

Part Meaning
10.0.0.0 Network (base) address — all host bits are zero
/24 Prefix length — number of bits in the network portion
10.0.0.255 Broadcast address — all host bits are one
10.0.0.110.0.0.254 Usable host range
254 Usable host count (2^(32-24) - 2)
FLSM vs VLSM
FLSM VLSM
Stands for Fixed-Length Subnet Masking Variable-Length Subnet Masking
Subnet sizes All equal Sized to individual requirements
Address waste Higher (over-allocates) Lower (right-sizes each subnet)
Use case Simple networks, uniform departments Complex networks with mixed host counts
Example Split 10.0.0.0/24 → four /26s Allocate /25, /26, /28 from 10.0.0.0/24
FLSM example
10.0.0.0/24 → split into /26:

 10.0.0.0/26    ┌────────────────────┐
                │  10.0.0.1 – .62   │  62 hosts
 10.0.0.64/26   ├────────────────────┤
                │ 10.0.0.65 – .126  │  62 hosts
 10.0.0.128/26  ├────────────────────┤
                │ 10.0.0.129 – .190 │  62 hosts
 10.0.0.192/26  └────────────────────┘
                │ 10.0.0.193 – .254 │  62 hosts
VLSM example
10.0.0.0/24 → DivideByHosts([100, 50, 10]):

 10.0.0.0/25   ┌────────────────────────────┐
               │ 10.0.0.1  – 10.0.0.126    │  126 hosts (satisfies 100)
 10.0.0.128/26 ├────────────────────────────┤
               │ 10.0.0.129 – 10.0.0.190   │   62 hosts (satisfies 50)
 10.0.0.192/28 ├────────────────────────────┤
               │ 10.0.0.193 – 10.0.0.206   │   14 hosts (satisfies 10)
               └────────────────────────────┘
                 10.0.0.207 – 10.0.0.255     (unused)

Package Architecture

File Responsibility
type.go Subnet struct definition (unexported fields) and accessor methods
parse.go ParseCIDR and MustParseCIDR entry points
subnet.go Address arithmetic: network/broadcast/host-range calculation
flsm.go Split and SplitIntoN — equal-size subnet division
vlsm.go DivideByHosts — VLSM host-based allocation
utilities.go Contains, Overlaps, NetworkSize, HostCount, PrefixForHosts, NextSubnet
doc.go Package-level GoDoc documentation

Installation

go get github.com/polarixa/replify

Import the package:

import "github.com/polarixa/replify/pkg/netx"

Requirements: Go 1.24.0 or higher. No external dependencies.


API Reference

CIDR Parsing
// Parse a CIDR string and compute all addressing attributes.
sub, err := netx.ParseCIDR("192.168.1.0/24")

// Panics on invalid input — suitable for init() or tests.
sub := netx.MustParseCIDR("10.0.0.0/8")
Subnet Accessors

All Subnet fields are unexported. Read them through accessor methods:

sub, _ := netx.ParseCIDR("192.168.1.0/24")

sub.IPNet()            *net.IPNet     // underlying net.IPNet
sub.NetworkAddress()   net.IP         // 192.168.1.0
sub.BroadcastAddress() net.IP         // 192.168.1.255
sub.FirstHost()        net.IP         // 192.168.1.1
sub.LastHost()         net.IP         // 192.168.1.254
sub.TotalHosts()       *big.Int       // 254
sub.Prefix()           int            // 24
sub.String()           string         // "192.168.1.0/24"
FLSM — Equal Subnet Splitting
base := netx.MustParseCIDR("10.0.0.0/24").IPNet()

// Split into equal /26 subnets
subnets, err := netx.Split(base, 26)
// → [10.0.0.0/26, 10.0.0.64/26, 10.0.0.128/26, 10.0.0.192/26]

// Split into exactly N equal parts (N must be a power of 2)
subnets, err = netx.SplitIntoN(base, 4)
// → same four /26 subnets

// Convert to strings
strs := netx.SubnetsToStrings(subnets)
VLSM — Host-Based Allocation
base := netx.MustParseCIDR("10.0.0.0/24").IPNet()

// Allocate subnets sized to satisfy each host requirement.
// Requirements are automatically sorted largest-first.
subnets, err := netx.DivideByHosts(base, []int{100, 50, 10})
// subnets[0]: 10.0.0.0/25   — 126 usable hosts (satisfies 100)
// subnets[1]: 10.0.0.128/26 —  62 usable hosts (satisfies  50)
// subnets[2]: 10.0.0.192/28 —  14 usable hosts (satisfies  10)

// Convert to strings
strs := netx.AllocatedSubnetsToStrings(subnets)
Utility Functions
// Check whether an IP belongs to a network
_, n, _ := net.ParseCIDR("10.0.0.0/8")
netx.Contains(n, net.ParseIP("10.1.2.3"))  // true

// Check whether two networks overlap
subA := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subB := netx.MustParseCIDR("10.0.0.128/25").IPNet()
netx.Overlaps(subA, subB)  // true

// Total address count (including network + broadcast)
netx.NetworkSize(n)  // *big.Int — e.g. 256 for /24

// Usable host count for a prefix
netx.HostCount(24, 32)  // 254 (IPv4 /24)
netx.HostCount(31, 32)  // 2   (RFC 3021 point-to-point)
netx.HostCount(32, 32)  // 1   (single host)

// Smallest prefix providing ≥ N usable hosts
netx.PrefixForHosts(100, 32)  // 25 → /25 provides 126 hosts
netx.PrefixForHosts(254, 32)  // 24 → /24 provides 254 hosts

// Next contiguous subnet of a given prefix
base := netx.MustParseCIDR("10.0.0.0/26").IPNet()
next, _ := netx.NextSubnet(base, 26)
fmt.Println(next)  // "10.0.0.64/26"

Usage Examples

Parse a CIDR and print its attributes
package main

import (
    "fmt"
    "github.com/polarixa/replify/pkg/netx"
)

func main() {
    sub, err := netx.ParseCIDR("10.128.0.0/18")
    if err != nil {
        panic(err)
    }
    fmt.Printf("Network:    %s\n", sub.NetworkAddress())
    fmt.Printf("Broadcast:  %s\n", sub.BroadcastAddress())
    fmt.Printf("First host: %s\n", sub.FirstHost())
    fmt.Printf("Last host:  %s\n", sub.LastHost())
    fmt.Printf("Hosts:      %s\n", sub.TotalHosts())
    fmt.Printf("Prefix:     /%d\n", sub.Prefix())
}
// Network:    10.128.0.0
// Broadcast:  10.191.255.255
// First host: 10.128.0.1
// Last host:  10.191.255.254
// Hosts:      16382
// Prefix:     /18
Split a block into equal subnets (FLSM)
base := netx.MustParseCIDR("172.16.0.0/20").IPNet()
subs, err := netx.Split(base, 24)
if err != nil {
    panic(err)
}
for _, s := range subs {
    fmt.Println(s)
}
// 172.16.0.0/24
// 172.16.1.0/24
// ...
// 172.16.15.0/24
Allocate right-sized subnets per department (VLSM)
base := netx.MustParseCIDR("10.0.0.0/22").IPNet()
subnets, err := netx.DivideByHosts(base, []int{500, 200, 100, 50, 25})
if err != nil {
    panic(err)
}
for _, s := range subnets {
    fmt.Printf("%s  hosts=%d\n", s.String(), s.TotalHosts())
}
Detect overlapping networks
networks := []string{
    "10.0.0.0/24",
    "10.0.0.128/25",
    "192.168.1.0/24",
}
parsed := make([]*net.IPNet, len(networks))
for i, c := range networks {
    parsed[i] = netx.MustParseCIDR(c).IPNet()
}
for i := 0; i < len(parsed); i++ {
    for j := i + 1; j < len(parsed); j++ {
        if netx.Overlaps(parsed[i], parsed[j]) {
            fmt.Printf("OVERLAP: %s ↔ %s\n", networks[i], networks[j])
        }
    }
}
// OVERLAP: 10.0.0.0/24 ↔ 10.0.0.128/25

Real-World DevOps Scenarios

IP Address Planning
// Divide a company's 10.0.0.0/16 block across regions and teams.
corporate := netx.MustParseCIDR("10.0.0.0/16").IPNet()
regions, _ := netx.SplitIntoN(corporate, 4)  // four /18s

for i, region := range regions {
    teams, _ := netx.Split(region, 24)  // each /18 → 64 x /24
    fmt.Printf("Region %d: %d team networks allocated\n", i+1, len(teams))
}
Kubernetes Cluster Networking
// Allocate pod and service CIDRs from a cluster block.
clusterCIDR := netx.MustParseCIDR("100.64.0.0/14").IPNet()

// Each node gets a /24 pod CIDR; service range is a /20.
subnets, err := netx.DivideByHosts(clusterCIDR, []int{
    65534, // node pod pool (a /16)
    4094,  // service CIDR  (a /20)
})
if err != nil {
    log.Fatal(err)
}
fmt.Println("Pod pool:     ", subnets[0].String())
fmt.Println("Service CIDR: ", subnets[1].String())
Cloud Infrastructure Automation
// Validate that a user-supplied CIDR is within the VPC's address space.
vpc := netx.MustParseCIDR("172.31.0.0/16").IPNet()
userInput := "172.31.5.0/24"

sub, err := netx.ParseCIDR(userInput)
if err != nil {
    log.Fatalf("invalid CIDR: %v", err)
}
if !netx.Contains(vpc, sub.NetworkAddress()) {
    log.Fatalf("subnet %s is outside the VPC %s", userInput, vpc)
}
fmt.Println("Subnet is within the VPC ✓")
Network Monitoring and Inventory
// Report all hosts in a monitored range.
sub := netx.MustParseCIDR("192.168.10.0/27")
fmt.Printf("Monitoring range: %s – %s (%d hosts)\n",
    sub.FirstHost(), sub.LastHost(), sub.TotalHosts())

Edge Case Handling

Scenario Behaviour
/31 network (RFC 3021) TotalHosts() = 2; FirstHost() = network address
/32 single host TotalHosts() = 1; FirstHost() = LastHost() = host address
IPv6 subnet All accessors work; TotalHosts() returns *big.Int
Insufficient space (VLSM) DivideByHosts returns a descriptive error
nil arguments All utility functions return safe zero values or errors
Invalid CIDR ParseCIDR returns a wrapped error; MustParseCIDR panics
Non-power-of-2 n in SplitIntoN Returns an error

Platform Notes

netx depends only on net, math/big, and sort from the Go standard library and produces identical results on Linux, macOS, and Windows.

No OS-specific code paths exist in this package.

Engineering Guide

For a comprehensive technical reference covering real-world subnetting scenarios, binary-level calculations, efficiency analysis, VLSM vs. FLSM comparison, route summarization, multi-VLAN design, and algorithm pseudocode for all major subnetting operations, see:

SUBNETTING_GUIDE.md

Topics covered in the guide:

Section Content
Background Classful addressing → CIDR transition
Bitwise logic Subnet mask AND/OR operations, binary examples
Power-of-two rule Standard formula, /31 and /32 edge cases
FLSM walkthrough 192.168.10.0/24 divided into 4 equal /26 subnets
VLSM walkthrough 10.0.0.0/24 allocated for Sales/IT/HR/P2P with 73% less waste than FLSM
IPv4 conservation /29 public block assignment and NAT strategies
Route summarization Binary LCP, aggregating four /24s into a /22
Multi-VLAN design VLAN-to-subnet alignment, gateway assignment, security policy
Algorithm pseudocode FLSM split, VLSM allocation, route summarization, prefix search
API mapping Every concept mapped to the corresponding netx Go function

Documentation

Overview

Package netx provides a production-ready IPv4 and IPv6 network subnetting toolkit built exclusively on the Go standard library.

netx is designed for backend infrastructure services, DevOps tooling, Kubernetes networking automation, and cloud infrastructure management where programmatic subnet calculation, allocation, and validation are required.

Data Structures

The central type is Subnet, which captures all addressing attributes of a network block:

  • NetworkAddress — the lowest address (all host bits zero)
  • BroadcastAddress — the highest address (all host bits one)
  • FirstHost — first usable host address
  • LastHost — last usable host address
  • TotalHosts — number of usable addresses (*big.Int, handles IPv6)
  • Prefix — subnet prefix length (e.g. 24 for a /24)

All fields are unexported; read them using accessor methods.

CIDR Parsing

sub, err := netx.ParseCIDR("192.168.1.0/24")
// sub.NetworkAddress()   → 192.168.1.0
// sub.BroadcastAddress() → 192.168.1.255
// sub.FirstHost()        → 192.168.1.1
// sub.LastHost()         → 192.168.1.254
// sub.TotalHosts()       → 254
// sub.Prefix()           → 24

Fixed-Length Subnet Masking (FLSM)

Split divides a network into equal-sized subnets:

base := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subnets, err := netx.Split(base, 26)
// → [10.0.0.0/26, 10.0.0.64/26, 10.0.0.128/26, 10.0.0.192/26]

// Or split into exactly N equal parts (N must be a power of 2):
subnets, err = netx.SplitIntoN(base, 4)

Variable-Length Subnet Masking (VLSM)

DivideByHosts allocates subnets sized to individual host requirements:

base := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subnets, err := netx.DivideByHosts(base, []int{100, 50, 10})
// subnets[0]: 10.0.0.0/25   (126 hosts — satisfies 100)
// subnets[1]: 10.0.0.128/26 ( 62 hosts — satisfies  50)
// subnets[2]: 10.0.0.192/28 ( 14 hosts — satisfies  10)

Requirements are automatically sorted largest-first to minimise waste.

Utility Functions

netx.Contains(network, ip)    // true when ip is within network
netx.Overlaps(netA, netB)     // true when two networks share addresses
netx.NetworkSize(ipnet)       // total addresses (*big.Int, incl. network+broadcast)
netx.HostCount(prefix, bits)  // usable hosts for a given prefix
netx.PrefixForHosts(n, bits)  // smallest prefix providing ≥ n usable hosts
netx.NextSubnet(ipnet, pfx)   // next contiguous subnet of given prefix

Edge Case Handling

The package correctly handles:

  • /31 (RFC 3021 point-to-point): TotalHosts = 2, FirstHost = NetworkAddress
  • /32 single-host: TotalHosts = 1, FirstHost = LastHost = NetworkAddress
  • IPv6 subnets of any prefix length
  • VLSM allocation failure when address space is exhausted

Cross-Platform Compatibility

netx relies only on the Go standard library (net, math/big, sort) and produces identical results on Linux, macOS, and Windows.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllocatedSubnetsToStrings

func AllocatedSubnetsToStrings(subnets []Subnet) []string

AllocatedSubnetsToStrings converts a slice of Subnet to their CIDR string representations.

Parameters:

  • `subnets`: the slice of Subnet values to convert.

Returns:

A slice of CIDR strings in the same order as the input.

Example:

base := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subs, _ := netx.DivideByHosts(base, []int{100, 50, 10})
fmt.Println(netx.AllocatedSubnetsToStrings(subs))

func Contains

func Contains(network *net.IPNet, ip net.IP) bool

Contains reports whether the given IP address belongs to the network.

This is a thin, descriptive wrapper around (*net.IPNet).Contains.

Parameters:

  • `network`: the network to test against.
  • `ip`: the IP address to look up.

Returns:

A boolean value:
 - true  when ip falls within the network's address range;
 - false otherwise or when either argument is nil.

Example:

_, n, _ := net.ParseCIDR("10.0.0.0/8")
netx.Contains(n, net.ParseIP("10.1.2.3"))  // true
netx.Contains(n, net.ParseIP("192.168.1.1")) // false

func HostCount

func HostCount(prefix, bits int) *big.Int

HostCount returns the number of usable host addresses for a subnet with the given prefix length in a standard IPv4 (/8–/32) or IPv6 (/0–/128) network.

Special cases:

  • prefix == bits (e.g. /32 for IPv4): returns 1.
  • prefix == bits-1 (e.g. /31 for IPv4): returns 2.
  • all other prefixes: returns 2^(bits-prefix) - 2.

bits must be either 32 (IPv4) or 128 (IPv6). If bits is neither, the function treats the prefix as IPv4.

Parameters:

  • `prefix`: the subnet prefix length.
  • `bits`: the total number of bits in the address family (32 or 128).

Returns:

A *big.Int representing the usable host count.

Example:

netx.HostCount(24, 32) // 254
netx.HostCount(31, 32) // 2
netx.HostCount(32, 32) // 1

func NetworkSize

func NetworkSize(ipnet *net.IPNet) *big.Int

NetworkSize returns the total number of addresses in the network block (including network and broadcast addresses). For a /24 this is 256.

A *big.Int is used so that IPv6 networks, which can contain up to 2^128 addresses, are handled correctly.

Parameters:

  • `ipnet`: the network whose size to compute.

Returns:

A *big.Int representing the total address count; 0 when ipnet is nil.

Example:

_, n, _ := net.ParseCIDR("192.168.1.0/24")
netx.NetworkSize(n) // 256

func NextSubnet

func NextSubnet(ipnet *net.IPNet, newPrefix int) (*net.IPNet, error)

NextSubnet returns the next contiguous subnet of the given prefix size that immediately follows ipnet.

For example, the next /26 after 10.0.0.0/26 is 10.0.0.64/26. The function does not check whether the returned subnet is within any enclosing block.

Parameters:

  • `ipnet`: the current subnet.
  • `newPrefix`: the prefix length for the next subnet.

Returns:

(*net.IPNet, error): the next subnet, or nil and a non-nil error when
ipnet is nil or newPrefix is invalid.

Example:

base := netx.MustParseCIDR("10.0.0.0/26").IPNet()
next, err := netx.NextSubnet(base, 26)
fmt.Println(next) // "10.0.0.64/26"

func Overlaps

func Overlaps(netA, netB *net.IPNet) bool

Overlaps reports whether two network blocks share any address in common.

Two networks overlap when one contains the network address of the other, or when one is entirely contained within the other.

Parameters:

  • `netA`: the first network.
  • `netB`: the second network.

Returns:

A boolean value:
 - true  when the two networks share at least one address;
 - false when they are disjoint or either argument is nil.

Example:

_, a, _ := net.ParseCIDR("10.0.0.0/24")
_, b, _ := net.ParseCIDR("10.0.0.128/25")
netx.Overlaps(a, b) // true

_, c, _ := net.ParseCIDR("192.168.0.0/24")
netx.Overlaps(a, c) // false

func PrefixForHosts

func PrefixForHosts(hosts, bits int) int

PrefixForHosts returns the smallest prefix length that provides at least the requested number of usable host addresses.

The function searches from the most specific prefix toward the least specific, returning the first prefix for which HostCount(prefix, bits) ≥ hosts.

Parameters:

  • `hosts`: the minimum number of usable host addresses required (≥ 1).
  • `bits`: the address family bit width (32 for IPv4, 128 for IPv6).

Returns:

An int containing the prefix length, or -1 when no valid prefix can
satisfy the requirement (e.g. more than 2^30 hosts requested for IPv4).

Example:

netx.PrefixForHosts(100, 32)  // 25 (provides 126 usable hosts)
netx.PrefixForHosts(254, 32)  // 24 (provides 254 usable hosts)
netx.PrefixForHosts(255, 32)  // 23 (provides 510 usable hosts)

func Split

func Split(network *net.IPNet, newPrefix int) ([]*net.IPNet, error)

Split divides a network block into equal-sized subnets, each with the given prefix length.

The function performs Fixed-Length Subnet Masking (FLSM): all resulting subnets are the same size, and together they exactly cover the original network without gaps or overlaps.

Parameters:

  • `network`: the base network to split.
  • `newPrefix`: the prefix length for each resulting subnet; must be strictly greater than network's prefix.

Returns:

([]*net.IPNet, error): an ordered slice of subnets covering the original
network, or nil and a non-nil error when the split is invalid.

Errors:

  • When newPrefix is not larger than the base prefix.
  • When newPrefix exceeds the maximum for the address family (32 for IPv4, 128 for IPv6).

Example:

base := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subnets, err := netx.Split(base, 26)
// subnets: [10.0.0.0/26, 10.0.0.64/26, 10.0.0.128/26, 10.0.0.192/26]

func SplitIntoN

func SplitIntoN(network *net.IPNet, n int) ([]*net.IPNet, error)

SplitIntoN divides a network block into exactly n equal-sized subnets.

SplitIntoN is a convenience wrapper around Split that automatically calculates the required prefix length. n must be a power of two.

Parameters:

  • `network`: the base network to split.
  • `n`: the number of subnets to produce; must be a power of 2 and at least 2.

Returns:

([]*net.IPNet, error): n equal-sized subnets, or nil and an error.

Example:

base := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subnets, err := netx.SplitIntoN(base, 4)
// subnets: [10.0.0.0/26, 10.0.0.64/26, 10.0.0.128/26, 10.0.0.192/26]

func SubnetsToStrings

func SubnetsToStrings(nets []*net.IPNet) []string

SubnetsToStrings converts a slice of *net.IPNet to their CIDR string representations.

Parameters:

  • `nets`: the slice of networks to convert.

Returns:

A slice of CIDR strings in the same order as the input.

Example:

base := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subs, _ := netx.Split(base, 26)
fmt.Println(netx.SubnetsToStrings(subs))
// ["10.0.0.0/26" "10.0.0.64/26" "10.0.0.128/26" "10.0.0.192/26"]

Types

type Subnet

type Subnet struct {
	// contains filtered or unexported fields
}

Subnet represents a fully computed IP network block, including all derived addressing attributes. It is the central data structure of the netx package.

A Subnet is created by ParseCIDR or returned from FLSM/VLSM allocation functions. All fields are computed automatically; use the accessor methods to read them.

Subnet is safe for concurrent reads after creation. It must not be modified after construction.

func DivideByHosts

func DivideByHosts(base *net.IPNet, hostRequirements []int) ([]Subnet, error)

DivideByHosts allocates variable-length subnets from a base network to satisfy a list of host-count requirements, using Variable Length Subnet Masking (VLSM).

The algorithm:

  1. Sorts host requirements in descending order so that the largest subnets are allocated first (minimising wasted address space).
  2. For each requirement, determines the smallest prefix that provides at least the requested number of usable hosts.
  3. Allocates subnets sequentially from the base network address with no gaps.
  4. Returns an error if the base network does not have enough address space to satisfy all requirements.

Parameters:

  • `base`: the network block from which subnets are allocated.
  • `hostRequirements`: the number of usable hosts required for each subnet. Values must be ≥ 1.

Returns:

([]Subnet, error): allocated subnets in the order corresponding to the
sorted requirements, or nil and a non-nil error when allocation fails.

Example:

base := netx.MustParseCIDR("10.0.0.0/24").IPNet()
subnets, err := netx.DivideByHosts(base, []int{100, 50, 10})
// subnets[0]: 10.0.0.0/25   (126 usable hosts)
// subnets[1]: 10.0.0.128/26 ( 62 usable hosts)
// subnets[2]: 10.0.0.192/28 ( 14 usable hosts)

func MustParseCIDR

func MustParseCIDR(cidr string) Subnet

MustParseCIDR is like ParseCIDR but panics when the CIDR string is invalid.

It is intended for use in tests and program initialisation where an invalid CIDR is a programming error rather than a runtime condition.

Parameters:

  • `cidr`: a CIDR notation string (e.g. "10.0.0.0/8").

Returns:

A fully computed Subnet.

Example:

sub := netx.MustParseCIDR("10.0.0.0/8")
fmt.Println(sub.NetworkAddress()) // 10.0.0.0

func ParseCIDR

func ParseCIDR(cidr string) (Subnet, error)

ParseCIDR parses a CIDR notation string and returns a fully populated Subnet with all addressing attributes calculated.

The CIDR string must be in standard notation, for example "192.168.1.0/24" or "2001:db8::/32". Both IPv4 and IPv6 are supported.

Unlike net.ParseCIDR, which silently masks the host bits, ParseCIDR always uses the network address derived from the mask — making it safe to pass host addresses such as "192.168.1.5/24" and receive the correct network.

Parameters:

  • `cidr`: a CIDR notation string (e.g. "10.0.0.0/8").

Returns:

(Subnet, error): a fully computed Subnet on success, or a zero Subnet
and a non-nil error when the input is malformed.

Example:

sub, err := netx.ParseCIDR("192.168.1.0/24")
if err != nil {
    log.Fatal(err)
}
fmt.Println(sub.NetworkAddress())   // 192.168.1.0
fmt.Println(sub.BroadcastAddress()) // 192.168.1.255
fmt.Println(sub.FirstHost())        // 192.168.1.1
fmt.Println(sub.LastHost())         // 192.168.1.254
fmt.Println(sub.TotalHosts())       // 254

func (Subnet) BroadcastAddress

func (s Subnet) BroadcastAddress() net.IP

BroadcastAddress returns the broadcast address of the subnet.

For IPv6 subnets and /31 or /32 blocks the value is still the bitwise all-ones host address, even though broadcast semantics differ.

Returns:

A net.IP containing the highest address of the block.

Example:

sub, _ := netx.ParseCIDR("10.0.0.0/24")
fmt.Println(sub.BroadcastAddress()) // "10.0.0.255"

func (Subnet) FirstHost

func (s Subnet) FirstHost() net.IP

FirstHost returns the first usable host address.

For /31 (RFC 3021) and /32 blocks the concept of "first host" maps to networkAddress and the single host address respectively.

Returns:

A net.IP containing the first usable address.

Example:

sub, _ := netx.ParseCIDR("10.0.0.0/24")
fmt.Println(sub.FirstHost()) // "10.0.0.1"

func (Subnet) IPNet

func (s Subnet) IPNet() *net.IPNet

IPNet returns the underlying *net.IPNet for this subnet.

Returns:

A pointer to the net.IPNet representing this network block.

func (Subnet) LastHost

func (s Subnet) LastHost() net.IP

LastHost returns the last usable host address.

For /31 and /32 blocks see the note on FirstHost.

Returns:

A net.IP containing the last usable address.

Example:

sub, _ := netx.ParseCIDR("10.0.0.0/24")
fmt.Println(sub.LastHost()) // "10.0.0.254"

func (Subnet) NetworkAddress

func (s Subnet) NetworkAddress() net.IP

NetworkAddress returns the network (base) address of the subnet.

Returns:

A net.IP containing the lowest address of the block.

Example:

sub, _ := netx.ParseCIDR("10.0.0.0/24")
fmt.Println(sub.NetworkAddress()) // "10.0.0.0"

func (Subnet) Prefix

func (s Subnet) Prefix() int

Prefix returns the prefix length of the subnet (e.g. 24 for a /24).

Returns:

An int containing the prefix length.

Example:

sub, _ := netx.ParseCIDR("192.168.1.0/24")
fmt.Println(sub.Prefix()) // 24

func (Subnet) String

func (s Subnet) String() string

String returns the CIDR notation of the subnet (e.g. "10.0.0.0/24").

Returns:

A string in CIDR notation.

func (Subnet) TotalHosts

func (s Subnet) TotalHosts() *big.Int

TotalHosts returns the number of usable host addresses in the subnet.

A *big.Int is returned to handle IPv6 subnets whose host counts exceed int64 range. For typical IPv4 subnets the value fits in int64.

Special cases:

  • /31 returns 2 (RFC 3021 point-to-point link)
  • /32 returns 1

Returns:

A *big.Int representing the usable host count.

Example:

sub, _ := netx.ParseCIDR("10.0.0.0/24")
fmt.Println(sub.TotalHosts()) // 254

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL