ntp_usg-client 3.3.2

NTP client library with sync, async (tokio/smol), and NTS support.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# ntp_usg

[![docs.rs](https://img.shields.io/docsrs/ntp_usg-proto?style=for-the-badge&logo=rust&label=proto%20docs)](https://docs.rs/ntp_usg-proto/latest/ntp_proto/)
[![docs.rs](https://img.shields.io/docsrs/ntp_usg-client?style=for-the-badge&logo=rust&label=client%20docs)](https://docs.rs/ntp_usg-client/latest/ntp_client/)
[![docs.rs](https://img.shields.io/docsrs/ntp_usg-server?style=for-the-badge&logo=rust&label=server%20docs)](https://docs.rs/ntp_usg-server/latest/ntp_server/)
[![Crates.io](https://img.shields.io/crates/v/ntp_usg-proto.svg?style=for-the-badge&logo=rust&label=proto%20crate)](https://crates.io/crates/ntp_usg-proto)
[![Crates.io](https://img.shields.io/crates/v/ntp_usg-client.svg?style=for-the-badge&logo=rust&label=client%20crate)](https://crates.io/crates/ntp_usg-client)
[![Crates.io](https://img.shields.io/crates/v/ntp_usg-server.svg?style=for-the-badge&logo=rust&label=server%20crate)](https://crates.io/crates/ntp_usg-server)
[![License](https://img.shields.io/crates/l/ntp_usg-proto.svg?style=for-the-badge)](https://github.com/192d-Wing/ntp_usg#license)
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/192d-Wing/ntp_usg/ci.yml?branch=master&style=for-the-badge&logo=github)](https://github.com/192d-Wing/ntp_usg/actions/workflows/ci.yml)
[![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/192d-Wing/ntp_usg?style=for-the-badge&logo=github)](https://github.com/192d-Wing/ntp_usg/issues)
[![GitHub Issues or Pull Requests](https://img.shields.io/github/issues-pr/192d-Wing/ntp_usg?style=for-the-badge&logo=github)](https://github.com/192d-Wing/ntp_usg/pulls)
[![Codecov](https://img.shields.io/codecov/c/github/192d-Wing/ntp_usg?style=for-the-badge&logo=codecov)](https://codecov.io/github/192d-Wing/ntp_usg)

A Network Time Protocol (NTP) library written in Rust, organized as a Cargo workspace with three crates:

| Crate | Lib name | Description |
|-------|----------|-------------|
| [`ntp_usg-proto`]crates/ntp_usg-proto | `ntp_proto` | Protocol types, extension fields, and NTS cryptographic primitives |
| [`ntp_usg-client`]crates/ntp_usg-client | `ntp_client` | NTP client (sync, async tokio/smol, NTS, clock adjustment) |
| [`ntp_usg-server`]crates/ntp_usg-server | `ntp_server` | NTP server (tokio/smol, NTS-KE) |

## Features

### 🎯 Version 3.1.0 - 100% RFC Compliance

- **RFC 5905 Full Compliance**: Selection, clustering, clock discipline (PLL/FLL), symmetric modes, and broadcast mode
- **RFC 4330 SNTP API**: Simplified client API for one-off time queries
- **RFC 7822 Extension Registry**: Generic dispatch system for extension field handlers
- **Security**: Eliminated unmaintained rustls-pemfile dependency (RUSTSEC-2025-0134)

### Core Features

- 🔒 **Safe & Secure**: `#![deny(unsafe_code)]` crate-wide; only platform FFI in the optional `clock` module uses unsafe
- 📚 **Well Documented**: Comprehensive API documentation with examples
-**Configurable Timeouts**: Control request timeouts for different network conditions
- 🔄 **Async Ready**: Optional async support via Tokio or smol
- 🕐 **Y2036 Safe**: Era-aware timestamp handling for the NTP 32-bit rollover
- 🌍 **Multi-Server Support**: Query multiple NTP servers for improved reliability
- 🔐 **Network Time Security**: NTS (RFC 8915) with TLS 1.3 key establishment and AEAD authentication
- 📡 **Continuous Client**: Adaptive poll interval, multi-peer selection, and interleaved mode (RFC 9769)
- 🌐 **IPv6 Dual-Stack**: Automatic IPv4/IPv6 socket binding
- 🧩 **`no_std` Support**: Core protocol parsing works without `std` or `alloc`
- ⏱️ **Clock Adjustment**: Platform-native slew/step correction (Linux, macOS, Windows)
- 📡 **NTP Server**: Full NTPv4 server with rate limiting, access control, and interleaved mode
- 🦀 **Modern Rust**: Edition 2024 with MSRV 1.93
-**Well Tested**: 290+ tests, CI/CD on Linux, macOS, and Windows

## Installation

Add the crate(s) you need to your `Cargo.toml`:

```toml
[dependencies]
# Protocol types only (also supports no_std)
ntp_usg-proto = "3.1"

# NTP client
ntp_usg-client = { version = "3.1", features = ["tokio"] }

# NTP server
ntp_usg-server = { version = "3.1", features = ["tokio"] }
```

**Minimum Supported Rust Version (MSRV):** 1.93
**Edition:** 2024

### Feature Flags

#### ntp_usg-proto

| Feature | Default | Description |
|---------|---------|-------------|
| `std` | Yes | Full I/O and `byteorder`-based APIs |
| `alloc` | No | `Vec`-based extension field types without full `std` |
| `nts` | No | NTS cryptographic primitives (AEAD, cookie handling) |

#### ntp_usg-client

| Feature | Default | Description |
|---------|---------|-------------|
| `tokio` | No | Async NTP client using Tokio |
| `smol-runtime` | No | Async NTP client using smol |
| `nts` | No | NTS authentication (Tokio + rustls) |
| `nts-smol` | No | NTS authentication (smol + futures-rustls) |
| `clock` | No | System clock slew/step adjustment (Linux, macOS, Windows) |

#### ntp_usg-server

| Feature | Default | Description |
|---------|---------|-------------|
| `tokio` | No | NTP server using Tokio |
| `smol-runtime` | No | NTP server using smol |
| `nts` | No | NTS-KE server (Tokio + rustls) |
| `nts-smol` | No | NTS-KE server (smol + futures-rustls) |

For `no_std` environments, use the proto crate with default features disabled:

```toml
[dependencies]
ntp_usg-proto = { version = "3.1", default-features = false }          # core parsing only
ntp_usg-proto = { version = "3.1", default-features = false, features = ["alloc"] }  # + Vec-based types
```

## Usage

### SNTP (Simple Network Time Protocol)

For simple, one-off time queries, use the SNTP API (RFC 4330 compliant):

```rust
use ntp_client::sntp;

fn main() -> std::io::Result<()> {
    let result = sntp::request("time.nist.gov:123")?;
    println!("Clock offset: {:.6} seconds", result.offset_seconds);
    println!("Round-trip delay: {:.6} seconds", result.delay_seconds);
    Ok(())
}
```

With async:

```rust
#[tokio::main]
async fn main() -> std::io::Result<()> {
    let result = sntp::async_request("time.cloudflare.com:123").await?;
    println!("Offset: {:.6}s", result.offset_seconds);
    Ok(())
}
```

### Basic Example (Full NTP)

```rust
use chrono::TimeZone;

fn main() {
    let address = "time.nist.gov:123";
    let response = ntp_client::request(address).unwrap();
    let unix_time = ntp_client::unix_time::Instant::from(response.transmit_timestamp);
    let local_time = chrono::Local
        .timestamp_opt(unix_time.secs(), unix_time.subsec_nanos() as _)
        .unwrap();
    println!("Current time: {}", local_time);
}
```

### Custom Timeout

```rust
use std::time::Duration;

let response = ntp_client::request_with_timeout("time.nist.gov:123", Duration::from_secs(10))?;
```

### Async with Tokio

Enable the `tokio` feature:

```toml
[dependencies]
ntp_usg-client = { version = "3.1", features = ["tokio"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let result = ntp_client::async_ntp::request("time.nist.gov:123").await?;
    println!("Offset: {:.6} seconds", result.offset_seconds);
    Ok(())
}
```

### Continuous Client

The continuous client polls servers with adaptive intervals and supports interleaved mode (RFC 9769):

```rust
use ntp_client::client::NtpClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (client, mut state_rx) = NtpClient::builder()
        .server("time.nist.gov:123")
        .min_poll(4)
        .max_poll(10)
        .build()
        .await?;

    tokio::spawn(client.run());

    // Wait for sync state updates.
    while state_rx.changed().await.is_ok() {
        let state = state_rx.borrow();
        println!("Offset: {:.6}s, Delay: {:.6}s", state.offset, state.delay);
    }
    Ok(())
}
```

### NTS (Network Time Security)

Enable the `nts` feature for authenticated NTP:

```toml
[dependencies]
ntp_usg-client = { version = "3.1", features = ["nts"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

```rust
use ntp_client::nts::NtsSession;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut session = NtsSession::from_ke("time.cloudflare.com").await?;
    let result = session.request().await?;
    println!("NTS offset: {:.6}s", result.offset_seconds);
    Ok(())
}
```

### NTS Continuous Client

Combine NTS authentication with the continuous polling client:

```rust
use ntp_client::client::NtpClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (client, mut state_rx) = NtpClient::builder()
        .nts_server("time.cloudflare.com")
        .min_poll(4)
        .max_poll(10)
        .build()
        .await?;

    tokio::spawn(client.run());

    while state_rx.changed().await.is_ok() {
        let state = state_rx.borrow();
        println!("Offset: {:.6}s, NTS: {}", state.offset, state.nts_authenticated);
    }
    Ok(())
}
```

### Async with smol

Enable the `smol-runtime` feature:

```toml
[dependencies]
ntp_usg-client = { version = "3.1", features = ["smol-runtime"] }
smol = "2"
```

```rust
use std::time::Duration;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    smol::block_on(async {
        let result = ntp_client::smol_ntp::request_with_timeout(
            "time.nist.gov:123",
            Duration::from_secs(5),
        ).await?;
        println!("Offset: {:.6} seconds", result.offset_seconds);
        Ok(())
    })
}
```

The smol continuous client uses `Arc<RwLock<NtpSyncState>>` for state sharing:

```rust
use ntp_client::smol_client::NtpClient;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    smol::block_on(async {
        let (client, state) = NtpClient::builder()
            .server("time.nist.gov:123")
            .build()
            .await?;

        smol::spawn(client.run()).detach();

        loop {
            smol::Timer::after(std::time::Duration::from_secs(5)).await;
            let s = state.read().unwrap();
            println!("Offset: {:.6}s, Delay: {:.6}s", s.offset, s.delay);
        }
    })
}
```

### Clock Adjustment

Enable the `clock` feature to correct the system clock based on NTP measurements:

```toml
[dependencies]
ntp_usg-client = { version = "3.1", features = ["clock", "tokio"] }
```

```rust
use ntp_client::clock;

// Gradual correction (slew) for small offsets
clock::slew_clock(0.05)?;

// Immediate correction (step) for large offsets
clock::step_clock(-1.5)?;

// Automatic: slew if |offset| <= 128ms, step otherwise
let method = clock::apply_correction(offset)?;
```

### NTP Server

Enable the `tokio` feature on the server crate:

```toml
[dependencies]
ntp_usg-server = { version = "3.1", features = ["tokio"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

```rust
use ntp_server::protocol::Stratum;
use ntp_server::server::NtpServer;

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let server = NtpServer::builder()
        .listen("0.0.0.0:123")
        .stratum(Stratum(2))
        .build()
        .await?;

    server.run().await
}
```

### Multiple Servers

See [crates/ntp_usg-client/examples/multiple_servers.rs](crates/ntp_usg-client/examples/multiple_servers.rs) for a complete example of querying multiple NTP servers.

## Examples

### Production Examples (v3.1.0+)

The following examples demonstrate production-ready deployments with comprehensive monitoring and error handling:

**Multi-Peer Deployment** - [examples/multi_peer_deployment.rs](crates/ntp_usg-client/examples/multi_peer_deployment.rs)

```bash
cargo run -p ntp_usg-client --example multi_peer_deployment --features ntp_usg-client/tokio
```

Demonstrates RFC 5905 selection, clustering, and combine algorithms with 5 diverse NTP servers. Includes real-time health assessment and offset trend analysis.

**NTS Multi-Peer** - [examples/nts_multi_peer.rs](crates/ntp_usg-client/examples/nts_multi_peer.rs)

```bash
cargo run -p ntp_usg-client --example nts_multi_peer --features ntp_usg-client/nts
```

Mixed NTS-authenticated and standard NTP deployment for maximum security and resilience. Tracks security posture with NTS failure monitoring.

**System Daemon** - [examples/daemon.rs](crates/ntp_usg-client/examples/daemon.rs)

```bash
cargo run -p ntp_usg-client --example daemon --features ntp_usg-client/tokio
```

Production-ready long-running service with structured logging, health-based alerts, and systemd integration documentation.

### Basic Examples

Run the included examples to see the library in action:

```bash
# Basic request example
cargo run -p ntp_usg-client --example request

# Custom timeout demonstration
cargo run -p ntp_usg-client --example timeout

# Query multiple servers
cargo run -p ntp_usg-client --example multiple_servers

# Detailed packet information
cargo run -p ntp_usg-client --example packet_details

# Async concurrent queries (requires tokio feature)
cargo run -p ntp_usg-client --example async_request --features ntp_usg-client/tokio

# Continuous client with poll management (requires tokio feature)
cargo run -p ntp_usg-client --example continuous --features ntp_usg-client/tokio

# NTS-authenticated request (requires nts feature)
cargo run -p ntp_usg-client --example nts_request --features ntp_usg-client/nts

# NTS continuous client (requires nts feature)
cargo run -p ntp_usg-client --example nts_continuous --features ntp_usg-client/nts

# Smol one-shot request
cargo run -p ntp_usg-client --example smol_request --features ntp_usg-client/smol-runtime

# Smol continuous client
cargo run -p ntp_usg-client --example smol_continuous --features ntp_usg-client/smol-runtime

# Clock adjustment (requires root/sudo on Unix, Administrator on Windows)
cargo run -p ntp_usg-client --example clock_adjust --features "ntp_usg-client/clock ntp_usg-client/tokio"

# NTP server (requires tokio feature)
cargo run -p ntp_usg-server --example server --features ntp_usg-server/tokio

# NTS server (requires nts feature + TLS certs)
cargo run -p ntp_usg-server --example nts_server --features ntp_usg-server/nts -- --cert server.crt --key server.key
```

## Roadmap

- [x] async support (tokio)
- [x] NTP era handling (Y2036)
- [x] IPv6 dual-stack support
- [x] Continuous client with adaptive polling
- [x] Interleaved mode (RFC 9769)
- [x] Network Time Security (RFC 8915)
- [x] IO-independent parsing (`FromBytes`/`ToBytes` traits)
- [x] `no_std` support (with optional `alloc`)
- [x] smol support (one-shot, continuous, and NTS)
- [x] System clock adjustment (slew/step on Linux, macOS, Windows)
- [x] NTP server with NTS-KE
- [x] Workspace restructure (proto, client, server crates)
- [ ] Reference clock interface (GPS, PPS)

## Contributing

Pull requests and issues are welcome! Please see our [GitHub repository](https://github.com/192d-Wing/ntp_usg) for more information.

## License

`ntp_usg` is distributed under the terms of both the MIT license and the Apache License (Version 2.0).

See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details.