I came up with a clever / elegant solution to this and I would like your
feedback. This approach minimizes the http.Server & http.handleFunc
structs needed to listen on both local interfaces.
func ListenWithDualListener() {
dual, err := multilistener.NewLocalLoopback("8080")
if err != nil {
panic(err)
}
defer dual.Close()
fmt.Printf("Serving HTTP %+v\n", dual.AllAddr())
fmt.Printf("Preferred Addr: %+v\n", dual.Addr())
if serveErr := http.Serve(dual, nil); serveErr != nil {
fmt.Println("http.Serve error:", serveErr)
}
see
https://github.com/tonymet/dualstack/blob/master/multilistener/multilistener.go
On Thursday, January 11, 2024 at 12:27:22 AM UTC-8 [email protected] wrote:
> Hi,
>
> Unfortunately, the only way to avoid having two sockets in this scenario,
> is to listen to only one of 127.0.0.1 or ::1 and live with that it's only
> one address family.
> As you might've noticed, some tools still struggle with connecting to ::1
> so listening to 127.0.0.1 is the most safe option.
> Most client will try to connect to both ::1 and 127.0.0.1 when given
> localhost as target. In the case of browsers, they usually do it in
> parallel and use the quickest succeeding connection (this is called Happy
> Eyeballs if you wish to Google it).
>
> The reason it works this way is that you bind the socket to an address,
> either ::1 or 127.0.0.1. There's no address that binds to multiple address
> families, except for :: that listen on all interfaces.
>
> Regards,
> Per Johansson
>
> On Wednesday, January 10, 2024 at 9:54:12 PM UTC+1 Tony M wrote:
>
>> How do I listen on all* local / loopback* ipv4 /ipv6 interfaces?
>> net.Listen('tcp', ':9999') listens on all interfaces. For my application
>> (oauth token listener) I only want to listen to local / loopback
>>
>> go doc Net.listen:
>>
>>
>> * if the host in the address parameter is empty or a literal
>> unspecified IP address, Listen listens on all available unicast and
>> anycast IP addresses of the local system.*
>>
>> My current workarounds are not ideal :
>> * implement MultiListener interface with 2 listeners\
>> * Listen on 2 net.Listen listeners with 2 http.Serve servers
>>
>>
>> Example test with netstat showing the issue.
>> SEE EXAMPLE CODE BELOW
>>
>> # Listen :9999
>> $ go run . -i all &
>> $ netstat -tulnp |grep v2
>> tcp6 0 0 :::9999 :::*
>> LISTEN 28107/v2
>>
>> # listen [127.0.0.1]:9999
>> $ go run . -i ipv4 &
>> $ netstat -tulnp |grep v2
>> tcp 0 0 127.0.0.1:9999 0.0.0.0:*
>> LISTEN 29244/v2
>>
>> # listen [::1]:9999
>> $ go run . -i ipv6
>> $ netstat -tulnp |grep v2
>> tcp6 0 0 ::1:9999 :::*
>> LISTEN 30163/v2
>>
>> Telnet v4 does not work with v6 listen:
>> $ go run . -i ipv6
>> $ telnet 127.0.0.1 9999
>> Trying 127.0.0.1...
>> telnet: Unable to connect to remote host: Connection refused
>>
>>
>> Example Code
>>
>> package main
>>
>> import (
>> "flag"
>> "fmt"
>> "net"
>> "time"
>> )
>>
>> func main() {
>> optListen := flag.String("i", "all", "all / ipv6, ipv4")
>>
>> addrMap := map[string]string{
>> "all": ":9999",
>> "ipv6": "[::1]:9999",
>> "ipv4": "[127.0.0.1]:9999",
>> }
>>
>> flag.Parse()
>>
>> fmt.Printf("Listen: %s\n", *optListen)
>> addr, ok := addrMap[*optListen]
>> if !ok {
>> panic("not found")
>> }
>> if l1, err := net.Listen("tcp", addr); err == nil {
>> fmt.Printf("l1: %s\n", l1.Addr().String())
>> } else {
>> panic(err)
>> }
>>
>> time.Sleep(30 * time.Second)
>> }
>>
>>
>>
--
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 [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/golang-nuts/b1e5c091-ddd6-42df-8bd6-dc4761094e0fn%40googlegroups.com.