|
1 | 1 | # easy-stun |
2 | | -Easy STUN client |
3 | 2 |
|
4 | | -This is work-in-progress client. Stay tuned! |
| 3 | +[](https://github.com/interpretica-io/easy-stun/actions/workflows/release.yml) |
| 4 | +[](https://github.com/interpretica-io/easy-stun/releases/latest) |
| 5 | +[](LICENSE) |
| 6 | + |
| 7 | +`easy-stun` is a small, fast STUN client focused on **discovering your public (NAT-mapped) address/port** by sending a STUN Binding Request and parsing the response. It’s designed to run continuously and keep the mapping alive, while executing optional user scripts on key events. |
| 8 | + |
| 9 | +## What this project is for |
| 10 | + |
| 11 | +- **NAT mapping discovery** (public IP/port as seen by a STUN server) |
| 12 | +- **Keepalive** to reduce NAT mapping expiration |
| 13 | +- **Event hooks** via external scripts: |
| 14 | + - `bind`: when a mapping is discovered/updated |
| 15 | + - `cr`: when something that looks like a TR-111 connection request is received (currently a placeholder) |
| 16 | + |
| 17 | +This is not a full STUN server implementation. It’s a client intended to be used as a building block in networking setups and automation. |
| 18 | + |
| 19 | +## How it works (high level) |
| 20 | + |
| 21 | +1. Creates a UDP socket (non-blocking). |
| 22 | +2. Sends a STUN Binding Request to a configured STUN server. |
| 23 | +3. Receives packets in an event-driven loop and processes STUN responses: |
| 24 | + - extracts `MAPPED-ADDRESS` or `XOR-MAPPED-ADDRESS` |
| 25 | +4. Periodically sends keepalive pings to keep NAT mappings alive. |
| 26 | +5. Spawns an external script on certain events (fire-and-forget; does not block packet processing). |
| 27 | + |
| 28 | +## Requirements |
| 29 | + |
| 30 | +- C toolchain (clang or gcc) |
| 31 | +- CMake (>= 3.5) |
| 32 | +- Ninja (recommended) or Make |
| 33 | +- OpenSSL development headers/libs |
| 34 | + |
| 35 | +### macOS (Homebrew) |
| 36 | + |
| 37 | +- `cmake`, `ninja`, `pkg-config`, `openssl@3` |
| 38 | + |
| 39 | +### Linux (Debian/Ubuntu) |
| 40 | + |
| 41 | +- `build-essential`, `cmake`, `ninja-build`, `pkg-config`, `libssl-dev` |
| 42 | + |
| 43 | +## Build |
| 44 | + |
| 45 | +From the repository root: |
| 46 | + |
| 47 | +### Using CMake + Ninja (recommended) |
| 48 | + |
| 49 | +``` |
| 50 | +cmake -S easy-stun -B easy-stun/build -G Ninja -DCMAKE_BUILD_TYPE=Release |
| 51 | +cmake --build easy-stun/build |
| 52 | +``` |
| 53 | + |
| 54 | +### Using the repo build script |
| 55 | + |
| 56 | +There is a helper script used by the project: |
| 57 | + |
| 58 | +``` |
| 59 | +cd easy-stun |
| 60 | +./scripts/make.sh |
| 61 | +``` |
| 62 | + |
| 63 | +## Run |
| 64 | + |
| 65 | +`easy-stun` expects a config file. The command line supports: |
| 66 | + |
| 67 | +- `--config <path>`: path to config file |
| 68 | +- `--fork`: run as a daemon (fork + detach) |
| 69 | + |
| 70 | +Example: |
| 71 | + |
| 72 | +``` |
| 73 | +./easy-stun/build/easy-stun --config ./config.txt |
| 74 | +./easy-stun/build/easy-stun --config ./config.txt --fork |
| 75 | +``` |
| 76 | + |
| 77 | +## Configuration |
| 78 | + |
| 79 | +The config file is space-delimited: `<key> <value>`, one per line. |
| 80 | + |
| 81 | +Keys used by `easy-stun`: |
| 82 | + |
| 83 | +- `local-port <port|any>` |
| 84 | + - UDP port to bind locally. Use `any` (or `0`) to let OS choose. |
| 85 | +- `remote-addr <host>` |
| 86 | + - STUN server hostname/IP. |
| 87 | +- `remote-port <port>` |
| 88 | + - STUN server port (typical STUN: 3478). |
| 89 | +- `username <string>` |
| 90 | +- `password <string>` |
| 91 | + - Credentials used for MESSAGE-INTEGRITY (project-specific; depends on your server setup). |
| 92 | +- `script <path>` |
| 93 | + - Path to an executable script that will be spawned on events. |
| 94 | +- `keepalive-interval <seconds>` |
| 95 | + - Keepalive interval in seconds. Set to `0` to disable keepalives. |
| 96 | +- `acs-addr <host>` |
| 97 | +- `acs-port <port>` |
| 98 | + - Address/port used for additional keepalive ping (useful for some deployments). |
| 99 | +- `restart-interval <seconds>` |
| 100 | + - If non-zero, on connection error the client waits N seconds and retries. |
| 101 | + |
| 102 | +### Example config |
| 103 | + |
| 104 | +``` |
| 105 | +local-port any |
| 106 | +remote-addr stun.example.com |
| 107 | +remote-port 3478 |
| 108 | +username myuser |
| 109 | +password mypass |
| 110 | +script /usr/local/bin/easy-stun-hook.sh |
| 111 | +keepalive-interval 30 |
| 112 | +acs-addr acs.example.com |
| 113 | +acs-port 7547 |
| 114 | +restart-interval 5 |
| 115 | +``` |
| 116 | + |
| 117 | +## Script hooks |
| 118 | + |
| 119 | +The configured `script` is spawned asynchronously. Exit codes are logged when the child process exits. |
| 120 | + |
| 121 | +The script is invoked as: |
| 122 | + |
| 123 | +- On mapping discovery/update: |
| 124 | + - `<script> bind <mapped_ip> <mapped_port>` |
| 125 | +- On “connection request” packet (currently a placeholder detector): |
| 126 | + - `<script> cr <mapped_ip> <mapped_port>` |
5 | 127 |
|
6 | 128 | ## License |
7 | 129 |
|
8 | | -MIT |
| 130 | +MIT |
0 commit comments