// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// IP address manipulations//// IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes.// An IPv4 address can be converted to an IPv6 address by// adding a canonical prefix (10 zeros, 2 0xFFs).// This library accepts either size of byte slice but always// returns 16-byte addresses.package netimport ()// IP address lengths (bytes).const (IPv4len = 4IPv6len = 16)// An IP is a single IP address, a slice of bytes.// Functions in this package accept either 4-byte (IPv4)// or 16-byte (IPv6) slices as input.//// Note that in this documentation, referring to an// IP address as an IPv4 address or an IPv6 address// is a semantic property of the address, not just the// length of the byte slice: a 16-byte slice can still// be an IPv4 address.typeIP []byte// An IPMask is a bitmask that can be used to manipulate// IP addresses for IP addressing and routing.//// See type [IPNet] and func [ParseCIDR] for details.typeIPMask []byte// An IPNet represents an IP network.typeIPNetstruct { IP IP// network number Mask IPMask// network mask}// IPv4 returns the IP address (in 16-byte form) of the// IPv4 address a.b.c.d.func (, , , byte) IP { := make(IP, IPv6len)copy(, v4InV6Prefix) [12] = [13] = [14] = [15] = return}var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}// IPv4Mask returns the IP mask (in 4-byte form) of the// IPv4 mask a.b.c.d.func (, , , byte) IPMask { := make(IPMask, IPv4len) [0] = [1] = [2] = [3] = return}// CIDRMask returns an [IPMask] consisting of 'ones' 1 bits// followed by 0s up to a total length of 'bits' bits.// For a mask of this form, CIDRMask is the inverse of [IPMask.Size].func (, int) IPMask {if != 8*IPv4len && != 8*IPv6len {returnnil }if < 0 || > {returnnil } := / 8 := make(IPMask, ) := uint()for := 0; < ; ++ {if >= 8 { [] = 0xff -= 8continue } [] = ^byte(0xff >> ) = 0 }return}// Well-known IPv4 addressesvar (IPv4bcast = IPv4(255, 255, 255, 255) // limited broadcastIPv4allsys = IPv4(224, 0, 0, 1) // all systemsIPv4allrouter = IPv4(224, 0, 0, 2) // all routersIPv4zero = IPv4(0, 0, 0, 0) // all zeros)// Well-known IPv6 addressesvar (IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}IPv6unspecified = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}IPv6interfacelocalallnodes = IP{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}IPv6linklocalallnodes = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02})// IsUnspecified reports whether ip is an unspecified address, either// the IPv4 address "0.0.0.0" or the IPv6 address "::".func ( IP) () bool {return .Equal(IPv4zero) || .Equal(IPv6unspecified)}// IsLoopback reports whether ip is a loopback address.func ( IP) () bool {if := .To4(); != nil {return [0] == 127 }return .Equal(IPv6loopback)}// IsPrivate reports whether ip is a private address, according to// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).func ( IP) () bool {if := .To4(); != nil {// Following RFC 1918, Section 3. Private Address Space which says: // The Internet Assigned Numbers Authority (IANA) has reserved the // following three blocks of the IP address space for private internets: // 10.0.0.0 - 10.255.255.255 (10/8 prefix) // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)return [0] == 10 || ([0] == 172 && [1]&0xf0 == 16) || ([0] == 192 && [1] == 168) }// Following RFC 4193, Section 8. IANA Considerations which says: // The IANA has assigned the FC00::/7 prefix to "Unique Local Unicast".returnlen() == IPv6len && [0]&0xfe == 0xfc}// IsMulticast reports whether ip is a multicast address.func ( IP) () bool {if := .To4(); != nil {return [0]&0xf0 == 0xe0 }returnlen() == IPv6len && [0] == 0xff}// IsInterfaceLocalMulticast reports whether ip is// an interface-local multicast address.func ( IP) () bool {returnlen() == IPv6len && [0] == 0xff && [1]&0x0f == 0x01}// IsLinkLocalMulticast reports whether ip is a link-local// multicast address.func ( IP) () bool {if := .To4(); != nil {return [0] == 224 && [1] == 0 && [2] == 0 }returnlen() == IPv6len && [0] == 0xff && [1]&0x0f == 0x02}// IsLinkLocalUnicast reports whether ip is a link-local// unicast address.func ( IP) () bool {if := .To4(); != nil {return [0] == 169 && [1] == 254 }returnlen() == IPv6len && [0] == 0xfe && [1]&0xc0 == 0x80}// IsGlobalUnicast reports whether ip is a global unicast// address.//// The identification of global unicast addresses uses address type// identification as defined in RFC 1122, RFC 4632 and RFC 4291 with// the exception of IPv4 directed broadcast addresses.// It returns true even if ip is in IPv4 private address space or// local IPv6 unicast address space.func ( IP) () bool {return (len() == IPv4len || len() == IPv6len) && !.Equal(IPv4bcast) && !.IsUnspecified() && !.IsLoopback() && !.IsMulticast() && !.IsLinkLocalUnicast()}// Is p all zeros?func isZeros( IP) bool {for := 0; < len(); ++ {if [] != 0 {returnfalse } }returntrue}// To4 converts the IPv4 address ip to a 4-byte representation.// If ip is not an IPv4 address, To4 returns nil.func ( IP) () IP {iflen() == IPv4len {return }iflen() == IPv6len &&isZeros([0:10]) && [10] == 0xff && [11] == 0xff {return [12:16] }returnnil}// To16 converts the IP address ip to a 16-byte representation.// If ip is not an IP address (it is the wrong length), To16 returns nil.func ( IP) () IP {iflen() == IPv4len {returnIPv4([0], [1], [2], [3]) }iflen() == IPv6len {return }returnnil}// Default route masks for IPv4.var ( classAMask = IPv4Mask(0xff, 0, 0, 0) classBMask = IPv4Mask(0xff, 0xff, 0, 0) classCMask = IPv4Mask(0xff, 0xff, 0xff, 0))// DefaultMask returns the default IP mask for the IP address ip.// Only IPv4 addresses have default masks; DefaultMask returns// nil if ip is not a valid IPv4 address.func ( IP) () IPMask {if = .To4(); == nil {returnnil }switch {case [0] < 0x80:returnclassAMaskcase [0] < 0xC0:returnclassBMaskdefault:returnclassCMask }}func allFF( []byte) bool {for , := range {if != 0xff {returnfalse } }returntrue}// Mask returns the result of masking the IP address ip with mask.func ( IP) ( IPMask) IP {iflen() == IPv6len && len() == IPv4len && allFF([:12]) { = [12:] }iflen() == IPv4len && len() == IPv6len && bytealg.Equal([:12], v4InV6Prefix) { = [12:] } := len()if != len() {returnnil } := make(IP, )for := 0; < ; ++ { [] = [] & [] }return}// String returns the string form of the IP address ip.// It returns one of 4 forms:// - "<nil>", if ip has length 0// - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address// - IPv6 conforming to RFC 5952 ("2001:db8::1"), if ip is a valid IPv6 address// - the hexadecimal form of ip, without punctuation, if no other cases applyfunc ( IP) () string {iflen() == 0 {return"<nil>" }iflen() != IPv4len && len() != IPv6len {return"?" + hexString() }var []byteswitchlen() {caseIPv4len:const = len("255.255.255.255") = make([]byte, 0, )caseIPv6len:const = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") = make([]byte, 0, ) } = .appendTo()returnstring()}func hexString( []byte) string { := make([]byte, len()*2)for , := range { [*2], [*2+1] = hexDigit[>>4], hexDigit[&0xf] }returnstring()}// ipEmptyString is like ip.String except that it returns// an empty string when ip is unset.func ipEmptyString( IP) string {iflen() == 0 {return"" }return .String()}// appendTo appends the string representation of ip to b and returns the expanded b// If len(ip) != IPv4len or IPv6len, it appends nothing.func ( IP) ( []byte) []byte {// If IPv4, use dotted notation.if := .To4(); len() == IPv4len { = } , := netip.AddrFromSlice()return .AppendTo()}// AppendText implements the [encoding.TextAppender] interface.// The encoding is the same as returned by [IP.String], with one exception:// When len(ip) is zero, it appends nothing.func ( IP) ( []byte) ([]byte, error) {iflen() == 0 {return , nil }iflen() != IPv4len && len() != IPv6len {return , &AddrError{Err: "invalid IP address", Addr: hexString()} }return .appendTo(), nil}// MarshalText implements the [encoding.TextMarshaler] interface.// The encoding is the same as returned by [IP.String], with one exception:// When len(ip) is zero, it returns an empty slice.func ( IP) () ([]byte, error) {// 24 is satisfied with all IPv4 addresses and short IPv6 addresses , := .AppendText(make([]byte, 0, 24))if != nil {returnnil, }return , nil}// UnmarshalText implements the [encoding.TextUnmarshaler] interface.// The IP address is expected in a form accepted by [ParseIP].func ( *IP) ( []byte) error {iflen() == 0 { * = nilreturnnil } := string() := ParseIP()if == nil {return &ParseError{Type: "IP address", Text: } } * = returnnil}// Equal reports whether ip and x are the same IP address.// An IPv4 address and that same address in IPv6 form are// considered to be equal.func ( IP) ( IP) bool {iflen() == len() {returnbytealg.Equal(, ) }iflen() == IPv4len && len() == IPv6len {returnbytealg.Equal([0:12], v4InV6Prefix) && bytealg.Equal(, [12:]) }iflen() == IPv6len && len() == IPv4len {returnbytealg.Equal([0:12], v4InV6Prefix) && bytealg.Equal([12:], ) }returnfalse}func ( IP) ( IP) bool {return .To4() != nil && .To4() != nil || .To16() != nil && .To4() == nil && .To16() != nil && .To4() == nil}// If mask is a sequence of 1 bits followed by 0 bits,// return the number of 1 bits.func simpleMaskLength( IPMask) int {varintfor , := range {if == 0xff { += 8continue }// found non-ff byte // count 1 bitsfor &0x80 != 0 { ++ <<= 1 }// rest must be 0 bitsif != 0 {return -1 }for ++; < len(); ++ {if [] != 0 {return -1 } }break }return}// Size returns the number of leading ones and total bits in the mask.// If the mask is not in the canonical form--ones followed by zeros--then// Size returns 0, 0.func ( IPMask) () (, int) { , = simpleMaskLength(), len()*8if == -1 {return0, 0 }return}// String returns the hexadecimal form of m, with no punctuation.func ( IPMask) () string {iflen() == 0 {return"<nil>" }returnhexString()}func networkNumberAndMask( *IPNet) ( IP, IPMask) {if = .IP.To4(); == nil { = .IPiflen() != IPv6len {returnnil, nil } } = .Maskswitchlen() {caseIPv4len:iflen() != IPv4len {returnnil, nil }caseIPv6len:iflen() == IPv4len { = [12:] }default:returnnil, nil }return}// Contains reports whether the network includes ip.func ( *IPNet) ( IP) bool { , := networkNumberAndMask()if := .To4(); != nil { = } := len()if != len() {returnfalse }for := 0; < ; ++ {if []&[] != []&[] {returnfalse } }returntrue}// Network returns the address's network name, "ip+net".func ( *IPNet) () string { return"ip+net" }// String returns the CIDR notation of n like "192.0.2.0/24"// or "2001:db8::/48" as defined in RFC 4632 and RFC 4291.// If the mask is not in the canonical form, it returns the// string which consists of an IP address, followed by a slash// character and a mask expressed as hexadecimal form with no// punctuation like "198.51.100.0/c000ff00".func ( *IPNet) () string {if == nil {return"<nil>" } , := networkNumberAndMask()if == nil || == nil {return"<nil>" } := simpleMaskLength()if == -1 {return .String() + "/" + .String() }return .String() + "/" + itoa.Uitoa(uint())}// ParseIP parses s as an IP address, returning the result.// The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6// ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form.// If s is not a valid textual representation of an IP address,// ParseIP returns nil. The returned address is always 16 bytes,// IPv4 addresses are returned in IPv4-mapped IPv6 form.func ( string) IP {if , := parseIP(); {returnIP([:]) }returnnil}func parseIP( string) ([16]byte, bool) { , := netip.ParseAddr()if != nil || .Zone() != "" {return [16]byte{}, false }return .As16(), true}// ParseCIDR parses s as a CIDR notation IP address and prefix length,// like "192.0.2.0/24" or "2001:db8::/32", as defined in// RFC 4632 and RFC 4291.//// It returns the IP address and the network implied by the IP and// prefix length.// For example, ParseCIDR("192.0.2.1/24") returns the IP address// 192.0.2.1 and the network 192.0.2.0/24.func ( string) (IP, *IPNet, error) { , , := stringslite.Cut(, "/")if ! {returnnil, nil, &ParseError{Type: "CIDR address", Text: } } , := netip.ParseAddr()if != nil || .Zone() != "" {returnnil, nil, &ParseError{Type: "CIDR address", Text: } } , , := dtoi()if ! || != len() || < 0 || > .BitLen() {returnnil, nil, &ParseError{Type: "CIDR address", Text: } } := CIDRMask(, .BitLen()) := .As16()returnIP([:]), &IPNet{IP: IP([:]).Mask(), Mask: }, nil}func copyIP( IP) IP { := make(IP, len())copy(, )return}
The pages are generated with Goldsv0.7.3. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.