dqlite
dqlite copied to clipboard
IPv6 support
Trying to bind to [::1]:9000
or [fdaa:0:1e1d:b8b:ce2:0:a:2]:9000
results in:
create node: failed to set bind address "[fdaa:0:1e1d:b8b:ce2:0:a:2]:9000": 2
It seems only IPv4 addresses are parsed:
rv = uv_ip4_addr(host, atoi(port), addr)
Otherwise everything seems IPv6 ready. I might try myself, but my C is a little rusty. Any plans to support IPv6? I'd appreciate it very much and could help with testing.
Trying to join with cluster in dqlite-go to a server listening on 0.0.0.0:9000
results in:
server [fdaa:0:1e1d:b8b:67:77ee:6577:2]:9000: dial: dial tcp [fdaa:0:1e1d:b8b:67:77ee:6577:2]:9000: connect: connection refused
It'd certainly be nice to see this fixed so that folks who don't provide their own transport for dqlite can still have it run properly on IPv6.
For LXD, we've been running fine in IPv6 environments for a long time (I run IPv6-only networks myself so I'd notice pretty quickly if we mess up), but LXD doesn't use dqlite's networking logic, instead providing its own transport (proxying dqlite traffic over LXD's own HTTPS API using websockets).
I've been looking into implementing this. It seems that dqlite has address parsing logic in two different places:
https://github.com/canonical/dqlite/blob/bbc45f801399ed4c12d4dd75d26e4220ea850cae/src/server.c#L202-L238
https://github.com/canonical/dqlite/blob/bbc45f801399ed4c12d4dd75d26e4220ea850cae/src/transport.c#L211-L234
And raft has its own address parsing code in the built-in TCP transport implementation (which dqlite doesn't use afaict):
https://github.com/canonical/raft/blob/4b641dedcdd8f42e68026d2b9b7d344b74eb8ea1/src/uv_ip.c#L10-L35
I'd love to deduplicate this stuff as part of implementing IPv6 support for dqlite.
Makes sense. Perhaps adding something like:
/* Binary structure holding either an IPv4 or an IPv6 address. */
struct raft_uv_tcp_addr {
union {
struct sockaddr_in;
struct sockaddr_in6;
}
}
/* Parse an @address string of the form IP:PORT and populate @addr accordingly. */
RAFT_API int raft_uv_tcp_parse_address(const char *address, struct raft_uv_tcp_addr *addr)
to raft/uv.h
. Or any similar variation that achieves the goal of supporting both IPv4 and IPv6 transparently in a single function.
Yeah, that would be ideal if we don't mind the additional API surface in raft. We'd also have to decide which layer should implement support for Unix sockets and the @...
notation that dqlite uses.
Yeah, that would be ideal if we don't mind the additional API surface in raft. We'd also have to decide which layer should implement support for Unix sockets and the
@...
notation that dqlite uses.
Right, avoiding the additional API surface was the motivation for the duplicate code. But I guess it's okay to add this sort of helpers.
By the way, IPv6 support should already be working just fine if you use dqlite via go-dqlite (which is effectively the only way to use it at the moment) AND you configure go-dqlite to use TLS, which is what people should generally do, since there's no particular reason not to use TLS.
@patte out of curiosity, how did you hit this issue? were you using dqlite directly without the go-dqlite?
Since we don't have client drivers for languages other than Go, using dqlite directly seems only useful as playground.
Thanks everyone for resolving this issue.
@freeekanayaka No I was using it with go-dqlite. I wanted to deploy an app to fly.io, which is IPv6-only for internal traffic. Everything worked at my localhost with v4. But just using the basic example with v6 Adresses was enough raise the errors.
Trying to join with cluster in dqlite-go to a server listening on
0.0.0.0:9000
results in:server [fdaa:0:1e1d:b8b:67:77ee:6577:2]:9000: dial: dial tcp [fdaa:0:1e1d:b8b:67:77ee:6577:2]:9000: connect: connection refused
Thanks everyone for resolving this issue.
@freeekanayaka No I was using it with go-dqlite. I wanted to deploy an app to fly.io, which is IPv6-only for internal traffic. Everything worked at my localhost with v4. But just using the basic example with v6 Adresses was enough raise the errors.
Trying to join with cluster in dqlite-go to a server listening on
0.0.0.0:9000
results in:server [fdaa:0:1e1d:b8b:67:77ee:6577:2]:9000: dial: dial tcp [fdaa:0:1e1d:b8b:67:77ee:6577:2]:9000: connect: connection refused
Thanks for the clarification.
Ok, using the TLS support in go-dqlite should have made it work. Of course now it should also work without TLS.