10

I have two network interfaces on my computer ( eth0 and eth1) and I'm trying to Dial a connection using a specific one (eth1). Given the statement that Go is a system language I assumed so but is it really possible with the current standard library?

So far I've got to get the interface by name InterfaceByName (eth1) then I range over the Addrs method and extracted the first address [0] which seems to be the source address of eth1 interface (e.g. xxx.xxx.xxx/24); the other one is the ipv6 address.
I've created a new Dialer and set Dialer.LocalAddr with the address extracted. However I get this error mismatched local address type wich seems related to dialSingle function from dial.go

Edit Some code:

package main
import (
        "net"
        "log"
)

func main(){
        ief, err := net.InterfaceByName("eth1")
        if err !=nil{
                log.Fatal(err)
        }
        addrs, err := ief.Addrs()
        if err !=nil{
                log.Fatal(err)
        }
        d := net.Dialer{LocalAddr: addrs[0]}
        _, err = d.Dial("tcp", "google.com:80")
        if err != nil {
                log.Fatal(err)
        }
}

Output: 2014/12/10 17:11:48 dial tcp 216.58.208.32:80: mismatched local address type ip+net

7
  • I'm having trouble reproducing this -- can you show an example of how you're getting the address and creating the dialer? Commented Dec 10, 2014 at 21:44
  • @JimB thanks for looking into it. I've posted some code. It seems I get the error regardless the address/interface I'm using so I can only assume address I provided in the Dialer.LocalAddr is not of the form it's expecting through it compiles. I've investigated and it seems that the default type assigned by Go has the same IP address (the src of the interface) but also a port number. I'm not sure why the port is required and how I can get/ assign it. Commented Dec 10, 2014 at 22:14
  • use port :0, it's probably part of the specification as some protocols may want a specific source port, so they needed some way to let you specify. :0 being the ephemeral "random" (unused) port Commented Dec 10, 2014 at 23:35
  • @DavidBudworth thanks! Still Addr[golang.org/pkg/net/#Addr] seems to be an interface. Should I call the String() method, replace the subnet (/24) with a port number and convert/implment it back as interface? Commented Dec 10, 2014 at 23:56
  • 1
    Here's an example on play. It turns out you needed *net.IPNet and then take that guy's IP. play.golang.org/p/E3iXXpq0mD (this grabs the addr of my mac wifi card, change en0 to eth1) Commented Dec 11, 2014 at 0:16

1 Answer 1

17

When you pull the address from an interface, it's of type *net.IPnet wrapped in a net.Addr interface, which contains an address and netmask NOT an address and port. You can use the IP address, however, you have to create a new TCPAddr after asserting it as a *net.IPnet

    ief, err := net.InterfaceByName("eth1")
    if err !=nil{
            log.Fatal(err)
    }
    addrs, err := ief.Addrs()
    if err !=nil{
            log.Fatal(err)
    }

    tcpAddr := &net.TCPAddr{
        IP: addrs[0].(*net.IPNet).IP,
    }
Sign up to request clarification or add additional context in comments.

5 Comments

thanks a lot! I'm not sure why I didn't see you answer earlier.... somehow I ended-up with a TCPAddr as well. However the issue is that the dialer is not working unless the interface used is the default one. Any idea if this is a Go bug or a kernel issue? Default I mean the one that is provided as default via dev .... when I run ip route show
nevermind it seems it's a driver issue. On some machines work (i.e. on my mac) on other machines doesn't work (i.e. on my server).
Remember that the order of addresses isn't guaranteed, so you need to check if you're using IPv4 or IPv6. Also, note that binding to an IP does not bind you to a specific device. The outgoing device is determined at routing time, and the traffic may be blocked because the network doesn't match or there are restrictions like reverse path checking.
Thanks for the advice. I already took into account that the order is not guaranteed. Concerning the device bid I guess that's why it works on some machines(e.g. my mac) but not on others(i.e. ubuntu) Any idea how can I bind to a specific device/nic without external routings (e.g. iptables/ip route)? There are some programs like wget (--bind-address) and cURL (--interface) that do this but I'm not sure how exactly they work internally. Initially the question was how to Dial with a specific network interface.
On Linux you can use syscall.BindToDevice, but that's a privileged call and often not the right solution. That may be what curl does if it's available. First figure out why it's failing at a network level (is your name resolution failing?). If the problem is simply that the destination matches the default gateway for another interface, you need to add a route to fix it. related: serverfault.com/questions/228195/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.