package host import ( "net" "strconv" ) func isValidIP(addr string) bool { ip := net.ParseIP(addr) if ip4 := ip.To4(); ip4 != nil { return !ip4.IsLoopback() } // Following RFC 4193, Section 3. Private Address Space which says: // The Internet Assigned Numbers Authority (IANA) has reserved the // following block of the IPv6 address space for local internets: // FC00:: - FDFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF (FC00::/7 prefix) return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc } // Port return a real port. func Port(lis net.Listener) (int, bool) { if addr, ok := lis.Addr().(*net.TCPAddr); ok { return addr.Port, true } return 0, false } // Extract returns a private addr and port. func Extract(hostPort string, lis net.Listener) (string, error) { addr, port, err := net.SplitHostPort(hostPort) if err != nil { return "", err } if lis != nil { if p, ok := Port(lis); ok { port = strconv.Itoa(p) } } if len(addr) > 0 && (addr != "0.0.0.0" && addr != "[::]" && addr != "::") { return net.JoinHostPort(addr, port), nil } ifaces, err := net.Interfaces() if err != nil { return "", err } for _, iface := range ifaces { addrs, err := iface.Addrs() if err != nil { continue } for _, rawAddr := range addrs { var ip net.IP switch addr := rawAddr.(type) { case *net.IPAddr: ip = addr.IP case *net.IPNet: ip = addr.IP default: continue } if isValidIP(ip.String()) { return net.JoinHostPort(ip.String(), port), nil } } } return "", nil }