mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-14 19:17:51 +01:00
dns.mitm: add GetAddrInfo redir, AtmosphereReloadHostsFile, debug logging control
This commit is contained in:
parent
97aa209c43
commit
1306d03136
@ -49,6 +49,9 @@
|
||||
; whatever is specified in the user's hosts file.
|
||||
; 0 = Disabled (use hosts file contents), 1 = Enabled (use defaults and hosts file contents)
|
||||
; add_defaults_to_dns_hosts = u8!0x1
|
||||
; Controls whether dns.mitm logs to the sd card for debugging
|
||||
; 0 = Disabled, 1 = Enabled
|
||||
; enable_dns_mitm_debug_log = u8!0x0
|
||||
[hbloader]
|
||||
; Controls the size of the homebrew heap when running as applet.
|
||||
; If set to zero, all available applet memory is used as heap.
|
||||
|
@ -18,4 +18,5 @@
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stratosphere/socket/socket_types.hpp>
|
||||
#include <stratosphere/socket/socket_errno.hpp>
|
||||
#include <stratosphere/socket/socket_api.hpp>
|
||||
|
@ -16,9 +16,13 @@
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/socket/socket_types.hpp>
|
||||
#include <stratosphere/socket/socket_errno.hpp>
|
||||
|
||||
namespace ams::socket {
|
||||
|
||||
Errno GetLastError();
|
||||
void SetLastError(Errno err);
|
||||
|
||||
u32 InetHtonl(u32 host);
|
||||
u16 InetHtons(u16 host);
|
||||
u32 InetNtohl(u32 net);
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::socket {
|
||||
|
||||
enum class Errno : u32 {
|
||||
ESuccess = 0,
|
||||
/* ... */
|
||||
ENoSpc = 28,
|
||||
/* ... */
|
||||
};
|
||||
|
||||
enum class HErrno : s32 {
|
||||
Netdb_Internal = -1,
|
||||
Netdb_Success = 0,
|
||||
Host_Not_Found = 1,
|
||||
Try_Again = 2,
|
||||
No_Recovery = 3,
|
||||
No_Data = 4,
|
||||
|
||||
No_Address = No_Data,
|
||||
};
|
||||
|
||||
enum class AiErrno : u32 {
|
||||
EAi_Success = 0,
|
||||
/* ... */
|
||||
};
|
||||
|
||||
constexpr inline bool operator!(Errno e) { return e == Errno::ESuccess; }
|
||||
constexpr inline bool operator!(HErrno e) { return e == HErrno::Netdb_Success; }
|
||||
constexpr inline bool operator!(AiErrno e) { return e == AiErrno::EAi_Success; }
|
||||
|
||||
}
|
@ -34,6 +34,31 @@ namespace ams::socket {
|
||||
constexpr inline InAddrT InAddr_None = EncodeInAddr<255, 255, 255, 255>;
|
||||
constexpr inline InAddrT InAddr_Loopback = EncodeInAddr<127, 0, 0, 1>;
|
||||
|
||||
enum class Protocol : s32 {
|
||||
IpProto_Ip = 0,
|
||||
IpProto_Icmp = 1,
|
||||
|
||||
IpProto_Tcp = 6,
|
||||
|
||||
IpProto_Udp = 17,
|
||||
|
||||
IpProto_UdpLite = 136,
|
||||
|
||||
IpProto_Raw = 255,
|
||||
|
||||
IpProto_Max = 256,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
Sock_Default = 0,
|
||||
Sock_Stream = 1,
|
||||
Sock_Dgram = 2,
|
||||
Sock_Raw = 3,
|
||||
Sock_SeqPacket = 5,
|
||||
|
||||
Sock_NonBlock = 0x20000000,
|
||||
};
|
||||
|
||||
enum class Family : u8 {
|
||||
Af_Unspec = 0,
|
||||
Pf_Unspec = Af_Unspec,
|
||||
@ -66,4 +91,54 @@ namespace ams::socket {
|
||||
InAddrT s_addr;
|
||||
};
|
||||
|
||||
enum class AddrInfoFlag : u32 {
|
||||
Ai_None = (0 << 0),
|
||||
Ai_Passive = (1 << 0),
|
||||
Ai_CanonName = (1 << 1),
|
||||
Ai_NumericHost = (1 << 2),
|
||||
Ai_NumericServ = (1 << 3),
|
||||
|
||||
Ai_AddrConfig = (1 << 10),
|
||||
};
|
||||
|
||||
struct SockAddr {
|
||||
u8 sa_len;
|
||||
Family sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
struct SockAddrIn {
|
||||
u8 sin_len;
|
||||
Family sin_family;
|
||||
InPortT sin_port;
|
||||
InAddr sin_addr;
|
||||
u8 sin_zero[8];
|
||||
};
|
||||
static_assert(sizeof(SockAddr) == sizeof(SockAddrIn));
|
||||
|
||||
struct AddrInfo {
|
||||
AddrInfoFlag ai_flags;
|
||||
Family ai_family;
|
||||
Type ai_socktype;
|
||||
Protocol ai_protocol;
|
||||
SockLenT ai_addrlen;
|
||||
SockAddr *ai_addr;
|
||||
char *ai_canonname;
|
||||
AddrInfo *ai_next;
|
||||
};
|
||||
|
||||
#define AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(__ENUM__) \
|
||||
constexpr inline __ENUM__ operator | (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) | static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \
|
||||
constexpr inline __ENUM__ operator |=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs | rhs; } \
|
||||
constexpr inline __ENUM__ operator & (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) & static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \
|
||||
constexpr inline __ENUM__ operator &=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs & rhs; } \
|
||||
constexpr inline __ENUM__ operator ^ (__ENUM__ lhs, __ENUM__ rhs) { return static_cast<__ENUM__>(static_cast<std::underlying_type_t<__ENUM__>>(lhs) ^ static_cast<std::underlying_type_t<__ENUM__>>(rhs)); } \
|
||||
constexpr inline __ENUM__ operator ^=(__ENUM__ &lhs, __ENUM__ rhs) { return lhs = lhs ^ rhs; } \
|
||||
constexpr inline __ENUM__ operator ~ (__ENUM__ e) { return static_cast<__ENUM__>(~static_cast<std::underlying_type_t<__ENUM__>>(e)); }
|
||||
|
||||
AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(Type)
|
||||
AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS(AddrInfoFlag)
|
||||
|
||||
#undef AMS_SOCKET_IMPL_DEFINE_ENUM_OPERATORS
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,9 @@
|
||||
|
||||
namespace ams::socket::impl {
|
||||
|
||||
Errno GetLastError();
|
||||
void SetLastError(Errno err);
|
||||
|
||||
u32 InetHtonl(u32 host);
|
||||
u16 InetHtons(u16 host);
|
||||
u32 InetNtohl(u32 net);
|
||||
|
@ -38,6 +38,16 @@ namespace ams::socket::impl {
|
||||
return ams::Free(ptr);
|
||||
}
|
||||
|
||||
Errno GetLastError() {
|
||||
/* TODO: check that client library is initialized. */
|
||||
return static_cast<Errno>(errno);
|
||||
}
|
||||
|
||||
void SetLastError(Errno err) {
|
||||
/* TODO: check that client library is initialized. */
|
||||
errno = static_cast<int>(err);
|
||||
}
|
||||
|
||||
u32 InetHtonl(u32 host) {
|
||||
if constexpr (util::IsBigEndian()) {
|
||||
return host;
|
||||
|
@ -18,6 +18,14 @@
|
||||
|
||||
namespace ams::socket {
|
||||
|
||||
Errno GetLastError() {
|
||||
return impl::GetLastError();
|
||||
}
|
||||
|
||||
void SetLastError(Errno err) {
|
||||
return impl::SetLastError(err);
|
||||
}
|
||||
|
||||
u32 InetHtonl(u32 host) {
|
||||
return impl::InetHtonl(host);
|
||||
}
|
||||
|
@ -19,28 +19,36 @@
|
||||
|
||||
namespace ams::mitm::socket::resolver {
|
||||
|
||||
#if 1
|
||||
|
||||
namespace {
|
||||
|
||||
::FsFile g_log_file;
|
||||
s64 g_log_ofs;
|
||||
constinit os::SdkMutex g_log_mutex;
|
||||
constinit bool g_log_enabled;
|
||||
|
||||
os::SdkMutex g_log_mutex;
|
||||
constinit ::FsFile g_log_file;
|
||||
constinit s64 g_log_ofs;
|
||||
|
||||
char g_log_buf[0x400];
|
||||
|
||||
constinit char g_log_buf[0x400];
|
||||
|
||||
}
|
||||
|
||||
void InitializeDebug() {
|
||||
/* Create the log file. */
|
||||
mitm::fs::CreateAtmosphereSdFile("dns_log.txt", 0, ams::fs::CreateOption_None);
|
||||
void InitializeDebug(bool enable_log) {
|
||||
{
|
||||
std::scoped_lock lk(g_log_mutex);
|
||||
|
||||
/* Open the log file. */
|
||||
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(g_log_file), "dns_log.txt", ams::fs::OpenMode_ReadWrite | ams::fs::OpenMode_AllowAppend));
|
||||
g_log_enabled = enable_log;
|
||||
|
||||
/* Get the current log offset. */
|
||||
R_ABORT_UNLESS(::fsFileGetSize(std::addressof(g_log_file), std::addressof(g_log_ofs)));
|
||||
if (g_log_enabled) {
|
||||
/* Create the log file. */
|
||||
mitm::fs::CreateAtmosphereSdFile("dns_log.txt", 0, ams::fs::CreateOption_None);
|
||||
|
||||
/* Open the log file. */
|
||||
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(g_log_file), "dns_log.txt", ams::fs::OpenMode_ReadWrite | ams::fs::OpenMode_AllowAppend));
|
||||
|
||||
/* Get the current log offset. */
|
||||
R_ABORT_UNLESS(::fsFileGetSize(std::addressof(g_log_file), std::addressof(g_log_ofs)));
|
||||
}
|
||||
}
|
||||
|
||||
/* Start a new log. */
|
||||
LogDebug("\n---\n");
|
||||
@ -49,28 +57,18 @@ namespace ams::mitm::socket::resolver {
|
||||
void LogDebug(const char *fmt, ...) {
|
||||
std::scoped_lock lk(g_log_mutex);
|
||||
|
||||
int len = 0;
|
||||
{
|
||||
std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
len = util::VSNPrintf(g_log_buf, sizeof(g_log_buf), fmt, vl);
|
||||
va_end(vl);
|
||||
if (g_log_enabled) {
|
||||
int len = 0;
|
||||
{
|
||||
std::va_list vl;
|
||||
va_start(vl, fmt);
|
||||
len = util::VSNPrintf(g_log_buf, sizeof(g_log_buf), fmt, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
R_ABORT_UNLESS(::fsFileWrite(std::addressof(g_log_file), g_log_ofs, g_log_buf, len, FsWriteOption_Flush));
|
||||
g_log_ofs += len;
|
||||
}
|
||||
|
||||
R_ABORT_UNLESS(::fsFileWrite(std::addressof(g_log_file), g_log_ofs, g_log_buf, len, FsWriteOption_Flush));
|
||||
g_log_ofs += len;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void InitializeDebug() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void LogDebug(const char *fmt, ...) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
namespace ams::mitm::socket::resolver {
|
||||
|
||||
void InitializeDebug();
|
||||
void InitializeDebug(bool enable_log);
|
||||
|
||||
void LogDebug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
|
@ -264,9 +264,20 @@ namespace ams::mitm::socket::resolver {
|
||||
return "/hosts/default.txt";
|
||||
}
|
||||
|
||||
bool ShouldAddDefaultResolverRedirections() {
|
||||
u8 en = 0;
|
||||
if (settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "add_defaults_to_dns_hosts") == sizeof(en)) {
|
||||
return (en != 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitializeResolverRedirections(bool add_defaults) {
|
||||
void InitializeResolverRedirections() {
|
||||
/* Get whether we should add defaults. */
|
||||
const bool add_defaults = ShouldAddDefaultResolverRedirections();
|
||||
|
||||
/* Acquire exclusive access to the map. */
|
||||
std::scoped_lock lk(g_redirection_lock);
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
namespace ams::mitm::socket::resolver {
|
||||
|
||||
void InitializeResolverRedirections(bool add_defaults);
|
||||
void InitializeResolverRedirections();
|
||||
|
||||
bool GetRedirectedHostByName(ams::socket::InAddrT *out, const char *hostname);
|
||||
|
||||
|
@ -102,9 +102,9 @@ namespace ams::mitm::socket::resolver {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShouldAddDefaultResolverRedirections() {
|
||||
bool ShouldEnableDebugLog() {
|
||||
u8 en = 0;
|
||||
if (settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "add_defaults_to_dns_hosts") == sizeof(en)) {
|
||||
if (settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "enable_dns_mitm_debug_log") == sizeof(en)) {
|
||||
return (en != 0);
|
||||
}
|
||||
return false;
|
||||
@ -122,10 +122,10 @@ namespace ams::mitm::socket::resolver {
|
||||
}
|
||||
|
||||
/* Initialize debug. */
|
||||
resolver::InitializeDebug();
|
||||
resolver::InitializeDebug(ShouldEnableDebugLog());
|
||||
|
||||
/* Initialize redirection map. */
|
||||
resolver::InitializeResolverRedirections(ShouldAddDefaultResolverRedirections());
|
||||
resolver::InitializeResolverRedirections();
|
||||
|
||||
/* Create mitm servers. */
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterMitmServer<ResolverImpl>(PortIndex_Mitm, DnsMitmServiceName)));
|
||||
|
@ -39,6 +39,51 @@ namespace ams::mitm::socket::resolver {
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t SerializeRedirectedAddrInfo(u8 * const dst, size_t dst_size, const char *hostname, ams::socket::InAddrT redirect_addr, u16 redirect_port, const struct addrinfo *hint) {
|
||||
struct addrinfo ai = {
|
||||
.ai_flags = 0,
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = 0,
|
||||
.ai_protocol = 0,
|
||||
.ai_addrlen = 0,
|
||||
.ai_canonname = nullptr,
|
||||
.ai_next = nullptr,
|
||||
};
|
||||
|
||||
if (hint != nullptr) {
|
||||
ai = *hint;
|
||||
}
|
||||
|
||||
switch (ai.ai_family) {
|
||||
case AF_UNSPEC: ai.ai_family = AF_INET; break;
|
||||
case AF_INET: ai.ai_family = AF_INET; break;
|
||||
case AF_INET6: AMS_ABORT_UNLESS("Redirected INET6 not supported"); break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
if (ai.ai_socktype == 0) {
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
}
|
||||
|
||||
if (ai.ai_protocol == 0) {
|
||||
ai.ai_protocol = IPPROTO_TCP;
|
||||
}
|
||||
|
||||
const struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = ams::socket::InetHtons(redirect_port),
|
||||
.sin_addr = { .s_addr = redirect_addr },
|
||||
.sin_zero = {},
|
||||
};
|
||||
|
||||
ai.ai_addrlen = sizeof(sin);
|
||||
ai.ai_addr = (struct sockaddr *)(std::addressof(sin));
|
||||
|
||||
const auto result = serializer::DNSSerializer::ToBuffer(dst, dst_size, ai);
|
||||
AMS_ABORT_UNLESS(result >= 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
Result ResolverImpl::GetHostByNameRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size) {
|
||||
const char *hostname = reinterpret_cast<const char *>(name.GetPointer());
|
||||
|
||||
@ -58,8 +103,36 @@ namespace ams::mitm::socket::resolver {
|
||||
}
|
||||
|
||||
Result ResolverImpl::GetAddrInfoRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size) {
|
||||
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
|
||||
|
||||
LogDebug("[%016lx]: GetAddrInfoRequest(%s, %s)\n", this->client_info.program_id.value, reinterpret_cast<const char *>(node.GetPointer()), reinterpret_cast<const char *>(srv.GetPointer()));
|
||||
return sm::mitm::ResultShouldForwardToSession();
|
||||
|
||||
ams::socket::InAddrT redirect_addr = {};
|
||||
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
u16 port = 0;
|
||||
for (const char *cur = reinterpret_cast<const char *>(srv.GetPointer()); *cur != 0; ++cur) {
|
||||
AMS_ABORT_UNLESS(std::isdigit(static_cast<unsigned char>(*cur)));
|
||||
port *= 10;
|
||||
port += *cur - '0';
|
||||
}
|
||||
|
||||
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
|
||||
const bool use_hint = serialized_hint.GetPointer() != nullptr;
|
||||
struct addrinfo hint = {};
|
||||
if (use_hint) {
|
||||
AMS_ABORT_UNLESS(serializer::DNSSerializer::FromBuffer(hint, serialized_hint.GetPointer(), serialized_hint.GetSize()) >= 0);
|
||||
}
|
||||
ON_SCOPE_EXIT { if (use_hint) { serializer::FreeAddrInfo(hint); } };
|
||||
|
||||
const auto size = SerializeRedirectedAddrInfo(out_addrinfo.GetPointer(), out_addrinfo.GetSize(), hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr);
|
||||
|
||||
*out_retval = 0;
|
||||
*out_errno = 0;
|
||||
*out_size = size;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ResolverImpl::GetHostByNameRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno) {
|
||||
@ -81,8 +154,43 @@ namespace ams::mitm::socket::resolver {
|
||||
}
|
||||
|
||||
Result ResolverImpl::GetAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno) {
|
||||
LogDebug("[%016lx]: GetAddrInfoRequestWithOptions(%s, %s)\n", this->client_info.program_id.value, reinterpret_cast<const char *>(node.GetPointer()), reinterpret_cast<const char *>(srv.GetPointer()));
|
||||
return sm::mitm::ResultShouldForwardToSession();
|
||||
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
|
||||
|
||||
LogDebug("[%016lx]: GetAddrInfoRequestWithOptions(%s, %s)\n", this->client_info.program_id.value, hostname, reinterpret_cast<const char *>(srv.GetPointer()));
|
||||
|
||||
ams::socket::InAddrT redirect_addr = {};
|
||||
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
u16 port = 0;
|
||||
for (const char *cur = reinterpret_cast<const char *>(srv.GetPointer()); *cur != 0; ++cur) {
|
||||
AMS_ABORT_UNLESS(std::isdigit(static_cast<unsigned char>(*cur)));
|
||||
port *= 10;
|
||||
port += *cur - '0';
|
||||
}
|
||||
|
||||
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
|
||||
const bool use_hint = serialized_hint.GetPointer() != nullptr;
|
||||
struct addrinfo hint;
|
||||
if (use_hint) {
|
||||
AMS_ABORT_UNLESS(serializer::DNSSerializer::FromBuffer(hint, serialized_hint.GetPointer(), serialized_hint.GetSize()) >= 0);
|
||||
}
|
||||
ON_SCOPE_EXIT { if (use_hint) { serializer::FreeAddrInfo(hint); } };
|
||||
|
||||
const auto size = SerializeRedirectedAddrInfo(out_addrinfo.GetPointer(), out_addrinfo.GetSize(), hostname, redirect_addr, port, use_hint ? std::addressof(hint) : nullptr);
|
||||
|
||||
*out_retval = 0;
|
||||
*out_host_error = 0;
|
||||
*out_errno = 0;
|
||||
*out_size = size;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ResolverImpl::AtmosphereReloadHostsFile() {
|
||||
/* Perform a hosts file reload. */
|
||||
InitializeResolverRedirections();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,11 +16,12 @@
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#define AMS_DNS_MITM_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, GetHostByNameRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, name, out_host_error, out_errno, out_hostent, out_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 6, Result, GetAddrInfoRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, node, srv, serialized_hint, out_addrinfo, out_errno, out_retval, out_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, GetHostByNameRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, name, out_hostent, out_size, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 12, Result, GetAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, node, srv, serialized_hint, out_addrinfo, out_size, out_retval, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0)
|
||||
#define AMS_DNS_MITM_INTERFACE_INFO(C, H) \
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, GetHostByNameRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &name, sf::Out<u32> out_host_error, sf::Out<u32> out_errno, const sf::OutBuffer &out_hostent, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, name, out_host_error, out_errno, out_hostent, out_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 6, Result, GetAddrInfoRequest, (u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size), (cancel_handle, client_pid, use_nsd_resolve, node, srv, serialized_hint, out_addrinfo, out_errno, out_retval, out_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, GetHostByNameRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, name, out_hostent, out_size, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 12, Result, GetAddrInfoRequestWithOptions, (const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno), (client_pid, node, srv, serialized_hint, out_addrinfo, out_size, out_retval, options_version, options, num_options, out_host_error, out_errno), hos::Version_5_0_0) \
|
||||
AMS_SF_METHOD_INFO(C, H, 65000, Result, AtmosphereReloadHostsFile, (), ())
|
||||
|
||||
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::socket::resolver, IResolver, AMS_DNS_MITM_INTERFACE_INFO)
|
||||
|
||||
@ -42,6 +43,9 @@ namespace ams::mitm::socket::resolver {
|
||||
Result GetAddrInfoRequest(u32 cancel_handle, const sf::ClientProcessId &client_pid, bool use_nsd_resolve, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutBuffer &out_addrinfo, sf::Out<u32> out_errno, sf::Out<s32> out_retval, sf::Out<u32> out_size);
|
||||
Result GetHostByNameRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InAutoSelectBuffer &name, const sf::OutAutoSelectBuffer &out_hostent, sf::Out<u32> out_size, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno);
|
||||
Result GetAddrInfoRequestWithOptions(const sf::ClientProcessId &client_pid, const sf::InBuffer &node, const sf::InBuffer &srv, const sf::InBuffer &serialized_hint, const sf::OutAutoSelectBuffer &out_addrinfo, sf::Out<u32> out_size, sf::Out<s32> out_retval, u32 options_version, const sf::InAutoSelectBuffer &options, u32 num_options, sf::Out<s32> out_host_error, sf::Out<s32> out_errno);
|
||||
|
||||
/* Extension commands. */
|
||||
Result AtmosphereReloadHostsFile();
|
||||
};
|
||||
static_assert(IsIResolver<ResolverImpl>);
|
||||
|
||||
|
@ -20,12 +20,6 @@ namespace ams::mitm::socket::resolver::serializer {
|
||||
|
||||
class DNSSerializer {
|
||||
public:
|
||||
template<typename T>
|
||||
static ssize_t ToBufferInternal(u8 * const dst, size_t dst_size, const T &in);
|
||||
|
||||
template<typename T>
|
||||
static ssize_t FromBufferInternal(T &out, const u8 *src, size_t src_size);
|
||||
|
||||
static ssize_t CheckToBufferArguments(const u8 *dst, size_t dst_size, size_t required, int error_id);
|
||||
|
||||
static u32 InternalHton(const u32 &v);
|
||||
@ -73,4 +67,7 @@ namespace ams::mitm::socket::resolver::serializer {
|
||||
void FreeHostent(ams::socket::HostEnt &ent);
|
||||
void FreeHostent(struct hostent &ent);
|
||||
|
||||
void FreeAddrInfo(ams::socket::AddrInfo &addr_info);
|
||||
void FreeAddrInfo(struct addrinfo &addr_info);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "../dnsmitm_debug.hpp"
|
||||
#include "../socket_allocator.hpp"
|
||||
#include "serializer.hpp"
|
||||
|
||||
namespace ams::mitm::socket::resolver::serializer {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline u32 AddrInfoMagic = 0xBEEFCAFE;
|
||||
|
||||
template<typename T>
|
||||
concept IsAddrInfo = std::same_as<T, ams::socket::AddrInfo> || std::same_as<T, struct addrinfo>;
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
using SockAddrType = typename std::conditional<std::same_as<T, ams::socket::AddrInfo>, ams::socket::SockAddr, struct sockaddr>::type;
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
using SockAddrInType = typename std::conditional<std::same_as<T, ams::socket::AddrInfo>, ams::socket::SockAddrIn, struct sockaddr_in>::type;
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
using SockAddrIn6Type = typename std::conditional<std::same_as<T, ams::socket::AddrInfo>, struct sockaddr_in6, struct sockaddr_in6>::type;
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
constexpr bool IsAfInet(const auto ai_family) {
|
||||
if constexpr (std::same_as<T, ams::socket::AddrInfo>) {
|
||||
return ai_family == ams::socket::Family::Af_Inet;
|
||||
} else {
|
||||
return ai_family == AF_INET;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
constexpr bool IsAfInet6(const auto ai_family) {
|
||||
if constexpr (std::same_as<T, ams::socket::AddrInfo>) {
|
||||
return ai_family == ams::socket::Family::Af_Inet6;
|
||||
} else {
|
||||
return ai_family == AF_INET;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
void FreeAddrInfoImpl(T &addr_info) {
|
||||
T *next = nullptr;
|
||||
for (T *cur = std::addressof(addr_info); cur != nullptr; cur = next) {
|
||||
next = cur->ai_next;
|
||||
|
||||
if (cur->ai_addr != nullptr) {
|
||||
if (IsAfInet<T>(cur->ai_family)) {
|
||||
ams::socket::impl::Free(reinterpret_cast<SockAddrInType<T> *>(cur->ai_addr));
|
||||
} else if (IsAfInet6<T>(cur->ai_family)) {
|
||||
ams::socket::impl::Free(reinterpret_cast<SockAddrIn6Type<T> *>(cur->ai_addr));
|
||||
} else {
|
||||
ams::socket::impl::Free(cur->ai_addr);
|
||||
}
|
||||
cur->ai_addr = nullptr;
|
||||
}
|
||||
|
||||
if (cur->ai_canonname != nullptr) {
|
||||
ams::socket::impl::Free(cur->ai_canonname);
|
||||
cur->ai_canonname = nullptr;
|
||||
}
|
||||
|
||||
if (cur != std::addressof(addr_info)) {
|
||||
ams::socket::impl::Free(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
size_t AddrInfoSingleSizeOf(const T *addr_info) {
|
||||
size_t rc = 6 * sizeof(u32);
|
||||
|
||||
if (addr_info->ai_addr == nullptr) {
|
||||
rc += sizeof(u32);
|
||||
} else if (IsAfInet<T>(addr_info->ai_family)) {
|
||||
rc += DNSSerializer::SizeOf(*reinterpret_cast<SockAddrInType<T> *>(addr_info->ai_addr));
|
||||
} else if (IsAfInet6<T>(addr_info->ai_family)) {
|
||||
rc += DNSSerializer::SizeOf(*reinterpret_cast<SockAddrIn6Type<T> *>(addr_info->ai_addr));
|
||||
} else if (addr_info->ai_addrlen == 0) {
|
||||
rc += sizeof(u32);
|
||||
} else {
|
||||
rc += addr_info->ai_addrlen;
|
||||
}
|
||||
|
||||
if (addr_info->ai_canonname != nullptr) {
|
||||
rc += DNSSerializer::SizeOf(static_cast<const char *>(addr_info->ai_canonname));
|
||||
} else {
|
||||
rc += sizeof(u8);
|
||||
}
|
||||
|
||||
if (addr_info->ai_next == nullptr) {
|
||||
rc += sizeof(u32);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
size_t SizeOfImpl(const T &in) {
|
||||
size_t rc = 0;
|
||||
|
||||
for (const T *addr_info = std::addressof(in); addr_info != nullptr; addr_info = addr_info->ai_next) {
|
||||
rc += AddrInfoSingleSizeOf(addr_info);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
ssize_t ToBufferInternalImpl(u8 * const dst, size_t dst_size, const T &addr_info) {
|
||||
ssize_t rc = -1;
|
||||
u8 *cur = dst;
|
||||
|
||||
{
|
||||
const u32 value = AddrInfoMagic;
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
const u32 value = static_cast<u32>(addr_info.ai_flags);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
const u32 value = static_cast<u32>(addr_info.ai_family);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
const u32 value = static_cast<u32>(addr_info.ai_socktype);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
const u32 value = static_cast<u32>(addr_info.ai_protocol);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
const u32 value = static_cast<u32>(addr_info.ai_addrlen);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if (addr_info.ai_addr == nullptr || addr_info.ai_addrlen == 0) {
|
||||
const u32 value = 0;
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
} else if (IsAfInet<T>(addr_info.ai_family)) {
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast<SockAddrInType<T> *>(addr_info.ai_addr))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
} else if (IsAfInet6<T>(addr_info.ai_family)) {
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), *reinterpret_cast<SockAddrIn6Type<T> *>(addr_info.ai_addr))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
if (dst_size - (cur - dst) < addr_info.ai_addrlen) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* NOTE: This is clearly a nintendo bug, see the accompanying note in FromBufferInternalImpl */
|
||||
std::memmove(cur, std::addressof(addr_info.ai_addr), addr_info.ai_addrlen);
|
||||
rc = addr_info.ai_addrlen;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), addr_info.ai_canonname)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
if (addr_info.ai_next == nullptr) {
|
||||
const u32 value = 0;
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), value)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
rc = cur - dst;
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
|
||||
ssize_t rc = -1;
|
||||
u8 *cur = dst;
|
||||
std::memset(dst, 0, dst_size);
|
||||
|
||||
const size_t required = DNSSerializer::SizeOf(in);
|
||||
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, required, __LINE__)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (const T *addr_info = std::addressof(in); addr_info != nullptr; addr_info = addr_info->ai_next) {
|
||||
if ((rc = ToBufferInternalImpl(cur, dst_size, *addr_info)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
rc = cur - dst;
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
ssize_t FromBufferInternalImpl(T &out, const u8 *src, size_t src_size) {
|
||||
ssize_t rc = -1;
|
||||
const u8 *cur = src;
|
||||
|
||||
std::memset(std::addressof(out), 0, sizeof(out));
|
||||
|
||||
ON_SCOPE_EXIT { if (rc < 0) { FreeAddrInfo(out); } };
|
||||
|
||||
u32 tmp_value;
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
} else if (tmp_value != AddrInfoMagic) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.ai_flags = static_cast<decltype(out.ai_flags)>(tmp_value);
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.ai_family = static_cast<decltype(out.ai_family)>(tmp_value);
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.ai_socktype = static_cast<decltype(out.ai_socktype)>(tmp_value);
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.ai_protocol = static_cast<decltype(out.ai_protocol)>(tmp_value);
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.ai_addrlen = static_cast<decltype(out.ai_addrlen)>(tmp_value);
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if (out.ai_addrlen == 0) {
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (tmp_value != 0) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
out.ai_addr = nullptr;
|
||||
} else if (IsAfInet<T>(out.ai_family)) {
|
||||
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrInType<T>)));
|
||||
if (out.ai_addr == nullptr) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
std::memset(out.ai_addr, 0, sizeof(SockAddrInType<T>));
|
||||
|
||||
if ((rc = DNSSerializer::FromBuffer(*reinterpret_cast<SockAddrInType<T> *>(out.ai_addr), cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
} else if (IsAfInet6<T>(out.ai_family)) {
|
||||
out.ai_addr = static_cast<SockAddrType<T> *>(ams::socket::impl::Alloc(sizeof(SockAddrIn6Type<T>)));
|
||||
if (out.ai_addr == nullptr) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
std::memset(out.ai_addr, 0, sizeof(SockAddrIn6Type<T>));
|
||||
|
||||
if ((rc = DNSSerializer::FromBuffer(*reinterpret_cast<SockAddrIn6Type<T> *>(out.ai_addr), cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
out.ai_addr = static_cast<decltype(out.ai_addr)>(ams::socket::impl::Alloc(out.ai_addrlen));
|
||||
if (out.ai_addr == nullptr) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* NOTE: This is *clearly* a nintendo bug. */
|
||||
/* They obviously intend to copy to the buffer they just allocated, but instead they copy to the addrinfo structure itself. */
|
||||
/* Probably &out.ai_addr instead of &out.ai_addr[0]? Either way, we'll implement what they do, but... */
|
||||
std::memcpy(std::addressof(out.ai_addr), cur, out.ai_addrlen);
|
||||
rc = out.ai_addrlen;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(out.ai_canonname, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
{
|
||||
if ((rc = DNSSerializer::FromBuffer(tmp_value, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
} else if (tmp_value == 0) {
|
||||
out.ai_next = nullptr;
|
||||
cur += rc;
|
||||
} else if (tmp_value == AddrInfoMagic) {
|
||||
out.ai_next = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
|
||||
if (out.ai_next == nullptr) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::memset(out.ai_next, 0, sizeof(T));
|
||||
} else {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = cur - src;
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsAddrInfo<T>
|
||||
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
|
||||
ssize_t rc = 0;
|
||||
const u8 *cur = src;
|
||||
|
||||
const size_t required = DNSSerializer::SizeOf(out);
|
||||
if (src_size < required) {
|
||||
ams::socket::SetLastError(ams::socket::Errno::ENoSpc);
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
for (T *addr_info = std::addressof(out); addr_info != nullptr; addr_info = addr_info->ai_next) {
|
||||
if ((rc = FromBufferInternalImpl(*addr_info, cur, src_size - (cur - src))) == -1) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
}
|
||||
|
||||
rc = cur - src;
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<> size_t DNSSerializer::SizeOf(const struct addrinfo &in) {
|
||||
return SizeOfImpl(in);
|
||||
}
|
||||
|
||||
template<> size_t DNSSerializer::SizeOf(const ams::socket::AddrInfo &in) {
|
||||
return SizeOfImpl(in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::AddrInfo &in) {
|
||||
return ToBufferImpl(dst, dst_size, in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct addrinfo &in) {
|
||||
return ToBufferImpl(dst, dst_size, in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::FromBuffer(ams::socket::AddrInfo &out, const u8 *src, size_t src_size) {
|
||||
return FromBufferImpl(out, src, src_size);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::FromBuffer(struct addrinfo &out, const u8 *src, size_t src_size) {
|
||||
return FromBufferImpl(out, src, src_size);
|
||||
}
|
||||
|
||||
void FreeAddrInfo(ams::socket::AddrInfo &addr_info) {
|
||||
return FreeAddrInfoImpl(addr_info);
|
||||
}
|
||||
|
||||
void FreeAddrInfo(struct addrinfo &addr_info) {
|
||||
return FreeAddrInfoImpl(addr_info);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "../dnsmitm_debug.hpp"
|
||||
#include "../socket_allocator.hpp"
|
||||
#include "serializer.hpp"
|
||||
|
||||
namespace ams::mitm::socket::resolver::serializer {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
concept IsSockAddrIn = std::same_as<T, ams::socket::SockAddrIn> || std::same_as<T, struct sockaddr_in>;
|
||||
|
||||
template<typename T> requires IsSockAddrIn<T>
|
||||
size_t SizeOfImpl(const T &in) {
|
||||
size_t rc = 0;
|
||||
rc += sizeof(u16);
|
||||
rc += sizeof(u16);
|
||||
rc += DNSSerializer::SizeOf(in.sin_addr);
|
||||
rc += sizeof(in.sin_zero);
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsSockAddrIn<T>
|
||||
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
|
||||
ssize_t rc = -1;
|
||||
u8 *cur = dst;
|
||||
|
||||
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, sizeof(in), __LINE__)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
const u16 sin_family = static_cast<u16>(in.sin_family);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin_family)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
|
||||
const u16 sin_port = static_cast<u16>(in.sin_port);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin_port)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
|
||||
const u32 s_addr = static_cast<u32>(in.sin_addr.s_addr);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), s_addr)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
|
||||
if (dst_size - (cur - dst) < sizeof(in.sin_zero)) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::memcpy(cur, in.sin_zero, sizeof(in.sin_zero));
|
||||
cur += sizeof(in.sin_zero);
|
||||
|
||||
rc = cur - dst;
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsSockAddrIn<T>
|
||||
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
|
||||
ssize_t rc = -1;
|
||||
const u8 *cur = src;
|
||||
|
||||
u16 sin_family;
|
||||
if ((rc = DNSSerializer::FromBuffer(sin_family, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.sin_family = static_cast<decltype(out.sin_family)>(sin_family);
|
||||
cur += rc;
|
||||
|
||||
u16 sin_port;
|
||||
if ((rc = DNSSerializer::FromBuffer(sin_port, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.sin_port = static_cast<decltype(out.sin_port)>(sin_port);
|
||||
cur += rc;
|
||||
|
||||
u32 s_addr;
|
||||
if ((rc = DNSSerializer::FromBuffer(s_addr, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.sin_addr.s_addr = static_cast<decltype(out.sin_addr.s_addr)>(s_addr);
|
||||
cur += rc;
|
||||
|
||||
if (src_size - (cur - src) < sizeof(out.sin_zero)) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::memcpy(out.sin_zero, cur, sizeof(out.sin_zero));
|
||||
cur += sizeof(out.sin_zero);
|
||||
|
||||
rc = cur - src;
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<> size_t DNSSerializer::SizeOf(const struct sockaddr_in &in) {
|
||||
return SizeOfImpl(in);
|
||||
}
|
||||
|
||||
template<> size_t DNSSerializer::SizeOf(const ams::socket::SockAddrIn &in) {
|
||||
return SizeOfImpl(in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct sockaddr_in &in) {
|
||||
return ToBufferImpl(dst, dst_size, in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::SockAddrIn &in) {
|
||||
return ToBufferImpl(dst, dst_size, in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::FromBuffer(struct sockaddr_in &out, const u8 *src, size_t src_size) {
|
||||
return FromBufferImpl(out, src, src_size);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::SockAddrIn &out, const u8 *src, size_t src_size) {
|
||||
return FromBufferImpl(out, src, src_size);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "../dnsmitm_debug.hpp"
|
||||
#include "../socket_allocator.hpp"
|
||||
#include "serializer.hpp"
|
||||
|
||||
namespace ams::mitm::socket::resolver::serializer {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
concept IsSockAddrIn6 = std::same_as<T, struct sockaddr_in6>;
|
||||
|
||||
template<typename T> requires IsSockAddrIn6<T>
|
||||
size_t SizeOfImpl(const T &in) {
|
||||
size_t rc = 0;
|
||||
rc += sizeof(u16);
|
||||
rc += sizeof(u16);
|
||||
rc += sizeof(u32);
|
||||
rc += DNSSerializer::SizeOf(in.sin6_addr);
|
||||
rc += sizeof(u32);
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsSockAddrIn6<T>
|
||||
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
|
||||
ssize_t rc = -1;
|
||||
u8 *cur = dst;
|
||||
|
||||
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, sizeof(in), __LINE__)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
const u16 sin6_family = static_cast<u16>(in.sin6_family);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_family)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
|
||||
const u16 sin6_port = static_cast<u16>(in.sin6_port);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_port)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
|
||||
const u32 sin6_flowinfo = static_cast<u32>(in.sin6_flowinfo);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_flowinfo)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
|
||||
std::memcpy(cur, std::addressof(in.sin6_addr), sizeof(in.sin6_addr));
|
||||
cur += sizeof(in.sin6_addr);
|
||||
|
||||
const u32 sin6_scope_id = static_cast<u32>(in.sin6_scope_id);
|
||||
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), sin6_scope_id)) == -1) {
|
||||
return rc;
|
||||
}
|
||||
cur += rc;
|
||||
|
||||
rc = cur - dst;
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<typename T> requires IsSockAddrIn6<T>
|
||||
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
|
||||
ssize_t rc = -1;
|
||||
const u8 *cur = src;
|
||||
|
||||
u16 sin6_family;
|
||||
if ((rc = DNSSerializer::FromBuffer(sin6_family, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.sin6_family = static_cast<decltype(out.sin6_family)>(sin6_family);
|
||||
cur += rc;
|
||||
|
||||
u16 sin6_port;
|
||||
if ((rc = DNSSerializer::FromBuffer(sin6_port, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.sin6_port = static_cast<decltype(out.sin6_port)>(sin6_port);
|
||||
cur += rc;
|
||||
|
||||
u32 sin6_flowinfo;
|
||||
if ((rc = DNSSerializer::FromBuffer(sin6_flowinfo, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.sin6_flowinfo = static_cast<decltype(out.sin6_flowinfo)>(sin6_flowinfo);
|
||||
cur += rc;
|
||||
|
||||
std::memcpy(std::addressof(out.sin6_addr), cur, sizeof(out.sin6_addr));
|
||||
cur += sizeof(out.sin6_addr);
|
||||
|
||||
u32 sin6_scope_id;
|
||||
if ((rc = DNSSerializer::FromBuffer(sin6_scope_id, cur, src_size - (cur - src))) == -1) {
|
||||
return rc;
|
||||
}
|
||||
out.sin6_scope_id = static_cast<decltype(out.sin6_scope_id)>(sin6_scope_id);
|
||||
cur += rc;
|
||||
|
||||
rc = cur - src;
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<> size_t DNSSerializer::SizeOf(const struct sockaddr_in6 &in) {
|
||||
return SizeOfImpl(in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct sockaddr_in6 &in) {
|
||||
return ToBufferImpl(dst, dst_size, in);
|
||||
}
|
||||
|
||||
template<> ssize_t DNSSerializer::FromBuffer(struct sockaddr_in6 &out, const u8 *src, size_t src_size) {
|
||||
return FromBufferImpl(out, src, src_size);
|
||||
}
|
||||
|
||||
}
|
@ -52,3 +52,46 @@ Result sfdnsresGetHostByNameRequestWithOptionsFwd(Service *s, u64 process_id, co
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result sfdnsresGetAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_host_error, s32 *out_errno) {
|
||||
const struct {
|
||||
u32 options_version;
|
||||
u32 num_options;
|
||||
u64 process_id;
|
||||
} in = { options_version, num_options, process_id };
|
||||
struct {
|
||||
u32 size;
|
||||
s32 rv;
|
||||
s32 host_error;
|
||||
s32 errno;
|
||||
} out;
|
||||
|
||||
Result rc = serviceMitmDispatchInOut(s, 12, in, out,
|
||||
.buffer_attrs = {
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
|
||||
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In
|
||||
},
|
||||
.buffers = {
|
||||
{ node, node_size },
|
||||
{ srv, srv_size },
|
||||
{ hint, hint_size },
|
||||
{ out_ai, out_ai_size },
|
||||
{ option, option_size }
|
||||
},
|
||||
.in_send_pid = true,
|
||||
.override_pid = process_id,
|
||||
);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
if (out_size) *out_size = out.size;
|
||||
if (out_rv) *out_rv = out.rv;
|
||||
if (out_host_error) *out_host_error = out.host_error;
|
||||
if (out_errno) *out_errno = out.errno;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@ extern "C" {
|
||||
/* Command forwarders. */
|
||||
Result sfdnsresGetHostByNameRequestWithOptionsFwd(Service *s, u64 process_id, const void *name, size_t name_size, void *out_hostent, size_t out_hostent_size, u32 *out_size, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_host_error, s32 *out_errno);
|
||||
|
||||
Result sfdnsresGetAddrInfoRequestWithOptionsFwd(Service *s, u64 process_id, const void *node, size_t node_size, const void *srv, size_t srv_size, const void *hint, size_t hint_size, void *out_ai, size_t out_ai_size, u32 *out_size, s32 *out_rv, u32 options_version, const void *option, size_t option_size, u32 num_options, s32 *out_host_error, s32 *out_errno);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -358,6 +358,10 @@ namespace ams::settings::fwdbg {
|
||||
/* 0 = Disabled (use hosts file contents), 1 = Enabled (use defaults and hosts file contents) */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "add_defaults_to_dns_hosts", "u8!0x1"));
|
||||
|
||||
/* Controls whether dns.mitm logs to the sd card for debugging. */
|
||||
/* 0 = Disabled, 1 = Enabled */
|
||||
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_dns_mitm_debug_log", "u8!0x0"));
|
||||
|
||||
/* Hbloader custom settings. */
|
||||
|
||||
/* Controls the size of the homebrew heap when running as applet. */
|
||||
|
Loading…
Reference in New Issue
Block a user