dns.mitm: add GetAddrInfo redir, AtmosphereReloadHostsFile, debug logging control

This commit is contained in:
Michael Scire 2021-02-01 13:40:23 -08:00
parent 4357086181
commit a4d7c90da7
22 changed files with 1093 additions and 56 deletions

View file

@ -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.

View file

@ -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>

View file

@ -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);

View file

@ -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; }
}

View file

@ -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
}

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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
}

View file

@ -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)));

View file

@ -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);

View file

@ -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);

View file

@ -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)));

View file

@ -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();
}
}

View file

@ -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>);

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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

View file

@ -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. */