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