// 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.package netimport (_// for linkname)// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the// "tcp" and "udp" networks does not listen for both IPv4 and IPv6// connections. This is due to the fact that IPv4 traffic will not be// routed to an IPv6 socket - two separate sockets are required if// both address families are to be supported.// See inet6(4) for details.type ipStackCapabilities struct {sync.Once// guards following ipv4Enabled bool ipv6Enabled bool ipv4MappedIPv6Enabled bool}var ipStackCaps ipStackCapabilities// supportsIPv4 reports whether the platform supports IPv4 networking// functionality.func supportsIPv4() bool {ipStackCaps.Once.Do(ipStackCaps.probe)returnipStackCaps.ipv4Enabled}// supportsIPv6 reports whether the platform supports IPv6 networking// functionality.func supportsIPv6() bool {ipStackCaps.Once.Do(ipStackCaps.probe)returnipStackCaps.ipv6Enabled}// supportsIPv4map reports whether the platform supports mapping an// IPv4 address inside an IPv6 address at transport layer// protocols. See RFC 4291, RFC 4038 and RFC 3493.func supportsIPv4map() bool {// Some operating systems provide no support for mapping IPv4 // addresses to IPv6, and a runtime check is unnecessary.switchruntime.GOOS {case"dragonfly", "openbsd":returnfalse }ipStackCaps.Once.Do(ipStackCaps.probe)returnipStackCaps.ipv4MappedIPv6Enabled}// An addrList represents a list of network endpoint addresses.type addrList []Addr// isIPv4 reports whether addr contains an IPv4 address.func isIPv4( Addr) bool {switch addr := .(type) {case *TCPAddr:return .IP.To4() != nilcase *UDPAddr:return .IP.To4() != nilcase *IPAddr:return .IP.To4() != nil }returnfalse}// isNotIPv4 reports whether addr does not contain an IPv4 address.func isNotIPv4( Addr) bool { return !isIPv4() }// forResolve returns the most appropriate address in address for// a call to ResolveTCPAddr, ResolveUDPAddr, or ResolveIPAddr.// IPv4 is preferred, unless addr contains an IPv6 literal.func ( addrList) (, string) Addr {varboolswitch {case"ip":// IPv6 literal (addr does NOT contain a port) = bytealg.CountString(, ':') > 0case"tcp", "udp":// IPv6 literal. (addr contains a port, so look for '[') = bytealg.CountString(, '[') > 0 }if {return .first(isNotIPv4) }return .first(isIPv4)}// first returns the first address which satisfies strategy, or if// none do, then the first address of any kind.func ( addrList) ( func(Addr) bool) Addr {for , := range {if () {return } }return [0]}// partition divides an address list into two categories, using a// strategy function to assign a boolean label to each address.// The first address, and any with a matching label, are returned as// primaries, while addresses with the opposite label are returned// as fallbacks. For non-empty inputs, primaries is guaranteed to be// non-empty.func ( addrList) ( func(Addr) bool) (, addrList) {varboolfor , := range { := ()if == 0 || == { = = append(, ) } else { = append(, ) } }return}// filterAddrList applies a filter to a list of IP addresses,// yielding a list of Addr objects. Known filters are nil, ipv4only,// and ipv6only. It returns every address when the filter is nil.// The result contains at least one address when error is nil.func filterAddrList( func(IPAddr) bool, []IPAddr, func(IPAddr) Addr, string) (addrList, error) {varaddrListfor , := range {if == nil || () { = append(, ()) } }iflen() == 0 {returnnil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: } }return , nil}// ipv4only reports whether addr is an IPv4 address.func ipv4only( IPAddr) bool {return .IP.To4() != nil}// ipv6only reports whether addr is an IPv6 address except IPv4-mapped IPv6 address.func ipv6only( IPAddr) bool {returnlen(.IP) == IPv6len && .IP.To4() == nil}// SplitHostPort splits a network address of the form "host:port",// "host%zone:port", "[host]:port" or "[host%zone]:port" into host or// host%zone and port.//// A literal IPv6 address in hostport must be enclosed in square// brackets, as in "[::1]:80", "[::1%lo0]:80".//// See func Dial for a description of the hostport parameter, and host// and port results.func ( string) (, string, error) {const ( = "missing port in address" = "too many colons in address" ) := func(, string) (, string, error) {return"", "", &AddrError{Err: , Addr: } } , := 0, 0// The port starts after the last colon. := bytealg.LastIndexByteString(, ':')if < 0 {return (, ) }if [0] == '[' {// Expect the first ']' just before the last ':'. := bytealg.IndexByteString(, ']')if < 0 {return (, "missing ']' in address") }switch + 1 {caselen():// There can't be a ':' behind the ']' now.return (, )case :// The expected result.default:// Either ']' isn't followed by a colon, or it is // followed by a colon that is not the last one.if [+1] == ':' {return (, ) }return (, ) } = [1:] , = 1, +1// there can't be a '[' resp. ']' before these positions } else { = [:]ifbytealg.IndexByteString(, ':') >= 0 {return (, ) } }ifbytealg.IndexByteString([:], '[') >= 0 {return (, "unexpected '[' in address") }ifbytealg.IndexByteString([:], ']') >= 0 {return (, "unexpected ']' in address") } = [+1:]return , , nil}func splitHostZone( string) (, string) {// The IPv6 scoped addressing zone identifier starts after the // last percent sign.if := bytealg.LastIndexByteString(, '%'); > 0 { , = [:], [+1:] } else { = }return}// JoinHostPort combines host and port into a network address of the// form "host:port". If host contains a colon, as found in literal// IPv6 addresses, then JoinHostPort returns "[host]:port".//// See func Dial for a description of the host and port parameters.func (, string) string {// We assume that host is a literal IPv6 address if host has // colons.ifbytealg.IndexByteString(, ':') >= 0 {return"[" + + "]:" + }return + ":" + }// internetAddrList resolves addr, which may be a literal IP// address or a DNS name, and returns a list of internet protocol// family addresses. The result contains at least one address when// error is nil.func ( *Resolver) ( context.Context, , string) (addrList, error) {var (error , stringint )switch {case"tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":if != "" {if , , = SplitHostPort(); != nil {returnnil, }if , = .LookupPort(, , ); != nil {returnnil, } }case"ip", "ip4", "ip6":if != "" { = }default:returnnil, UnknownNetworkError() } := func( IPAddr) Addr {switch {case"tcp", "tcp4", "tcp6":return &TCPAddr{IP: .IP, Port: , Zone: .Zone}case"udp", "udp4", "udp6":return &UDPAddr{IP: .IP, Port: , Zone: .Zone}case"ip", "ip4", "ip6":return &IPAddr{IP: .IP, Zone: .Zone}default:panic("unexpected network: " + ) } }if == "" {returnaddrList{(IPAddr{})}, nil }// Try as a literal IP address, then as a DNS name. , := .lookupIPAddr(, , )if != nil {returnnil, }// Issue 18806: if the machine has halfway configured // IPv6 such that it can bind on "::" (IPv6unspecified) // but not connect back to that same address, fall // back to dialing 0.0.0.0.iflen() == 1 && [0].IP.Equal(IPv6unspecified) { = append(, IPAddr{IP: IPv4zero}) }varfunc(IPAddr) boolif != "" && [len()-1] == '4' { = ipv4only }if != "" && [len()-1] == '6' { = ipv6only }returnfilterAddrList(, , , )}// loopbackIP should be an internal detail,// but widely used packages access it using linkname.// Notable members of the hall of shame include:// - github.com/database64128/tfo-go/v2// - github.com/metacubex/tfo-go// - github.com/sagernet/tfo-go//// Do not remove or change the type signature.// See go.dev/issue/67401.////go:linkname loopbackIPfunc loopbackIP( string) IP {if != "" && [len()-1] == '6' {returnIPv6loopback }returnIP{127, 0, 0, 1}}
The pages are generated with Goldsv0.7.0-preview. (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.