SO_REUSEADDR.

1,796 views
Skip to first unread message

Bruno Albuquerque

unread,
May 7, 2013, 12:15:47 PM5/7/13
to golang-nuts
Recently I implemented UDP NAT Hole Punching in go just for the sake of it (seemed like something interesting to do) and now this weekend I will give a go at implementing TCP NAT Hole Punching.

To do that, I need to be able to listen for connections on a TCP port and at the same time, create a connection out of it. The usual way to be able to do something like that is simply setting SO_REUSEADDR on the relevant sockets but I could not find a way to do that in Go. This is my current test program:

package main

import (
        "fmt"
        "net"
)

func main() {
        localAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")
        if err != nil {
                panic(err)
        }

        remoteAddr, err := net.ResolveTCPAddr("tcp", "www.bug-br.org.br:80")
        if err != nil {
                panic(err)
        }

        _, err = net.ListenTCP("tcp", localAddr)
        if err != nil {
                panic(err)
        }
        _, err = net.DialTCP("tcp", localAddr, remoteAddr)
        if err != nil {
                panic(err)
        }

        fmt.Println("IT WORKS!")
}

The DialTCP() call fails with "address already in use".

Is there a way to set SO_REUSEADDR using Go? More generally, is there any way in go to achieve what I want?

Thanks.

-Bruno

Carlos Castillo

unread,
May 7, 2013, 10:12:23 PM5/7/13
to golan...@googlegroups.com, b...@bug-br.org.br
Note: I am not an expert on the net package, nor low-level sockets in unix, so take this advice with a grain of salt.

You can find setsockopt and friends in the syscall package, but there are two big caveats:
  1. You need to convert a net.Conn or a net.Listener (using in part the File() method of TCPConn/TCPListener) to a FD first, and the semantics of doing so may not be able to give you what you want.
  2. The syscall package is the only part of the go std libs that are platform dependent, as the functions & constants there are just a thin layer above platform functions & constants. Using syscall thus reduces the portability of your code.
To get around #1 you could write the entire sequence that needs SO_REUSEADDR using syscall methods, as they wrap the C functions you may be familiar with, but then you are essentially writing C code, and have to jump through some hoops if you want to use the net package to interact with it in go.

Eli Janssen

unread,
May 8, 2013, 3:34:36 AM5/8/13
to Bruno Albuquerque, golang-nuts
It appears you are specifying the host/port you just bound as the tcp server, as the source host/port for the outgoing tcp connection attempt. That won't work, as you can see from the error you got. You would need to change the source port you want to use, or specify nil for the second param to let the kernel pick an appropriate source host/port.

Was there some particular reason you wanted to specify the host/port for the outbound conn?


> if err != nil {
> panic(err)
> }
>
> fmt.Println("IT WORKS!")
> }
>
> The DialTCP() call fails with "address already in use".
>
> Is there a way to set SO_REUSEADDR using Go? More generally, is there any
> way in go to achieve what I want?
>
> Thanks.
>
> -Bruno
>
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

dlin

unread,
May 8, 2013, 4:32:08 AM5/8/13
to golan...@googlegroups.com, b...@bug-br.org.br
I face the same question.

After check this

The possible solve method is "Don't assign local port" or wait the timeout.

As I searched in this group, the Go has already assigned SO_REUSEADDR.

Mikio Hara

unread,
May 8, 2013, 6:58:57 AM5/8/13
to Bruno Albuquerque, golang-nuts
On Wed, May 8, 2013 at 1:15 AM, Bruno Albuquerque <b...@bug-br.org.br> wrote:

> Is there a way to set SO_REUSEADDR using Go?

Using syscall is the only way in go 1.1.
But you can also contribute a CL that extends net.Dialer struct for
your purpose in go 1.2.

> More generally, is there any way in go to achieve what I want?

Writing TURN and STUN server, client, relay and/or PCP client, sever,
proxy.... no? ;)

Bruno Albuquerque

unread,
May 8, 2013, 8:12:49 AM5/8/13
to Carlos Castillo, golang-nuts
Yeah, it seems using the sycall package is the only way to go.

The high-level problem is that the canonical (only?) method to connect to a TCP endpoint in the net package is through DialTCP() which does al the work to setup a connection and them returns it to the user. DialTCP() would need to be modified to set SO_REUSEADDR in the socket it uses before trying to bind to it. It seems like this would be a trivial change (for some definition of trivial, anyway.

Thanks.

-Bruno


2013/5/7 Carlos Castillo <cook...@gmail.com>

Bruno Albuquerque

unread,
May 8, 2013, 8:14:27 AM5/8/13
to Eli Janssen, golang-nuts
Yes. I want to be able to set up a TCP connection between 2 computers that are behind NATs. This requires some magic (as in, I must be able to listen to connections and send data on the same address/port).


2013/5/8 Eli Janssen <eli...@gmail.com>

Bruno Albuquerque

unread,
May 8, 2013, 8:15:50 AM5/8/13
to dlin, golang-nuts
Go does that for TCPListeners automatically, yes. But to be able to do what I want, I need to do it on the socket used by DialTCP too.

-Bruno


2013/5/8 dlin <dli...@gmail.com>

Bruno Albuquerque

unread,
May 8, 2013, 8:18:57 AM5/8/13
to Mikio Hara, golang-nuts
I would be more than willing to contribute a CL, but I am wondering how is this supposed to be done. Somehow I need to tell DialTCP() that I want it to set SO_REUSEADDR but the current interface does not seem to provide an elegant way to do that. I guess simply setting SO_REUSEADDR in all sockets would be overkill and prone to bugs.

-Bruno




2013/5/8 Mikio Hara <mikioh...@gmail.com>

Mikio Hara

unread,
May 8, 2013, 8:52:17 AM5/8/13
to Bruno Albuquerque, golang-nuts
I think you can just add an appropriate member to net.Dialer struct.
For example,

d := &Dialer{TransportMap: map[string]bool{"localport": true}, LocalAddr: addr}
c, err := d.Dial("tcp", "www.bug-br.org.br:80")

Bruno Albuquerque

unread,
May 8, 2013, 9:45:54 AM5/8/13
to Mikio Hara, golang-nuts
Ah... Dialer is new in Go 1.1. I was not aware of it yet. This looks like the perfect place to add something like this. Thanks for the heads up.

So, do you guys think this would be a worth addition? Should I go ahead and create a patch?



2013/5/8 Mikio Hara <mikioh...@gmail.com>

Mikio Hara

unread,
May 10, 2013, 10:30:13 AM5/10/13
to Bruno Albuquerque, golang-nuts
On Wed, May 8, 2013 at 10:45 PM, Bruno Albuquerque <b...@bug-br.org.br> wrote:

> So, do you guys think this would be a worth addition?

Yup. I'm not an expert of P2P stuff, but all of us know that at the moment
a combo of SO_REUSEADDR and SO_REUSEPORT or similar options is
the only way to archive handling both incoming and outgoing multiple stream
connections on the same TCP port simultaneously.

> Should I go ahead and create a patch?

I'm happy to review it.
But please discuss API design first with golang-dev guys.

Peter Waller

unread,
May 16, 2013, 8:02:55 PM5/16/13
to golan...@googlegroups.com, b...@bug-br.org.br
On Tuesday, 7 May 2013 17:15:47 UTC+1, Bruno Albuquerque wrote:
Recently I implemented UDP NAT Hole Punching in go just for the sake of it (seemed like something interesting to do) and now this weekend I will give a go at implementing TCP NAT Hole Punching.

To do that, I need to be able to listen for connections on a TCP port and at the same time, create a connection out of it. The usual way to be able to do something like that is simply setting SO_REUSEADDR on the relevant sockets but I could not find a way to do that in Go. 

Forgive my ignorance if there is a simple answer, but how do you intend to set TCP primitives such as sequence and acknowledgement numbers? From a cursory look on the web it looks like you have to resort to raw sockets.

Also, would you be willing to make your code available?

Thanks,

- Peter

Mikio Hara

unread,
May 17, 2013, 6:47:29 AM5/17/13
to golan...@googlegroups.com, b...@bug-br.org.br
Fortunately TCP will take care of it.
Keywords: "TCP simultaneous open" , "Simultaneous open connection establishment", RFC 793, P2P

Bruno Albuquerque

unread,
May 17, 2013, 6:54:16 AM5/17/13
to Peter Waller, golang-nuts
Right now I am using a method called NAT-P2P which is the simplest of all methods and does not require root/admin access to the machine (so no raw sockets nor anything like that). It is based on the fact that a double connect (2 hosts sending connect requests to each other) is enough to set up a connection without any single host listening for connections. The complicated part is to be sure both hosts are connecting on the correct ports on the other host (the externally visible port opened by the firewall) and that the timing is correct (the SYN packet from one host must arrive at the other host before it gets a connection refused back, as no one is listening. Only one host needs to get t for the connection to complete).

And yes, I will share the code as soon as I am ready to. Right now UDP works but I did not test TCP yet using the mediator server (which is the part that introduces the 2 peers).

Reply all
Reply to author
Forward
0 new messages