Repository navigation
Releases: andriykohut/hawse
Release list
v0.8.0
The wire protocol did not change. 0.8.0 speaks hawse/2 as 0.5.0 through 0.7.0 do, so a server and a client need not be upgraded together.
New:
hawse completions SHELLprints the completion script for bash, zsh, fish, elvish or PowerShell, generated from the arguments the binary parses. The install page gives the line for the rc file (#129).- The client says how far away its server is: the round trip is in its header on a terminal and in the
connectedlog line asround_trip_ms. It is timed once per connection, on the greeting the client already makes, over QUIC and over the TCP fallback alike (#128). - The reference moved out of the README to a site, https://andriykohut.github.io/hawse/ (#130, #132).
Behaviour changes:
install.shends with a line pointing at the completions section of the install page (#129).
Breaking for library users: client::Event::Connected gained round_trip.
What's Changed
- Show the round trip to the server in the client's header and its connected line by @andriykohut in #128
- Print a shell's completion script, generated from the arguments the binary parses by @andriykohut in #129
- Publish a homepage and the README's reference sections as a site on GitHub Pages by @andriykohut in #130
- Bump the cargo-compatible group with 4 updates by @dependabot[bot] in #131
- Give links to the site a preview image and a description, and point the crate at the site by @andriykohut in #132
- Time the stream refuser's shutdown test to the session's close, not the server's task by @andriykohut in #133
- Name UDP in the README's first sentence and say the client opens the connection once by @andriykohut in #134
- Carry Google Search Console's verification tag on every page by @andriykohut in #135
- chore: bump to 0.8.0 by @andriykohut in #136
Full Changelog: v0.7.0...v0.8.0
v0.7.0
The wire protocol did not change. 0.7.0 speaks hawse/2 as 0.5.0 and 0.6.0 do, so a server and a client need not be upgraded together.
New:
hawse join HOST[:PORT] --server-key KEYsets a client up in one command: it creates the key, writesclient.toml, and waits until the server authorizes the key. The server's startup output gives the command with its own key filled in (#120).- Both ends read their config again when the file changes, and on SIGHUP. The server takes up
[clients.*]: a client whose table is gone is disconnected at once, and a fixed port taken out ofportsis unbound. The client takes up[expose.*]within its session, and reconnects for any other change (#116). hawse checkvalidates a config without starting anything, andhawse check --connectdials the server a client config names and reports the transport that answered (#114).install.shinstalls the latest release for the machine it runs on, checked againstSHA256SUMS(#121).- On a terminal, the server and the client print a header and a row for each client and service in place of log lines (#123, #126).
Behaviour changes:
- A server or a client run on a terminal at the default level no longer prints timestamped log lines.
--log pretty,-v,-qandHAWSE_LOGeach bring them back, and anything that is not a terminal is unchanged, a unit's journal and JSON included (#123, #126). - A SIGHUP reloads the config (#116), except for a hawse run on a terminal, which it stops, as closing the terminal stops anything run in it. On a terminal means stdin and stderr both, so
nohup hawse clientreloads and stays (#125). - The server's line for a key it does not know prints the
[clients.NAME]table to add toserver.toml, and no longer names ahawse authorizecommand, which was never written (#118). - A session gives each service id out once. After 65,535 binds in one session the server ends it with
Shutdownand the client reconnects, where an id was given out again before (#115). - The stop signals are in place before the server says it is listening, so a signal sent on seeing that is answered with a clean stop (#125).
Fixed:
- After 65,535 binds in one session a UDP reply still on its way could reach a visitor of the service that took its id over (#115).
Breaking for library users: Transport gained a required method, kind. New beside it and not breaking: server::Event with Server::events(), Client::probe and Client::expose.
What's Changed
- Check a config without starting anything, and dial its server on request by @andriykohut in #114
- Give a session's service ids out once, and end the session when none is left by @andriykohut in #115
- Reload a changed config without a restart, and disconnect a client it no longer names by @andriykohut in #116
- Print the table to paste for an unknown key, and drop the authorize and revoke verbs by @andriykohut in #118
- Join a server with one command, which writes the client's config and waits to be authorized by @andriykohut in #120
- Install the latest release with one command, on any of the release targets by @andriykohut in #121
- Test that a visitor stream outlives a change of the client's address, and say so in the README by @andriykohut in #122
- Print a header and a row per service for a client on a terminal by @andriykohut in #123
- Stop on SIGHUP when run on a terminal, where it says the terminal has gone by @andriykohut in #125
- Print a header and a row per client and service for a server on a terminal by @andriykohut in #126
- chore: bump to 0.7.0 by @andriykohut in #127
Full Changelog: v0.6.0...v0.7.0
v0.6.0
The wire protocol did not change. 0.6.0 speaks hawse/2 as 0.5.0 does, so a server and a client need not be upgraded together.
Behaviour changes:
limits.streams_per_clientis now enforced. A session holds that many streams less one, the one being its control stream; a visitor past it is reset, and a UDP service's stream waits for room. The setting must be at least 2, and above 4097 it takes effect as 4097 with a warning at startup (#101).- More stops exit 2: a config that does not load (#77), a client stopped by an error its config cannot be retried past (#106), and
keygenagainst a client config that does not parse (#107). keygenwrites the key whereclientloads it from. It takes--config, withHAWSE_CONFIGbehind it, and follows the config'skey;--outstill decides when given (#107).- A peer that has gone quiet is dropped at the 45 s deadline, not on the ping after it (#79), and a client that sends and never reads its control stream is dropped as unresponsive at 45 s (#109).
- A peer key that is not the canonical Ed25519 encoding is refused (#75).
- A range of one port prints as the bare number,
443and not443-443(#73).
Fixed:
- A stalled control stream held a session past the server's 5 s wait (#109) and a client past its stop, for the 30 s of QUIC's idle timeout (#110).
- A process whose stderr was a pipe with the reader gone survived SIGTERM (#108).
- On the TCP fallback, a session at its stream limit that dropped a stream and opened another could lose the whole connection (#101).
- The client gave up after the first address a name resolved to; it now dials each (#77).
- Visitor and local sockets had no keepalive (#78).
New:
- A warning at startup when
prefer = "tcp"leaves a QUIC setting without effect (#77).
Breaking for library users: tls::PinnedServer and tls::AnyEd25519Client are no longer public, and ClientError, ServerError and PeerKeyError each gained a variant (Buffer, Buffer, Encoding).
What's Changed
- Close the proto findings from the phase 1 reviews by @andriykohut in #73
- Move the backlog to GitHub issues by @andriykohut in #68
- Close the small test and comment findings from the phase 1 reviews by @andriykohut in #74
- Close the identity and TLS findings from the phase 1 reviews by @andriykohut in #75
- Make the supersede wait and the dial cancel-aware, and close three small session gaps by @andriykohut in #76
- Exit 2 on a config that does not load, warn about inert settings, and dial every resolved address by @andriykohut in #77
- Set a keepalive on visitor and local sockets, and keep a session's teardown inside the server's wait by @andriykohut in #78
- Show a recording of a server, a client and a visitor in the README by @andriykohut in #98
- Notice a quiet peer at the deadline, and close with a reason on the paths that had none by @andriykohut in #79
- Take the tests' fixed ports from below the ephemeral range by @andriykohut in #100
- Bound the streams a session opens toward its client, and reset a visitor past the limit by @andriykohut in #101
- Exit 2 when a config error stops the client by @andriykohut in #106
- Have keygen write the key where the client loads it from by @andriykohut in #107
- Stop on SIGTERM after the stderr reader has gone away by @andriykohut in #108
- Keep a stalled control stream from holding a session past the server's wait by @andriykohut in #109
- Keep a stalled control stream from holding a client past its stop by @andriykohut in #110
- Bump the cargo-compatible group with 3 updates by @dependabot[bot] in #111
- Keep a descheduled caller from failing the test of reopening as fast as dropping by @andriykohut in #112
- chore: bump to 0.6.0 by @andriykohut in #113
Full Changelog: v0.5.0...v0.6.0
v0.5.0
The wire protocol changed. 0.5.0 speaks hawse/2 and does not talk to 0.4.0 or older: upgrade the server and its clients together. A 0.5.0 client that meets an older server names the mismatch in its error.
Behaviour changes:
transport.prefer = "auto", the default, now falls back. The client dials QUIC, and when QUIC has not connected after 2 seconds it dials TLS over TCP beside it and takes whichever connects first. A session that lands on the fallback stays there until it ends; the next connection tries QUIC first again.prefer = "quic"keeps the old behaviour.- A visitor's TCP connection that was cut short now ends in a connection reset where it used to end in a clean close: when the local service resets it, when nothing is listening on
local, or when the tunnel drops. - A wildcard bind of a service port or of the server's listen port now fails as in use when an IPv6 address already holds the port. It used to come up answering IPv4 only.
Breaking for library users: ClientError gained Version and NoTransport, ServerMessage::Bound gained address, FrameError gained Visitor, ConfigError::UdpProxy is gone, and pump takes an Edge (#22).
New in this release (#22):
proxy_protocol = trueon a UDP service sends a PROXY protocol v2 header in front of every datagram. The visitor's address costs 7 bytes of each packet for an IPv4 visitor and 19 for IPv6.- On the TCP fallback a refused or aborted stream carries its reset code, and a stream that was cut short no longer reads as one that finished. That costs a small request about 3 ms under heavy transfers; docs/measurements.md has the figures.
What's Changed
- Unwrap the prose in the bug form by @andriykohut in #19
- Run the Linux CI jobs on ubuntu-26.04 by @andriykohut in #20
- Run the release workflow's Linux jobs on ubuntu-26.04 by @andriykohut in #21
- The wire change: resets for cut-short connections, the TCP fallback under auto, PROXY v2 for UDP by @andriykohut in #22
Full Changelog: v0.4.0...v0.5.0
v0.4.0
PROXY v2 needs both ends on 0.4.0. The wire protocol is otherwise unchanged: no message changes shape, and a 0.3.0 client still works with a 0.4.0 server and the other way round. But a 0.3.0 client accepts proxy_protocol = true on a TCP service and, against a 0.4.0 server, now gets the bind instead of a refusal, while sending no header. Upgrade the client before turning it on.
Breaking for library users: config::ClientPolicy gained allow, config::ServerTransport gained tcp_fallback, udp::DropCounts gained not_allowed, client::Target gained proxy_protocol, and ConfigError has new variants (#16).
Behaviour change: limits.auth_failures_per_minute now takes effect at its default of 30. An address (an IPv6 /64) that keeps failing to authenticate is refused before the TLS or QUIC handshake until its budget refills. Reconnects by a known client never count. Set it to 0 to turn it off. quic_retry = true now takes effect too.
New in this release (#16):
allowon a service limits it to the listed networks, enforced on the server for TCP and UDP. The same key on a[clients.NAME]table inserver.tomlcaps what that client may allow.proxy_protocol = trueon a TCP service sends a PROXY protocol v2 header ahead of each visitor's bytes. UDP services cannot use it yet.transport.tcp_fallback = falseruns a server on QUIC only.- Streams a client opens past its control stream are refused instead of queueing unread.
What's Changed
- Allow lists, PROXY v2 for TCP, and server hardening by @andriykohut in #16
- chore: bump to 0.4.0 by @andriykohut in #17
Full Changelog: v0.3.0...v0.4.0
v0.3.0
Breaking for library users: client::Event::Disconnected gained retry_in: Option<Duration> (#10). The wire protocol is unchanged, so a 0.3.0 client works with a 0.2.0 server and the other way round.
Behaviour change: a client without congestion in its [transport] now uses bbr instead of cubic (#12). Measured over a real 27 ms path, it matched a connection-per-visitor tunnel on throughput and latency, and cubic collapses on a path with random loss. Set congestion = "cubic" to keep the old behaviour. The server's default is still cubic.
The client also backs off between reconnects (1, 2, 4, 8, 16, then 30 s, with jitter) instead of retrying every 5 s.
What's Changed
- Back off between reconnects by @andriykohut in #10
- Update yoke-derive past the yanked 0.8.3 by @andriykohut in #13
- Default the client to bbr by @andriykohut in #12
- Bump the cargo-compatible group across 1 directory with 2 updates by @dependabot[bot] in #11
- chore: bump to 0.3.0 by @andriykohut in #14
New Contributors
- @dependabot[bot] made their first contribution in #11
Full Changelog: v0.2.0...v0.3.0
v0.2.0
v0.1.1
What's Changed
- Carry the tunnel over TCP as well as QUIC by @andriykohut in #1
- Update dependencies and add Dependabot by @andriykohut in #2
- Drop the versioning strategy Dependabot rejects for Cargo by @andriykohut in #3
- Keep the end-to-end listen port out of the dynamic pool by @andriykohut in #4
- Drop the mipsel target by @andriykohut in #5
- Bring the README's configuration notes in line with the code by @andriykohut in #6
- Add releases: binaries, a container image, and crates by @andriykohut in #7
- Release 0.1.1 by @andriykohut in #8
New Contributors
- @andriykohut made their first contribution in #1
Full Changelog: https://github.com/andriykohut/hawse/commits/v0.1.1