Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue(network): go - tcp dial behavior mismatch (unexpected failures) #2069

Closed
rinor opened this issue Sep 25, 2024 · 2 comments
Closed

issue(network): go - tcp dial behavior mismatch (unexpected failures) #2069

rinor opened this issue Sep 25, 2024 · 2 comments

Comments

@rinor
Copy link
Contributor

rinor commented Sep 25, 2024

  • config.json
{
  "Dirs": [ "etc" ]
}
  • cat etc/hosts
127.0.0.1   localhost
::1         localhost
  • ops run -c config.json netdial
running local instance
booting /home/rinor/.ops/images/netdial ...
en1: assigned 10.0.2.15
en1: assigned FE80::F038:1DFF:FEE4:97DC

Listen tcp4/6: [::]:58530
Listen tcp4  : 0.0.0.0:58531
Listen tcp6  : [::]:58532

Listener provided IP:PORT - dial

dialer.Dial(tcp?, [::]:58530)		net.Dial: dial tcp [::]:58530: i/o timeout
dialer.Dial(tcp4, 0.0.0.0:58531)	net.Dial: dial tcp4 0.0.0.0:58531: connect: connection reset by peer
dialer.Dial(tcp6, [::]:58532)		net.Dial: dial tcp6 [::]:58532: i/o timeout

:PORT - dial

dialer.Dial(tcp?, :58530)		net.Dial: dial tcp :58530: connect: connection reset by peer
dialer.Dial(tcp4, :58531)		net.Dial: dial tcp4 :58531: connect: connection reset by peer
dialer.Dial(tcp6, :58532)		net.Dial: dial tcp6 :58532: i/o timeout

127.0.0.1:PORT - dial

dialer.Dial(tcp?, 127.0.0.1:58530)	TCP? connection established:	127.0.0.1:58530	<- 127.0.0.1:58539
dialer.Dial(tcp4, 127.0.0.1:58531)	TCP4 connection established:	127.0.0.1:58531	<- 127.0.0.1:58540
dialer.Dial(tcp6, [::1]:58532)		TCP6 connection established:	[::1]:58532	<- [::1]:58541

localhost:PORT - dial (needs /etc/hosts)

dialer.Dial(tcp?, localhost:58530)	TCP? connection established:	127.0.0.1:58530	<- 127.0.0.1:58542
dialer.Dial(tcp4, localhost:58531)	TCP4 connection established:	127.0.0.1:58531	<- 127.0.0.1:58543
dialer.Dial(tcp6, localhost:58532)	TCP6 connection established:	[::1]:58532	<- [::1]:58544
  • ./netdial - on linux
Listen tcp4/6: [::]:36231
Listen tcp4  : 0.0.0.0:46819
Listen tcp6  : [::]:34691

Listener provided IP:PORT - dial

dialer.Dial(tcp?, [::]:36231)		TCP? connection established:	[::1]:36231	<- [::1]:48372
dialer.Dial(tcp4, 0.0.0.0:46819)	TCP4 connection established:	127.0.0.1:46819	<- 127.0.0.1:43712
dialer.Dial(tcp6, [::]:34691)		TCP6 connection established:	[::1]:34691	<- [::1]:49164

:PORT - dial

dialer.Dial(tcp?, :36231)		TCP? connection established:	127.0.0.1:36231	<- 127.0.0.1:59636
dialer.Dial(tcp4, :46819)		TCP4 connection established:	127.0.0.1:46819	<- 127.0.0.1:44074
dialer.Dial(tcp6, :34691)		TCP6 connection established:	[::1]:34691	<- [::1]:45546

127.0.0.1:PORT - dial

dialer.Dial(tcp?, 127.0.0.1:36231)	TCP? connection established:	127.0.0.1:36231	<- 127.0.0.1:59644
dialer.Dial(tcp4, 127.0.0.1:46819)	TCP4 connection established:	127.0.0.1:46819	<- 127.0.0.1:44082
dialer.Dial(tcp6, [::1]:34691)		TCP6 connection established:	[::1]:34691	<- [::1]:45552

localhost:PORT - dial (needs /etc/hosts)

dialer.Dial(tcp?, localhost:36231)	TCP? connection established:	[::1]:36231	<- [::1]:60582
dialer.Dial(tcp4, localhost:46819)	TCP4 connection established:	127.0.0.1:46819	<- 127.0.0.1:44088
dialer.Dial(tcp6, localhost:34691)	TCP6 connection established:	[::1]:34691	<- [::1]:45560
  • go build -ldflags "-s -w" -tags "netgo" -trimpath -o bin/netdial main.go
package main

import (
	"fmt"
	"net"
	"os"
	"strconv"
	"time"
)

func main() {
	// TCP - listener (both tcp4/tcp6)
	nl, err := net.Listen("tcp", ":0")
	if err != nil {
		fmt.Println("Error net.Listen:", err)
		os.Exit(1)
	}

	go func() {
		for {
			conn, err := nl.Accept()
			if err != nil {
				fmt.Println("Error accepting TCP connection:", err)
				continue
			}
			go func() {
				defer conn.Close()
				fmt.Printf("TCP? connection established:\t%s\t<- %s\n", conn.LocalAddr(), conn.RemoteAddr())
			}()
		}
	}()

	// TCP4
	nl4, err := net.Listen("tcp4", ":0")
	if err != nil {
		fmt.Println("Error net.Listen:", err)
		os.Exit(1)
	}
	go func() {
		for {
			conn, err := nl4.Accept()
			if err != nil {
				fmt.Println("Error accepting TCP4 connection:", err)
				continue
			}
			go func() {
				defer conn.Close()
				fmt.Printf("TCP4 connection established:\t%s\t<- %s\n", conn.LocalAddr(), conn.RemoteAddr())
			}()
		}
	}()

	// TCP6
	nl6, err := net.Listen("tcp6", ":0")
	if err != nil {
		fmt.Println("Error net.Listen:", err)
		os.Exit(1)
	}
	go func() {
		for {
			conn, err := nl6.Accept()
			if err != nil {
				fmt.Println("Error accepting TCP6 connection:", err)
				continue
			}
			go func() {
				defer conn.Close()
				fmt.Printf("TCP6 connection established:\t%s\t<- %s\n", conn.LocalAddr(), conn.RemoteAddr())
			}()
		}
	}()

	time.Sleep(2 * time.Second)

	dialer := net.Dialer{Timeout: 100 * time.Millisecond}

	fmt.Println()
	fmt.Println("Listen tcp4/6:", nl.Addr().String())
	fmt.Println("Listen tcp4  :", nl4.Addr().String())
	fmt.Println("Listen tcp6  :", nl6.Addr().String())
	fmt.Println()
	fmt.Println("Listener provided IP:PORT - dial")

	for i := 0; i < 1; i++ {
		fmt.Println()

		// TCP
		fmt.Printf("dialer.Dial(%s, %s)\t\t", "tcp?", nl.Addr().String())
		c, err := dialer.Dial("tcp", nl.Addr().String())
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP4
		fmt.Printf("dialer.Dial(%s, %s)\t", "tcp4", nl4.Addr().String())
		c4, err := dialer.Dial("tcp4", nl4.Addr().String())
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c4.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP6
		fmt.Printf("dialer.Dial(%s, %s)\t\t", "tcp6", nl6.Addr().String())
		c6, err := dialer.Dial("tcp6", nl6.Addr().String())
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c6.Close()
		}
		time.Sleep(200 * time.Millisecond)
	}

	// port only dial

	fmt.Println()
	fmt.Println(":PORT - dial")

	for i := 0; i < 1; i++ {
		fmt.Println()

		// TCP
		tcpAddr := nl.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, :%d)\t\t", "tcp?", tcpAddr.Port)
		c, err := dialer.Dial("tcp", ":"+strconv.Itoa(tcpAddr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP4
		tcp4Addr := nl4.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, :%d)\t\t", "tcp4", tcp4Addr.Port)
		c4, err := dialer.Dial("tcp4", ":"+strconv.Itoa(tcp4Addr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c4.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP6
		tcp6Addr := nl6.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, :%d)\t\t", "tcp6", tcp6Addr.Port)
		c6, err := dialer.Dial("tcp6", ":"+strconv.Itoa(tcp6Addr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c6.Close()
		}
		time.Sleep(200 * time.Millisecond)
	}

	// local ip:port dial

	fmt.Println()
	fmt.Println("127.0.0.1:PORT - dial")

	for i := 0; i < 1; i++ {
		fmt.Println()

		// TCP
		tcpAddr := nl.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, 127.0.0.1:%d)\t", "tcp?", tcpAddr.Port)
		c, err := dialer.Dial("tcp", "127.0.0.1:"+strconv.Itoa(tcpAddr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP4
		tcp4Addr := nl4.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, 127.0.0.1:%d)\t", "tcp4", tcp4Addr.Port)
		c4, err := dialer.Dial("tcp4", "127.0.0.1:"+strconv.Itoa(tcp4Addr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c4.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP6
		tcp6Addr := nl6.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, [::1]:%d)\t\t", "tcp6", tcp6Addr.Port)
		c6, err := dialer.Dial("tcp6", "[::1]:"+strconv.Itoa(tcp6Addr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c6.Close()
		}
		time.Sleep(200 * time.Millisecond)
	}

	// localhost:port dial (needs /etc/hosts)

	fmt.Println()
	fmt.Println("localhost:PORT - dial (needs /etc/hosts)")

	for i := 0; i < 1; i++ {
		fmt.Println()

		// TCP
		tcpAddr := nl.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, localhost:%d)\t", "tcp?", tcpAddr.Port)
		c, err := dialer.Dial("tcp", "localhost:"+strconv.Itoa(tcpAddr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP4
		tcp4Addr := nl4.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, localhost:%d)\t", "tcp4", tcp4Addr.Port)
		c4, err := dialer.Dial("tcp4", "localhost:"+strconv.Itoa(tcp4Addr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c4.Close()
		}
		time.Sleep(200 * time.Millisecond)

		// TCP6
		tcp6Addr := nl6.Addr().(*net.TCPAddr)
		fmt.Printf("dialer.Dial(%s, localhost:%d)\t", "tcp6", tcp6Addr.Port)
		c6, err := dialer.Dial("tcp6", "localhost:"+strconv.Itoa(tcp6Addr.Port))
		if err != nil {
			fmt.Println("net.Dial:", err)
		} else {
			c6.Close()
		}
		time.Sleep(200 * time.Millisecond)
	}
}
@rinor
Copy link
Contributor Author

rinor commented Sep 26, 2024

#2070 - might be the expected functionality, but is there any better way/place to implement that?

@rinor
Copy link
Contributor Author

rinor commented Sep 27, 2024

As per #2070 (comment) this is the expected/desired behavior on nanos, so in such scenarios one should correct the application, not the kernel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant