TCP busy idling

Great read from cloudflare-blog with the catchy name This is strictly a violation of the TCP specification.

Also the comments: wrong stateful firewall?

Command to check states of connections: ss -4ntp '( dport = :5000 or sport = :5000 )'

Wireshark for packet view

Server and Client scripts:

Code samples from https://golangr.com/socket-client/ Server

// This is a trivial TCP server leaking sockets.

package main

import (
	"fmt"
	"net"
)

func handle(conn net.Conn) {
	fmt.Println("Incoming connection from", conn.RemoteAddr())

	fmt.Print("Press enter to terminate connection ...")
	fmt.Scanln()
	err := conn.Close()
	if err != nil {
		panic(err)
	}
}

func main() {
	ip := ""
	port := 5000
	listener, err := net.Listen("tcp4", fmt.Sprintf("%s:%d", ip, port))
	if err != nil {
		panic(err)
	}
	defer listener.Close()
	fmt.Println("Server ready to receive connections on port", port)

	conn, err := listener.Accept()
	if err == nil {
		handle(conn)
	} else {
		panic(err)
	}
}

Client

package main

import (
	"fmt"
	"net"
)

func main() {

	fmt.Println("Connecting to 127.0.0.1:5000 ...")
	conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 5000, Zone: ""})
	if err != nil {
		panic(err)
	}
	fmt.Println("Connected to 127.0.0.1:5000. Clientport is", conn.LocalAddr())
	conn.SetKeepAlive(false)
	if err != nil {
		panic(err)
	}

	fmt.Print("Press enter to terminate connection ...")
	fmt.Scanln()
	err = conn.Close()
	if err != nil {
		panic(err)
	}
}

Disabling keepalive will result in the Kernel not removing the hanging CLOSED_WAIT connection after MAX(15 seconds (Go default keepalive interval for TCP), timeout specified in /proc/sys/net/ipv4/tcp_fin_timeout)

That’s because in Linux (and other OS) you don’t know when a connection is closed, until you read the socket and it returns 0.

Helpful for getting all the TCP proc settings and values: man 7 tcp

Also check docs https://golang.org/pkg/net/#Conn