1
0
mirror of https://github.com/go-micro/go-micro.git synced 2024-12-18 08:26:38 +02:00
go-micro/util/addr/addr.go

150 lines
2.9 KiB
Go
Raw Normal View History

// addr provides functions to retrieve local IP addresses from device interfaces.
2019-05-31 00:52:10 +02:00
package addr
import (
"net"
"github.com/pkg/errors"
2019-05-31 00:52:10 +02:00
)
var (
// ErrIPNotFound no IP address found, and explicit IP not provided.
ErrIPNotFound = errors.New("no IP address found, and explicit IP not provided")
2019-05-31 00:52:10 +02:00
)
// IsLocal checks whether an IP belongs to one of the device's interfaces.
func IsLocal(addr string) bool {
// Extract the host
host, _, err := net.SplitHostPort(addr)
if err == nil {
addr = host
}
if addr == "localhost" {
return true
}
// Check against all local ips
for _, ip := range IPs() {
if addr == ip {
return true
}
}
return false
}
// Extract returns a valid IP address. If the address provided is a valid
// address, it will be returned directly. Otherwise the available interfaces
// be itterated over to find an IP address, prefferably private.
2019-05-31 00:52:10 +02:00
func Extract(addr string) (string, error) {
// if addr is already specified then it's directly returned
if len(addr) > 0 && (addr != "0.0.0.0" && addr != "[::]" && addr != "::") {
2019-05-31 00:52:10 +02:00
return addr, nil
}
var (
addrs []net.Addr
loAddrs []net.Addr
)
2019-05-31 00:52:10 +02:00
ifaces, err := net.Interfaces()
if err != nil {
return "", errors.Wrap(err, "failed to get interfaces")
2019-05-31 00:52:10 +02:00
}
for _, iface := range ifaces {
ifaceAddrs, err := iface.Addrs()
if err != nil {
2020-05-29 18:49:22 +02:00
// ignore error, interface can disappear from system
2019-05-31 00:52:10 +02:00
continue
}
2019-08-26 08:37:49 +02:00
if iface.Flags&net.FlagLoopback != 0 {
loAddrs = append(loAddrs, ifaceAddrs...)
2019-08-26 08:37:49 +02:00
continue
}
2019-05-31 00:52:10 +02:00
addrs = append(addrs, ifaceAddrs...)
2019-05-31 00:52:10 +02:00
}
// Add loopback addresses to the end of the list
addrs = append(addrs, loAddrs...)
2019-05-31 00:52:10 +02:00
// Try to find private IP in list, public IP otherwise
ip, err := findIP(addrs)
if err != nil {
return "", err
2019-05-31 00:52:10 +02:00
}
return ip.String(), nil
2019-05-31 00:52:10 +02:00
}
// IPs returns all available interface IP addresses.
2019-05-31 00:52:10 +02:00
func IPs() []string {
ifaces, err := net.Interfaces()
if err != nil {
return nil
}
var ipAddrs []string
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip == nil {
continue
}
ipAddrs = append(ipAddrs, ip.String())
}
}
return ipAddrs
}
// findIP will return the first private IP available in the list,
// if no private IP is available it will return a public IP if present.
func findIP(addresses []net.Addr) (net.IP, error) {
var publicIP net.IP
for _, rawAddr := range addresses {
var ip net.IP
switch addr := rawAddr.(type) {
case *net.IPAddr:
ip = addr.IP
case *net.IPNet:
ip = addr.IP
default:
continue
}
if !ip.IsPrivate() {
publicIP = ip
continue
}
// Return private IP if available
return ip, nil
}
// Return public or virtual IP
if len(publicIP) > 0 {
return publicIP, nil
}
return nil, ErrIPNotFound
}