170 lines
3.7 KiB
Go
170 lines
3.7 KiB
Go
package sockaddr
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"net"
|
|
"strings"
|
|
)
|
|
|
|
// Constants for the sizes of IPv3, IPv4, and IPv6 address types.
|
|
const (
|
|
IPv3len = 6
|
|
IPv4len = 4
|
|
IPv6len = 16
|
|
)
|
|
|
|
// IPAddr is a generic IP address interface for IPv4 and IPv6 addresses,
|
|
// networks, and socket endpoints.
|
|
type IPAddr interface {
|
|
SockAddr
|
|
AddressBinString() string
|
|
AddressHexString() string
|
|
Cmp(SockAddr) int
|
|
CmpAddress(SockAddr) int
|
|
CmpPort(SockAddr) int
|
|
FirstUsable() IPAddr
|
|
Host() IPAddr
|
|
IPPort() IPPort
|
|
LastUsable() IPAddr
|
|
Maskbits() int
|
|
NetIP() *net.IP
|
|
NetIPMask() *net.IPMask
|
|
NetIPNet() *net.IPNet
|
|
Network() IPAddr
|
|
Octets() []int
|
|
}
|
|
|
|
// IPPort is the type for an IP port number for the TCP and UDP IP transports.
|
|
type IPPort uint16
|
|
|
|
// IPPrefixLen is a typed integer representing the prefix length for a given
|
|
// IPAddr.
|
|
type IPPrefixLen byte
|
|
|
|
// ipAddrAttrMap is a map of the IPAddr type-specific attributes.
|
|
var ipAddrAttrMap map[AttrName]func(IPAddr) string
|
|
var ipAddrAttrs []AttrName
|
|
|
|
func init() {
|
|
ipAddrInit()
|
|
}
|
|
|
|
// NewIPAddr creates a new IPAddr from a string. Returns nil if the string is
|
|
// not an IPv4 or an IPv6 address.
|
|
func NewIPAddr(addr string) (IPAddr, error) {
|
|
ipv4Addr, err := NewIPv4Addr(addr)
|
|
if err == nil {
|
|
return ipv4Addr, nil
|
|
}
|
|
|
|
ipv6Addr, err := NewIPv6Addr(addr)
|
|
if err == nil {
|
|
return ipv6Addr, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("invalid IPAddr %v", addr)
|
|
}
|
|
|
|
// IPAddrAttr returns a string representation of an attribute for the given
|
|
// IPAddr.
|
|
func IPAddrAttr(ip IPAddr, selector AttrName) string {
|
|
fn, found := ipAddrAttrMap[selector]
|
|
if !found {
|
|
return ""
|
|
}
|
|
|
|
return fn(ip)
|
|
}
|
|
|
|
// IPAttrs returns a list of attributes supported by the IPAddr type
|
|
func IPAttrs() []AttrName {
|
|
return ipAddrAttrs
|
|
}
|
|
|
|
// MustIPAddr is a helper method that must return an IPAddr or panic on invalid
|
|
// input.
|
|
func MustIPAddr(addr string) IPAddr {
|
|
ip, err := NewIPAddr(addr)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err))
|
|
}
|
|
return ip
|
|
}
|
|
|
|
// ipAddrInit is called once at init()
|
|
func ipAddrInit() {
|
|
// Sorted for human readability
|
|
ipAddrAttrs = []AttrName{
|
|
"host",
|
|
"address",
|
|
"port",
|
|
"netmask",
|
|
"network",
|
|
"mask_bits",
|
|
"binary",
|
|
"hex",
|
|
"first_usable",
|
|
"last_usable",
|
|
"octets",
|
|
}
|
|
|
|
ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{
|
|
"address": func(ip IPAddr) string {
|
|
return ip.NetIP().String()
|
|
},
|
|
"binary": func(ip IPAddr) string {
|
|
return ip.AddressBinString()
|
|
},
|
|
"first_usable": func(ip IPAddr) string {
|
|
return ip.FirstUsable().String()
|
|
},
|
|
"hex": func(ip IPAddr) string {
|
|
return ip.AddressHexString()
|
|
},
|
|
"host": func(ip IPAddr) string {
|
|
return ip.Host().String()
|
|
},
|
|
"last_usable": func(ip IPAddr) string {
|
|
return ip.LastUsable().String()
|
|
},
|
|
"mask_bits": func(ip IPAddr) string {
|
|
return fmt.Sprintf("%d", ip.Maskbits())
|
|
},
|
|
"netmask": func(ip IPAddr) string {
|
|
switch v := ip.(type) {
|
|
case IPv4Addr:
|
|
ipv4Mask := IPv4Addr{
|
|
Address: IPv4Address(v.Mask),
|
|
Mask: IPv4HostMask,
|
|
}
|
|
return ipv4Mask.String()
|
|
case IPv6Addr:
|
|
ipv6Mask := new(big.Int)
|
|
ipv6Mask.Set(v.Mask)
|
|
ipv6MaskAddr := IPv6Addr{
|
|
Address: IPv6Address(ipv6Mask),
|
|
Mask: ipv6HostMask,
|
|
}
|
|
return ipv6MaskAddr.String()
|
|
default:
|
|
return fmt.Sprintf("<unsupported type: %T>", ip)
|
|
}
|
|
},
|
|
"network": func(ip IPAddr) string {
|
|
return ip.Network().NetIP().String()
|
|
},
|
|
"octets": func(ip IPAddr) string {
|
|
octets := ip.Octets()
|
|
octetStrs := make([]string, 0, len(octets))
|
|
for _, octet := range octets {
|
|
octetStrs = append(octetStrs, fmt.Sprintf("%d", octet))
|
|
}
|
|
return strings.Join(octetStrs, " ")
|
|
},
|
|
"port": func(ip IPAddr) string {
|
|
return fmt.Sprintf("%d", ip.IPPort())
|
|
},
|
|
}
|
|
}
|