Skip to content

NTP Overview

Elbasiouny, Mahmoud edited this page May 29, 2026 · 6 revisions

This example builds a complete parser for NTP packets (RFC 5905) using Hammer. By the end you'll have a working validator that accepts or rejects raw NTP packets, and you'll have used most of Hammer's key combinators along the way.

Prerequisites: Make sure you've completed Getting Started and have either built Hammer in the checkout with scons examples or installed Hammer system-wide.


The NTP Protocol

NTP synchronizes clocks across networks. Every NTP message follows this structure:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Root Delay                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Root Dispersion                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Reference Identifier                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                    Reference Timestamp (64)                   +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                     Origin Timestamp (64)                     +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                    Receive Timestamp (64)                     +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                    Transmit Timestamp (64)                    +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
.              Extension Field 1 (variable, optional)           .
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
.              Extension Field 2 (variable, optional)           .
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Key Identifier (optional)               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                    Message Digest (128, optional)             |
|                                                               |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The first 48 bytes are mandatory. After that, there may be zero or more extension fields and an optional MAC (Key Identifier + Message Digest).

Why NTP Is a Good Hammer Example

NTP exercises a wide range of Hammer features:

  • Sub-byte fields - LI (2 bits), VN (3 bits), Mode (3 bits) require h_bits
  • Value validation - Version must be 1-4, requiring h_int_range
  • Fixed-point numbers - Root Delay/Dispersion aren't standard integers
  • Variable-length data - Extension fields use length-prefixed values
  • Repetition - Zero or more extension fields need h_many
  • Alternatives - Packets with/without a MAC need h_choice

Project Structure

examples/ntp/
├── main.c          # Entry point: reads input and runs the parser
├── ntp.c           # NTP protocol grammar defined with Hammer
├── hex.c           # Hex-string-to-bytes preprocessing parser
├── Makefile        # Build system
└── packet/
    ├── ntp_stream.hex   # Sample captured NTP packet (hex)
    ├── ntp_stream.bin   # Same packet as raw bytes
    └── steps.md         # How the sample packet was captured
File Role
main.c Entry point. Reads input (stdin or file), calls ntpParser(), prints result.
ntp.c Defines the NTP protocol grammar using Hammer combinators. This is where the parsing logic lives.
hex.c Utility parser that converts hex-encoded strings into raw bytes.

main.c pulls in the other files with #include:

#include "hex.c"
#include "ntp.c"

Why #include C files? This is a simple single-translation-unit approach for small projects. In a larger project you'd use separate compilation with header files. This tutorial focuses on the parsing logic, not build architecture.


Building

From the Hammer repository root, build the checkout-local library first:

scons examples

Then build the NTP example:

cd examples/ntp
make

This produces the ntp_parser executable. The Makefile first looks for a checkout-local Hammer library at ../../build/opt/src. If that library is not present, it falls back to pkg-config libhammer.

Quick Smoke Test

make testp

Expected output:

Reading from stdin
Packet accepted

If you see this, everything is wired up and you're ready to walk through the parser.


Walkthrough Pages

Follow these pages in order for the full tutorial:

# Page Hammer Concepts
1 Parsing the Header h_bits, h_int_range, h_sequence
2 Parsing Data Fields h_sequence for fixed-point and timestamps
3 Extension Fields and MAC h_put_value, h_free_value, h_action, h_length_value, h_many
4 Assembling the Parser h_choice, h_left, h_end_p
5 Hex Input Preprocessing h_ch_range, h_repeat_n, H_ARULE, parse tree walking
6 Running and Testing Build, run, test with real and synthetic packets

Next: Parsing the Header

Back to: Examples Index · Hammer Fundamentals

Clone this wiki locally