Hey! We've covered a lot of ground in our previous articles about net/netip. Today, we're going to do a deep dive into all the methods available on the Addr type. While we've touched on some of these before, now we'll explore each one in detail with real-world examples and use cases.
Core Methods Overview
The Addr type has quite a few methods, and understanding when to use each one is crucial for effective network programming. Let's break them down by category.
Address Creation and Validation
package main import ( "fmt" "net/netip" ) func demoAddressCreation() { // From string addr1, _ := netip.ParseAddr("192.168.1.1") // From 4-byte array addr2 := netip.AddrFrom4([4]byte{192, 168, 1, 1}) // From 16-byte array addr3 := netip.AddrFrom16([16]byte{ 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, }) fmt.Printf("From string: %v\n", addr1) fmt.Printf("From bytes4: %v\n", addr2) fmt.Printf("From bytes16: %v\n", addr3) }
Byte Array Conversions
func demoByteConversions(addr netip.Addr) { if addr.Is4() { bytes4 := addr.As4() fmt.Printf("IPv4 bytes: %v\n", bytes4) // Convert to 16-byte representation bytes16 := addr.As16() fmt.Printf("IPv4-mapped IPv6 bytes: %v\n", bytes16) } else if addr.Is6() { bytes16 := addr.As16() fmt.Printf("IPv6 bytes: %v\n", bytes16) } }
Address Type Checking
Let's create a comprehensive function to analyze an IP address:
func analyzeAddress(addr netip.Addr) { // Basic version checks fmt.Printf("Address: %v\n", addr) fmt.Printf("Is IPv4? %v\n", addr.Is4()) fmt.Printf("Is IPv6? %v\n", addr.Is6()) fmt.Printf("Is IPv4-mapped IPv6? %v\n", addr.Is4In6()) // Address properties fmt.Printf("Unmap if mapped: %v\n", addr.Unmap()) fmt.Printf("Bit length: %d\n", addr.BitLen()) fmt.Printf("Zone: %q\n", addr.Zone()) // Classification checks := []struct { name string fn func() bool }{ {"IsGlobalUnicast", addr.IsGlobalUnicast}, {"IsPrivate", addr.IsPrivate}, {"IsLoopback", addr.IsLoopback}, {"IsMulticast", addr.IsMulticast}, {"IsLinkLocalUnicast", addr.IsLinkLocalUnicast}, {"IsLinkLocalMulticast", addr.IsLinkLocalMulticast}, {"IsInterfaceLocalMulticast", addr.IsInterfaceLocalMulticast}, {"IsUnspecified", addr.IsUnspecified}, } fmt.Println("\nAddress Classifications:") for _, check := range checks { if check.fn() { fmt.Printf("- %s\n", check.name) } } }
Practical Use Cases
1. Network Interface Configuration Validator
This tool helps validate network interface configurations:
type InterfaceConfig struct { Address netip.Addr AllowedUse []string } func validateInterfaceConfig(config InterfaceConfig) []string { var issues []string // Check for unspecified address if config.Address.IsUnspecified() { issues = append(issues, "address is unspecified") } // Validate based on intended use for _, use := range config.AllowedUse { switch use { case "public": if !config.Address.IsGlobalUnicast() { issues = append(issues, "address is not suitable for public use") } if config.Address.IsPrivate() { issues = append(issues, "public interface cannot use private address") } case "private": if !config.Address.IsPrivate() && !config.Address.IsLoopback() { issues = append(issues, "private interface must use private address") } case "link-local": if !config.Address.IsLinkLocalUnicast() { issues = append(issues, "address is not link-local") } } } return issues }
2. IP Address Classifier Service
A service that provides detailed information about IP addresses:
type AddressInfo struct { Address string `json:"address"` Version int `json:"version"` Categories []string `json:"categories"` Properties []string `json:"properties"` Warnings []string `json:"warnings"` } func classifyAddress(addrStr string) (AddressInfo, error) { info := AddressInfo{ Address: addrStr, } addr, err := netip.ParseAddr(addrStr) if err != nil { return info, fmt.Errorf("invalid address: %w", err) } // Determine version if addr.Is4() { info.Version = 4 } else { info.Version = 6 } // Categorize address if addr.IsGlobalUnicast() { info.Categories = append(info.Categories, "global-unicast") if addr.IsPrivate() { info.Categories = append(info.Categories, "private") } else { info.Categories = append(info.Categories, "public") } } if addr.IsLoopback() { info.Categories = append(info.Categories, "loopback") } if addr.IsMulticast() { info.Categories = append(info.Categories, "multicast") if addr.IsLinkLocalMulticast() { info.Categories = append(info.Categories, "link-local-multicast") } if addr.IsInterfaceLocalMulticast() { info.Categories = append(info.Categories, "interface-local-multicast") } } if addr.IsLinkLocalUnicast() { info.Categories = append(info.Categories, "link-local-unicast") } // Add properties if zone := addr.Zone(); zone != "" { info.Properties = append(info.Properties, fmt.Sprintf("zone:%s", zone)) } if addr.Is4In6() { info.Properties = append(info.Properties, "ipv4-mapped-ipv6") } // Add warnings if addr.IsUnspecified() { info.Warnings = append(info.Warnings, "address is unspecified") } return info, nil }
3. Network Security Analyzer
A tool to check for potentially problematic IP configurations:
type SecurityCheck struct { Level string Issue string } func analyzeSecurityImplications(addr netip.Addr) []SecurityCheck { var checks []SecurityCheck // Check for obvious issues if addr.IsUnspecified() { checks = append(checks, SecurityCheck{ Level: "HIGH", Issue: "unspecified address should not be used in production", }) } if addr.IsLoopback() { checks = append(checks, SecurityCheck{ Level: "MEDIUM", Issue: "loopback address might indicate misconfiguration", }) } // Public service checks if addr.IsGlobalUnicast() && !addr.IsPrivate() { if addr.Is4() { checks = append(checks, SecurityCheck{ Level: "INFO", Issue: "public IPv4 address - ensure proper firewall rules", }) } else { checks = append(checks, SecurityCheck{ Level: "INFO", Issue: "public IPv6 address - ensure proper firewall rules and address privacy", }) } } // Link-local checks if addr.IsLinkLocalUnicast() { checks = append(checks, SecurityCheck{ Level: "LOW", Issue: "link-local address - verify if this is intended", }) if addr.Zone() == "" { checks = append(checks, SecurityCheck{ Level: "MEDIUM", Issue: "link-local address without zone identifier", }) } } // Multicast checks if addr.IsMulticast() { checks = append(checks, SecurityCheck{ Level: "INFO", Issue: "multicast address - verify scope and purpose", }) } return checks }
Method Deep-Dives
Compare and Less Methods
Understanding the comparison methods:
func demonstrateComparisons() { addr1 := netip.MustParseAddr("192.168.1.1") addr2 := netip.MustParseAddr("192.168.1.2") addr3 := netip.MustParseAddr("2001:db8::1") fmt.Printf("Compare 1 vs 2: %d\n", addr1.Compare(addr2)) // -1 fmt.Printf("Less 1 vs 2: %v\n", addr1.Less(addr2)) // true // Note: Comparing IPv4 and IPv6 fmt.Printf("Compare IPv4 vs IPv6: %d\n", addr1.Compare(addr3)) }
Next and Prev Methods
Working with address sequences:
func demonstrateSequencing() { start := netip.MustParseAddr("192.168.1.1") // Print next 5 addresses current := start fmt.Printf("Starting from: %v\n", current) for i := 0; i < 5; i++ { current = current.Next() fmt.Printf("Next: %v\n", current) } // Print previous 5 addresses current = start for i := 0; i < 5; i++ { current = current.Prev() fmt.Printf("Previous: %v\n", current) } }
Common Patterns and Best Practices
- Version-Specific Operations
func handleAddress(addr netip.Addr) { if addr.Is4() { // IPv4-specific code bytes4 := addr.As4() // ... } else if addr.Is6() { // IPv6-specific code bytes16 := addr.As16() // ... } }
- Safe Conversion Patterns
func convertToIPv4IfPossible(addr netip.Addr) netip.Addr { if addr.Is4In6() { return addr.Unmap() } return addr }
- Zone Handling
func handleZonedAddress(addr netip.Addr) error { if addr.IsLinkLocalUnicast() && addr.Zone() == "" { return fmt.Errorf("link-local address requires zone") } return nil }
Performance Tips
- Avoid Unnecessary String Conversions
// Bad addr.String() // Called in a loop // Good // Keep as Addr until string representation is needed
- Use As4/As16 Efficiently
// Bad bytes := addr.As16() // Always converts to 16 bytes // Good if addr.Is4() { bytes4 := addr.As4() // More efficient for IPv4 }
- Caching Results
type CachedAddr struct { addr netip.Addr isPrivate bool // Cached result } func newCachedAddr(addr netip.Addr) CachedAddr { return CachedAddr{ addr: addr, isPrivate: addr.IsPrivate(), } }
What's Next?
In our next article, we'll explore AddrPort methods in detail, building on what we've learned about Addr methods. We'll see how these types work together in real-world networking applications.
Until then, keep experimenting with these methods! They're the building blocks of robust network programming in Go.
Top comments (0)