IPv4/IPv6 dual stack on Linux

918 views
Skip to first unread message

Louis Opter

unread,
Jul 11, 2013, 2:23:51 PM7/11/13
to golang-nuts
Hello,

I'm trying to get IPv4/IPv6 dual stack working in Go on GNU/Linux.

If I understand net.favorideAddrFamily correctly the following sample of
code should accept IPv4 connections:

----8<----

package main

import (
"fmt"
"io"
"net"
)

func main() {
listener, err := net.Listen("tcp", "[::1]:0")
if err != nil {
panic(fmt.Errorf("Cannot listen on [::1]:0: %v", err.Error()))
}
fmt.Printf("EchoServer listening on tcp:%v\n", listener.Addr().String())
for {
client, err := listener.Accept()
if err != nil {
return
}
go func(client net.Conn) {
fmt.Printf("TCP client accepted on the EchoServer\n")
written, err := io.Copy(client, client)
fmt.Printf("%v bytes echoed back to the client\n", written)
if err != nil {
fmt.Printf("can't echo to the client: %v\n", err.Error())
}
client.Close()
}(client)
}
}

---->8----

But it doesn't, so maybe I'm doing something wrong? And/or what's the
way to do dual stack in Go on Linux?

Thanks!

--
Louis Opter

Dave Cheney

unread,
Jul 12, 2013, 12:22:28 AM7/12/13
to Louis Opter, golang-nuts
I think it works like this

If you want ipv4, net.Listen("tcp4", ":0")
If you want ipv6, use tcp6
If you want to roll the dice and let someone else choose, use straight "tcp"
> --
> 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.
>
>

Louis Opter

unread,
Jul 12, 2013, 2:08:55 PM7/12/13
to Dave Cheney, golang-nuts
On Fri, 12 Jul 2013 14:22:28 +1000 Dave Cheney <da...@cheney.net> wrote:

> I think it works like this
>
> If you want ipv4, net.Listen("tcp4", ":0")
> If you want ipv6, use tcp6
> If you want to roll the dice and let someone else choose, use
> straight "tcp"

Hello David,

I don't want to roll a dice, I'm looking for the way to use both ipv4
and ipv6 on the same net.Conn (same socket).

Hope that clarifies things!

--
Louis Opter

Kyle Lemons

unread,
Jul 12, 2013, 2:27:45 PM7/12/13
to Louis Opter, Dave Cheney, golang-nuts
On Fri, Jul 12, 2013 at 11:08 AM, Louis Opter <kale...@kalessin.fr> wrote:
On Fri, 12 Jul 2013 14:22:28 +1000 Dave Cheney <da...@cheney.net> wrote:

> I think it works like this
>
> If you want ipv4, net.Listen("tcp4", ":0")
> If you want ipv6, use tcp6
> If you want to roll the dice and let someone else choose, use
> straight "tcp"

Hello David,

I don't want to roll a dice, I'm looking for the way to use both ipv4
and ipv6 on the same net.Conn (same socket).

Do you mean the same net.Listener?  A connected socket will be either ipv4 or ipv6.

To start with, I've listened on "localhost" and seen it listening on both before, so what OS are you on? Have you tried listening on both tcp4 127.0.0.1 and tcp6 ::0?
 
Hope that clarifies things!

--
Louis Opter

Louis Opter

unread,
Jul 12, 2013, 3:11:42 PM7/12/13
to Kyle Lemons, Dave Cheney, golang-nuts
On Fri, 12 Jul 2013 11:27:45 -0700 Kyle Lemons <kev...@google.com>
wrote:

> On Fri, Jul 12, 2013 at 11:08 AM, Louis Opter <kale...@kalessin.fr>
> wrote:
>
> > On Fri, 12 Jul 2013 14:22:28 +1000 Dave Cheney <da...@cheney.net>
> > wrote:
> >
> > > I think it works like this
> > >
> > > If you want ipv4, net.Listen("tcp4", ":0")
> > > If you want ipv6, use tcp6
> > > If you want to roll the dice and let someone else choose, use
> > > straight "tcp"
> >
> > I don't want to roll a dice, I'm looking for the way to use both
> > ipv4 and ipv6 on the same net.Conn (same socket).
> >
>
> Do you mean the same net.Listener? A connected socket will be either
> ipv4 or ipv6.

My bad, I meant net.Listener. An inet socket will be either IPv4 or IPv6
but (at least on Linux) an IPv6 socket can be configured to also accept
IPv4 connections (and the address will appear as an IPv4 mapped IPv6
address [1]).

> To start with, I've listened on "localhost" and seen it listening on
> both before, so what OS are you on? Have you tried listening on both
> tcp4 127.0.0.1 and tcp6 ::0?

I'm really concerned about Linux here. And the point is to not listen
on both tcp4 and tcp6 but use the same net.Listener (so same socket)
for both. This is what I'm trying to achieve.

[1] https://en.wikipedia.org/wiki/Ipv6#IPv4-mapped_IPv6_addresses

PS: Dave, sorry I meant Dave and not David, please blame my four
different friends called David.

--
Louis Opter

Kyle Lemons

unread,
Jul 12, 2013, 4:19:28 PM7/12/13
to Louis Opter, Dave Cheney, golang-nuts
This may not be what you want, but here's the behavior I was thinking about:

$ go run listen.go
2013/07/12 13:17:49 Listening on [::]:48086
2013/07/12 13:18:16 Accepted connection from 127.0.0.1:45292
2013/07/12 13:18:21 Accepted connection from [::1]:39904

$ cat listen.go
package main

import (
        "log"
        "net"
)

func main() {
        l, err := net.Listen("tcp", "0.0.0.0:0")
        if err != nil {
                log.Fatalf("listen: %s", err)
        }

        log.Printf("Listening on %s", l.Addr())

        for {
                conn, err := l.Accept()
                if err != nil {
                        log.Fatalf("accept: %s", err)
                }
                log.Printf("Accepted connection from %s", conn.RemoteAddr())
                conn.Close()
        }
}



--
Louis Opter

Louis Opter

unread,
Jul 12, 2013, 5:11:02 PM7/12/13
to Kyle Lemons, Dave Cheney, golang-nuts
On Fri, 12 Jul 2013 13:19:28 -0700 Kyle Lemons <kev...@google.com>
wrote:

> This may not be what you want, but here's the behavior I was thinking
> about:
>
> $ go run listen.go
> 2013/07/12 13:17:49 Listening on [::]:48086
> 2013/07/12 13:18:16 Accepted connection from 127.0.0.1:45292
> 2013/07/12 13:18:21 Accepted connection from [::1]:39904
>
> $ cat listen.go
> package main
>
> import (
> "log"
> "net"
> )
>
> func main() {
> l, err := net.Listen("tcp", "0.0.0.0:0")

Indeed, in that case we have dual-stack working which is what I want,
however I wanted to get that on a specific IP address: ::1 (i.e:
localhost).

But, I'm now realizing that it doesn't make sense, because while
0.0.0.0 is indeed equal to ::, this is false for every other address.
127.0.0.1 doesn't correspond to ::1, it's two different address spaces,
in other words it doesn't make sense to listen on ::1 and then try to
connect to 127.0.0.1.

Please correct me if I'm wrong!

--
Louis Opter

Kyle Lemons

unread,
Jul 12, 2013, 5:43:24 PM7/12/13
to Louis Opter, Dave Cheney, golang-nuts
If you want to listen on ::1 and 127.0.0.1 you need two listening sockets, I'd think.  I'm not sure if listening on ::ffff:127.0.0.1 would listen on both or not.

Luckily, two listening sockets in Go that both call the same serve function is trivial.


On Fri, Jul 12, 2013 at 2:11 PM, Louis Opter <kale...@kalessin.fr> wrote:
On Fri, 12 Jul 2013 13:19:28 -0700 Kyle Lemons <kev...@google.com>
wrote:

> This may not be what you want, but here's the behavior I was thinking
> about:
>
> $ go run listen.go
> 2013/07/12 13:17:49 Listening on [::]:48086
> 2013/07/12 13:18:16 Accepted connection from 127.0.0.1:45292
> 2013/07/12 13:18:21 Accepted connection from [::1]:39904
>
> $ cat listen.go
> package main
>
> import (
>         "log"
>         "net"
> )
>
> func main() {
>         l, err := net.Listen("tcp", "0.0.0.0:0")

Louis Opter

unread,
Jul 12, 2013, 7:26:42 PM7/12/13
to Kyle Lemons, Dave Cheney, golang-nuts
On Fri, 12 Jul 2013 14:43:24 -0700
Kyle Lemons <kev...@google.com> wrote:

> If you want to listen on ::1 and 127.0.0.1 you need two listening
> sockets, I'd think. I'm not sure if listening on ::ffff:127.0.0.1
> would listen on both or not.

Yes, I guess not, since ::1 and 127.0.0.1 (or ::ffff:127.0.0.1) are
different addresses.

Thanks for making me realize this!

> Luckily, two listening sockets in Go that both call the same serve
> function is trivial.

Sure, but I wanted to explore that too!

--
Louis Opter
Reply all
Reply to author
Forward
0 new messages