Context
Surfaced in review of PR #397. Both inbound-bind paths format the listen address with naive string interpolation and no IPv6 bracketing:
ServerConfig::to_socket_address() (packages/cipherstash-proxy/src/config/server.rs) — format!("{}:{}", self.host, self.port), used by the primary bind / retry path.
- The random-port fallback in
connect::bind_with_retry (packages/cipherstash-proxy/src/connect/mod.rs) — format!("{}:0", server.host).
If the configured listen host is an IPv6 literal (e.g. ::1 or fe80::1), the result is an unparseable address like ::1:6432 / ::1:0 rather than the required [::1]:6432. So an IPv6 listen host fails to bind.
This is a pre-existing limitation (the primary path has always done this); PR #397's fallback just inherits the same pattern. The same database-side helper (DatabaseConfig::to_socket_address) has the same shape and may warrant the same treatment.
Proposed fix
Build a real SocketAddr (resolve/parse host + port) or bracket IPv6 literals before combining with the port, in one shared helper used by both the primary and fallback bind paths (and consider the database helper).
Acceptance criteria
- A configured IPv6 listen host binds successfully on both the primary and random-port-fallback paths.
- IPv4 / hostname behaviour is unchanged.
- Regression coverage for an IPv6 listen address.
Context
Surfaced in review of PR #397. Both inbound-bind paths format the listen address with naive string interpolation and no IPv6 bracketing:
ServerConfig::to_socket_address()(packages/cipherstash-proxy/src/config/server.rs) —format!("{}:{}", self.host, self.port), used by the primary bind / retry path.connect::bind_with_retry(packages/cipherstash-proxy/src/connect/mod.rs) —format!("{}:0", server.host).If the configured listen host is an IPv6 literal (e.g.
::1orfe80::1), the result is an unparseable address like::1:6432/::1:0rather than the required[::1]:6432. So an IPv6 listen host fails to bind.This is a pre-existing limitation (the primary path has always done this); PR #397's fallback just inherits the same pattern. The same database-side helper (
DatabaseConfig::to_socket_address) has the same shape and may warrant the same treatment.Proposed fix
Build a real
SocketAddr(resolve/parse host + port) or bracket IPv6 literals before combining with the port, in one shared helper used by both the primary and fallback bind paths (and consider the database helper).Acceptance criteria