How to Use IP Utilities for Network Address Processing in go-pantheon/fabrica-kit

The ip package in go-pantheon/fabrica-kit provides pure Go functions to detect internal IPv4 addresses, resolve service advertisement endpoints, extract client IPs from Kratos contexts, and validate private network ranges without external dependencies.

The go-pantheon/fabrica-kit repository offers a lightweight networking toolkit designed for microservices that need reliable address detection across containerized and bare-metal environments. This guide examines the IP utilities for network address processing implemented in ip/ip.go, demonstrating how to leverage InternalIP(), Extract(), and GetClientIP() for robust service discovery and client identification.

Core IP Utility Functions in fabrica-kit

The ip package exposes five primary functions that handle distinct network address processing scenarios. Each utility operates without network I/O beyond local interface enumeration, making them safe for high-frequency calls during service startup and request handling.

InternalIP: Detecting Private IPv4 Addresses

The InternalIP() function scans the host's network interfaces to return the first available private IPv4 address. It iterates through net.Interfaces(), skips downed or loopback devices, and extracts the IPv4 component from each address using ipNet.IP.To4().

This function is essential when services must auto-detect their LAN address for registration with service discovery systems or health check endpoints. If no suitable interface exists, it returns an empty string rather than an error, allowing callers to implement fallback logic.

Extract: Resolving Advertised Service Addresses

The Extract(hostPort string, lis net.Listener) function builds a resolvable host:port string suitable for service advertisement. It implements a four-step resolution strategy:

  1. Parse the input using net.SplitHostPort, returning ErrInvalidHostPort on malformed input.
  2. Override Port with the listener's actual port if available via the Port() helper.
  3. Explicit Address preservation when the host is not a wildcard (0.0.0.0, [::], ::).
  4. Private IP Fallback that enumerates interfaces and returns the first address satisfying isPrivateIP, or returns ErrNoPrivateIPFound if none exist.

This function solves the common microservice problem of binding to 0.0.0.0:0 (all interfaces, random port) while still advertising a concrete, reachable address to registries.

Port: Retrieving Dynamic Listener Ports

The Port(lis net.Listener) function extracts the concrete TCP port from a listener. It type-asserts lis.Addr() to *net.TCPAddr and returns the Port field.

This utility is critical when starting servers with net.Listen("tcp", ":0"), where the operating system assigns an available ephemeral port. The returned port enables dynamic service registration without pre-configuration.

isPrivateIP: Validating Private Address Ranges

The isPrivateIP(addr string) function validates whether an IP address falls within standard private ranges. It implements RFC1918 checks for IPv4:

  • 10.0.0.0/8 (10.x.x.x)
  • 172.16.0.0/12 (172.16.x.x - 172.31.x.x)
  • 192.168.0.0/16 (192.168.x.x)

For IPv6, it checks the unique local address prefix FC00::/7 by verifying (ip[0] & 0xfe) == 0xfc.

The function returns false for public IPs, loopback addresses, and malformed strings, making it suitable for security filtering and network segmentation logic.

GetClientIP: Extracting Client Addresses in Kratos

The GetClientIP(ctx context.Context) function extracts the originating client IP from a Kratos server context. It retrieves the transport layer via transport.FromServerContext(ctx) and inspects request headers in priority order:

  1. X-Forwarded-For: Returns the first comma-separated entry if present (handles proxy chains).
  2. X-Real-IP: Returns the value if X-Forwarded-For is absent.

This function is essential for microservices running behind reverse proxies or load balancers, where the transport connection's RemoteAddr reflects the proxy rather than the end user. It returns an empty string when the context lacks transport information or headers.

Working with Network Address Errors

The ip package defines exported sentinel errors that enable precise error handling without string parsing. These constants reside in ip/ip.go and cover the primary failure modes:

  • ErrInvalidHostPort: Returned when Extract receives a malformed host:port string that fails net.SplitHostPort.
  • ErrNoPrivateIPFound: Returned when Extract cannot locate a suitable private IP address on the host after checking all network interfaces.
  • ErrInterfaceLookup: Returned when the underlying call to net.Interfaces() fails, preventing address enumeration.
  • ErrInvalidIPFormat: Returned when isPrivateIP receives a string that cannot be parsed as an IP address.
  • ErrIPComponentOutOfRange: Returned when parsing IP components reveals values outside valid byte ranges.

Using these errors allows applications to implement differentiated retry logic, fallback to configuration values, or fail fast with clear telemetry.

Practical Implementation Examples

The following examples demonstrate common patterns for using fabrica-kit's IP utilities in production Go applications.

Example 1: Obtaining the Host's Private IP

Use InternalIP() when your service needs to register its LAN address with a service discovery registry.

package main

import (
	"fmt"
	"github.com/go-pantheon/fabrica-kit/ip"
)

func main() {
	ifaceIP := ip.InternalIP()
	if ifaceIP == "" {
		fmt.Println("No internal IP found")
		return
	}
	fmt.Println("Detected internal IP:", ifaceIP)
}

Example 2: Resolving Service Advertisement Addresses

Use Extract() when binding to wildcard addresses but advertising a concrete private IP to clients.

package main

import (
	"fmt"
	"net"
	"github.com/go-pantheon/fabrica-kit/ip"
)

func main() {
	// Bind to all interfaces with OS-assigned port
	ln, err := net.Listen("tcp", "0.0.0.0:0")
	if err != nil {
		panic(err)
	}
	defer ln.Close()

	// Resolve to private IP for service registration
	addr, err := ip.Extract("0.0.0.0:0", ln)
	if err != nil {
		// Handle ErrNoPrivateIPFound or ErrInvalidHostPort
		panic(err)
	}
	fmt.Println("Service should be advertised as:", addr)
}

Example 3: Handling Dynamic Ports

Use Port() to retrieve the actual port when using :0 for dynamic allocation.

ln, _ := net.Listen("tcp", ":0")
if port, ok := ip.Port(ln); ok {
    fmt.Printf("Listener is on port %d\n", port)
}

Example 4: Validating Client IPs in Kratos Handlers

Use GetClientIP() inside Kratos handlers to identify real client addresses behind proxies.

import (
	"context"
	"github.com/go-kratos/kratos/v2/transport"
	"github.com/go-pantheon/fabrica-kit/ip"
	pb "myapp/api"
)

func MyHandler(ctx context.Context, req *pb.MyRequest) (*pb.MyResponse, error) {
	clientIP := ip.GetClientIP(ctx)
	if clientIP != "" {
		// Log or validate the originating IP
		fmt.Printf("Request from %s\n", clientIP)
	}
	
	// ... business logic ...
	return &pb.MyResponse{}, nil
}

Summary

  • The go-pantheon/fabrica-kit ip package provides pure Go utilities for network address processing without external dependencies.
  • InternalIP() auto-detects the host's first private IPv4 address for service registration.
  • Extract() resolves wildcard bind addresses (0.0.0.0:0) into concrete private IPs suitable for service discovery.
  • Port() retrieves runtime-assigned ports from listeners created with :0.
  • isPrivateIP() validates RFC1918 IPv4 and unique local IPv6 addresses for security filtering.
  • GetClientIP() extracts real client IPs from Kratos contexts, respecting X-Forwarded-For and X-Real-IP headers.
  • All functions return exported sentinel errors (ErrNoPrivateIPFound, ErrInvalidHostPort, etc.) for robust error handling.

Frequently Asked Questions

How does fabrica-kit determine if an IP is private?

The isPrivateIP function in ip/ip.go implements RFC1918 checks for IPv4 addresses by verifying if the IP falls within the 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16 ranges using byte-wise comparison. For IPv6, it checks the unique local address prefix FC00::/7 by validating that the first byte matches (ip[0] & 0xfe) == 0xfc.

What error should I handle when no private IP is available?

When calling Extract() or InternalIP() on hosts without private network interfaces (such as public cloud instances with only public IPs), handle ErrNoPrivateIPFound. This sentinel error defined in ip/ip.go indicates that the function successfully scanned all network interfaces but failed to locate any address satisfying the private IP criteria, allowing your application to fall back to configuration values or public IP detection.

Can I use these utilities without the Kratos framework?

Yes, all IP utilities except GetClientIP function independently of the Kratos framework. InternalIP(), Extract(), Port(), and isPrivateIP() rely solely on Go's standard library (net package) and require no external dependencies. Only GetClientIP depends on Kratos's transport package to extract headers from the context, but the core network address processing capabilities remain framework-agnostic.

How do I handle dynamic port allocation with fabrica-kit?

When binding to port 0 to allow the OS to assign an available ephemeral port, use the Port() function to retrieve the actual assigned port number. First create the listener with net.Listen("tcp", ":0"), then pass that listener to ip.Port(lis) which type-asserts the address to *net.TCPAddr and returns the concrete port integer. Combine this with Extract() to build the complete host:port string for service registration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →