-
Notifications
You must be signed in to change notification settings - Fork 1
NTP Overview
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 examplesor installed Hammer system-wide.
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).
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
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
#includeC 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.
From the Hammer repository root, build the checkout-local library first:
scons examplesThen build the NTP example:
cd examples/ntp
makeThis 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.
make testpExpected output:
Reading from stdin
Packet accepted
If you see this, everything is wired up and you're ready to walk through the parser.
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
Learn Hammer
Protocol Examples
NTP
- NTP Overview
- Parsing the Header
- Parsing Data Fields
- Extension Fields and MAC
- Assembling the Parser
- Hex Input Preprocessing
- Running and Testing
DNS
TFTP
- TFTP Overview
- RRQ/WRQ Packets
- DATA Packets
- ACK Packets
- ERROR Packets
- Assembling the Parser
- Running and Testing
References
- Hammer Quick Reference
- Parsing Backends
- Unit Testing
- Using RTEMS
- Extending Hammer
- Adding a New Example
- Adding a New Binding
Further Reading