ipv6-bridge 1.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,159 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.1.1] - 2026-09-13
9
+
10
+ A final-audit pass over 2.1.0's embeddable API, before its first npm publish,
11
+ found one critical bug and one contract violation. Neither shipped to npm.
12
+
13
+ ### Fixed
14
+
15
+ - **A malformed TLS option crashed the host process.** `BridgeHttpsAgent` and
16
+ `createConnector()` called `tls.connect()` in a way that let a synchronous
17
+ throw (from an invalid `secureProtocol`, cipher list, or similar) escape as
18
+ an uncaught exception rather than a request error — on the very first
19
+ request, before any application-level error handler had a chance to run.
20
+ Reproduced directly: a bad `secureProtocol` value took down the entire
21
+ process with no `error` event and no rejected promise to catch. Both now
22
+ route connection setup through a single guarded path that always reports
23
+ failure through the callback.
24
+ - `createLookup()` silently ignored the documented `dns.lookup(hostname,
25
+ family, callback)` integer-shorthand form, since `(4).family` is
26
+ `undefined`. It now handles that form (and a `null` options argument), and
27
+ errors with `EAI_ADDRFAMILY` rather than silently returning a different
28
+ family when the requested one isn't available.
29
+
30
+ ## [2.1.0] - 2026-09-13
31
+
32
+ ### Added
33
+
34
+ - **Embedded API.** The bridge can now be used from inside an application, with
35
+ no proxy and no system configuration. Previously the only way to use it was to
36
+ run a proxy and point clients at it, which is impractical for a deployed
37
+ service.
38
+ - `createAgent()` and `createHttpsAgent()` — drop-in agents for `http`/`https`
39
+ and any client that accepts one (axios, got, node-fetch). Connections try
40
+ native IPv6, then NAT64 synthesis, then direct IPv4, with keep-alive pooling.
41
+ TLS certificates are validated against the requested hostname rather than
42
+ the synthesized address the connection travelled over.
43
+ - `createAgents()` — both protocols at once.
44
+ - `createLookup()` — a `dns.lookup`-compatible function for anything taking a
45
+ `lookup` option, including `net.connect` and many database drivers.
46
+ - `createConnector()` — an undici connector, so Node's global `fetch` can use
47
+ the bridge. undici remains outside this package's dependencies.
48
+ - `resolve()` — report which route would be taken, without connecting.
49
+ - `getStats()` — the data behind `/status`, available to embedded users so a
50
+ service can alert when translation stops happening.
51
+ - A test fixture certificate covering `localhost` and `127.0.0.1`, so TLS
52
+ behaviour is verified locally without network access.
53
+
54
+ ## [2.0.0] - 2026-09-13
55
+
56
+ A correctness, security and production-readiness release. An audit found that
57
+ the plain-HTTP proxy path never worked with real proxy clients, that the
58
+ listener was an open relay by default, and that failed translation was
59
+ indistinguishable from success. All of that is fixed here.
60
+
61
+ ### Fixed
62
+
63
+ - **Plain HTTP proxying never worked.** Request targets were built by
64
+ concatenating the `Host` header with `req.url`. Real proxy clients send
65
+ absolute-form targets (RFC 7230 section 5.3.2), so every request produced a
66
+ malformed URL and returned `500`. Absolute-form is now parsed directly, with
67
+ origin-form accepted as a fallback.
68
+ - **Proxy credentials leaked to origin servers.** `Proxy-Authorization` and
69
+ other hop-by-hop headers were forwarded verbatim. They are now stripped in
70
+ both directions per RFC 7230 section 6.1, including headers named by the
71
+ `Connection` header.
72
+ - **CONNECT to IPv6 literals was broken.** `[::1]:443` was split on every colon,
73
+ yielding the hostname `[`, and the client hung with no response. Authority
74
+ parsing now handles bracketed literals, bare literals and `host:port`.
75
+ - **Detection reported a false positive on dual-stack networks.** `needsBridge()`
76
+ never checked whether IPv4 already worked, so the bridge activated on healthy
77
+ networks where it could only cause harm. IPv4 reachability is now the first check.
78
+ - **DNS resolution failed on DoH-only and split-DNS hosts.** Resolution used
79
+ `dns.resolve*`, which bypasses the system resolver, hosts file and
80
+ DNS-over-HTTPS configuration. It now uses `dns.lookup`.
81
+ - **Failed translation was silent.** A DNS64 failure fell through to a direct
82
+ IPv4 connection with no log, making a non-functioning bridge look like a
83
+ working one. Fallbacks now log a warning and are counted separately.
84
+ - **`stop()` never resolved with an open CONNECT tunnel**, hanging any test
85
+ suite that used the programmatic API. Live sockets are now torn down.
86
+ - **Concurrent `start()` calls leaked an uncloseable server.** The guard ran
87
+ before an `await`, so both callers passed it. The second call now rejects.
88
+ - **Every DNS resolution leaked a 5-second timer**, keeping the event loop alive
89
+ long after the work finished. The timeout is now cleared.
90
+ - **CONNECT failures closed the socket silently**; they now return `502` or `504`.
91
+ - Path traversal in the demo application allowed reading files outside its
92
+ public directory, and its "bridge running" indicator reported the status of an
93
+ unrelated website. Both are fixed, and the demo now binds to loopback.
94
+
95
+ ### Added
96
+
97
+ - **Full RFC 6052 prefix support** — `/32`, `/40`, `/48`, `/56`, `/64` and `/96`,
98
+ validated against the official section 2.4 test vectors, including the
99
+ reserved `u` octet at bits 64–71.
100
+ - **NAT64 prefix discovery (RFC 7050)** — the bridge resolves `ipv4only.arpa` at
101
+ startup to learn the prefix the network actually uses, instead of assuming the
102
+ well-known one.
103
+ - **SOCKS5 listener (RFC 1928/1929)** — carries any TCP protocol, so ssh, git and
104
+ database clients can use the same translation. Enable with `IPV6_BRIDGE_SOCKS_PORT`.
105
+ - **`ipv6-bridge doctor`** — diagnoses resolvers, connectivity, NAT64 availability,
106
+ prefix mismatches and listener exposure, and explains what each result means.
107
+ - **Operational endpoints** — `/healthz`, `/status`, `/metrics` (Prometheus) and
108
+ `/proxy.pac`. `/status` reports a `translationRate` so operators can confirm
109
+ the bridge is actually translating.
110
+ - **Connection failover** — candidate addresses are tried in preference order
111
+ (native IPv6, then NAT64, then direct IPv4) instead of giving up on the first.
112
+ - **DNS caching** with a bounded LRU and TTL expiry.
113
+ - **Keep-alive connection pooling** for upstream HTTP requests.
114
+ - **Authentication and access control** — `IPV6_BRIDGE_AUTH` for Basic
115
+ credentials and `IPV6_BRIDGE_ALLOW` for a client CIDR allowlist, enforced on
116
+ the HTTP, CONNECT and SOCKS5 paths.
117
+ - **Bypass rules** — `IPV6_BRIDGE_BYPASS` routes matching hosts directly.
118
+ - Continuous integration across Node 18/20/22 on Linux, Windows and macOS.
119
+
120
+ ### Changed
121
+
122
+ - **The proxy now binds to `127.0.0.1` by default** instead of all interfaces.
123
+ This is a breaking change: previously any host on the same network could relay
124
+ traffic through it without authentication. Set `IPV6_BRIDGE_HOST` to expose it
125
+ deliberately, and pair that with `IPV6_BRIDGE_AUTH` or `IPV6_BRIDGE_ALLOW`.
126
+ - Non-global IPv4 addresses are no longer synthesized with the well-known prefix
127
+ (RFC 6052 section 3.1); they are reached directly over IPv4 instead. This makes
128
+ targets such as `127.0.0.1` and `192.168.x.x` work through the proxy.
129
+ - Synthesized addresses are emitted in RFC 5952 canonical form, so
130
+ `64:ff9b::0808:0808` is now written `64:ff9b::808:808`. The address is unchanged.
131
+ - Configuration is validated at startup; an invalid prefix, port or timeout fails
132
+ immediately with an explanatory message.
133
+ - `start()` accepts an options object (`host`, `force`, `discoverPrefix`, `socksPort`).
134
+ - The logger gained a `silent` level, and `index.js` no longer writes directly to
135
+ the console, so library consumers can suppress output.
136
+ - Detection endpoints are configurable via `IPV4_TEST_URL`, `IPV6_TEST_URL` and
137
+ `NAT64_TEST_HOST`, and accept any 2xx/3xx response as reachable.
138
+ - `npm test` no longer relies on shell glob expansion, so it works on Windows.
139
+ - Tests run entirely against local servers and need no network access.
140
+
141
+ ### Removed
142
+
143
+ - `.npmignore`, which was redundant with the `files` field in `package.json` and
144
+ listed paths that no longer existed.
145
+
146
+ ## [1.0.0] - 2026-01-31
147
+
148
+ ### Added
149
+
150
+ - DNS64 resolver for IPv4-to-IPv6 address synthesis (RFC 6052)
151
+ - HTTP/HTTPS proxy with NAT64 routing (RFC 6146)
152
+ - Auto-detection of IPv6-only networks (`needsBridge()`)
153
+ - IP version detection (`detectIPVersion()`)
154
+ - Command-line interface (`npx ipv6-bridge start`)
155
+ - Programmatic API (`start()` / `stop()`)
156
+ - Environment variable configuration (`IPV6_BRIDGE_PORT`, `FORCE_BRIDGE`, `NAT64_PREFIX`)
157
+ - Interactive demo application with diagnostics
158
+ - Dual-stack test server for manual testing
159
+ - Comprehensive test suite
@@ -0,0 +1,88 @@
1
+ # Contributing
2
+
3
+ Thank you for your interest in contributing to IPv6 Bridge!
4
+
5
+ ## Getting Started
6
+
7
+ 1. Fork and clone the repository.
8
+ 2. Install dependencies: `npm install`
9
+ 3. Run the tests: `npm test`
10
+
11
+ ## Development Workflow
12
+
13
+ 1. Create a feature branch from `main`.
14
+ 2. Make your changes with clear, focused commits.
15
+ 3. Add or update tests for any new functionality.
16
+ 4. Ensure all tests pass: `npm test`
17
+ 5. Submit a pull request with a clear description of the change.
18
+
19
+ ## Code Style
20
+
21
+ - **Indentation**: 2 spaces.
22
+ - **Semicolons**: Required.
23
+ - **Quotes**: Single quotes for strings.
24
+ - **Module system**: CommonJS (`require`/`module.exports`).
25
+ - **No external dependencies**: The core library must remain dependency-free. Development dependencies (linting, testing) are fine.
26
+
27
+ ## Project Structure
28
+
29
+ ```
30
+ src/ Core library (zero dependencies)
31
+ tests/ Test suite (Node.js built-in test runner)
32
+ demo-app/ Interactive demo application
33
+ test-server/ Dual-stack test server for manual testing
34
+ examples/ Usage examples
35
+ docs/ Extended documentation
36
+ ```
37
+
38
+ ## Testing
39
+
40
+ We use the Node.js built-in test runner:
41
+
42
+ ```bash
43
+ npm test
44
+ ```
45
+
46
+ When adding a new feature or fixing a bug:
47
+
48
+ - Add tests that cover the new behavior.
49
+ - Tests must be deterministic and must not depend on network connectivity.
50
+ Spin up a local server on an ephemeral port instead — `tests/helpers.js` has
51
+ helpers for HTTP and TCP servers, raw requests and module reloading.
52
+ - Prefer a test that exercises the real path end to end over one that asserts a
53
+ function exists. The proxy shipped a release where every plain-HTTP request
54
+ returned `500` while the entire suite passed, because no test ever sent one.
55
+ - Configuration is captured when a module loads, so a test that changes
56
+ environment variables must call `reloadModules()` before requiring anything.
57
+
58
+ ### Verifying protocol behavior
59
+
60
+ The proxy is easiest to verify with a real client:
61
+
62
+ ```bash
63
+ FORCE_BRIDGE=1 node src/cli.js start &
64
+ curl -x http://127.0.0.1:8080 http://example.com/ # plain HTTP
65
+ curl -x http://127.0.0.1:8080 https://example.com/ # CONNECT tunnel
66
+ curl --socks5-hostname 127.0.0.1:1080 https://example.com/
67
+ curl http://127.0.0.1:8080/status
68
+ ```
69
+
70
+ Note that proxy clients send *absolute-form* request targets, which is different
71
+ from how a normal HTTP server is addressed. Reading the code is not enough to
72
+ confirm proxy behavior — drive it with a client.
73
+
74
+ ## Standards
75
+
76
+ Changes to address handling should cite the relevant RFC and, where the RFC
77
+ provides test vectors, use them. `tests/ipv6.test.js` checks the RFC 6052
78
+ section 2.4 vectors directly.
79
+
80
+ ## Reporting Issues
81
+
82
+ - Search existing issues before creating a new one.
83
+ - Include your Node.js version, operating system, and steps to reproduce.
84
+ - If relevant, include the output of `npx ipv6-bridge --help`.
85
+
86
+ ## License
87
+
88
+ By contributing, you agree that your contributions will be licensed under the MIT License.