Octet

TCP, UDP and applications

0 of 37 nailed

Core14

  1. What is the difference between TCP and UDP, and when would you pick each one?

    Say this first

    TCP gives the application a connection and a reliable, ordered byte stream, with flow control and congestion control. It pays for that with a handshake and with waiting for retransmissions. UDP adds only ports, a length and a checksum to IP: no connection, no retransmission, no ordering, and it keeps message boundaries. I pick TCP when every byte must arrive in order (web, SSH, BGP, databases, file transfer) and UDP when late data is useless or the application wants its own reliability (voice and video over RTP, DNS queries, DHCP, NTP, QUIC).

    Go deeper

    Side by side

    TCPUDP
    SetupThree-way handshakeNone
    DeliveryReliable, in order, duplicates removedBest effort, may be lost, duplicated or reordered
    UnitByte stream (no message boundaries)Datagram (one send, one receive)
    Flow controlReceive windowNone
    Congestion controlYes (CUBIC, BBR and others)None, the application must behave
    Header20 to 60 bytes8 bytes
    Multicast and broadcastNoYes
    IP protocol number617

    How I decide

    • Does late data still have value? A retransmitted voice sample arrives after the jitter buffer has played the gap. For real-time media, a lost packet is better than a late one, so RTP runs on UDP.
    • Is the exchange one small question and answer? DNS, NTP and SNMP fit in one datagram each way. A handshake would double the latency for no gain. DHCP has another reason: the client has no IP address yet and must broadcast.
    • Do I need one-to-many? Multicast and broadcast only work with UDP.
    • Do I want reliability but not TCP's behaviour? QUIC builds streams, retransmission and congestion control on top of UDP in user space, so it can evolve without kernel or middlebox changes.
    • Everything else that must be complete and correct goes on TCP.

    Traps

    • Saying UDP is "worse" because it is unreliable. It is a different tool: lower latency, no state, multicast.
    • Saying TCP guarantees delivery. It guarantees that the application gets the data in order or gets an error.
  2. Walk me through the TCP header. What does each field do?

    Say this first

    The TCP header is 20 bytes without options and up to 60 with them. It carries source and destination ports, a 32-bit sequence number, a 32-bit acknowledgment number, the data offset (header length in 4-byte words), the flags, a 16-bit receive window, a checksum, the urgent pointer, and then options such as MSS, window scale, SACK and timestamps.

    Go deeper

    Fields in order

    FieldBitsWhat it does
    Source port16Sender's port, usually ephemeral on the client
    Destination port16Receiver's port, for example 443
    Sequence number32Byte number of the first data byte in this segment (or the ISN in a SYN)
    Acknowledgment number32Next byte the sender of this segment expects to receive, valid when ACK is set
    Data offset4Header length in 32-bit words, 5 to 15, so 20 to 60 bytes
    Reserved4Must be zero
    Flags8CWR, ECE, URG, ACK, PSH, RST, SYN, FIN
    Window16Receive window in bytes, shifted left by the window scale factor if one was agreed
    Checksum16Covers a pseudo-header (source IP, destination IP, protocol, TCP length), the header and the data
    Urgent pointer16Only meaningful with URG, almost never used
    Options0 to 320Up to 40 bytes

    Options worth knowing by number

    KindOptionWhere
    0End of option listPadding
    1NOPAlignment padding
    2MSS (4 bytes)SYN and SYN-ACK only
    3Window scale (3 bytes)SYN and SYN-ACK only
    4SACK permitted (2 bytes)SYN and SYN-ACK only
    5SACK blocks (variable)Any segment after the handshake
    8Timestamps (10 bytes)SYN, then every segment if both agreed

    TCP has no length field of its own: the segment length is the IP total length minus the IP header minus the TCP data offset.

    Traps

    • Calling the window field "the congestion window". It is the receive window. The congestion window is never sent on the wire.
    • Forgetting that the header length field counts 4-byte words, so a value of 5 means 20 bytes.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  3. What are the TCP flags and when is each one set?

    Say this first

    There are eight in common use. SYN opens a connection and carries the initial sequence number. ACK says the acknowledgment field is valid and is set on every segment after the first SYN. FIN closes one direction gracefully. RST aborts the connection immediately. PSH asks the receiver to hand data to the application without waiting. URG marks urgent data and is almost unused. ECE and CWR carry explicit congestion notification signals.

    Go deeper

    What each flag means

    FlagtcpdumpMeaning
    SYNSSynchronize sequence numbers. Consumes one sequence number.
    ACK.Acknowledgment number is valid
    FINFNo more data from this side. Consumes one sequence number.
    RSTRAbort. No ACK is expected and the receiver drops the connection state.
    PSHPPush buffered data up to the application now
    URGUUrgent pointer is valid
    ECEEECN echo: a packet was marked CE (or, in a SYN, "I support ECN")
    CWRWCongestion window reduced: sender has reacted to ECE

    Common combinations in a capture

    • [S] client SYN, [S.] SYN-ACK, [.] pure ACK.
    • [P.] data with ACK, the normal data segment.
    • [F.] FIN with ACK, a graceful close.
    • [R] or [R.] reset. [R.] in reply to a SYN means the port is closed.

    Capturing only control segments

    Shell
    tcpdump -ni eth0 'tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0'

    Traps

    • Saying PSH is required for data to be delivered. Receivers deliver data without it. It is a hint.
    • Thinking a RST gets acknowledged. It does not; the receiver validates it and tears the connection down.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  4. What is in a UDP header, and what does UDP leave to the application?

    Say this first

    Eight bytes: source port, destination port, length (header plus data) and checksum, 16 bits each. UDP leaves everything else to the application: no handshake, no acknowledgment, no retransmission, no ordering, no flow control and no congestion control. The checksum is optional in IPv4 (zero means none) and mandatory in IPv6, apart from narrow tunnel exceptions.

    Go deeper

    Fields

    FieldBitsNotes
    Source port16May be 0 if no reply is expected, rarely seen
    Destination port16Selects the application
    Length16Header plus payload, minimum 8
    Checksum16Covers a pseudo-header, the header and the data

    Sizes

    The largest UDP payload over IPv4 is 65,507 bytes (65,535 minus 20 for IP and 8 for UDP). Anything over the path MTU is fragmented by IP, and losing one fragment loses the whole datagram. That is why DNS over UDP now aims for answers of about 1,232 bytes and QUIC sizes its own packets.

    What runs on UDP

    DNS 53, DHCP 67 and 68, TFTP 69, NTP 123, SNMP 161 and 162, syslog 514, IKE 500 and NAT-T 4500, RIP 520, BFD 3784, VXLAN 4789, QUIC and HTTP/3 on 443, RTP media on dynamic ports.

    What the application must add

    Timeouts and retries (DNS, TFTP), sequence numbers (RTP), its own rate control (RFC 8085 sets out guidelines for UDP applications), and keepalives to hold NAT and firewall state open.

    Traps

    • Saying UDP has no checksum. It has one; IPv4 lets it be zero, IPv6 normally requires it.
    How did you do?Book 5.1 Simple Demultiplexor (UDP)Own page
  5. Explain the TCP three-way handshake. What is exchanged besides SYN and ACK?

    Say this first

    The client sends a SYN with a random initial sequence number and its options. The server answers with a SYN-ACK carrying its own ISN and acknowledging the client's ISN plus one. The client sends an ACK for the server's ISN plus one. Along the way both sides announce their MSS, window scale, SACK support, timestamps and ECN support. The client goes SYN_SENT to ESTABLISHED; the server goes LISTEN to SYN_RCVD to ESTABLISHED.

    Go deeper

    The three segments

    Output
    Client (SYN_SENT)                              Server (LISTEN)
      SYN  seq=x       MSS 1460, SACK ok, TS, wscale 7       ->
                                                    (SYN_RCVD)
      <-   SYN,ACK  seq=y ack=x+1   MSS 1460, SACK ok, TS, wscale 7
    (ESTABLISHED)
      ACK  seq=x+1 ack=y+1                                   ->
                                                    (ESTABLISHED)

    The SYN and the SYN-ACK each use up one sequence number, which is why the acknowledgments are ISN plus one.

    Why three and not two

    Each side has to learn the other's ISN and know that its own ISN was received. Two ISNs need two acknowledgments; the server's SYN and its ACK share one segment, so three segments are enough. The exchange also defeats old duplicate SYNs: if a stale SYN reaches the server, the client answers the unexpected SYN-ACK with a RST instead of an ACK, and no connection opens.

    Why the ISN is random

    A predictable ISN lets an attacker who cannot see the traffic forge segments into a connection. RFC 6528 describes generating it from a keyed hash of the four-tuple plus a clock.

    Options that only exist in the handshake

    MSS, window scale and SACK permitted are only valid in SYN and SYN-ACK. If one side does not offer window scaling or SACK, neither side uses it. The third ACK may already carry data.

    Traps

    • Saying the acknowledgment number is the next byte the sender will send. It is the next byte it expects to receive.
    • Reading Wireshark's relative sequence numbers and claiming the ISN is 0.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  6. How does a TCP connection close? Walk through the four-way close and the states on each side.

    Say this first

    Each direction closes on its own with a FIN. The side that closes first sends FIN and enters FIN_WAIT_1. The peer ACKs it and enters CLOSE_WAIT; the first side moves to FIN_WAIT_2. When the peer's application closes, the peer sends its own FIN and enters LAST_ACK. The first side ACKs that FIN and sits in TIME_WAIT for two maximum segment lifetimes; the peer goes to CLOSED when that ACK arrives.

    Go deeper

    The sequence

    Output
    Active closer (A)                         Passive closer (B)
    ESTABLISHED                               ESTABLISHED
      FIN  ->
    FIN_WAIT_1                                CLOSE_WAIT   (B's app is told: end of stream)
                    <-  ACK
    FIN_WAIT_2                                 ... B may keep sending data ...
                    <-  FIN                   LAST_ACK     (B's app called close())
    TIME_WAIT
      ACK  ->                                 CLOSED
    (after 2 x MSL) CLOSED

    Three segments instead of four

    If B's application closes straight away, B sends its FIN in the same segment as the ACK. A capture then shows [F.], [F.], [.]. That is still the same state machine, just with the ACK and FIN combined.

    Half-close

    Between FIN_WAIT_2 and LAST_ACK, B can still send data and A must still receive and acknowledge it. shutdown(SHUT_WR) uses this on purpose: "I have finished sending, now give me the result".

    Simultaneous close

    If both sides send FIN at the same time, each goes FIN_WAIT_1, then CLOSING when it receives the other's FIN, then TIME_WAIT when its own FIN is acknowledged. Both sides end in TIME_WAIT.

    Traps

    • Mixing up CLOSE_WAIT and TIME_WAIT. CLOSE_WAIT is on the passive side waiting for its own app; TIME_WAIT is on the active side after the close.
    • Saying a FIN closes the connection in both directions. It only ends the sender's direction.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  7. What is a socket, and how can one web server on port 443 serve thousands of clients at once?

    Say this first

    A socket is the operating system's handle for one end of a conversation: protocol, local IP and port, and for a connected TCP socket the remote IP and port too. A TCP connection is identified by the five-tuple, so the server's listening socket on 443 can accept any number of connections: each new one has the same local address and port and a different client address or client port. Clients pick their source port from the ephemeral range.

    Go deeper

    Port ranges

    RangeNameNotes
    0 to 1023Well-known (system)Binding needs root or CAP_NET_BIND_SERVICE on Linux
    1024 to 49151Registered (user)Assigned by IANA to applications
    49152 to 65535Dynamic (private)IANA's suggested ephemeral range

    Defaults differ: Linux uses 32768 to 60999 (net.ipv4.ip_local_port_range), Windows uses 49152 to 65535.

    What really limits connections

    On the server: memory and file descriptors, not ports. One port can carry millions of connections. On the client: the number of free source ports for each destination IP and port, because the four-tuple must be unique. Behind PAT, every inside host shares the outside address's ports, which is where port exhaustion usually shows up.

    Listening versus accepted sockets

    Shell
    ss -tn state established '( sport = :443 )'

    Every line has local port 443 and a different peer. The single LISTEN socket is separate and only queues new connections for the application to accept().

    Traps

    • Saying a server "runs out of ports" because it has many clients. Clients run out of source ports; servers run out of memory or file descriptors.
  8. Rattle off the well-known ports an interviewer expects you to know, with TCP or UDP for each.

    Say this first

    FTP 20 and 21, SSH 22, Telnet 23, SMTP 25, DNS 53 on UDP and TCP, DHCP 67 and 68 UDP, TFTP 69 UDP, HTTP 80, POP3 110, NTP 123 UDP, IMAP 143, SNMP 161 and 162 UDP, BGP 179 TCP, LDAP 389, HTTPS 443 on TCP and on UDP for QUIC, SMB 445, IKE 500 UDP, syslog 514 UDP, RDP 3389, RADIUS 1812 and 1813 UDP, TACACS+ 49 TCP.

    Go deeper

    Network engineer's list

    PortProtoService
    20, 21TCPFTP data, FTP control
    22TCPSSH, SCP, SFTP
    23TCPTelnet
    25, 587, 465TCPSMTP relay, mail submission, submission over implicit TLS
    49TCPTACACS+
    53UDP, TCPDNS (853 TCP for DNS over TLS)
    67, 68UDPDHCP server, DHCP client
    69UDPTFTP
    80, 443TCPHTTP, HTTPS
    443UDPQUIC and HTTP/3
    110, 995TCPPOP3, POP3S
    123UDPNTP
    143, 993TCPIMAP, IMAPS
    161, 162UDPSNMP queries, SNMP traps and informs
    179TCPBGP
    389, 636TCPLDAP, LDAPS
    445TCPSMB
    500, 4500UDPIKE, IPsec NAT traversal
    514UDPSyslog (6514 TCP for syslog over TLS)
    520UDPRIP
    646TCP, UDPLDP sessions, LDP discovery
    830TCPNETCONF over SSH
    1812, 1813UDPRADIUS authentication, accounting (old: 1645, 1646)
    1985UDPHSRP
    3389TCPRDP
    3784UDPBFD single-hop control
    4789UDPVXLAN
    5060, 5061UDP, TCPSIP, SIP over TLS

    Protocols that are not ports

    These ride directly on IP and are matched by protocol number: ICMP 1, TCP 6, UDP 17, GRE 47, ESP 50, AH 51, EIGRP 88, OSPF 89, VRRP 112.

    Traps

    • Giving a port number for OSPF, EIGRP, GRE or ESP. They are IP protocol numbers.
    • Saying SNMP traps go to 161. Agents listen on 161; managers receive traps and informs on 162.
  9. What is the TCP sliding window, and how is flow control different from congestion control?

    Say this first

    The receiver advertises a receive window in every segment: how many more bytes it has buffer space for. The sender may have at most the smaller of that receive window and its own congestion window sent but not yet acknowledged. As ACKs arrive the window slides forward and more data can go. Flow control protects the receiver and is driven by the receiver's advertised window. Congestion control protects the network and is the sender's private estimate, the congestion window, which never appears in a packet.

    Go deeper

    The picture

    Output
    bytes:  | acked | sent, not acked | can send now | cannot send yet |
                    ^ SND.UNA         ^ SND.NXT      ^ SND.UNA + window

    Usable window = min(rwnd, cwnd) minus bytes in flight. When the receiver's application reads data, the receiver advertises a bigger window. When the sender gets ACKs, SND.UNA moves right.

    Why it bounds throughput

    A sender can put at most one window of data on the wire per round trip, so one flow's throughput is at most window / RTT. That single formula explains most "fast link, slow transfer" tickets.

    Who sets what

    ControlVariableSet byVisible in packets
    Flow controlrwndReceiver, from free bufferYes, Window field
    Congestion controlcwndSender's algorithmNo

    Traps

    • Saying the window is counted in segments. The advertised window is in bytes (after scaling).
  10. Explain slow start and congestion avoidance. What is ssthresh?

    Say this first

    A new connection does not know the path's capacity, so it starts with a small congestion window, 10 segments on modern stacks. In slow start cwnd grows by one segment per ACK, which doubles it every round trip. When cwnd reaches ssthresh, TCP switches to congestion avoidance and grows by about one segment per round trip. On loss detected by duplicate ACKs, ssthresh is set to about half the data in flight and cwnd drops to it. On a timeout, cwnd goes back to one segment and slow start begins again. ssthresh is the line between the two phases.

    Go deeper

    Round by round

    RTTPhasecwnd (segments)
    1Slow start10
    2Slow start20
    3Slow start40
    4Slow start80, loss detected
    5Recoveryssthresh = 40, cwnd = 40
    6Congestion avoidance41
    7Congestion avoidance42

    This additive increase and multiplicative decrease (AIMD) makes the familiar sawtooth.

    Why the initial window matters

    An initial window of 10 segments (RFC 6928) is about 14.6 KB. A small web response fits in the first flight; a large one needs several round trips of slow start, which is why latency, not bandwidth, dominates small transfers.

    Slow start after idle

    Linux shrinks cwnd back toward the initial window when a connection has been idle for longer than one RTO (net.ipv4.tcp_slow_start_after_idle=1). Long-lived connections that send in bursts, like HTTP/2 or database links, sometimes turn it off.

    Traps

    • Saying cwnd starts at one segment on modern systems. Linux and most stacks start at 10.
    How did you do?Book 6.3 TCP Congestion ControlOwn page
  11. What is the difference between MTU and MSS, and why is the usual MSS 1460?

    Say this first

    The MTU is the largest IP packet a link can carry without fragmenting it: 1,500 bytes on standard Ethernet. The MSS is the largest TCP payload a host is willing to receive in one segment, announced in its SYN. On a 1,500-byte link it is 1,500 minus 20 bytes of IPv4 header minus 20 bytes of TCP header, so 1,460; with IPv6's 40-byte header it is 1,440. MSS is about TCP data only, MTU is about whole IP packets.

    Go deeper

    The layers of a full-size packet

    PieceBytes
    TCP payload (MSS)1,460
    TCP header20
    IPv4 header20
    IP packet = MTU1,500
    Ethernet header + FCS14 + 4
    Frame on the wire1,518 (1,522 with an 802.1Q tag)

    With TCP timestamps on, every segment carries 12 bytes of options, so the data per packet is 1,448 even though the SYN still advertises 1,460. ss -ti shows this as mss:1448.

    Common MTUs and matching MSS

    LinkIP MTUMSS
    Ethernet1,5001,460
    PPPoE (8-byte header)1,4921,452
    GRE over 1,500 (24 bytes overhead)1,4761,436
    GRE over IPsec, common safe value1,4001,360
    Jumbo frames9,0008,960

    MSS is announced, not negotiated

    Each side tells the other what it can receive. The two directions can use different sizes. If a SYN has no MSS option, the default is 536 bytes for IPv4 and 1,220 for IPv6.

    Traps

    • Saying MSS includes the TCP header. It is payload only.
    • Saying the two hosts negotiate one shared MSS. Each announces its own receive limit.
  12. What changed between HTTP/1.1, HTTP/2 and HTTP/3?

    Say this first

    HTTP/1.1 is text over TCP with persistent connections, but one request at a time per connection, so browsers open about six connections per host. HTTP/2 keeps TCP but switches to binary frames and multiplexes many streams over one connection, with HPACK header compression; one lost TCP segment still stalls every stream. HTTP/3 runs over QUIC on UDP 443, with streams that are independent at the transport layer, TLS 1.3 built in and QPACK compression.

    Go deeper

    Side by side

    HTTP/1.1HTTP/2HTTP/3
    TransportTCPTCPQUIC over UDP
    FormatTextBinary framesBinary frames
    Requests per connectionOne at a time (pipelining unused)Many concurrent streamsMany concurrent streams
    Header compressionNoneHPACKQPACK
    EncryptionOptional (HTTPS)Browsers require TLSAlways TLS 1.3
    Lost packet blocksThat connectionAll streams on the connectionOnly the affected stream
    Setup round trips with TLS 1.32 (TCP + TLS)2 (TCP + TLS)1, or 0 on resumption

    How the client chooses

    • HTTP/2: ALPN in the TLS handshake. The client offers h2,http/1.1 and the server picks.
    • HTTP/3: the server advertises it, either with an Alt-Svc: h3=":443" response header or a DNS HTTPS record. The browser then tries QUIC and falls back to TCP if UDP 443 is blocked.

    RFCs

    HTTP semantics RFC 9110, HTTP/1.1 RFC 9112, HTTP/2 RFC 9113 (originally 7540), HTTP/3 RFC 9114, QUIC RFC 9000.

    Traps

    • Saying HTTP/2 needs TLS by specification. The spec allows cleartext h2c; browsers only use h2 over TLS.
    • Saying HTTP/3 uses TCP 443.
  13. What is a certificate chain of trust, and what does a client check before it trusts a server certificate?

    Say this first

    A server certificate (the leaf) binds a public key to names and is signed by an intermediate CA, which is signed by a root CA that the client already trusts in its store. The server sends the leaf plus the intermediates; the client builds a path to a trusted root and checks each signature, the validity dates, that the hostname matches a Subject Alternative Name, that the key usage allows server authentication, that each issuer is really a CA, and revocation and certificate transparency where its policy requires. A missing intermediate is the classic outage.

    Go deeper

    The chain

    Output
    Root CA            (self-signed, in the OS or browser trust store, not sent by the server)
      signs ->  Intermediate CA   (sent by the server)
                  signs ->  Leaf: shop.example.com   (sent by the server, first)

    Roots stay offline; intermediates do daily issuing so a compromise can be contained.

    Checks, in the order a client roughly applies them

    1. Build a path from leaf to a trusted root using what the server sent and the local store.
    2. Each certificate's signature verifies with its issuer's public key.
    3. Every certificate is within its notBefore and notAfter dates.
    4. Issuers have Basic Constraints CA:TRUE, and path length and name constraints are respected.
    5. The leaf's Extended Key Usage includes serverAuth.
    6. The hostname matches a DNS name in the SAN. Browsers ignore the Common Name.
    7. Revocation (CRL or OCSP, often stapled by the server) and, in browsers, certificate transparency proofs.

    Wildcards

    *.example.com matches shop.example.com, but not example.com and not a.shop.example.com. The wildcard covers exactly one label.

    Lifetimes are shrinking

    The CA/Browser Forum has voted to cut the maximum lifetime of public TLS certificates in steps, down to 47 days by 2029. Renewal has to be automated, usually with ACME.

    Traps

    • Saying the browser checks the Common Name. Modern clients only match the SAN.
    • Fixing a chain error by installing the intermediate on one client. Fix the server so every client works.
  14. What does HTTPS protect, and what can someone watching the network still see?

    Say this first

    HTTPS protects the content of the HTTP exchange: the URL path and query, headers, cookies and bodies are encrypted and tamper-proof, and the certificate proves the client is talking to the named server. An observer still sees the IP addresses and ports, the timing and size of the traffic, the DNS lookup unless it is encrypted, and the hostname in the SNI field of the ClientHello unless Encrypted Client Hello is used. With TLS 1.2 the server certificate is also visible.

    Go deeper

    Visible versus hidden

    ItemVisible on the wire
    Client and server IP, portsYes
    DNS query for the nameYes, unless DNS over HTTPS or TLS
    Hostname in SNIYes, unless ECH
    Server certificateTLS 1.2 yes, TLS 1.3 no
    Path, query string, headers, cookies, bodyNo
    Size and timing of requestsYes, which allows traffic analysis

    How enterprise firewalls filter HTTPS

    • Without decryption: by destination IP, SNI and, for TLS 1.2, the certificate.
    • With decryption: the firewall acts as a proxy and signs a substitute certificate with an enterprise CA that managed devices trust. Pinned or mutually authenticated applications break and are usually exempted.

    HSTS

    A Strict-Transport-Security header tells the browser to use HTTPS only for that site for a period, so a later typed http:// link is upgraded before any packet is sent. Preload lists ship that rule in the browser.

    Traps

    • Saying HTTPS hides the domain name. The SNI is plaintext without ECH.

Working16

  1. Why does TIME_WAIT exist, how long does it last, and is a server with 30,000 sockets in TIME_WAIT a problem?

    Say this first

    The side that closes first waits two maximum segment lifetimes for two reasons: to re-send the last ACK if the peer's FIN is retransmitted, and to let stray segments from this connection expire before the same four-tuple can be reused. RFC 793 set MSL at 2 minutes, so 4 minutes; Linux uses a fixed 60 seconds. Thirty thousand TIME_WAIT sockets on a server cost little memory and are normal. The real risk is on a client or proxy opening many short connections to one destination IP and port, where TIME_WAIT can use up the ephemeral ports.

    Go deeper

    Why it is cheap on a server

    A server's TIME_WAIT entries all share its listening port and differ by client address and port, so they never block new connections. Linux keeps them in a small structure without buffers.

    Where it hurts

    A proxy, load balancer or application server connecting to one backend 10.0.0.50:8080 needs a unique source port per connection. Linux's default range is 32768 to 60999, so 28,232 ports. If each connection is closed by the client and waits 60 seconds, the ceiling is about 28,232 / 60, roughly 470 new connections per second to that one backend address and port. Past that, connect() fails with EADDRNOTAVAIL ("Cannot assign requested address").

    Fixes, best first

    1. Reuse connections: HTTP keep-alive, connection pools, gRPC.
    2. Let the server close first, so TIME_WAIT lands on the side that is not short of ports.
    3. Add source IPs or backend IPs, since the limit is per four-tuple.
    4. Widen net.ipv4.ip_local_port_range.
    5. net.ipv4.tcp_tw_reuse=1 lets new outgoing connections reuse a TIME_WAIT four-tuple when timestamps show it is safe. Recent kernels default to 2, which means loopback only.

    What not to do

    tcp_tw_recycle was removed in Linux 4.12. It dropped SYNs from clients behind NAT whose timestamps did not increase across hosts. Closing with SO_LINGER set to 0 avoids TIME_WAIT by sending RST, and throws away unsent data.

    Traps

    • Tuning servers to "fix" TIME_WAIT counts that cause no errors. Measure port exhaustion first.
    • Recommending tcp_tw_recycle. It no longer exists and broke clients behind NAT.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  2. Name the TCP states and tell me what a pile-up in each one usually means when you run ss or netstat.

    Say this first

    The states are LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, CLOSE_WAIT, CLOSING, LAST_ACK, TIME_WAIT and CLOSED. Many SYN_SENT means SYNs are not answered; many SYN_RCVD points at a SYN flood or lost final ACKs; many CLOSE_WAIT is almost always an application that does not close its sockets; many TIME_WAIT is normal on the side that closes first.

    Go deeper

    What each pile-up tells you

    StateSideMany of them usually means
    SYN_SENTClientPeer down, route missing, or a firewall dropping SYNs silently
    SYN_RCVDServerSYN flood, or the client's final ACK not arriving (asymmetric path through a stateful firewall)
    ESTABLISHEDBothNormal. Steady growth is a connection leak or a slow backend
    FIN_WAIT_1Active closerOur FIN is not acknowledged: peer gone, or unsent data stuck behind a zero window
    FIN_WAIT_2Active closerPeer acknowledged our FIN but its application never closed
    CLOSE_WAITPassive closerOur application received end of stream and never called close()
    LAST_ACKPassive closerOur FIN is not acknowledged, peer probably gone
    CLOSINGBothSimultaneous close, rare and short-lived
    TIME_WAITActive closerNormal. A problem only if ephemeral ports run out

    Naming differs by tool

    netstat prints SYN_SENT, ESTABLISHED, CLOSE_WAIT. ss prints SYN-SENT, SYN-RECV, ESTAB, CLOSE-WAIT, TIME-WAIT, and UNCONN for unconnected UDP sockets.

    Quick count on Linux

    Shell
    ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn

    Traps

    • Blaming the network for CLOSE_WAIT. The kernel has done its part; the local application has not.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  3. Walk me through sequence and acknowledgment numbers for a short exchange, with real numbers.

    Say this first

    The sequence number is the number of the first data byte in a segment; the acknowledgment number is the next byte the receiver expects, and it is cumulative. SYN and FIN each use one number; pure ACKs use none. If the client starts at 1000 and sends 200 bytes after the handshake, its data segment is seq 1001 and the server acknowledges 1201.

    Go deeper

    Worked example

    Real ISNs are random 32-bit numbers. Small ones keep the arithmetic visible. Client ISN 1000, server ISN 5000.

    #DirectionFlagsSeqAckLenWhy
    1C to SSYN10000Client ISN
    2S to CSYN, ACK500010010Server ISN; SYN used byte 1000
    3C to SACK100150010Pure ACK uses no number
    4C to SPSH, ACK10015001200Request, bytes 1001 to 1200
    5S to CACK500112011460Response part 1, bytes 5001 to 6460
    6S to CPSH, ACK64611201500Response part 2, bytes 6461 to 6960
    7C to SACK120169610One ACK covers both segments
    8C to SFIN, ACK120169610FIN uses byte 1201
    9S to CFIN, ACK696112020Acks the FIN; FIN uses byte 6961
    10C to SACK120269620Final ACK, client enters TIME_WAIT

    Rules to say out loud

    • Next seq from a sender = this seq + payload length (+1 for SYN or FIN).
    • Ack = highest in-order byte received + 1. It never jumps over a hole.
    • One ACK can cover many segments (segment 7), and with delayed ACK it usually covers two.

    When segment 5 is lost

    The client receives segment 6 first. It cannot advance past the hole, so it sends ack 5001 again (a duplicate ACK), with a SACK block 6461-6961 if SACK was agreed. The server sees exactly which bytes to resend.

    Traps

    • Adding 1 for a pure ACK. Only SYN, FIN and data bytes use sequence numbers.
  4. What is the difference between a connection closed with FIN and one reset with RST, and what causes resets?

    Say this first

    FIN is a graceful close of one direction: all data sent before it is delivered and acknowledged, and the other side can keep sending. RST aborts the whole connection at once: unsent and unread data is thrown away and the application gets "connection reset by peer". Resets come from a SYN to a closed port, an application closing with unread data or with linger set to zero, a segment that matches no connection (for example after a reboot), and middleboxes such as firewalls and load balancers that kill sessions.

    Go deeper

    Common sources of RST

    CauseWhat you see
    SYN to a port with no listener[R.] right after the SYN, client error "connection refused"
    Peer rebooted or lost stateOur next data segment gets a RST (the half-open case)
    App closed with data still unread in its receive bufferLinux sends RST instead of FIN
    SO_LINGER with timeout 0Deliberate abortive close
    Firewall or IPS policyRST injected toward one or both ends
    Load balancer or firewall idle timeoutNext packet after idle hits no state; some devices send RST

    Who really sent it

    Compare the RST with the real peer's packets. A RST forged by a middlebox often has a different IP TTL, a different IP ID pattern, or arrives faster than the peer's RTT allows. Capturing on both sides of the firewall settles it.

    RST validation

    A RST is only accepted if its sequence number matches exactly what the receiver expects next. If it is merely inside the window, the receiver sends a challenge ACK instead (RFC 5961). That makes blind reset attacks much harder.

    Traps

    • Assuming every RST came from the server. Middleboxes send them too, and the capture must prove who did.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  5. Why was TCP window scaling needed, and how does it work?

    Say this first

    The window field is 16 bits, so without help the receive window tops out at 65,535 bytes. At 100 ms RTT that caps one flow at about 5.2 Mbit/s whatever the link speed. The window scale option (RFC 7323) is sent in the SYN and SYN-ACK with a shift count from 0 to 14; after the handshake each side multiplies the window field by 2 to the power of the peer's shift, up to about 1 GiB. Both sides must offer it, or neither side scales.

    Go deeper

    Example

    A Linux host with default buffers sends wscale 7 in its SYN. Later its segments show win 502. The real window is 502 x 128 = 64,256 bytes. Each side picks its own shift from its maximum receive buffer, so the two values can differ.

    Rules worth saying

    • Only in SYN and SYN-ACK. The factor cannot change during the connection.
    • If the client sends it and the SYN-ACK does not, scaling is off in both directions.
    • The maximum shift is 14, so the largest window is 65,535 x 16,384, about 1 GiB.

    Where it goes wrong

    • A capture that starts mid-connection. Wireshark cannot know the factor and shows the raw field; it labels the scaling factor -1 (unknown). Capture from the SYN.
    • A middlebox that strips or rewrites the option. The connection works but every flow is capped at 64 KB per RTT. Captures on both sides of the device show the option disappearing.
    • An application that sets SO_RCVBUF. On Linux that fixes the buffer and turns off receive autotuning for that socket, which can leave the window far smaller than the path needs.

    Traps

    • Reading win 502 in tcpdump as 502 bytes. tcpdump prints the raw field; multiply by the agreed scale.
  6. What is the bandwidth-delay product? Work out the window you need for a 1 Gbit/s path with 80 ms RTT.

    Say this first

    The bandwidth-delay product is how much data must be in flight to keep a path full: bandwidth times round-trip time. For 1 Gbit/s and 80 ms that is 1,000,000,000 x 0.08 = 80,000,000 bits, which is 10 MB. One TCP flow needs a receive window, a congestion window and a send buffer of at least 10 MB to fill it. With an unscaled 64 KB window the same flow tops out at 65,535 x 8 / 0.08, about 6.5 Mbit/s.

    Go deeper

    The formulas

    • BDP (bytes) = bandwidth (bit/s) x RTT (s) / 8
    • Max throughput of one flow = window (bytes) x 8 / RTT (s)

    Worked examples

    PathBDP64 KB window gives
    1 Gbit/s, 1 ms (inside a data center)125 KBabout 524 Mbit/s
    100 Mbit/s, 20 ms250 KBabout 26 Mbit/s
    1 Gbit/s, 80 ms10 MBabout 6.5 Mbit/s
    10 Gbit/s, 100 ms125 MBabout 5.2 Mbit/s

    Loss matters too

    Even with big enough windows, loss-based congestion control limits a flow on a lossy long path. The Mathis approximation for Reno-style TCP is throughput = (MSS / RTT) x (1.22 / sqrt(loss)). With MSS 1460, RTT 80 ms and 0.01% loss: (1460 x 8 / 0.08) x (1.22 / 0.01) = 146 kbit/s x 122, about 17.8 Mbit/s. That is why long-haul transfers also need a clean path, or a less loss-sensitive algorithm such as BBR.

    What I check on a slow long-distance transfer

    1. RTT with ping, and the observed rate. If rate x RTT is close to 64 KB, the window is the limit.
    2. ss -ti on the sender: wscale, cwnd, rtt, retrans, and rwnd_limited time.
    3. Buffer maximums on both hosts (tcp_rmem, tcp_wmem) against the BDP.

    Traps

    • Forgetting to convert bits to bytes. 1 Gbit/s x 80 ms is 80 Mbit, which is 10 MB, not 80 MB.
    • Using one-way delay instead of round-trip time.
  7. How does TCP decide when to retransmit, and how is the retransmission timeout calculated?

    Say this first

    TCP retransmits either when the retransmission timer fires or earlier, when duplicate ACKs or SACK show a hole (fast retransmit). The timer, RTO, comes from measured round-trip times (RFC 6298): RTO = smoothed RTT + 4 x RTT variance, starting at 1 second before any sample. Each time the timer fires, the RTO doubles. A timeout is expensive: the congestion window drops to one segment and the sender goes back to slow start. Linux uses a 200 ms minimum RTO, lower than the RFC's 1 second.

    Go deeper

    The calculation

    • First sample R: SRTT = R, RTTVAR = R / 2.
    • Later samples R': RTTVAR = 3/4 RTTVAR + 1/4 abs(SRTT - R'), then SRTT = 7/8 SRTT + 1/8 R'.
    • RTO = SRTT + max(G, 4 x RTTVAR), where G is the clock granularity.
    • Bounds: the RFC says at least 1 second; Linux uses 200 ms minimum and 120 seconds maximum.

    Karn's algorithm

    An ACK for a retransmitted segment is ambiguous: it may acknowledge the first copy or the second. TCP takes no RTT sample from it, and keeps the backed-off RTO until a fresh sample arrives. Timestamps remove the ambiguity because the echoed value says which copy is being acknowledged.

    When the timer fires

    ssthresh = max(flight size / 2, 2 x MSS), cwnd = 1 segment, retransmit the oldest unacknowledged segment, double the RTO. On Linux an established connection gives up after net.ipv4.tcp_retries2 (15) retransmissions, at least about 15 minutes.

    Avoiding the timer

    Most losses should be repaired by fast retransmit. Linux also sends a tail loss probe about two RTTs after the last segment if nothing has been acknowledged, so a lost final segment triggers recovery without waiting for the full RTO.

    Traps

    • Saying the RTO is a fixed value. It adapts to the measured RTT and backs off exponentially.
  8. What is fast retransmit, why three duplicate ACKs, and what happens to the congestion window afterwards?

    Say this first

    When one segment is lost, every later segment that arrives makes the receiver repeat the same ACK for the missing byte. After three duplicate ACKs, the fourth identical ACK in a row, the sender retransmits the missing segment at once instead of waiting for the RTO. Three is the threshold because reordering commonly causes one or two duplicates. Then fast recovery cuts ssthresh to about half the flight size (to 0.7 times with CUBIC) and continues from there instead of dropping to one segment.

    Go deeper

    Worked example

    The sender sends segments 1 to 6, each 1,000 bytes, starting at byte 1. Segment 3 (bytes 2001 to 3000) is lost.

    Receiver getsIt sendsSender sees
    Seg 1ACK 1001
    Seg 2ACK 2001
    Seg 4ACK 2001 (SACK 3001-4001)Dup ACK 1
    Seg 5ACK 2001 (SACK 3001-5001)Dup ACK 2
    Seg 6ACK 2001 (SACK 3001-6001)Dup ACK 3: retransmit seg 3
    Seg 3 (again)ACK 6001Hole filled, everything acknowledged

    Wireshark labels these TCP Dup ACK and TCP Fast Retransmission.

    Fast recovery (RFC 5681, Reno style)

    1. ssthresh = max(flight size / 2, 2 x MSS).
    2. Retransmit the lost segment.
    3. Keep sending new data as duplicate ACKs show segments leaving the network.
    4. When new data is acknowledged, set cwnd to ssthresh and continue in congestion avoidance.

    NewReno handles several losses in one window. SACK tells the sender exactly which blocks are missing. Linux now detects loss by time with RACK-TLP (RFC 8985) rather than only counting duplicates, which copes better with reordering, and paces the reduction with proportional rate reduction.

    Traps

    • Saying "three ACKs" trigger it. It is three duplicates, the fourth identical ACK in a row.
  9. What does selective acknowledgment add on top of cumulative ACKs?

    Say this first

    A cumulative ACK only says "everything up to here". With several losses in one window the sender learns about one hole per round trip. SACK (RFC 2018), agreed with SACK-permitted in the handshake, lets the receiver list up to three or four blocks of data it holds beyond the hole. The sender resends only the gaps and can repair several losses in about one RTT.

    Go deeper

    What it looks like

    Output
    10.2.20.30.5201 > 10.1.10.20.51544: Flags [.], ack 1001, win 501, options [nop,nop,TS val 2154883120 ecr 1209364471,nop,nop,sack 1 {2461:5381}], length 0

    The receiver has everything up to byte 1000 and also bytes 2461 to 5380. Bytes 1001 to 2460, one 1,460-byte segment, are missing.

    Details that come up

    • SACK blocks are advisory. The receiver may discard SACKed data, so the sender keeps it until it is cumulatively acknowledged.
    • D-SACK (RFC 2883) reports data received twice, which lets the sender detect spurious retransmissions.
    • Any device that rewrites sequence numbers, for example a firewall that randomises ISNs, must rewrite SACK edges as well. When one did not, SACK-based recovery stalled.

    Traps

    • Thinking a SACKed segment can be forgotten by the sender. Only the cumulative ACK releases data.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  10. What are TCP keepalives, what are the Linux defaults, and how are they different from HTTP keep-alive and BGP keepalives?

    Say this first

    A TCP keepalive is an empty probe the stack sends on an idle connection, carrying a sequence number one below what the peer expects, so the peer must answer with an ACK. If enough probes go unanswered, the connection is reset and the application gets an error. It is off unless the application sets SO_KEEPALIVE. Linux defaults are 7,200 seconds idle, 75 seconds between probes and 9 probes, so a dead peer is found after about 2 hours 11 minutes. HTTP keep-alive just means reusing a connection for more requests. BGP keepalives are BGP messages, every 60 seconds with a 180-second hold time on Cisco.

    Go deeper

    Two jobs

    1. Find dead peers. A peer that crashed or lost its state leaves a half-open connection: our side thinks it is ESTABLISHED forever if we never send. A probe gets a RST or no answer.
    2. Keep middlebox state alive. Firewalls and NAT remove idle flows after their idle timeout, often an hour or less. A 2-hour default keepalive is too slow to help; the application's next packet then hits a device with no state and is dropped or reset.

    Tuning

    System-wide on Linux:

    Shell
    sysctl net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_intvl net.ipv4.tcp_keepalive_probes

    Per socket, which is better: TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT. A common rule is an idle time shorter than the shortest idle timeout in the path, for example 300 seconds.

    Related

    TCP_USER_TIMEOUT caps how long sent data may stay unacknowledged before the connection is dropped, which catches dead peers on busy connections where keepalive never triggers.

    Traps

    • Confusing HTTP keep-alive (connection reuse) with TCP keepalive (idle probes).
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  11. You see TCP ZeroWindow in a capture. What does it mean and whose fault is it?

    Say this first

    The receiver advertised a window of zero: its receive buffer is full because its application is not reading fast enough. The sender stops, starts the persist timer and sends small zero-window probes until the receiver advertises space again with a window update. It points at the receiving host or its application (CPU, disk, a slow consumer), not at the network.

    Go deeper

    Wireshark labels and who sends them

    LabelSent byMeaning
    TCP Window FullSenderIt has sent everything the receiver's window allows
    TCP ZeroWindowReceiverWindow field is 0
    TCP ZeroWindowProbeSenderPersist timer probe
    TCP ZeroWindowProbeAckReceiverAnswer, usually still 0
    TCP Window UpdateReceiverWindow opened again

    Proving it on the hosts

    • Receiver: ss -tn shows a large Recv-Q on that connection: data the kernel holds that the application has not read.
    • Sender: ss -tn shows a large Send-Q: data waiting for window.

    Why the persist timer exists

    If the receiver's window update were lost, both sides would wait forever. The sender's probes force a fresh ACK carrying the current window.

    Silly window syndrome

    A receiver that advertises every few freed bytes makes the sender send tiny segments. Receivers wait until they can open a meaningful amount (an MSS or half the buffer) before advertising.

    Traps

    • Treating ZeroWindow as packet loss or congestion. It is flow control doing its job.
  12. How does Path MTU Discovery work, and what is a PMTUD black hole?

    Say this first

    The sender sets the Don't Fragment bit on its packets. A router that cannot forward a packet because the next link's MTU is smaller drops it and sends back ICMP type 3 code 4, "fragmentation needed and DF set", with the next-hop MTU. The sender lowers its packet size for that destination and resends. In IPv6 the message is ICMPv6 Packet Too Big, and routers never fragment. A black hole happens when that ICMP message never reaches the sender, usually because a firewall drops all ICMP. Small packets work, large ones vanish, and connections hang as soon as a full-size segment is needed.

    Go deeper

    Symptoms that shout MTU

    • Ping works, the TCP handshake works, small requests work.
    • Large transfers stall: web pages load partly, SSH logs in but a long directory listing hangs, file copies freeze at the first big read.
    • TLS handshakes stall when the server sends its certificate chain, the first large packet.
    • One direction works and the other does not (uploads fine, downloads hang).

    How I test from Linux

    Shell
    ping -M do -s 1472 -c 3 10.30.0.10
    ping -M do -s 1448 -c 3 10.30.0.10
    tracepath -n 10.30.0.10

    1472 + 8 ICMP + 20 IP = 1,500. If 1,472 fails with no "Frag needed" message and a smaller size works, something is dropping packets above the real path MTU and the ICMP is not coming back.

    Fixes, best first

    1. Permit ICMP type 3 code 4 (and ICMPv6 type 2) through every firewall and ACL in the path.
    2. Clamp the TCP MSS where the MTU shrinks, such as tunnel interfaces (ip tcp adjust-mss).
    3. Set a correct ip mtu on tunnels so the router itself sends a correct ICMP message.
    4. Enable packetization layer PMTUD on hosts (net.ipv4.tcp_mtu_probing=1 on Linux), which probes with smaller segments when it detects a black hole instead of relying on ICMP.

    Clearing the DF bit on a router makes TCP work by forcing fragmentation, which costs CPU and can break under load. It also cannot help IPv6.

    Traps

    • Blocking all ICMP "for security". Type 3 code 4 and ICMPv6 type 2 are needed for the network to work.
    How did you do?Book 3.3 Internet (IP)Own page
  13. What is MSS clamping, how do you configure it on IOS and Linux, and what does it not fix?

    Say this first

    MSS clamping makes a router rewrite the MSS option in TCP SYN and SYN-ACK segments passing through it, so both hosts agree to segments that fit the smallest link without relying on ICMP. On IOS it is ip tcp adjust-mss 1360 on the interface, typically a tunnel; on Linux it is an iptables or nftables rule. It only works for TCP whose handshake passes through the device, so it does nothing for UDP traffic such as QUIC, DNS or other VPNs.

    Go deeper

    IOS-XE

    Cisco IOS
    interface Tunnel0
     ip mtu 1400
     ip tcp adjust-mss 1360
     ipv6 mtu 1400
     ipv6 tcp adjust-mss 1340

    ip tcp adjust-mss acts on SYNs entering and leaving the interface, only ever lowers the value, and accepts 500 to 1460. 1360 = 1400 - 20 (IP) - 20 (TCP). For IPv6 subtract 60.

    Linux router

    Shell
    iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

    nftables:

    Shell
    nft add rule inet filter forward tcp flags syn tcp option maxseg size set rt mtu

    Junos SRX

    Junos
    set security flow tcp-mss ipsec-vpn mss 1350

    What clamping does not cover

    • UDP: QUIC, DNS, IPsec from hosts, WireGuard. They need PMTUD or conservative sizes of their own.
    • TCP whose SYN takes a different path (asymmetric routing) than the data.
    • TCP inside an encrypted tunnel the router only sees from outside.
    • Packets that are already large for other reasons, such as non-TCP protocols.

    So clamping is a strong safety net, but ICMP should still be allowed.

    Traps

    • Claiming MSS clamping fixes all MTU problems. It only helps TCP whose handshake it sees.
  14. What is QUIC, why does it run over UDP, and what does it change for network engineers?

    Say this first

    QUIC (RFC 9000) is a reliable, multiplexed, encrypted transport built on UDP, normally on port 443 under HTTP/3. It has its own streams, retransmission, flow control and congestion control, with TLS 1.3 built into the handshake, so a new connection is ready in one round trip. It uses UDP because a new IP protocol would be blocked by NAT and firewalls and would need kernel changes everywhere; UDP passes through and QUIC can live in user space. For network teams it means almost everything is encrypted, including ACKs, so firewalls see far less, MSS clamping does not apply, and UDP idle timeouts matter.

    Go deeper

    Features worth naming

    • Connection IDs instead of the four-tuple identify a connection, so a phone moving from Wi-Fi to LTE keeps its connection (connection migration).
    • Streams are independent: a loss stalls only its own stream.
    • Packet numbers never repeat, so retransmissions are not ambiguous for RTT measurement.
    • 0-RTT on resumption, with the same replay caveats as TLS 1.3.
    • Header protection encrypts packet numbers. On-path devices see little more than the destination connection ID and a few flag bits, including an optional spin bit that lets them estimate RTT.

    Sizes and safety

    • The client pads its first Initial datagram to at least 1,200 bytes, and QUIC assumes the path carries at least 1,200-byte UDP payloads.
    • Before the client's address is validated, a server may send at most three times the bytes it received, which limits amplification attacks.

    What the network can and cannot see

    Initial packets are encrypted with keys derived from the connection ID that is sent in clear, so any middlebox can decrypt them and read the ClientHello, including the SNI. Everything after the handshake is opaque. A firewall that wants TLS inspection or URL filtering has to block UDP 443 and force a TCP fallback.

    Traps

    • Saying QUIC is unreliable because it runs over UDP. It provides its own reliability.
  15. Walk me through a TLS 1.3 handshake. Why is it one round trip instead of two?

    Say this first

    The client sends a ClientHello with its supported versions, cipher suites, signature algorithms, SNI, ALPN and, the key change, a key share: its ephemeral Diffie-Hellman public key for the group it guesses the server will pick. The server replies with ServerHello and its own key share, and both sides can now compute the handshake keys. Everything after ServerHello is encrypted: EncryptedExtensions, Certificate, CertificateVerify and Finished. The client checks them and sends its Finished, already able to send its request. TLS 1.2 needed a separate round trip to agree on parameters before exchanging keys; TLS 1.3 sends the key share up front.

    Go deeper

    The messages

    Output
    Client                                              Server
    ClientHello
      + supported_versions, key_share, signature_algorithms,
        server_name (SNI), ALPN, psk_key_exchange_modes   ->
                                                        ServerHello + key_share
                                                        {EncryptedExtensions}  (ALPN result)
                                                        {Certificate}
                                                        {CertificateVerify}    (signature over the transcript)
                                                   <-   {Finished}
    {Finished}
    [Application data: GET /]                          ->

    Braces mean encrypted with handshake keys. The server can send data right after its Finished.

    Round trips before the first request byte

    StackRound trips
    TCP + TLS 1.23
    TCP + TLS 1.32
    QUIC (TLS 1.3 inside)1
    TLS 1.3 or QUIC resumption with 0-RTTdata in the first flight

    What 1.3 removed

    RSA key transport (no forward secrecy), static Diffie-Hellman, CBC and RC4 ciphers, SHA-1 in signatures, compression and renegotiation. The cipher suites are AEAD only, for example TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256.

    Things that look odd in captures

    • The version field says TLS 1.2; the real version is in the supported_versions extension. This middlebox compatibility mode also sends a dummy ChangeCipherSpec.
    • If the server does not like the client's key share group it sends a HelloRetryRequest, which costs one more round trip.
    • Hybrid post-quantum key shares such as X25519MLKEM768 make the ClientHello larger than one packet, which has exposed middleboxes that assumed a ClientHello fits in one segment.

    Traps

    • Saying the server certificate is visible to observers in TLS 1.3. It is encrypted.
  16. What are SNI and ALPN in the TLS ClientHello, and why do network engineers care about them?

    Say this first

    SNI (Server Name Indication) is the hostname the client wants, sent in the ClientHello so a server hosting many sites on one IP can pick the right certificate. ALPN (Application-Layer Protocol Negotiation) lists the application protocols the client speaks, such as h2 and http/1.1, and the server picks one inside the handshake, avoiding an extra round trip. Network engineers care because firewalls filter on SNI, load balancers route on it, and a missing SNI or a proxy that does not offer h2 causes odd failures.

    Go deeper

    SNI in practice

    • Without SNI the server returns its default certificate, and the client reports a name mismatch. Typical culprits: health checks or scripts connecting by IP, and old clients.
    • Load balancers and reverse proxies use SNI to choose a certificate and a backend pool, even when they pass the TLS through without terminating it.
    • Firewalls use it for URL categories and application identification. Encrypted Client Hello hides the real SNI behind an outer, generic one.

    ALPN in practice

    • HTTP/2 over TLS is selected only through ALPN h2. A proxy in the middle that offers only http/1.1 downgrades the connection.
    • gRPC needs HTTP/2. A TLS-terminating load balancer that does not negotiate h2 toward the client or the backend breaks gRPC calls.
    • QUIC uses ALPN too; HTTP/3 is h3.

    Testing

    Shell
    openssl s_client -connect 203.0.113.80:443 -servername shop.example.com -alpn h2,http/1.1

    The output shows the certificate the server chose for that name and ALPN protocol: h2 when HTTP/2 was selected.

    Traps

    • Saying SNI is encrypted by TLS 1.3. It is not; only ECH hides it.
    How did you do?Book 8.5 Example SystemsOwn page

Expert7

  1. How does a SYN flood work, and how do SYN cookies defend against it without breaking TCP?

    Say this first

    A SYN flood sends huge numbers of SYNs, usually from spoofed addresses, so the server allocates a half-open entry for each and retransmits SYN-ACKs that are never answered. The SYN queue fills and real clients are refused. With SYN cookies the server stores nothing: it encodes the connection's details and a keyed hash into its own initial sequence number. When the client's ACK returns, the server checks the hash in ack minus one and rebuilds the connection from it.

    Go deeper

    Two queues on a Linux listener

    • SYN queue: half-open connections in SYN_RCVD, waiting for the final ACK.
    • Accept queue: completed connections waiting for the application to call accept(). Its size is the listen() backlog, capped by net.core.somaxconn (4096 by default since kernel 5.4).

    A SYN flood fills the first. A slow application fills the second, which shows as ListenOverflows in nstat and as Recv-Q at or near Send-Q on the LISTEN line of ss -lnt.

    How cookies work

    The server sets its ISN from a time counter, a small index for the client's MSS, and a cryptographic hash of the four-tuple with a secret. It keeps no state. A real client's ACK carries that ISN plus one; the server checks the hash and the time counter, then creates the connection. Spoofed sources never send the ACK, so they cost the server only an outgoing SYN-ACK.

    The trade-off

    Only a few MSS values fit in the cookie, and window scale and SACK would be lost. Linux stores those options in the TCP timestamp when timestamps are on, which avoids most of the loss. Linux only switches to cookies when the SYN queue overflows (net.ipv4.tcp_syncookies=1, the default), and the kernel log then shows a "Possible SYN flooding on port ... Sending cookies" message.

    Other layers of defence

    SYN proxy on a firewall or load balancer, which completes the handshake itself before opening the server side; rate limits; and upstream scrubbing for volumetric floods that fill the link itself.

    Traps

    • Saying SYN cookies are always on. Linux uses them only when the queue overflows.
  2. Compare loss-based congestion control like Reno and CUBIC with BBR. When would you switch a server to BBR?

    Say this first

    Reno and CUBIC treat packet loss as the congestion signal: they grow the window until a queue overflows, then cut it. CUBIC, the Linux default, grows as a cubic function of time since the last loss, so it recovers quickly on long fat paths, and cuts to 0.7 of the window on loss. BBR does not react to loss by design: it measures the bottleneck bandwidth and the minimum RTT, paces at that rate and keeps about one to two BDPs in flight. I would try BBR on servers sending over long, slightly lossy paths, such as video or downloads to the internet, after testing fairness with existing traffic.

    Go deeper

    CUBIC (RFC 9438)

    • Window as a function of time t since the last reduction: W(t) = C x (t - K)^3 + Wmax, with C = 0.4.
    • Concave as it approaches the old maximum Wmax, flat near it, then convex as it probes beyond it.
    • Multiplicative decrease factor 0.7. Growth does not depend on RTT, so long-RTT flows compete better than with Reno.
    • Still loss-based: it fills buffers before it backs off, so it adds queueing delay.

    BBR (Google, 2016)

    • Builds a model: BtlBw, the maximum recent delivery rate, and RTprop, the minimum recent RTT.
    • Paces sending at about BtlBw, with cwnd around 2 x BtlBw x RTprop.
    • Phases: Startup (gain about 2.89), Drain, ProbeBW (cycles pacing gain 1.25, 0.75, then 1), and ProbeRTT (drops to 4 packets for at least 200 ms if the minimum RTT has not been refreshed for 10 s).
    • Random loss that is not caused by congestion barely slows it, which is a big win on long lossy paths.

    Cautions

    • BBR v1 can take more than its share from CUBIC flows when buffers are shallow and less when buffers are deep, and can cause high retransmission rates. Later versions add a response to loss and ECN.
    • Congestion control is sender-side only. Changing a client does not change how a server sends to it.
    • BBR relies on pacing. Older kernels needed the fq qdisc; newer kernels pace inside TCP, though fq is still commonly set.

    Switching on Linux

    Shell
    sysctl net.ipv4.tcp_available_congestion_control
    sysctl -w net.core.default_qdisc=fq
    sysctl -w net.ipv4.tcp_congestion_control=bbr

    Traps

    • Saying BBR fixes a receiver-side window limit. If rwnd or the send buffer is the limit, no congestion control helps.
  3. What are Nagle's algorithm and delayed ACK, and why do they sometimes add 40 or 200 ms of latency together?

    Say this first

    Nagle's algorithm (RFC 896) holds back a small segment while earlier data is still unacknowledged, so many tiny writes become fewer full segments. Delayed ACK has the receiver wait a short time before acknowledging, hoping to combine the ACK with a reply or with the next segment. When a sender does two small writes and then waits for a reply, Nagle holds the second write until the first is acknowledged, and the receiver delays that ACK because it has no reply yet. Both wait until the delayed ACK timer fires: about 40 ms on Linux, 200 ms on Windows.

    Go deeper

    The stall step by step

    1. Client writes a 100-byte header. No data is outstanding, so it goes immediately.
    2. Client writes a 50-byte body. Data is outstanding and the segment is small, so Nagle holds it.
    3. Server gets the header. It cannot answer until it has the body, so there is no reply to piggyback on, and it delays its ACK.
    4. The delayed ACK timer fires, the ACK goes, Nagle releases the body, the server answers. Every request pays the timer.

    Fixes

    • Write the whole message in one call (or use writev), so there is no second small write.
    • Set TCP_NODELAY on the sender for request and response or interactive protocols. SSH and many RPC libraries do this; Go sets it by default.
    • On Linux the receiver can use TCP_QUICKACK, which is temporary and needs resetting.

    Delayed ACK rules

    A receiver acknowledges at least every second full-sized segment, and must not delay more than 500 ms (RFC 1122). Linux adapts its delay between about 40 ms and 200 ms.

    Traps

    • Disabling delayed ACK everywhere. It roughly halves ACK traffic and is not the problem in bulk flows.
    How did you do?Book 5.2 Reliable Byte Stream (TCP)Own page
  4. How does ECN work in IP and TCP, and why is it not used everywhere?

    Say this first

    Explicit Congestion Notification (RFC 3168) lets a router with active queue management mark a packet as congestion experienced instead of dropping it. ECN uses the two low bits of the old IP ToS byte. The receiver echoes the mark with the ECE flag; the sender reduces cwnd as if a loss had happened, without any retransmission, and confirms with CWR. It needs support at both ends and marking routers. Linux by default only accepts ECN when the peer asks for it and does not request it itself, and old middleboxes that mishandled the bits slowed deployment.

    Go deeper

    IP codepoints (2 bits after the 6-bit DSCP)

    BitsNameMeaning
    00Not-ECTSender does not support ECN
    10ECT(0)ECN-capable transport
    01ECT(1)ECN-capable transport, used by L4S
    11CECongestion experienced, set by a router

    TCP negotiation

    • SYN with ECE and CWR set: "I support ECN".
    • SYN-ACK with ECE set: "So do I".
    • Data packets then carry ECT. A router marks CE; the receiver sets ECE on its ACKs until the sender replies with CWR.

    Where it matters

    • Data centers: DCTCP and RoCEv2 congestion control rely on ECN marking at low queue thresholds.
    • L4S (RFC 9330 to 9332) uses ECT(1) for very low queueing delay.
    • Linux: net.ipv4.tcp_ecn=2 by default (accept, do not initiate); 1 requests ECN on outgoing connections.

    Network gotcha

    QoS policies that rewrite the whole ToS byte instead of only DSCP wipe ECN bits. Remarking DSCP should leave the two ECN bits alone.

    Traps

    • Saying ECN uses DSCP bits. It uses the two bits after DSCP in the same byte.
  5. Explain head-of-line blocking in HTTP/1.1, HTTP/2 and HTTP/3. Which layer does each version fix?

    Say this first

    Head-of-line blocking is when one slow or lost item holds up everything queued behind it. HTTP/1.1 has it at the application layer: responses on a connection come back in request order. HTTP/2 fixes that by multiplexing streams, but moves the problem down to TCP: TCP delivers bytes strictly in order, so one lost segment stalls every stream on the connection until it is retransmitted. HTTP/3 fixes the transport layer too, because QUIC orders data per stream: a loss only stalls the stream it belongs to.

    Go deeper

    HTTP/1.1

    Pipelining lets a client send several requests without waiting, but responses must return in order, so a slow first response blocks the rest. Browsers never enabled it and open about six parallel connections instead.

    HTTP/2

    Frames from many streams interleave on one TCP connection. The application is no longer blocked, but the kernel will not hand over bytes after a gap. With 1% loss on a busy page, one gap freezes every image, script and API call on the connection for a round trip or more.

    HTTP/3 and QUIC

    QUIC numbers packets, not bytes of one stream. Each stream has its own offsets, so data for stream 8 can be delivered while stream 4 waits for a retransmission. Order is only kept inside a stream.

    The header compression detail

    HPACK's dynamic table assumes in-order delivery: every header block may refer to earlier ones. QPACK was designed so that header decoding does not reintroduce cross-stream blocking, using separate encoder and decoder streams and letting the encoder limit how much a stream may depend on unacknowledged table entries.

    Traps

    • Saying HTTP/2 solved head-of-line blocking. It solved the HTTP-level kind and exposed the TCP-level kind.
  6. What is TLS 1.3 0-RTT, and why is it risky?

    Say this first

    0-RTT lets a client that has connected before send application data in its very first flight, encrypted with keys from a pre-shared key the server gave it in a session ticket. It saves a full round trip. The risk is replay: an attacker who captures the ClientHello and early data can send it again, and the server may process the request twice. Early data also lacks forward secrecy, because its keys come only from the ticket. So 0-RTT is only safe for idempotent requests, and many servers turn it off.

    Go deeper

    How it works

    1. In a previous connection, the server sent a NewSessionTicket.
    2. The new ClientHello carries pre_shared_key and early_data, followed by application data encrypted with the early traffic key.
    3. The server accepts by echoing early_data in EncryptedExtensions, or rejects it, in which case the client resends the data after the normal 1-RTT handshake.

    Why replay is hard to stop

    Within one server, single-use tickets or a cache of recent ClientHellos can catch duplicates. Across a cluster or many data centers, that state would have to be shared, so most deployments accept some replay window and limit what early data may do.

    How applications protect themselves

    • Only allow safe, idempotent requests in early data, such as GET without side effects.
    • A server or CDN that forwards early data to a backend marks it with Early-Data: 1; the backend can answer 425 Too Early to make the client retry after the handshake (RFC 8470).
    • nginx has ssl_early_data off by default.

    Traps

    • Saying TLS 1.3 handshakes are always 0-RTT. A first connection is 1-RTT; 0-RTT needs a prior ticket.
  7. What happens, in as much depth as you can, when you type https://shop.example.com into a browser and press Enter?

    Say this first

    The browser checks HSTS and its caches, then resolves the name: its own cache, the OS stub resolver, then a recursive resolver that walks root, TLD and authoritative servers for A, AAAA and HTTPS records. It races IPv6 and IPv4 connections (Happy Eyeballs). The host sees the address is off-subnet, ARPs for its default gateway's MAC and sends the SYN there; NAT at the edge rewrites the source, and BGP-routed paths carry it to the nearest edge, often a CDN. TCP and TLS 1.3 handshakes (or one QUIC handshake) follow, with SNI, ALPN and certificate validation. Then the HTTP request goes through load balancers to the application, the response comes back under slow start, and the browser parses, fetches subresources and renders.

    Go deeper

    1. Before any packet

    • Parse the URL. HSTS or the preload list may force HTTPS for http:// links.
    • Check the HTTP cache and service worker; reuse an open connection to the same origin if one exists.

    2. Name resolution

    • Browser DNS cache, then the OS (hosts file, then the stub resolver), then the configured recursive resolver over UDP 53 or encrypted DNS.
    • On a cache miss the resolver asks a root server for .com, a .com TLD server for example.com, and the authoritative server for the A, AAAA and HTTPS records. TTLs govern caching at each step.
    • An HTTPS record can announce alpn="h3,h2" and keys for Encrypted Client Hello.

    3. Getting the first packet out

    • The destination is off-subnet, so the frame goes to the default gateway. ARP (IPv4) or neighbor discovery (IPv6) finds its MAC if not cached.
    • Happy Eyeballs (RFC 8305) starts IPv6 first and IPv4 after a short delay, about 250 ms, and keeps whichever connects first.
    • The edge firewall does PAT: a private source like 192.168.1.20:51544 becomes a public address and port.
    • Routers forward hop by hop on longest prefix match; across providers, BGP chose the path. The service is often anycast, so the nearest CDN site answers.

    4. Transport and security

    • TCP: SYN with MSS, window scale, SACK and timestamps, then SYN-ACK and ACK: one RTT.
    • TLS 1.3: ClientHello with SNI shop.example.com, ALPN h2,http/1.1 and a key share; the server returns its certificate chain encrypted; the client validates the chain and the name: one more RTT.
    • Or, if HTTP/3 was advertised: one QUIC handshake on UDP 443 covers both.

    5. The request and the server side

    • HTTP/2 GET / with :authority, cookies and Accept-Encoding, compressed with HPACK.
    • A CDN may answer from cache. Otherwise a layer 7 load balancer terminates TLS, picks a healthy backend, and the application talks to caches and databases.

    6. The response and rendering

    • Status and headers (Cache-Control, Set-Cookie, Strict-Transport-Security, Alt-Svc), then a compressed body.
    • The first flight is limited by the initial congestion window of 10 segments, about 14.6 KB.
    • The browser parses HTML, finds CSS, JavaScript and images, fetches them over the same multiplexed connection, builds the DOM and CSSOM, lays out and paints.

    7. Afterwards

    The connection stays open for reuse. When it finally closes, whichever side sends the first FIN holds TIME_WAIT.

    Traps

    • Saying the client ARPs for the web server's IP. It ARPs for the default gateway.
    • Skipping certificate validation and congestion control. That is where a deep answer stands out.