Networking in C · intermediate · ~12 min

TLS handshake bytes — where SNI lives

Locate and extract the hostname stored inside a TLS Server Name Indication (SNI) extension.

Overview

Read two big-endian lengths, check one type byte, then perform a bounds-checked copy of the host bytes.

Why it matters

SNI is the one plaintext hostname in a TLS session. It is the field that monitors and filters rely on.

Lesson

Why this matters

TLS encrypts almost everything in a connection. The one exception is the ClientHello — the very first message the client sends.

The ClientHello goes out before any encryption keys exist, so it travels in the clear. Inside it sits the SNI extension (Server Name Indication), which names the host the client wants to reach. That hostname is plaintext.

This is the field every passive TLS monitor, SNI-based filter, and traffic classifier reads.

What the SNI extension payload looks like

The payload is a short, fixed sequence of length-prefixed fields:

[server_name_list_len : 2]   big-endian
[name_type : 1]              0x00 = host_name
[name_len : 2]               big-endian
[host bytes ...]

All multi-byte lengths are big-endian — also called network byte order. Big-endian means the most significant byte comes first. For example, the two bytes 0x01 0x2C represent the value 300 (1 * 256 + 44).

Your job

Implement this function:

int extract_sni(const uint8_t *ext, size_t n, char *out, size_t cap);

It must:

  • Read the list length.
  • Check that the type is 0x00 (host_name).
  • Read the host length.
  • Copy the host into out.

Validate every length against n (the input size) and the host length against cap (the output buffer size). Never read past the input. Never write past the output.

What this is NOT

  • It is not a TLS client or a man-in-the-middle tool. We only parse a captured extension payload.
  • It is not a full ClientHello walker. That walker wraps this same field — here we focus on the SNI field alone.

Summary

Key takeaways

  • SNI is the one plaintext hostname in a TLS session. It lives in the ClientHello, which is sent before encryption begins.
  • The payload layout is: list_len (2 bytes), type (1 byte, must be 0x00), name_len (2 bytes), then the host bytes.
  • All multi-byte lengths are big-endian (network byte order).
  • Bounds-check every length against both n (input size) and cap (output buffer size).

Practice with these exercises