From cffe85e6c50a76d7c64122d8b1423fe2d2c55e29 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 30 Aug 2023 23:41:36 +0100 Subject: [PATCH] fshttp: fix --bind 0.0.0.0 allowing IPv6 and --bind ::0 allowing IPv4 Due to a bug/misfeature in the go standard library as described here: https://github.com/golang/go/issues/48723 the go standard library binds to both IPv4 and IPv6 when passed 0.0.0.0 or ::0. This patch detects the bind address and forces the correct IP protocol. Fixes #6124 Fixes #6244 See: https://forum.rclone.org/t/issues-with-bind-0-0-0-0-and-onedrive-getting-etag-mismatch-when-using-ipv6/41379/ --- docs/content/docs.md | 3 +++ fs/fshttp/dialer.go | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/docs/content/docs.md b/docs/content/docs.md index c229bef19..a520424e0 100644 --- a/docs/content/docs.md +++ b/docs/content/docs.md @@ -641,6 +641,9 @@ IPv4 address (1.2.3.4), an IPv6 address (1234::789A) or host name. If the host name doesn't resolve or resolves to more than one IP address it will give an error. +You can use `--bind 0.0.0.0` to force rclone to use IPv4 addresses and +`--bind ::0` to force rclone to use IPv6 addresses. + ### --bwlimit=BANDWIDTH_SPEC ### This option controls the bandwidth limit. For example diff --git a/fs/fshttp/dialer.go b/fs/fshttp/dialer.go index adeece185..a41b478b8 100644 --- a/fs/fshttp/dialer.go +++ b/fs/fshttp/dialer.go @@ -52,6 +52,17 @@ var warnDSCPFail, warnDSCPWindows sync.Once // DialContext connects to the network address using the provided context. func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + // If local address is 0.0.0.0 or ::0 force IPv4 or IPv6 + // This works around https://github.com/golang/go/issues/48723 + // Which means 0.0.0.0 and ::0 both bind to both IPv4 and IPv6 + if ip, ok := d.Dialer.LocalAddr.(*net.TCPAddr); ok && ip.IP.IsUnspecified() && (network == "tcp" || network == "udp") { + if ip.IP.To4() != nil { + network += "4" // IPv4 address + } else { + network += "6" // IPv6 address + } + } + c, err := d.Dialer.DialContext(ctx, network, address) if err != nil { return c, err