Releases: wiresock/alighieri
Release list
v0.4.0
Alighieri 0.4.0 is the first crates.io release and establishes the supported 0.4.x CLI, configuration, lifecycle, and plugin-SDK contract.
Highlights
- Install the stock SOCKS5 server directly from crates.io with
cargo install alighieri --locked. - Use the curated Rust surface for configuration, errors, server lifecycle, and runtime shutdown/reload handling.
- Build custom hosts with the feature-gated
pluginsSDK, including control-plane hooks plus typed TCP and UDP interception facades. - Plugins are statically linked into a custom host binary. The stock Alighieri binary does not dynamically load plugins.
- Public configuration and SDK vocabulary is hardened for additive evolution. Patch releases throughout
0.4.xpreserve the supported contract; breaking API or SDK changes wait for0.5.0.
Install
cargo install alighieri --locked
alighieri --versionFor custom plugin hosts, see the plugin SDK guide and the AGPL/commercial licensing guidance.
Artifacts
Four native archives are attached for x86-64 and ARM64 on Linux and Windows. Multi-architecture container images are available as ghcr.io/wiresock/alighieri:0.4.0, :0.4, and :latest.
v0.3.1
Alighieri 0.3.1 is a maintenance and hardening release — a drop-in upgrade from 0.3.0 with no breaking changes and no config changes required.
What's new
Reliable UDP through NAT — udp.advertise
When the proxy runs behind NAT or a port-forward, UDP clients could be handed a local relay address they couldn't actually reach. Set udp.advertise to the public IP or hostname clients should use, and the proxy advertises that in the UDP ASSOCIATE reply while still listening on its real port. Pairs with udp.portrange for a stable port-forward.
Security and hardening
- Windows installs now lock down their data folder.
C:\ProgramData\Alighieri— which holds your config and user list — is restricted to SYSTEM, Administrators, and the service account, so other users on the machine can't read your password hashes or tamper with the config the service loads. Re-run the installer to apply it. (Linux was already protected.) - Misconfigurations are caught at
--check, not at runtime. Hostnames inudp.advertiseandtls.acme.domains, and the domains clients request, are now validated. Notably,tls.acme.domainsrejects names a public certificate authority can never issue for (IP addresses, wildcards,localhost, internal.local-style names, and similar) — so you learn about a bad entry immediately instead of when certificate issuance quietly fails. - Stronger guard against reaching internal addresses (SSRF). More IPv6 forms that map onto loopback, private, or reserved ranges are now caught by the DNS deny policy.
- Stricter external-auth credentials — the verifier now also rejects a stray carriage return, matching its newline and NUL handling.
Reliability
- The metrics endpoint and the UDP relay no longer spin on certain transient OS errors — they back off and recover instead.
shutdown.draintimeout: 0now clearly warns that it cuts in-flight connections immediately (the most aggressive setting — not an unlimited wait).
Get it
- Binaries for Linux and Windows (x86-64 and ARM64) are attached below.
- Container:
docker pull ghcr.io/wiresock/alighieri:0.3.1(also tagged0.3andlatest).
Upgrading
Replace the binary or pull the new image and restart — no config changes needed. On Windows, re-running the installer applies the new data-folder permissions.
All changes in this release (merged pull requests)
- Harden Windows service install rollback and config-marker write by @wiresock in #75
- Store an absolute service config path and surface marker read errors by @wiresock in #76
- Decouple the Event Log source from service-create/uninstall failures by @wiresock in #77
- Source ERROR_SERVICE_EXISTS from windows_sys instead of hardcoding 1073 by @wiresock in #78
- Reject relative service config markers and test the no-follow read by @wiresock in #79
- Fail fast when one TCP relay direction errors by @wiresock in #80
- Validate the config before writing the systemd unit on install by @wiresock in #81
- Add udp.advertise to override the UDP ASSOCIATE reply address by @wiresock in #82
- Warn when start/reload falls back to the default config on a missing marker by @wiresock in #83
- Warn when the ACME cache is outside the systemd StateDirectory by @wiresock in #84
- Bound udp.advertise DNS and warn on hardened-unit path footguns by @wiresock in #85
- Resolve udp.advertise at associate time; harden installer path checks by @wiresock in #86
- Wire-test udp.advertise, sync its docs, and normalise installer paths in-shell by @wiresock in #87
- Add installer self-tests, make the advertise hostname test resolver-agnostic by @wiresock in #88
- Canonicalize the UDP ASSOCIATE source-endpoint lock; fail advertise test loudly by @wiresock in #89
- Back off on persistent accept() failures instead of spinning by @wiresock in #90
- Surface UDP-reply send failures; harden the dual-stack test; cover the accept metric by @wiresock in #91
- Parse installer --check --json with an escape-aware extractor instead of sed by @wiresock in #92
- Make installer field-presence checks escape- and key-aware by @wiresock in #93
- Match the installer's acme boolean key-aware and whitespace-tolerant by @wiresock in #94
- Back off the metrics-accept and UDP-recv loops instead of spinning by @wiresock in #95
- Catch IPv4-compatible and special-use IPv6 forms in the deny policy by @wiresock in #96
- Reject a carriage return in external-verifier credentials by @wiresock in #97
- Warn (and document) that shutdown.draintimeout 0 cuts connections at once by @wiresock in #98
- Harden the Windows ProgramData\Alighieri ACL on install by @wiresock in #99
- Add security tests: SSRF deny, per-datagram UDP deny, parser rejects, connection cap by @wiresock in #101
- Validate SOCKS domain names; gate Windows DACL tests; fix README drift by @wiresock in #102
- Gate Windows DACL tests on harden failure; tighten domain validation; doc ACL grammar by @wiresock in #103
- Validate config hostnames; require the Windows DACL tests in CI by @wiresock in #104
- Validate tls.acme.domains against TLS-ALPN-01 issuability by @wiresock in #105
- Reject special-use TLDs for ACME; document the grammar by @wiresock in #106
- Scope the ACME validation docs to what --check checks; fix the .alt RFC by @wiresock in #107
- Release 0.3.1 by @wiresock in #108
Full changelog: v0.3.0...v0.3.1
v0.3.0
Alighieri 0.3.0
A security-focused release: substantial hardening of the UDP relay, DNS path, filesystem handling, and the Windows service, plus graceful connection draining on shutdown and stricter config parsing. Two breaking changes — please read before upgrading.
⚠️ Breaking changes
1. Public metrics now require an explicit opt-in.
A non-loopback metrics.listen (including 0.0.0.0) is refused at startup unless you also set metrics.allowpublic: true. The metrics endpoint is unauthenticated and exposes operational counters and rule labels, so exposing it off-loopback is now a deliberate choice.
→ Action: if you bind metrics to a routable address, add metrics.allowpublic: true (and keep it behind your own access controls). Loopback binds are unaffected.
2. UDP reply filtering is strict by default.
udp.strictreply now defaults to true: a UDP ASSOCIATE reply must come from the exact host:port the client contacted, not just the host — blocking a co-located attacker on the same host but a different port.
→ Action: if a server legitimately answers from a different port (e.g. TFTP), set udp.strictreply: false to restore host-only matching.
🔒 Security hardening
- UDP relay: replies are accepted only from remotes the client actually sent to; the idle timer is refreshed only by validated, authorized traffic, so spoofed or unrelated datagrams can no longer pin an association (and its port) open; and UDP is authorized against the
socksrules before any relay socket is bound. IPv6 UDP destinations now work, and empty UDP domain names are rejected. - Open-proxy guardrail: warns at startup and on reload when the no-auth (
none) SOCKS method is offered on a non-loopback listener with permissive rules. - DNS path: concurrent system lookups are capped per resolver, timed-out names get a brief fail-fast backoff, and every resolution path is bounded by
dns.timeout(default 5s) — so a slow or wedged resolver can no longer pin connection permits or stall UDP forwarding.dns.deny: reservednow also covers the 6to4-relay and benchmarking ranges. - Filesystem / TOCTOU: userlist, config-wizard, and ACME backups and lock files refuse symlinked paths (
O_NOFOLLOW+ atomic rename), and the ACME cache directory is created owner-only (0700). - Abuse controls: the per-client map (and its prune scan) can no longer grow without bound under a connection spray from many distinct source IPs.
- Hardened inputs: the metrics endpoint answers only
GET/HEAD(others get405); RFC 1929 rejects zero-length usernames before they reach an auth backend; and theproxyprotocoltrust gate canonicalizes IPv4-mapped peers so a dual-stack listener recognizes trusted IPv4 upstreams.
🔁 Reliability & operations
- Graceful shutdown drain: on stop, the accept loop stops taking new connections and waits up to the new
shutdown.draintimeout(default 10s;0cuts immediately) for in-flight connections to finish, then aborts the rest — a busy server is no longer severed mid-transfer, and an idle one still exits at once. - Shutdown stays responsive during a config reload — a slow or wedged config/userlist read no longer delays a stop signal.
- Reload correctness: restart-only settings no longer drift (
metrics.allowpublic), footgun warnings now reflect the effective config, anddns.cachettl/ratelimit.byteratechanges take effect immediately. - Windows service: install is now transactional around its config marker, and
install/start/reloadrun the same startup validation as the server — so misconfigurations surface up front instead of at bind time. - Userlist is read and hash-parsed off the runtime worker threads during startup and reload, so a large userlist on slow storage can't stall a worker.
🧱 Stricter config parsing (fail loud, not silent)
Several settings that previously silently broadened a policy on a typo now fail to parse instead:
- stray tokens after an address or rule selector (e.g.
ports =no longer parses as "all ports"), emptyprotocol:/command:selectors, and tokens after a rule's closing}; - trailing tokens on numeric / boolean / keyword settings, and
0forconnecttimeout/handshaketimeout; maxconnectionsandlogrotate.keepare now bounded both ways (no pointer-width overflow, no absurd values).
config metadata --json again lists every configuration setting, guarded by a regression test.
📦 Supply chain
- The
Dockerfilepins its base images by digest, with a new Dependabotdockerecosystem to keep them current.
Install
Prebuilt binaries for Linux and Windows (x86-64 and ARM64) are attached below.
Container image (multi-arch amd64 + arm64):
docker pull ghcr.io/wiresock/alighieri:0.3.0
Full details: CHANGELOG.md · Compare: v0.2.0...v0.3.0
Alighieri v0.2.0
Alighieri's biggest release yet. Since v0.1.x it learned to manage its own HTTPS
certificates, ships as a container and on ARM, can sit behind load balancers and
external auth systems, shapes bandwidth more gracefully — and closes a security
hole worth upgrading for.
🔐 Automatic TLS certificates from Let's Encrypt
Point the TLS listener at a domain and Alighieri obtains and renews certificates
for you — no certbot, no cron, no port 80, no DNS API:
tls.acme.domains: proxy.example.com
tls.acme.email: you@example.com
tls.acme.cache: /var/lib/alighieri/acme
# tls.acme.staging: on # use Let's Encrypt staging while testingValidation uses the TLS-ALPN-01 challenge answered on the listener itself, so it
just needs to be reachable on port 443. On Linux, scripts/alighieri.sh
sets up the hardened systemd unit automatically (writable cert cache +
CAP_NET_BIND_SERVICE so the non-root service can bind 443). There's a
step-by-step VPS walkthrough in
doc/acme-tls-test.md.
📦 Run it anywhere
- Official container image — multi-arch (
amd64+arm64), distroless,
non-root,--read-only-friendly:docker run --rm -p 1080:1080 \ -v "$PWD/alighieri.conf:/etc/alighieri/alighieri.conf:ro" \ ghcr.io/wiresock/alighieri:0.2.0 - ARM64 binaries —
aarch64Linux and Windows are now attached to every
release alongside the x86-64 builds.
🧱 More access control & traffic shaping
- PROXY protocol (v1/v2) — run behind HAProxy / nginx / AWS·GCP NLBs and have
rules, limits, metrics, and logs key on the real client, not the balancer
(proxyprotocol, honoured only from trusted upstream CIDRs). - External auth hook — verify credentials against LDAP / OIDC / PAM /
anything via a script (auth.command; the username/password go on the
command's stdin, exit0allows). - Hostname rules —
socksto:selectors now match names:.example.com
(the domain and all subdomains) or an exactexample.com, matched on the
requested name before DNS resolution (so it's DNS-rebinding-resistant). - Smoother bandwidth limits —
ratelimit.byterateis now a token-bucket
throttle that slows a flow instead of dropping it, plus a new per-rule
bandwidth:selector to throttle individual CONNECT sessions.
🛡️ Security fix — please upgrade
A client could reach blocked loopback/private addresses by requesting their
IPv4-mapped IPv6 form (e.g. [::ffff:127.0.0.1]), slipping past a
dns.deny: loopback private … policy and to: 127.0.0.0/8-style CIDR rules.
Addresses are now canonicalised before every policy decision and the outbound
connection. Upgrade is recommended if you rely on dns.deny or CIDR rules for
network segmentation. (Hostname-allowlist deployments were never affected.)
🪟 Windows service reliability
The installed service now auto-restarts on crash (the Windows equivalent of
systemd's Restart=on-failure) and stops gracefully on an OS shutdown/restart.
⚠️ Upgrade notes (read before bumping)
ratelimit.byteratechanged meaning. It used to be a hard cap that
dropped traffic once the per-window budget was spent; it's now a sustained
rate (BYTES / WINDOW, burst up toBYTES) that shapes TCP (slows it via
backpressure) and polices UDP. The same value now throttles smoothly instead
of cutting connections — re-check yours if you relied on the old hard-cap.- Building from source now needs Rust 1.88 (was 1.85), pulled in by a
security-patched dependency. Prebuilt binaries and the container image are
unaffected — onlycargo buildneeds the newer toolchain.
Getting it
Download a prebuilt binary for your platform from the assets below, pull the
container image above, or build from source with Rust 1.88+. New here? The
README's quick start and the built-in alighieri config wizard will get you a
first config in a minute.
Full changelog: v0.1.1...v0.2.0
Alighieri v0.1.1
A small, backward-compatible patch release.
Added
-
udp.portrange— bind the client-facing UDP relay socket (theBND.PORTadvertised in the UDP ASSOCIATE reply, where clients send their datagrams) within a fixed inclusive port range instead of an OS-assigned ephemeral port, so the inbound UDP ports can be opened predictably on a firewall. Unset keeps the previous ephemeral behaviour.udp.portrange: 20000-21000 # or a single port: udp.portrange: 20000
Also landed on main (docs only): a Comparison with Dante section in the README and a refreshed roadmap.
Full changelog: v0.1.0...v0.1.1
Install
Prebuilt binaries are attached below (each bundles the binary with README, LICENSE, and CHANGELOG):
| Platform | Asset |
|---|---|
| Linux x86-64 | alighieri-v0.1.1-x86_64-unknown-linux-gnu.tar.gz |
| Windows x86-64 | alighieri-v0.1.1-x86_64-pc-windows-msvc.zip |
Linux (systemd service):
curl -O https://raw.githubusercontent.com/wiresock/alighieri/v0.1.1/scripts/alighieri.sh
chmod +x alighieri.sh
sudo ./alighieri.sh # install
# upgrading an existing install:
sudo ./scripts/alighieri.sh upgrade # rebuild/replace the binary and restartAlighieri v0.1.0
Alighieri is a lightweight, secure, asynchronous SOCKS5 proxy server with Dante-inspired configuration. This is the first public release.
Dual-licensed under AGPL-3.0-or-later, with a commercial license available for proprietary use — see LICENSING.md.
Features
- SOCKS5 (RFC 1928) — TCP
CONNECTand UDPASSOCIATE, including IPv4-mapped clients on dual-stack[::]listeners, with username/password authentication (RFC 1929) backed by Argon2id userlist hashes and a verified credential cache. - Dante-inspired access control — deny-by-default
client/socksrules with CIDR, port, command, protocol, and auth-method selectors across IPv4 and IPv6, plus named rules andincludesupport. - DNS policy — address-family preference, all-address TCP fallback, post-resolution deny categories, and optional answer caching with request coalescing.
- Observability — an optional Prometheus-style metrics endpoint, and structured text/JSON logging with size-based rotation and a non-blocking background writer.
- Per-client abuse controls — connection-rate, auth-failure-rate, concurrent-connection, and
ratelimit.byteratecaps. - Sustained high-rate UDP tuning — enlarged kernel socket buffers and resilience to transient
recv_fromerrors. - Optional TLS-wrapped listener (rustls 0.23,
ringprovider). - Hot reload of policy, DNS, auth, userlist, and timeout settings via
SIGHUP(Unix) and the Service Control Manager (Windows). - Windows Service integration with Windows Event Log reporting.
- Linux systemd lifecycle manager (
scripts/alighieri.sh) — install, upgrade, uninstall, and status, with a self-bootstrapping standalone mode. - Configuration wizard — a short-lived, loopback-only web wizard that generates a new config or imports and edits an existing one (logs to stdout by default).
- Tooling — userlist management (
user add/delete/list/verify), config validation (--check,--check --json), reload metadata (config metadata --json), and--version/-V.
Install
Prebuilt binaries — download and extract the archive for your platform from the Assets below (each bundles the binary with README, LICENSE, and CHANGELOG):
| Platform | Asset |
|---|---|
| Linux x86-64 | alighieri-v0.1.0-x86_64-unknown-linux-gnu.tar.gz |
| Windows x86-64 | alighieri-v0.1.0-x86_64-pc-windows-msvc.zip |
Linux (systemd service) — install and manage with the bundled script:
curl -O https://raw.githubusercontent.com/wiresock/alighieri/v0.1.0/scripts/alighieri.sh
chmod +x alighieri.sh
sudo ./alighieri.sh # build from source and install the service
# …or install a prebuilt binary from the Assets above:
sudo ./alighieri.sh install --binary ./alighieriFrom source (Rust 1.85+):
git clone https://github.com/wiresock/alighieri
cd alighieri
cargo build --releaseFirst steps
alighieri config wizard # generate a config via the loopback-only wizard
alighieri --version # 0.1.0See the README for configuration, deployment, and the management script, and the CHANGELOG for the full list.