IPFreely.uk site logo

Niche open source software libraries that treat IP addresses as mathematical types.

Use for arithmetic, bitwise operations, iteration, and arbitrary sets and ranges of IP addresses. Useful for implementing network element management systems, DOCSIS provisioning systems, etc. Supports IPv4 & IPv6.

These libraries do not perform any network I/O but enable conversion to/from standard types that do. Types tend towards immutable values and type safety via generics. Implementations are available for the Java and Go languages.

Implementations 🔗

Java

Feature Java
API Javadoc/javadoc.io
License Apache License Version 2.0
Compatibiliy Java 8 and above
Dependency Hint uk.ipfreely:addresses
Source Code Java Maven Project
Distribution Maven Central

Go

Feature Go
API pkg.go.dev Go Reference
License Apache License Version 2.0
Compatibiliy Go 1.22.1 and above
Dependency Hint github.com/ipfreely-uk/go
Source Code Go Module
Distribution GitHub

Examples 🔗

This Go code picks a random address from a subnet:


// Random IP address from CIDR block
func randFrom[A ip.Number[A]](b ipset.Block[A]) A {
  netAddr := b.First()
  inverseMask := b.Mask().Not()
  f := netAddr.Family()
  slice := make([]byte, f.Width()/8)
  _, _ = rand.Read(slice)
  r := f.MustFromBytes(slice...)
  return r.And(inverseMask).Or(netAddr)
}
    

This Java code divides addresses into subnets of a minumum size:


/**
 * @param initial available range
 * @param count min number of allocatable addresses required
 * @return stream of subnets
 * @param <A> address family
 */
 static <A extends Address<A>> Stream<Block<A>> divide(Block<A> initial, BigInteger count) {
  Family<A> f = initial.first().family();
  Subnets<A> s = f.subnets();
  BigInteger min = f == Family.v4()
                 ? count.add(BigInteger.valueOf(2))
                 : count;
  int bits = f.width();
  int maskBits = IntStream.rangeClosed(0, bits)
                          .map(i -> bits - i)
                          .filter(m -> s.count(m).compareTo(min) >= 0)
                          .findFirst()
                          .orElseThrow(IllegalArgumentException::new);
  return initial.subnets(maskBits);
}