Fix IPv6 announce socket binding interface. (#3692)

When Transmission listens on both IPv4 and IPv6 interfaces IPv4 listen address
is always passed to CURL's CURLOPT_INTERFACE. In general it stays unnoticed but
if user has multiple IPv6 addresses configured on his system random (first?)
IPv6 address is used. It happens because passed value to CURLOPT_INTERFACE
is not correct -- IPv6 expected but IPv4 is passed.
This commit is contained in:
Viacheslav Chimishuk 2022-08-22 02:37:38 +03:00 committed by GitHub
parent a0305a3a12
commit cb17ea4914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 11 deletions

View File

@ -145,15 +145,23 @@ std::optional<std::string_view> tr_session::WebMediator::userAgent() const
return TR_NAME "/" SHORT_VERSION_STRING;
}
std::optional<std::string> tr_session::WebMediator::publicAddress() const
std::optional<std::string> tr_session::WebMediator::publicAddressV4() const
{
for (auto const type : { TR_AF_INET, TR_AF_INET6 })
auto const [addr, is_default_value] = session_->publicAddress(TR_AF_INET);
if (!is_default_value)
{
auto const [addr, is_default_value] = session_->publicAddress(type);
if (!is_default_value)
{
return addr.readable();
}
return addr.readable();
}
return std::nullopt;
}
std::optional<std::string> tr_session::WebMediator::publicAddressV6() const
{
auto const [addr, is_default_value] = session_->publicAddress(TR_AF_INET6);
if (!is_default_value)
{
return addr.readable();
}
return std::nullopt;

View File

@ -825,7 +825,8 @@ private:
~WebMediator() override = default;
[[nodiscard]] std::optional<std::string> cookieFile() const override;
[[nodiscard]] std::optional<std::string> publicAddress() const override;
[[nodiscard]] std::optional<std::string> publicAddressV4() const override;
[[nodiscard]] std::optional<std::string> publicAddressV6() const override;
[[nodiscard]] std::optional<std::string_view> userAgent() const override;
[[nodiscard]] unsigned int clamp(int torrent_id, unsigned int byte_count) const override;
void notifyBandwidthConsumed(int torrent_id, size_t byte_count) override;

View File

@ -249,6 +249,25 @@ public:
}
}
[[nodiscard]] auto publicAddress() const
{
switch (options.ip_proto)
{
case FetchOptions::IPProtocol::V4:
return impl.mediator.publicAddressV4();
case FetchOptions::IPProtocol::V6:
return impl.mediator.publicAddressV6();
default:
auto ip = impl.mediator.publicAddressV4();
if (ip == std::nullopt)
{
ip = impl.mediator.publicAddressV6();
}
return ip;
}
}
void done()
{
if (options.done_func == nullptr)
@ -394,7 +413,7 @@ public:
(void)curl_easy_setopt(e, CURLOPT_WRITEFUNCTION, onDataReceived);
(void)curl_easy_setopt(e, CURLOPT_MAXREDIRS, MaxRedirects);
if (auto const addrstr = impl->mediator.publicAddress(); addrstr)
if (auto const addrstr = task->publicAddress(); addrstr)
{
(void)curl_easy_setopt(e, CURLOPT_INTERFACE, addrstr->c_str());
}

View File

@ -119,8 +119,14 @@ public:
return std::nullopt;
}
// Return the preferred user public address string, or nullopt to not use one
[[nodiscard]] virtual std::optional<std::string> publicAddress() const
// Return IPv4 user public address string, or nullopt to not use one
[[nodiscard]] virtual std::optional<std::string> publicAddressV4() const
{
return std::nullopt;
}
// Return IPv6 user public address string, or nullopt to not use one
[[nodiscard]] virtual std::optional<std::string> publicAddressV6() const
{
return std::nullopt;
}