Skip to content

Releases: getlantern/soar

Soar v0.2.4

Choose a tag to compare

@myleshorton myleshorton released this 22 Oct 16:01
fea80aa

Fixes

  • An unused round tripper no longer holds a stream for good.
    • The bug: NewRoundTripper confirms its connection before returning, and that connection holds one of the session's streams until a request takes it. A round tripper discarded unused, as a race does when another transport wins, kept its stream open. Open streams kept the session from looking idle, so it was never retired. Once MaxStreams (64 by default) had leaked, every dial failed with soar: too many streams until the process restarted.
    • Impact: one Windows client on a Lantern beta failed every Soar attempt about 1,800 times over two days. It was losing short races to Unbounded's signaling polls, which run every ~14 s.
    • The fix: the returned transport implements io.Closer. Close releases an untaken connection and closes idle connections. An untaken connection also closes itself after 10 s, for callers that never call Close. (#15)
  • getlantern/kindling#61 makes kindling's race close the round trippers it doesn't use. Either fix alone stops this leak.

Compatibility

There are no API changes: NewRoundTripper still returns an http.RoundTripper, which can now also be asserted to io.Closer. The wire protocol is unchanged: v0.2.4 interoperates with v0.2.x, v0.1.0 and soar-rs clients and servers. soar-rs needs no matching change, since its connections close their streams when dropped.

Full changelog: v0.2.3...v0.2.4

Soar v0.2.3

Choose a tag to compare

@myleshorton myleshorton released this 18 Oct 03:55
a8af533

Fixes

  • A dial no longer fails on a session left behind by an abandoned handshake.
    • The bug: when a dial's context ended mid-handshake, typically because another transport won a race, the handshake still completed. That left a session that never carried a stream. The server ends such a session 15 s after its hello, but the client kept it for SessionIdle (90 s), so the next dial in that window failed with soar: server lost the session.
    • Impact: with kindling's 8 s start delay this was the common case. Soar joins the race, domain fronting wins half a second later, and the next Soar attempt fails at once.
    • The fix: a session that has never carried a stream is retired 10 s after its first hello, timed from the hello rather than its reply, since retried hellos get the same session back. A session that came up less than a second ago is kept, because a dial waiting on it is about to use it. (#14)
  • SPEC.md §7.4 notes the behavior.

Compatibility

There are no API changes, and the wire protocol is unchanged: v0.2.3 interoperates with v0.2.x, v0.1.0 and soar-rs clients and servers.

Full changelog: v0.2.2...v0.2.3

Soar v0.2.2

Choose a tag to compare

@myleshorton myleshorton released this 15 Oct 20:08
f0d5504

Fixes

  • The first dial after a pause no longer fails with soar: server lost the session.
    • The bug: an idle client sends nothing, so the server ends its session after its idle timeout (2 minutes) without the client knowing. The client kept the session, and the next stream failed as soon as the server's signed unknown-session answer arrived.
    • Impact: Lantern calls Soar minutes apart, so this cost its first Soar attempt after nearly every pause.
    • The fix: a session with no streams and no authenticated answer for Config.SessionIdle (default 90 s) is retired, and the next dial handshakes again. The check and the close happen under one lock, and a dial that loses that race handshakes again instead of failing. (#13)

Additions

  • Config.SessionIdle sets that limit. Keep it below the server's IdleTimeout.
  • SPEC.md §7.4 now recommends this behavior for clients.

Compatibility

There are no breaking API changes; the new field is optional.

The wire protocol is unchanged: v0.2.2 interoperates with v0.2.x, v0.1.0, and soar-rs clients and servers.

Also in this range

Full changelog: v0.2.1...v0.2.2

Soar v0.2.1

Choose a tag to compare

@myleshorton myleshorton released this 14 Oct 12:44
d9b982c

Fixes

  • Mixed upload/download no longer shrinks query names for good. The client judged a held poll lost once three later data queries were answered, but the server holds polls and answers data at once by design. Two such false losses demoted names from 253 to 101 characters, cutting upload capacity per query about 2.5×. Loss is now judged by later polls only, and the server releases held polls oldest first. (#8)
  • Conn.Close could lose the request. RESET went out once the data was acked, before the FIN was, so the server aborted the stream before dialing. It now waits for the FIN's ack. (#10)
  • Discovery resumes when working resolvers get blocked. Want now counts only healthy paths (verified, usable, not on a run of losses), and discovery wakes at its configured pace instead of about once a second. (#10)
  • Liveness, hello retries and caps: the liveness clock restarts instead of stopping while queries are outstanding; hello retries rotate through all resolvers, not the first 16; the tail copy of an upload respects MaxInflight; and a full DNS ID space can no longer spin newTxnLocked holding the client lock. (#10)
  • Session and server: a full control queue ends the session instead of silently dropping frames (a dropped MAX_STREAM_DATA stalled a stream for good); a malformed destination gets RESET_STREAM code 1 instead of hanging waitOpened; PublicOnly rejects 192.88.99.0/24, 2001:20::/28 and 3fff::/20. (#10)

Behavior changes

  • ClientConfig.MaxInflight is capped at 1,024, and MaxStreams at 256 on both client and server. Larger values are clamped.

Compatibility

No API changes, and the wire protocol is unchanged: v0.2.1 interoperates with v0.2.0 and v0.1.0 clients and servers.

Also in this range

  • SPEC.md specifies the wire format (version 1), and testdata/vectors.json holds test vectors generated from the real encoders; CI fails on any unregenerated wire change. (#7)
  • dnsbench adds soar-rs, the Rust implementation, as a contender. (#9)

Full changelog: v0.2.0...v0.2.1

Soar v0.2.0

Choose a tag to compare

@myleshorton myleshorton released this 13 Oct 12:57
2167099

What's new

  • Client.PathStats() returns a read-only snapshot of every resolver path: transport (udp/tcp), verified, suspended, candidate, RTT, loss, inflight, window, query-name cap, the answer-size limit sizing has accepted, record type (TXT/AAAA), successes and last success. Use it to tell which resolvers actually carry the tunnel on a given network. (#5, thanks @mrgluek)
  • Client.Established() reports whether a session with the server is up. (#5)
  • Config.StreamOnly func(resolver string) bool marks resolvers that only speak a stream transport (plain TCP/53, or DNS over TLS through a custom DialTCP). They get a TCP path from the start and no UDP path, whatever TCP is set to. Nil keeps the previous behavior. (#5)
  • golang.org/x/crypto 0.49.0 → 0.52.0.

Compatibility

All changes are additive and the wire protocol is unchanged: v0.2.0 clients work with v0.1.0 servers and the reverse.

Also in this range

  • dnsbench (bench/, a separate Go module) is the benchmark harness behind the README's comparison table. The README and site figures are now medians of three runs on incompressible data. (#6)

Full changelog: v0.1.0...v0.2.0