|
| 1 | +# Published Linux 7.x compatibility verification |
| 2 | + |
| 3 | +Verified on 2026-10-21 against the dedicated **staging** `http-proxy-test` |
| 4 | +route `3e9aa468-47ca-4fc3-b61e-4049a3f92e34` (`45.79.155.229:8021`). |
| 5 | +Production was not changed. No client was rebuilt or patched. |
| 6 | + |
| 7 | +## Artifacts |
| 8 | + |
| 9 | +Clients came from the `update_linux_amd64.bz2` assets of the official |
| 10 | +[7.9.5](https://github.com/getlantern/lantern/releases/tag/7.9.5) and |
| 11 | +[7.7.2](https://github.com/getlantern/lantern/releases/tag/7.7.2) releases. |
| 12 | +The decompressed executables had these SHA256 hashes before and after testing: |
| 13 | + |
| 14 | +| Release | Executable SHA256 | |
| 15 | +| --- | --- | |
| 16 | +| 7.9.5 | `fc62e4b3b5d457b43c7b5bbab7ff78d813c5046871ef5473ed0ee0bcfdac7293` | |
| 17 | +| 7.7.2 | `bc8614165560b734c823760a30315530344f0415e695e1668a8f98db86f88ff7` | |
| 18 | + |
| 19 | +The candidate was built from runtime revision `e335fd0` using Go 1.26.10, |
| 20 | +`CGO_ENABLED=0`, `GOARCH=amd64`, and `-trimpath`. Its executable SHA256 was |
| 21 | +`fec124ccfb6dfd9958e8646fff57e697d6cac7b49f89d66ae148754f81640092`; |
| 22 | +the running staging process's `/proc/<pid>/exe` matched. The subsequent |
| 23 | +workflow-only change does not change the candidate's runtime source. |
| 24 | + |
| 25 | +## Method and results |
| 26 | + |
| 27 | +The original binaries ran headless under Xvfb in an isolated Ubuntu 22.04 |
| 28 | +container with their required GUI/libpcap libraries. Their cached `proxies.yaml` |
| 29 | +selected only the staging route. `-stickyconfig -readableconfig -proxyall` |
| 30 | +prevented remote configuration replacement. A valid cached global config |
| 31 | +set `MustProxy` rules for the test domains and disabled autoupdate. This |
| 32 | +configuration change was necessary: a standalone partial global config is |
| 33 | +rejected by these releases and causes fallback to their embedded config. |
| 34 | + |
| 35 | +Every positive run required all of: |
| 36 | + |
| 37 | +- Plain HTTP `http://example.com` and HTTPS `https://example.com` returning |
| 38 | + status 200 and the expected page body through the client's local HTTP proxy. |
| 39 | +- `https://api.ipify.org` reporting **45.79.155.229**, rather than the test |
| 40 | + machine's direct address. |
| 41 | +- Five further successful HTTPS requests with the same staging egress. |
| 42 | + |
| 43 | +| Client | Normal route: Shadowsocks + smux | TLS + smux, API-issued ticket | Cached server-issued ticket after proxy restart | |
| 44 | +| --- | --- | --- | --- | |
| 45 | +| Linux 7.9.5 | PASS | PASS | PASS | |
| 46 | +| Linux 7.7.2 | PASS | PASS | PASS | |
| 47 | + |
| 48 | +For TLS, a temporary config on the same staging listener used fixtures |
| 49 | +generated by lantern-cloud's actual `makeTLSSessionState`, `proxyini.Build`, |
| 50 | +and `LegacyConnectConfig` paths. The binary required authenticated tickets. |
| 51 | +The API-issued ticket was 121 bytes; the old client persisted a **new 123-byte |
| 52 | +server-issued ticket**. Cached runs reused that state after restarting the |
| 53 | +proxy. Client logs confirmed loading the persisted state. Thus both ticket |
| 54 | +encodings were exercised through actual old client executables. |
| 55 | + |
| 56 | +### Server-side packet verification |
| 57 | + |
| 58 | +The tests were repeated with `tcpdump` on the staging VPS, filtered to TCP |
| 59 | +port 8021 and the test machine's source IP. Wireshark 3.6.2 decoded the capture. |
| 60 | +For both releases the verification matched the **exact bytes** of the ticket |
| 61 | +in the client's persisted cache to a `NewSessionTicket` sent by the staging |
| 62 | +server, then matched those bytes to a subsequent ClientHello after a proxy |
| 63 | +restart. These were 123-byte Go-issued tickets, distinct from the 121-byte |
| 64 | +API-issued bootstrap ticket. |
| 65 | + |
| 66 | +The server echoed the ClientHello session ID and sent an abbreviated TLS 1.2 |
| 67 | +handshake: ServerHello, NewSessionTicket, ChangeCipherSpec, Finished, with no |
| 68 | +Certificate or ServerKeyExchange. Resumed connections carried application |
| 69 | +records in both directions, and the client-side HTTP/HTTPS/egress checks passed. |
| 70 | +This verifies actual resumption, rather than merely successful connection with |
| 71 | +a cached ticket that might have fallen back to a full handshake. |
| 72 | + |
| 73 | +| Client | Server issuance → client reuse | Cached reuse after restart | Resumed application traffic | |
| 74 | +| --- | --- | --- | --- | |
| 75 | +| 7.9.5 | Capture stream 0 → 1 | Ticket from stream 2 offered in stream 4 | Renewed tickets in streams 5–8 | |
| 76 | +| 7.7.2 | Capture stream 9 → 10 | Ticket from stream 9 offered in stream 11 | Streams 10–11 | |
| 77 | + |
| 78 | +The [sanitized assertions](test-results/emudhra-staging-resumption.json) |
| 79 | +contain the per-release result and stream identifiers. The private capture's |
| 80 | +SHA256 is `e6fb3674047aef8c57e33cb110ba56459d4dc6f0a151fcc5f971f4e6a8bfa43a`. |
| 81 | +Raw captures, ticket contents, session secrets, and route credentials are not |
| 82 | +committed. The temporary TLS listener and capture were removed; the tested |
| 83 | +candidate continues to use the route's original configuration. |
| 84 | + |
| 85 | +A negative control flipped one byte in the API-issued ticket. A fresh 7.9.5 |
| 86 | +client then failed to proxy traffic and produced no egress response. This |
| 87 | +checks ticket rejection and rules out a direct-connection success masking a |
| 88 | +transport failure. Unit tests separately reject tickets issued under a |
| 89 | +different key. |
| 90 | + |
| 91 | +The original staging package was `http-proxy-lantern 0.0.0+22da31e9`, binary |
| 92 | +SHA256 `1c1ac5b4fb3eb4ed88365c20cd6ec111288d9a267fd8391107c248f9c48f9132`. |
| 93 | +The 7.9.5 baseline passed HTTPS/egress/repeated requests, but plain HTTP |
| 94 | +returned 403 (`requested local address example.com:80 ()`). The candidate |
| 95 | +returns 200 because it includes the origin-form Host handling fix already |
| 96 | +present on main. This was recorded separately from the trust/ticket changes. |
| 97 | + |
| 98 | +## Repetition after the actual lantern-cloud staging deployment |
| 99 | + |
| 100 | +Lantern-cloud was subsequently merged into staging at |
| 101 | +[`57280b004ea01d4e5394e46aa7cab9d30811034c`](https://github.com/getlantern/lantern-cloud/commit/57280b004ea01d4e5394e46aa7cab9d30811034c). |
| 102 | +The new base and deploy tooling were built first; Vault, Ops, API, Unleash, |
| 103 | +backoffice, netstated and update-server were deployed successfully. |
| 104 | +[Cloud validation and infrastructure limitations in getlantern/lantern-cloud#3665](https://github.com/getlantern/lantern-cloud/pull/3665). |
| 105 | + |
| 106 | +After checking the running API's revision, both unchanged clients repeated |
| 107 | +all three positive cases in the table above. This time the bootstrap ticket |
| 108 | +and client configuration came from the **deployed API's route endpoint**, with |
| 109 | +`connect_config=true&legacy_connect_config=true`, rather than an in-process |
| 110 | +fixture generator. The normal Shadowsocks config was used unchanged. For TLS, |
| 111 | +the existing IPv6 staging route `0a49204c-4605-4aa5-bcf0-7c480478ec46` was |
| 112 | +temporarily mirrored onto the IPv4 canary using its stored certificate, |
| 113 | +authentication token and ticket keys. Only the API-returned endpoint addresses |
| 114 | +were rewritten. The API generated the 121-byte bootstrap ticket; no local |
| 115 | +helper minted it. The source route and database were not modified. |
| 116 | + |
| 117 | +Both releases passed HTTP 200, HTTPS 200, staging egress and five subsequent |
| 118 | +requests for fresh and cached TLS sessions, including proxy restarts. A new |
| 119 | +server-side capture again matched each exact 123-byte server-issued ticket |
| 120 | +to the client cache and a later ClientHello. Both releases used abbreviated |
| 121 | +TLS 1.2 handshakes and carried application records in both directions. |
| 122 | +The [new sanitized assertions](test-results/emudhra-staging-live-api-resumption.json) |
| 123 | +record those results. Capture SHA256: |
| 124 | +`5a0be0fb1937660825f8e478eea6a049b89dc688cef58e4d91199d9d290ee3c3`. |
| 125 | +A one-bit mutation of the live API ticket was rejected with no egress response. |
| 126 | +The normal Shadowsocks tests also passed for both releases afterward. |
| 127 | + |
| 128 | +The temporary TLS fixtures and remote capture were removed and the rollback |
| 129 | +timer stopped. The candidate is back on the original normal route config; |
| 130 | +its running executable still matches the candidate SHA256 above. |
| 131 | + |
| 132 | +## Staging deployment and rollback |
| 133 | + |
| 134 | +The installed package and original `/etc/http-proxy/config.ini` were preserved. |
| 135 | +Only `http-proxy.service` was restarted. The candidate is selected through |
| 136 | +`/etc/systemd/system/http-proxy.service.d/99-emudhra-canary.conf`; the temporary |
| 137 | +TLS fixture is replaced by the normal route configuration after testing. |
| 138 | +A timed rollback protected the test window. |
| 139 | + |
| 140 | +To restore the original staging executable and restart that service: |
| 141 | + |
| 142 | +```bash |
| 143 | +timeout 120 mise -E staging x -- bin/lc routes ssh \ |
| 144 | + 3e9aa468-47ca-4fc3-b61e-4049a3f92e34 \ |
| 145 | + sh /tmp/emudhra-staging-canary.sh restore |
| 146 | +``` |
| 147 | + |
| 148 | +Run this from a lantern-cloud checkout. The restore script removes the canary |
| 149 | +override, restarts the service, and verifies that the installed binary and |
| 150 | +normal config match their saved originals. For production, use the normal |
| 151 | +reviewed release/package rollout, not this temporary override. |
| 152 | + |
| 153 | +Coverage is Linux amd64 for these two releases, TLS 1.2, and the two listed |
| 154 | +transports. Other operating systems, architectures, transports, sustained |
| 155 | +load, and a full installed-package/container rollout remain release gates. |
0 commit comments