Created
August 27, 2016 03:23
-
-
Save andres-erbsen/62d7defe8dce2e182bd9a90da2e1f659 to your computer and use it in GitHub Desktop.
Get public IP address in Go #golang
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"net" | |
"sort" | |
"strconv" | |
"strings" | |
) | |
func rfc1918private(ip net.IP) bool { | |
for _, cidr := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} { | |
_, subnet, err := net.ParseCIDR(cidr) | |
if err != nil { | |
panic("failed to parse hardcoded rfc1918 cidr: " + err.Error()) | |
} | |
if subnet.Contains(ip) { | |
return true | |
} | |
} | |
return false | |
} | |
func rfc4193private(ip net.IP) bool { | |
_, subnet, err := net.ParseCIDR("fd00::/8") | |
if err != nil { | |
panic("failed to parse hardcoded rfc4193 cidr: " + err.Error()) | |
} | |
return subnet.Contains(ip) | |
} | |
func isLoopback(ip net.IP) bool { | |
for _, cidr := range []string{"127.0.0.0/8", "::1/128"} { | |
_, subnet, err := net.ParseCIDR(cidr) | |
if err != nil { | |
panic("failed to parse hardcoded loopback cidr: " + err.Error()) | |
} | |
if subnet.Contains(ip) { | |
return true | |
} | |
} | |
return false | |
} | |
func mightBePublic(ip net.IP) bool { | |
return !rfc1918private(ip) && !rfc4193private(ip) && !isLoopback(ip) | |
} | |
type name_and_ip struct { | |
string | |
net.IP | |
} | |
func heuristic(ni name_and_ip) (ret int) { | |
a := strings.ToLower(ni.string) | |
ip := ni.IP | |
if isLoopback(ip) { | |
ret += 1000 | |
} | |
if rfc1918private(ip) || rfc4193private(ip) { | |
ret += 500 | |
} | |
if strings.Contains(a, "dyn") { | |
ret += 100 | |
} | |
if strings.Contains(a, "dhcp") { | |
ret += 99 | |
} | |
for i := 0; i < len(ip); i++ { | |
if strings.Contains(a, strconv.Itoa(int(ip[i]))) { | |
ret += 5 | |
} | |
} | |
return ret | |
} | |
type nameAndIPByStabilityHeuristic []name_and_ip | |
func (nis nameAndIPByStabilityHeuristic) Len() int { return len(nis) } | |
func (nis nameAndIPByStabilityHeuristic) Swap(i, j int) { nis[i], nis[j] = nis[j], nis[i] } | |
func (nis nameAndIPByStabilityHeuristic) Less(i, j int) bool { return heuristic(nis[i]) < heuristic(nis[j]) } | |
func publicAddresses() ([]name_and_ip, error) { | |
var ret []name_and_ip | |
addrs, err := net.InterfaceAddrs() | |
if err != nil { | |
return nil, err | |
} | |
for _, addr := range addrs { | |
ip, _, err := net.ParseCIDR(addr.String()) | |
if err != nil { | |
return nil, err | |
} | |
// ignore unresolvable addresses | |
names, err := net.LookupAddr(ip.String()) | |
if err != nil { | |
continue | |
} | |
for _, name := range names { | |
ret = append(ret, name_and_ip{name, ip}) | |
} | |
} | |
sort.Sort(nameAndIPByStabilityHeuristic(ret)) | |
return ret, nil | |
} | |
func main() { | |
if names, err := publicAddresses(); err == nil { | |
for _, ni := range names { | |
println(ni.string, ni.IP.String(), heuristic(ni)) | |
} | |
} else { | |
panic(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@andres-erbsen Hello, I have a very simple echo server app with a public domain dedication that prints the local IP and I'd like to use this to print the public IP as well. Would you be okay with me using this as part of the public domain project and mentioning your name in the README?