Skip to content

Instantly share code, notes, and snippets.

@andres-erbsen
Created August 27, 2016 03:23
Show Gist options
  • Save andres-erbsen/62d7defe8dce2e182bd9a90da2e1f659 to your computer and use it in GitHub Desktop.
Save andres-erbsen/62d7defe8dce2e182bd9a90da2e1f659 to your computer and use it in GitHub Desktop.
Get public IP address in Go #golang
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)
}
}
@PaluMacil
Copy link

PaluMacil commented Feb 18, 2018

@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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment