mirror of
https://github.com/transmission/transmission
synced 2025-02-20 21:26:53 +00:00
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:
parent
a0305a3a12
commit
cb17ea4914
4 changed files with 45 additions and 11 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue