rkik 2.2.0

Rusty Klock Inspection Kit - NTP Query and Compare Tool
Documentation
# rkik - Rusty Klock Inspection Kit

[![Build & Tests](https://github.com/aguacero7/rkik/actions/workflows/ci-test-n-build.yml/badge.svg)](https://github.com/aguacero7/rkik/actions/workflows/ci-test-n-build.yml)
[![crates.io](https://img.shields.io/crates/v/rkik.svg)](https://crates.io/crates/rkik)
[![Packaging status](https://repology.org/badge/tiny-repos/rkik.svg)](https://repology.org/project/rkik/versions)

> Think `dig`, but for time sources. No daemon, no root, no config to touch.

rkik queries NTP, NTS, and PTP servers and tells you what they say — offset, RTT, stratum, authentication status. One shot, stateless, done.

---

## Why rkik?

- **Passive by design.** It never touches your system clock unless you explicitly ask (`--sync`). Run it anywhere, as anyone.
- **NTS that actually works.** rkik-nts 1.0.0 is the first CLI implementation of RFC 8915 verified against real public servers (`time.cloudflare.com`, `nts.ntp.se`). Older tools either skip authentication or implement it wrong.
- **Three protocols, one tool.** NTP over IPv4/IPv6, NTS with full TLS diagnostics, and PTP/IEEE 1588 — all with compare mode, JSON output, and Nagios/Centreon plugin support.

---

## Demo

[![asciicast](https://asciinema.org/a/LBiUOMMoimo3DWHh.svg)](https://asciinema.org/a/LBiUOMMoimo3DWHh)

```
$ rkik --nts time.cloudflare.com -v

Server: time.cloudflare.com [NTS Authenticated]
IP: 162.159.200.1:123
UTC Time: Tue, 28 Apr 2026 14:32:10 +0000
Local Time: 2026-04-28 16:32:10
Clock Offset: 1.243 ms
Round Trip Delay: 14.871 ms

=== NTS-KE Diagnostics ===
Handshake Duration: 87.342 ms
Cookies Received:   8 cookies
AEAD Algorithm:     AEAD_AES_SIV_CMAC_256
NTP Server:         162.159.200.1:123

=== TLS Certificate ===
Subject:    CN=time.cloudflare.com
Issuer:     C=US, O=DigiCert Inc, CN=GeoTrust TLS ECC CA G1
Valid:      2025-02-10 → 2026-03-12
Fingerprint (SHA-256): 4b060f4d...462119
SANs:       time.cloudflare.com
```

---

## Installation

```bash
cargo install rkik
```

**Arch Linux (AUR):**
```bash
yay -S rkik-git
```

**Nix / NixOS:**
```bash
nix shell nixpkgs#rkik
```

**DEB / RPM / tar.gz:** grab the latest from [GitHub Releases](https://github.com/aguacero7/rkik/releases/latest).

```bash
# Debian / Ubuntu
sudo apt install ./rkik_2.1.0-1_amd64.deb

# Fedora / RHEL / Alma / Rocky
sudo dnf install rkik-2.1.0-1.x86_64.rpm
```

[![Packaging status](https://repology.org/badge/vertical-allrepos/rkik.svg)](https://repology.org/project/rkik/versions)

---

## Quick start

```bash
# Basic NTP probe
rkik pool.ntp.org

# NTS — cryptographically authenticated
rkik --nts time.cloudflare.com

# Compare a few servers side by side
rkik --compare pool.ntp.org time.google.com time.cloudflare.com

# Plugin output for Nagios / Centreon / Zabbix
rkik pool.ntp.org --plugin --warning 50 --critical 200

# JSON, prettified
rkik pool.ntp.org --json --pretty
```

---

## NTP

```bash
rkik time.google.com              # basic probe
rkik time.google.com -v           # adds stratum, ref ID
rkik time.google.com --count 10 --interval 2   # repeat 10 times
rkik -6 pool.ntp.org              # IPv6-only resolution
```

Output:
```
Server: time.google.com
IP: 216.239.35.4:123
UTC Time: Tue, 28 Apr 2026 14:32:08 +0000
Local Time: 2026-04-28 16:32:08
Clock Offset: 0.312 ms
Round Trip Delay: 9.449 ms
```

---

## NTS — Network Time Security ★

NTS (RFC 8915) is authenticated NTP — every packet is verified with AEAD encryption, so you know the response hasn't been tampered with.

```bash
rkik --nts time.cloudflare.com          # authenticated probe
rkik --nts time.cloudflare.com -v       # with TLS/KE diagnostics
rkik --nts --compare nts.ntp.se time.cloudflare.com
```

When something goes wrong, rkik tells you what kind of failure it is:

| Kind | Meaning |
|------|---------|
| `aead_failure` | AEAD verification failed — possible tampering |
| `missing_authenticator` | Authenticator extension absent in response |
| `unauthenticated_response` | Server completed NTS-KE but sent plain NTP |
| `ke_handshake_failed` | TLS or NTS-KE handshake failed |
| `timeout` | Connection timed out |

Security-critical failures (`aead_failure`, `missing_authenticator`, `unauthenticated_response`, `invalid_unique_id`, `invalid_origin_timestamp`) exit with code 2 in plugin mode.

See [docs/user-guide.md#nts](docs/user-guide.md#nts--network-time-security) for the full error reference.

---

## PTP — Precision Time Protocol

PTP mode (IEEE 1588-2019) is Linux-only and requires the `ptp` feature (on by default).

```bash
rkik --ptp 192.0.2.10
rkik --ptp --ptp-domain 24 --ptp-event-port 3319 --ptp-general-port 3320 127.0.0.1
rkik --ptp --compare 192.168.1.100 192.168.1.101 --format json
```

See [docs/user-guide.md#ptp](docs/user-guide.md#ptp--precision-time-protocol) for flags and output format.

---

## Plugin mode

```bash
rkik time.google.com --plugin --warning 50 --critical 200
# → RKIK OK - offset 4.006ms rtt 9.449ms from time.google.com (216.239.35.4) | offset_ms=4.006ms;50;200;0; rtt_ms=9.449ms;;;0;
```

Exit codes: `0` OK · `1` WARNING · `2` CRITICAL · `3` UNKNOWN (request failed or security error)

---

## Debugging a time issue

Your monitoring fires a time alert on `ntp.server.local`. You don't know yet whether the problem is that server or its upstream.

```bash
$ rkik ntp.server.local -v
Clock Offset: 5000.145 ms
Reference ID: 145.238.80.80
```

Five seconds of drift, and you can see the upstream. Check it directly:

```bash
$ rkik 145.238.80.80
Clock Offset: 5001.531 ms
```

Same offset upstream. The problem isn't your server — it's the reference. Time to point it somewhere else.

---

## For developers

rkik is split into a library and a CLI. The library has no `clap`, no `process::exit`, no terminal code — just async functions you can call directly.

```toml
[dependencies]
rkik = { version = "2", default-features = false, features = ["json"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

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

let r = query_one("time.google.com", false, Duration::from_secs(3), false, 4460).await?;
println!("{}: offset={:.3}ms", r.target.name, r.offset_ms);
```

Full API reference, architecture overview, and contribution guide: [docs/developer-guide.md](docs/developer-guide.md)

To contribute, see [CONTRIBUTING](docs/developer-guide.md#contributing) — issues labelled [`good first issue`](https://github.com/aguacero7/rkik/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) are a good starting point.