Skip to content

Releases: wiresock/alighieri

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 23 Jul 18:55
Immutable release. Only release title and notes can be modified.
6673f01

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 plugins SDK, 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.x preserve the supported contract; breaking API or SDK changes wait for 0.5.0.

Install

cargo install alighieri --locked
alighieri --version

For 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

Choose a tag to compare

@github-actions github-actions released this 28 Jun 09:05
b74db2e

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 in udp.advertise and tls.acme.domains, and the domains clients request, are now validated. Notably, tls.acme.domains rejects 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: 0 now 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 tagged 0.3 and latest).

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

Choose a tag to compare

@github-actions github-actions released this 24 Jun 21:54
5425f4d

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 socks rules 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: reserved now 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 get 405); RFC 1929 rejects zero-length usernames before they reach an auth backend; and the proxyprotocol trust 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; 0 cuts 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, and dns.cachettl / ratelimit.byterate changes take effect immediately.
  • Windows service: install is now transactional around its config marker, and install / start / reload run 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"), empty protocol: / command: selectors, and tokens after a rule's closing };
  • trailing tokens on numeric / boolean / keyword settings, and 0 for connecttimeout / handshaketimeout;
  • maxconnections and logrotate.keep are 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 Dockerfile pins its base images by digest, with a new Dependabot docker ecosystem 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

Choose a tag to compare

@github-actions github-actions released this 22 Jun 07:53
d4b5981

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 testing

Validation 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 binariesaarch64 Linux 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, exit 0 allows).
  • Hostname rulessocks to: selectors now match names: .example.com
    (the domain and all subdomains) or an exact example.com, matched on the
    requested name before DNS resolution (so it's DNS-rebinding-resistant).
  • Smoother bandwidth limitsratelimit.byterate is 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.byterate changed 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 to BYTES) 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
    — only cargo build needs 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

Choose a tag to compare

@github-actions github-actions released this 18 Jun 07:47
c0e7e27

A small, backward-compatible patch release.

Added

  • udp.portrange — bind the client-facing UDP relay socket (the BND.PORT advertised 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 restart

Alighieri v0.1.0

Choose a tag to compare

@github-actions github-actions released this 17 Jun 13:41
0a4d432

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 CONNECT and UDP ASSOCIATE, 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 / socks rules with CIDR, port, command, protocol, and auth-method selectors across IPv4 and IPv6, plus named rules and include support.
  • 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.byterate caps.
  • Sustained high-rate UDP tuning — enlarged kernel socket buffers and resilience to transient recv_from errors.
  • Optional TLS-wrapped listener (rustls 0.23, ring provider).
  • 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 ./alighieri

From source (Rust 1.85+):

git clone https://github.com/wiresock/alighieri
cd alighieri
cargo build --release

First steps

alighieri config wizard      # generate a config via the loopback-only wizard
alighieri --version          # 0.1.0

See the README for configuration, deployment, and the management script, and the CHANGELOG for the full list.