103

I want to get the computer's IP address. I used the code below, but it returns 127.0.0.1.

I want to get the IP address, such as 10.32.10.111, instead of the loopback address.

name, err := os.Hostname()
if err != nil {
     fmt.Printf("Oops: %v\n", err)
     return
}

addrs, err := net.LookupHost(name)
if err != nil {
    fmt.Printf("Oops: %v\n", err)
    return
}

for _, a := range addrs {
    fmt.Println(a)
}  
ale
  • 6,369
  • 7
  • 55
  • 65
Jerry YY Rain
  • 4,134
  • 7
  • 35
  • 52

8 Answers8

181

Here is a better solution to retrieve the preferred outbound ip address when there are multiple ip interfaces exist on the machine.

import (
    "log"
    "net"
    "strings"
)

// Get preferred outbound ip of this machine
func GetOutboundIP() net.IP {
    conn, err := net.Dial("udp", "8.8.8.8:80")
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    localAddr := conn.LocalAddr().(*net.UDPAddr)

    return localAddr.IP
}
Marcel Molina
  • 994
  • 6
  • 6
Mr.Wang from Next Door
  • 13,670
  • 12
  • 64
  • 97
  • 2
    I was searching for the same and this is only one that worked fine for me :) , By the way i wanted to know why you are doing udp connection to Google Dns and whats the value whole of "conn.LocalAddr().String()" ? – StackB00m Nov 30 '16 at 16:52
  • 11
    Actually it does not establish any connection and the destination does not need to be existed at all :) So, what the code does actually, is to get the local up address if it would connect to that target, you can change to any other IP address you want. `conn.LocalAddr().String()` is the local ip and port. – Mr.Wang from Next Door Dec 01 '16 at 08:17
  • 2
    This is better than the accepted solution. Even if you have 2 IP addresses on the subnet of the default route's gateway (say a wired and wireless IP), this (for me) is picking the default IP that traffic will use. – dimalinux Jul 20 '17 at 04:48
  • Wait what? Why does `Dial` "not establish any connection". According to the [doc](https://golang.org/pkg/net/#Dial) "Dial connects to the address on the named network." How is this working? Does Dial connect or not? – ddrake12 Oct 11 '17 at 19:24
  • 15
    @darkwing it is using the udp protocol, unlike TCP, it does not have handshake nor a connection. hence, the target does not need be there and you will receive the outbound IP. – Mr.Wang from Next Door Oct 12 '17 at 07:24
  • 1
    @darkwing: See it as a "logical" connection, not a "physical" one. – ereOn Mar 09 '19 at 16:36
  • @Mr.WangfromNextDoor Does this needs be "8.8.8.8:53" instead of "8.8.8.8:80" ? – Sanket Sudake Jun 20 '19 at 06:22
  • 1
    @SanketSudake any port number is ok. there is no connection established – Mr.Wang from Next Door Jun 23 '19 at 00:51
  • Is there a way to get the local IP back in CIDR notation? I found various examples using DefaultMask but not the actual mask. – Steve Crook Apr 18 '20 at 08:43
149

You need to loop through all network interfaces

ifaces, err := net.Interfaces()
// handle err
for _, i := range ifaces {
    addrs, err := i.Addrs()
    // handle err
    for _, addr := range addrs {
        var ip net.IP
        switch v := addr.(type) {
        case *net.IPNet:
                ip = v.IP
        case *net.IPAddr:
                ip = v.IP
        }
        // process IP address
    }
}

Play (taken from util/helper.go)

Sebastian
  • 16,813
  • 4
  • 49
  • 56
  • Thanks, added it to the answer – Sebastian May 09 '14 at 07:08
  • 1
    util/helper.go is probably this https://code.google.com/p/whispering-gophers/source/browse/util/helper.go . What about IPv6? This only seems to work for IPv4 Addresses. –  Oct 13 '14 at 16:55
  • 1
    The call to net.Interfaces() returns no error and 0 interfaces on my Linux host (Manjaro, current) https://play.golang.org/p/0K5bL_eqFm :( – HankB Nov 28 '16 at 03:26
45

To ensure that you get a non-loopback address, simply check that an IP is not a loopback when you are iterating.

// GetLocalIP returns the non loopback local IP of the host
func GetLocalIP() string {
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        return ""
    }
    for _, address := range addrs {
        // check the address type and if it is not a loopback the display it
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                return ipnet.IP.String()
            }
        }
    }
    return ""
}
Shane Jarvie
  • 451
  • 4
  • 3
26

net.LookupHost() on your os.Hostname() is probably always going to give you 127.0.0.1, because that's what's in your /etc/hosts or equivalent.

I think what you want to use is net.InterfaceAddrs():

func InterfaceAddrs() ([]Addr, error)

InterfaceAddrs returns a list of the system's network interface addresses.

Community
  • 1
  • 1
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • This has its own wrinkles. The addresses are provided as strings. Given an IP address (specific Go type, not the generic term) there is no direct comparison. It is either necessary to convert the IP to a string and compare or parse the strings to get the IP to compare, neither of which looks trivial to this neophyte Go programmer. I'm looking for library procedures to convert the string to an IP but have not yet found one. – HankB Dec 01 '16 at 15:42
  • What is the IP address Go type you refer to? – Jonathon Reinhart Dec 01 '16 at 16:53
  • https://golang.org/pkg/net/#IP type IP []byte And the parser I seek is just below that on the page: func ParseCIDR(s string) (IP, *IPNet, error) (Cannot seem to format those lines as code.) – HankB Dec 01 '16 at 17:06
16

This worked for me:

host, _ := os.Hostname()
addrs, _ := net.LookupIP(host)
for _, addr := range addrs {
    if ipv4 := addr.To4(); ipv4 != nil {
        fmt.Println("IPv4: ", ipv4)
    }   
}

Unlike the poster's example, it returns only non-loopback addresses, e.g. 10.120.X.X.

eric gilbertson
  • 965
  • 7
  • 10
  • but if i use if loop it will be local inside that loop... i want to use the ipv4 value outside this loop – Vijay Kumar Jun 25 '15 at 10:17
  • @VijayKumar, `var ipv4 net.IP` outside of the loop and use `ipv4 = addr.To4()` (instead of `ipv4 := addr.To4()` – Noel Yap Jan 06 '22 at 22:29
4
func GetInternalIP() string {
    itf, _ := net.InterfaceByName("enp1s0") //here your interface
    item, _ := itf.Addrs()
    var ip net.IP
    for _, addr := range item {
        switch v := addr.(type) {
        case *net.IPNet:
            if !v.IP.IsLoopback() {
                if v.IP.To4() != nil {//Verify if IP is IPV4
                    ip = v.IP
                }
            }
        }
    }
    if ip != nil {
        return ip.String()
    } else {
        return ""
    }
}
Darlan Dieterich
  • 2,369
  • 1
  • 27
  • 37
2
func resolveHostIp() (string) {

    netInterfaceAddresses, err := net.InterfaceAddrs()

    if err != nil { return "" }

    for _, netInterfaceAddress := range netInterfaceAddresses {

        networkIp, ok := netInterfaceAddress.(*net.IPNet)

        if ok && !networkIp.IP.IsLoopback() && networkIp.IP.To4() != nil {

            ip := networkIp.IP.String()

            fmt.Println("Resolved Host IP: " + ip)

            return ip
        }
    }
    return ""
}
Abdul Wasae
  • 3,614
  • 4
  • 34
  • 56
0

If you only have one IP address except 127.0.0.1, You can check the code down here.

conn,err := net.Dial("ip:icmp","google.com")
fmt.Println(conn.LocalAddr())

The second parameter can be any IP address except 127.0.0.1

Inasa Xia
  • 433
  • 5
  • 12