// Copyright (c) 2016 Uber Technologies, Inc. // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package utils import ( "errors" "net" ) // This code is borrowed from https://github.com/uber/tchannel-go/blob/dev/localip.go // scoreAddr scores how likely the given addr is to be a remote address and returns the // IP to use when listening. Any address which receives a negative score should not be used. // Scores are calculated as: // -1 for any unknown IP addresses. // +300 for IPv4 addresses // +100 for non-local addresses, extra +100 for "up" interaces. func scoreAddr(iface net.Interface, addr net.Addr) (int, net.IP) { var ip net.IP if netAddr, ok := addr.(*net.IPNet); ok { ip = netAddr.IP } else if netIP, ok := addr.(*net.IPAddr); ok { ip = netIP.IP } else { return -1, nil } var score int if ip.To4() != nil { score += 300 } if iface.Flags&net.FlagLoopback == 0 && !ip.IsLoopback() { score += 100 if iface.Flags&net.FlagUp != 0 { score += 100 } } return score, ip } // HostIP tries to find an IP that can be used by other machines to reach this machine. func HostIP() (net.IP, error) { interfaces, err := net.Interfaces() if err != nil { return nil, err } bestScore := -1 var bestIP net.IP // Select the highest scoring IP as the best IP. for _, iface := range interfaces { addrs, err := iface.Addrs() if err != nil { // Skip this interface if there is an error. continue } for _, addr := range addrs { score, ip := scoreAddr(iface, addr) if score > bestScore { bestScore = score bestIP = ip } } } if bestScore == -1 { return nil, errors.New("no addresses to listen on") } return bestIP, nil }