Frontend Labs
⋯

Day 33 — TCP Server Patterns

Learning Objectives

  • Implement connection limits to protect against resource exhaustion
  • Set deadlines on connections to prevent slowloris-style attacks
  • Track connection states for observability and incident response

Exercise: Hardened TCP Server with Connection Limits

package main

import (
    "fmt"
    "net"
    "sync/atomic"
    "time"
)

const (
    maxConnections = 1000
    idleTimeout    = 30 * time.Second
    readTimeout    = 60 * time.Second
)

type HardenedServer struct {
    listener   net.Listener
    active     atomic.Int64
    total      atomic.Int64
    rejected   atomic.Int64
}

func (s *HardenedServer) Serve() {
    for {
        conn, err := s.listener.Accept()
        if err != nil {
            return
        }

        // Connection limit check — reject immediately if at capacity
        current := s.active.Load()
        if current >= maxConnections {
            s.rejected.Add(1)
            fmt.Fprintf(conn, "ERR: server at capacity (%d/%d connections)\n", current, maxConnections)
            conn.Close()
            continue
        }

        s.active.Add(1)
        s.total.Add(1)
        go s.handleConn(conn)
    }
}

func (s *HardenedServer) handleConn(conn net.Conn) {
    defer conn.Close()
    defer s.active.Add(-1)

    remote := conn.RemoteAddr()

    // Set absolute deadline (protects against very slow clients)
    conn.SetDeadline(time.Now().Add(readTimeout))

    buf := make([]byte, 4096)
    for {
        // Reset idle timer on each read
        conn.SetReadDeadline(time.Now().Add(idleTimeout))

        n, err := conn.Read(buf)
        if err != nil {
            if ne, ok := err.(net.Error); ok && ne.Timeout() {
                fmt.Printf("IDLE_TIMEOUT %s\n", remote)
            }
            return
        }

        // Echo data back
        conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
        if _, err := conn.Write(buf[:n]); err != nil {
            return
        }
    }
}

Real-World Context

Without maxConnections, a DDoS opening 1 million TCP connections would exhaust file descriptors (ulimit -n) and kill your server. Without idleTimeout, a Slowloris attack keeping 10,000 connections open but never sending data would do the same. Both are OWASP A05 (Security Misconfiguration).


Generated from week5.md · 8 Oct 2026 16:36