Totpgate – Single-packet authorization via TOTP, written in C99 from scratch

tpimenta1 pts0 comments

GitHub - PepperDev/totpgate: Lightweight SPA TOTP port knocking daemon · GitHub

/" data-turbo-transient="true" />

Skip to content

Search or jump to...

Search code, repositories, users, issues, pull requests...

-->

Search

Clear

Search syntax tips

Provide feedback

--><br>We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

-->

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

PepperDev

totpgate

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

master

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>42 Commits<br>42 Commits

.github/workflows

.github/workflows

man

man

src

src

test

test

.gitignore

.gitignore

AGENTS.md

AGENTS.md

BUG_PREVENTION.md

BUG_PREVENTION.md

DOMAIN.md

DOMAIN.md

LICENSE

LICENSE

Makefile

Makefile

README.md

README.md

TODO.md

TODO.md

View all files

Repository files navigation

totpgate

Single Packet Authorization via TOTP — a lightweight port knocking daemon<br>that listens on UDP for a valid TOTP and, upon matching, temporarily opens a<br>TCP port via direct netlink firewall manipulation.

No external binaries, no shared libraries — just a statically linked<br>binary speaking netlink directly to the kernel.

Why

Traditional port knocking sequences are predictable (fixed port order) and<br>replayable. TOTP-based single-packet authorization replaces the sequence with<br>a time-based one-time password, making each grant unique and replay-proof.

Design

┌──────────┐ UDP/TOTP ┌──────────────┐ netlink ┌──────────┐<br>│ client │ ────────────→ │ totpgated │ ───────────→ │ kernel │<br>│ (CLI) │ │ (daemon) │ │ (nftables)│<br>└──────────┘ └──────────────┘ └──────────┘

Client sends a single UDP packet containing a TOTP value.

Daemon validates the TOTP against the configured shared secret.

On success the daemon inserts a temporary nftables rule that permits the<br>client's IP to reach the target TCP port.

The rule auto-expires after a configurable idle timeout.

Build

Requirements

musl-gcc recommended (falls back to cc; any C99 compiler works)

Linux kernel headers (for linux/netfilter.h, libnl-ish macros)

indent (for code-style checks)

Commands

make # build daemon and client<br>make test # build & run unit tests<br>make style # reformat source to project style<br>make coverage # generate coverage report (requires gcov)<br>make clean # remove build artefacts

Output lands in bin/.

Coverage gate

make coverage

All TODO sections require ≥ 80 % line coverage and zero compiler<br>warnings before the section is considered complete.

Usage

totpgated --port 2222 --target-port 22 --secret "JBSWY3DPEHPK3PXP" --timeout 30<br>totpgated --port 2222 --target-port 22 --secret-file /etc/totpgate.key --foreground<br>totpgated --port 0.0.0.0:2222 --port 192.168.1.1:2223 --interface eth0 --secret "JBSWY3DPEHPK3PXP"<br>totpgate --secret "hex:48656c6c6f" --port 2222 server.example.com

The daemon listens on UDP --port for a valid TOTP. On match the<br>sender's IP is allowed to open a TCP connection to --target-port for --timeout seconds.<br>--port may be given multiple times to listen on different addresses/ports,<br>and --interface restricts firewall rules to a single network interface.

When totpgated starts it flushes any stale rules from a prior session,<br>inserts a permanent ct state established,related accept rule, and installs<br>a silent tcp dport drop for unmatched SYN packets.

See the man pages (totpgated.1, totpgate.1) or --help for full options.

Project map

├── AGENTS.md — agent / AI guidelines<br>├── DOMAIN.md — business rules & entities<br>├── TODO.md — tracked task list<br>├── BUG_PREVENTION.md— recurring-bug checklist<br>├── Makefile<br>├── src/ — source code<br>│ ├── main.c — daemon entrypoint, event loop, CLI parsing<br>│ ├── client.c / h — CLI client tool<br>│ ├── auth.c / .h — auth packet parse / build<br>│ ├── encode.c / h — base32, base64, hex decode<br>│ ├── totp.c / .h — TOTP token validation<br>│ ├── sha1.c / .h — SHA-1 hash<br>│ ├── hmac.c / .h — HMAC-SHA1<br>│ ├── netlink.c / h— nftables rule management via netlink<br>│ ├── udp.c / .h — UDP socket bind / send / recv<br>│ ├── privdrop.c/h— privilege drop & seccomp filter<br>│ ├── ratelimit.c/h— per-IP rate limiting with backoff<br>│ ├── seccomp.c / h— seccomp-BPF syscall filter<br>│ └── util.c / .h — logging helpers<br>├── test/ — unit tests (no third-party test libs)<br>└── bin/ — build artifacts

License

MIT

About

Lightweight...

port totp daemon totpgate client totpgated

Related Articles