mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 01:26:34 +00:00
dns: implement GetHostByName redirection (backend TODO)
This commit is contained in:
parent
45709aa9cd
commit
3fd094436e
20 changed files with 1251 additions and 5 deletions
|
@ -74,6 +74,7 @@
|
||||||
#include <stratosphere/settings.hpp>
|
#include <stratosphere/settings.hpp>
|
||||||
#include <stratosphere/sf.hpp>
|
#include <stratosphere/sf.hpp>
|
||||||
#include <stratosphere/sm.hpp>
|
#include <stratosphere/sm.hpp>
|
||||||
|
#include <stratosphere/socket.hpp>
|
||||||
#include <stratosphere/spl.hpp>
|
#include <stratosphere/spl.hpp>
|
||||||
#include <stratosphere/time.hpp>
|
#include <stratosphere/time.hpp>
|
||||||
#include <stratosphere/updater.hpp>
|
#include <stratosphere/updater.hpp>
|
||||||
|
|
|
@ -14,4 +14,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
#include <stratosphere/socket/socket_types.hpp>
|
#include <stratosphere/socket/socket_types.hpp>
|
||||||
|
#include <stratosphere/socket/socket_api.hpp>
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
#include <stratosphere/socket/socket_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::socket {
|
||||||
|
|
||||||
|
u32 InetHtonl(u32 host);
|
||||||
|
u16 InetHtons(u16 host);
|
||||||
|
u32 InetNtohl(u32 net);
|
||||||
|
u16 InetNtohs(u16 net);
|
||||||
|
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ namespace ams::socket {
|
||||||
constexpr inline unsigned int FdSetSize = 0x400;
|
constexpr inline unsigned int FdSetSize = 0x400;
|
||||||
|
|
||||||
template<u32 A, u32 B, u32 C, u32 D>
|
template<u32 A, u32 B, u32 C, u32 D>
|
||||||
constexpr inline InAddrT EncodeInAddr = (A << 24) | (B << 16) | (C << 8) | (D << 0);
|
constexpr inline InAddrT EncodeInAddr = util::ConvertToBigEndian(InAddrT{(A << 24) | (B << 16) | (C << 8) | (D << 0)});
|
||||||
|
|
||||||
constexpr inline InAddrT InAddr_Any = EncodeInAddr< 0, 0, 0, 0>;
|
constexpr inline InAddrT InAddr_Any = EncodeInAddr< 0, 0, 0, 0>;
|
||||||
constexpr inline InAddrT InAddr_Broadcast = EncodeInAddr<255, 255, 255, 255>;
|
constexpr inline InAddrT InAddr_Broadcast = EncodeInAddr<255, 255, 255, 255>;
|
||||||
|
@ -62,4 +62,8 @@ namespace ams::socket {
|
||||||
char **h_addr_list;
|
char **h_addr_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct InAddr {
|
||||||
|
InAddrT s_addr;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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 <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::socket::impl {
|
||||||
|
|
||||||
|
void *Alloc(size_t size);
|
||||||
|
void *Calloc(size_t num, size_t size);
|
||||||
|
void Free(void *ptr);
|
||||||
|
|
||||||
|
}
|
25
libraries/libstratosphere/source/socket/impl/socket_api.hpp
Normal file
25
libraries/libstratosphere/source/socket/impl/socket_api.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
namespace ams::socket::impl {
|
||||||
|
|
||||||
|
u32 InetHtonl(u32 host);
|
||||||
|
u16 InetHtons(u16 host);
|
||||||
|
u32 InetNtohl(u32 net);
|
||||||
|
u16 InetNtohs(u16 net);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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 "socket_api.hpp"
|
||||||
|
#include "socket_allocator.hpp"
|
||||||
|
|
||||||
|
namespace ams::socket::impl {
|
||||||
|
|
||||||
|
void *Alloc(size_t size) {
|
||||||
|
/* TODO: expheap, heap generation. */
|
||||||
|
return ams::Malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Calloc(size_t num, size_t size) {
|
||||||
|
if (void *ptr = Alloc(size * num); ptr != nullptr) {
|
||||||
|
std::memset(ptr, 0, size * num);
|
||||||
|
return ptr;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Free(void *ptr) {
|
||||||
|
/* TODO: expheap, heap generation. */
|
||||||
|
return ams::Free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 InetHtonl(u32 host) {
|
||||||
|
if constexpr (util::IsBigEndian()) {
|
||||||
|
return host;
|
||||||
|
} else {
|
||||||
|
return util::SwapBytes(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 InetHtons(u16 host) {
|
||||||
|
if constexpr (util::IsBigEndian()) {
|
||||||
|
return host;
|
||||||
|
} else {
|
||||||
|
return util::SwapBytes(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 InetNtohl(u32 net) {
|
||||||
|
if constexpr (util::IsBigEndian()) {
|
||||||
|
return net;
|
||||||
|
} else {
|
||||||
|
return util::SwapBytes(net);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 InetNtohs(u16 net) {
|
||||||
|
if constexpr (util::IsBigEndian()) {
|
||||||
|
return net;
|
||||||
|
} else {
|
||||||
|
return util::SwapBytes(net);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
libraries/libstratosphere/source/socket/socket_api.cpp
Normal file
37
libraries/libstratosphere/source/socket/socket_api.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 "impl/socket_api.hpp"
|
||||||
|
|
||||||
|
namespace ams::socket {
|
||||||
|
|
||||||
|
u32 InetHtonl(u32 host) {
|
||||||
|
return impl::InetHtonl(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 InetHtons(u16 host) {
|
||||||
|
return impl::InetHtons(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 InetNtohl(u32 net) {
|
||||||
|
return impl::InetNtohl(net);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 InetNtohs(u16 net) {
|
||||||
|
return impl::InetNtohs(net);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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 "../amsmitm_fs_utils.hpp"
|
||||||
|
#include "dnsmitm_debug.hpp"
|
||||||
|
#include "dnsmitm_host_redirection.hpp"
|
||||||
|
|
||||||
|
namespace ams::mitm::socket::resolver {
|
||||||
|
|
||||||
|
bool GetRedirectedHostByName(ams::socket::InAddrT *out, const char *hostname) {
|
||||||
|
/* TODO: Real implementation */
|
||||||
|
if (std::strcmp(hostname, "receive-lp1.dg.srv.nintendo.net") == 0) {
|
||||||
|
*out = ams::socket::InAddr_Loopback;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::mitm::socket::resolver {
|
||||||
|
|
||||||
|
bool GetRedirectedHostByName(ams::socket::InAddrT *out, const char *hostname);
|
||||||
|
|
||||||
|
}
|
|
@ -16,12 +16,45 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "dnsmitm_resolver_impl.hpp"
|
#include "dnsmitm_resolver_impl.hpp"
|
||||||
#include "dnsmitm_debug.hpp"
|
#include "dnsmitm_debug.hpp"
|
||||||
|
#include "dnsmitm_host_redirection.hpp"
|
||||||
|
#include "serializer/serializer.hpp"
|
||||||
|
#include "sfdnsres_shim.h"
|
||||||
|
|
||||||
namespace ams::mitm::socket::resolver {
|
namespace ams::mitm::socket::resolver {
|
||||||
|
|
||||||
|
ssize_t SerializeRedirectedHostEnt(u8 * const dst, size_t dst_size, const char *hostname, ams::socket::InAddrT redirect_addr) {
|
||||||
|
struct in_addr addr = { .s_addr = redirect_addr };
|
||||||
|
struct in_addr *addr_list[2] = { &addr, nullptr };
|
||||||
|
|
||||||
|
struct hostent ent = {
|
||||||
|
.h_name = const_cast<char *>(hostname),
|
||||||
|
.h_aliases = nullptr,
|
||||||
|
.h_addrtype = AF_INET,
|
||||||
|
.h_length = sizeof(u32),
|
||||||
|
.h_addr_list = (char **)addr_list,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto result = serializer::DNSSerializer::ToBuffer(dst, dst_size, ent);
|
||||||
|
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) {
|
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) {
|
||||||
LogDebug("[%016lx]: GetHostByNameRequest(%s)\n", this->client_info.program_id.value, reinterpret_cast<const char *>(name.GetPointer()));
|
const char *hostname = reinterpret_cast<const char *>(name.GetPointer());
|
||||||
return sm::mitm::ResultShouldForwardToSession();
|
|
||||||
|
LogDebug("[%016lx]: GetHostByNameRequest(%s)\n", this->client_info.program_id.value, hostname);
|
||||||
|
|
||||||
|
ams::socket::InAddrT redirect_addr = {};
|
||||||
|
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||||
|
const auto size = SerializeRedirectedHostEnt(out_hostent.GetPointer(), out_hostent.GetSize(), hostname, redirect_addr);
|
||||||
|
|
||||||
|
*out_host_error = 0;
|
||||||
|
*out_errno = 0;
|
||||||
|
*out_size = size;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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) {
|
||||||
|
@ -30,8 +63,21 @@ namespace ams::mitm::socket::resolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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) {
|
||||||
LogDebug("[%016lx]: GetHostByNameRequestWithOptions(%s)\n", this->client_info.program_id.value, reinterpret_cast<const char *>(name.GetPointer()));
|
const char *hostname = reinterpret_cast<const char *>(name.GetPointer());
|
||||||
return sm::mitm::ResultShouldForwardToSession();
|
|
||||||
|
LogDebug("[%016lx]: GetHostByNameRequestWithOptions(%s)\n", this->client_info.program_id.value, hostname);
|
||||||
|
|
||||||
|
ams::socket::InAddrT redirect_addr = {};
|
||||||
|
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
|
||||||
|
|
||||||
|
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||||
|
const auto size = SerializeRedirectedHostEnt(out_hostent.GetPointer(), out_hostent.GetSize(), hostname, redirect_addr);
|
||||||
|
|
||||||
|
*out_host_error = 0;
|
||||||
|
*out_errno = 0;
|
||||||
|
*out_size = size;
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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) {
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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 "serializer.hpp"
|
||||||
|
|
||||||
|
namespace ams::mitm::socket::resolver::serializer {
|
||||||
|
|
||||||
|
ssize_t DNSSerializer::CheckToBufferArguments(const u8 *dst, size_t dst_size, size_t required, int error_id) {
|
||||||
|
if (dst == nullptr) {
|
||||||
|
return -1;
|
||||||
|
} else if (dst_size < required) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DNSSerializer::InternalHton(const u32 &v) {
|
||||||
|
return ams::socket::InetHtonl(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DNSSerializer::InternalHton(const u16 &v) {
|
||||||
|
return ams::socket::InetHtons(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DNSSerializer::InternalNtoh(const u32 &v) {
|
||||||
|
return ams::socket::InetNtohl(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DNSSerializer::InternalNtoh(const u16 &v) {
|
||||||
|
return ams::socket::InetNtohs(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* 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 <stratosphere.hpp>
|
||||||
|
|
||||||
|
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);
|
||||||
|
static u16 InternalHton(const u16 &v);
|
||||||
|
static u32 InternalNtoh(const u32 &v);
|
||||||
|
static u16 InternalNtoh(const u16 &v);
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
static size_t SizeOf(const T &in);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static size_t SizeOf(const T *in);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static size_t SizeOf(const T *in, size_t count);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static size_t SizeOf(const T **arr, u32 &out_count);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t ToBuffer(u8 * const dst, size_t dst_size, const T &in);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t FromBuffer(T &out, const u8 *src, size_t src_size);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t ToBuffer(u8 * const dst, size_t dst_Size, T *in);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t ToBuffer(u8 * const dst, size_t dst_size, T **arr);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t FromBuffer(T *&out, const u8 *src, size_t src_size);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t FromBuffer(T **&out_arr, const u8 *src, size_t src_size);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t ToBuffer(u8 * const dst, size_t dst_size, const T * const arr, size_t count);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static ssize_t FromBuffer(T * const arr, size_t arr_size, const u8 *src, size_t src_size, size_t count);
|
||||||
|
};
|
||||||
|
|
||||||
|
void FreeHostent(ams::socket::HostEnt &ent);
|
||||||
|
void FreeHostent(struct hostent &ent);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,234 @@
|
||||||
|
/*
|
||||||
|
* 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 IsHostEnt = std::same_as<T, ams::socket::HostEnt> || std::same_as<T, struct hostent>;
|
||||||
|
|
||||||
|
template<typename T> requires IsHostEnt<T>
|
||||||
|
using InAddrType = typename std::conditional<std::same_as<T, ams::socket::HostEnt>, ams::socket::InAddr, struct in_addr>::type;
|
||||||
|
|
||||||
|
template<typename T> requires IsHostEnt<T>
|
||||||
|
constexpr bool IsAfInet(const auto h_addrtype) {
|
||||||
|
if constexpr (std::same_as<T, ams::socket::HostEnt>) {
|
||||||
|
return h_addrtype == ams::socket::Family::Af_Inet;
|
||||||
|
} else {
|
||||||
|
return h_addrtype == AF_INET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsHostEnt<T>
|
||||||
|
constexpr bool IsAfInet6(const auto h_addrtype) {
|
||||||
|
if constexpr (std::same_as<T, ams::socket::HostEnt>) {
|
||||||
|
return h_addrtype == ams::socket::Family::Af_Inet6;
|
||||||
|
} else {
|
||||||
|
return h_addrtype == AF_INET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsHostEnt<T>
|
||||||
|
size_t SizeOfImpl(const T &in) {
|
||||||
|
size_t rc = 0;
|
||||||
|
u32 dummy = 0;
|
||||||
|
|
||||||
|
rc += DNSSerializer::SizeOf((const char *)(in.h_name));
|
||||||
|
rc += DNSSerializer::SizeOf((const char **)(in.h_aliases), dummy);
|
||||||
|
rc += sizeof(u32);
|
||||||
|
rc += sizeof(u32);
|
||||||
|
rc += DNSSerializer::SizeOf((const InAddrType<T> **)(in.h_addr_list), dummy);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsHostEnt<T>
|
||||||
|
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
|
||||||
|
const size_t required = DNSSerializer::SizeOf(in);
|
||||||
|
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, required, __LINE__)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), in.h_name)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), in.h_aliases)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
const u16 h_addrtype = static_cast<u16>(in.h_addrtype);
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), h_addrtype)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
const u16 h_length = in.h_length;
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), h_length)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
if (IsAfInet<T>(in.h_addrtype)) {
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), (InAddrType<T> **)(in.h_addr_list))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else if (IsAfInet6<T>(in.h_addrtype)) {
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), (InAddrType<T> **)(in.h_addr_list))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const u32 null = 0;
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), null)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
rc = cur - dst;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsHostEnt<T>
|
||||||
|
ssize_t FromBufferImpl(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) {
|
||||||
|
FreeHostent(out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(out.h_name, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(out.h_aliases, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
u16 h_addrtype = 0;
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(h_addrtype, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out.h_addrtype = static_cast<decltype(out.h_addrtype)>(h_addrtype);
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
u16 h_length = 0;
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(h_length, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out.h_length = h_length;
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
InAddrType<T> **addrs = nullptr;
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(addrs, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out.h_addr_list = (char **)addrs;
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
rc = cur - src;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsHostEnt<T>
|
||||||
|
void FreeHostentImpl(T &ent) {
|
||||||
|
if (ent.h_name != nullptr) {
|
||||||
|
ams::socket::impl::Free(ent.h_name);
|
||||||
|
ent.h_name = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent.h_aliases != nullptr) {
|
||||||
|
u32 i = 0;
|
||||||
|
for (char *str = ent.h_aliases[i]; str != nullptr; str = ent.h_aliases[++i]) {
|
||||||
|
ams::socket::impl::Free(str);
|
||||||
|
ent.h_aliases[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ams::socket::impl::Free(ent.h_aliases);
|
||||||
|
ent.h_aliases = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent.h_addr_list != nullptr) {
|
||||||
|
AMS_ASSERT(ent.h_length == sizeof(u32));
|
||||||
|
if (ent.h_length == sizeof(u32)) {
|
||||||
|
auto **addr_list = reinterpret_cast<InAddrType<T> **>(ent.h_addr_list);
|
||||||
|
|
||||||
|
u32 i = 0;
|
||||||
|
for (auto *addr = addr_list[i]; addr != nullptr; addr = addr_list[++i]) {
|
||||||
|
ams::socket::impl::Free(addr);
|
||||||
|
addr_list[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ams::socket::impl::Free(ent.h_addr_list);
|
||||||
|
ent.h_addr_list = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(std::addressof(ent), 0, sizeof(ent));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const struct hostent &in) {
|
||||||
|
return SizeOfImpl(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct hostent &in) {
|
||||||
|
return ToBufferImpl(dst, dst_size, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(struct hostent &out, const u8 *src, size_t src_size) {
|
||||||
|
return FromBufferImpl(out, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const ams::socket::HostEnt &in) {
|
||||||
|
return SizeOfImpl(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::HostEnt &in) {
|
||||||
|
return ToBufferImpl(dst, dst_size, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(ams::socket::HostEnt &out, const u8 *src, size_t src_size) {
|
||||||
|
return FromBufferImpl(out, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeHostent(ams::socket::HostEnt &ent) {
|
||||||
|
return FreeHostentImpl(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeHostent(struct hostent &ent) {
|
||||||
|
return FreeHostentImpl(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* 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 IsInAddr = std::same_as<T, ams::socket::InAddr> || std::same_as<T, struct in_addr>;
|
||||||
|
|
||||||
|
template<typename T> requires IsInAddr<T>
|
||||||
|
size_t SizeOfImpl(const T &in) {
|
||||||
|
return sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsInAddr<T>
|
||||||
|
size_t SizeOfImpl(const T **in, u32 &out_count) {
|
||||||
|
size_t rc = sizeof(u32);
|
||||||
|
out_count = 0;
|
||||||
|
|
||||||
|
if (in != nullptr) {
|
||||||
|
for (const T ** cur_addr = in; *cur_addr != nullptr; ++cur_addr) {
|
||||||
|
++out_count;
|
||||||
|
rc += sizeof(u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsInAddr<T>
|
||||||
|
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, const T &in) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
|
||||||
|
const u32 val = DNSSerializer::InternalHton(in.s_addr);
|
||||||
|
|
||||||
|
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, sizeof(in), __LINE__)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(cur, std::addressof(val), sizeof(val));
|
||||||
|
rc += sizeof(val);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsInAddr<T>
|
||||||
|
ssize_t FromBufferImpl(T &out, const u8 *src, size_t src_size) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
if (src_size < sizeof(out)) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(std::addressof(out), 0, sizeof(out));
|
||||||
|
out.s_addr = DNSSerializer::InternalNtoh(*reinterpret_cast<const u32 *>(src));
|
||||||
|
|
||||||
|
rc = sizeof(u32);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsInAddr<T>
|
||||||
|
ssize_t ToBufferImpl(u8 * const dst, size_t dst_size, T **arr) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
|
||||||
|
if (arr == nullptr && dst_size < sizeof(u32)) {
|
||||||
|
return rc;
|
||||||
|
} else if (arr == nullptr) {
|
||||||
|
const u32 null = 0;
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), null)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
} else {
|
||||||
|
u32 count = 0;
|
||||||
|
for (auto *tmp = arr; *tmp != nullptr; ++tmp) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = DNSSerializer::CheckToBufferArguments(cur, dst_size, (count + 1) * sizeof(**arr), __LINE__)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), count)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
for (auto i = 0; arr[i] != nullptr; ++i) {
|
||||||
|
const T addr = *arr[i];
|
||||||
|
if ((rc = DNSSerializer::ToBuffer(cur, dst_size - (cur - dst), addr)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cur - dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> requires IsInAddr<T>
|
||||||
|
ssize_t FromBufferImpl(T **&out, const u8 *src, size_t src_size) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
const u8 *cur = src;
|
||||||
|
|
||||||
|
out = nullptr;
|
||||||
|
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
if (rc == -1 && out != nullptr) {
|
||||||
|
for (auto i = 0; out[i] != nullptr; ++i) {
|
||||||
|
ams::socket::impl::Free(out[i]);
|
||||||
|
out[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ams::socket::impl::Free(out);
|
||||||
|
out = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (src == nullptr) {
|
||||||
|
rc = 0;
|
||||||
|
return rc;
|
||||||
|
} else if (src_size == 0) {
|
||||||
|
rc = 0;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 count = 0;
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(count, cur, src_size)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = static_cast<T **>(ams::socket::impl::Alloc((count + 1) * sizeof(T *)));
|
||||||
|
if (out == nullptr) {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
std::memset(out, 0, (count + 1) * sizeof(T *));
|
||||||
|
|
||||||
|
for (u32 i = 0; i < count; ++i) {
|
||||||
|
out[i] = static_cast<T *>(ams::socket::impl::Alloc(sizeof(T)));
|
||||||
|
if (out[i] == nullptr) {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 s_addr = 0;
|
||||||
|
if ((rc = DNSSerializer::FromBuffer(s_addr, cur, src_size - (cur - src))) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
out[i]->s_addr = s_addr;
|
||||||
|
cur += rc;
|
||||||
|
}
|
||||||
|
out[count] = nullptr;
|
||||||
|
|
||||||
|
rc = cur - src;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const struct in_addr &in) {
|
||||||
|
return SizeOfImpl(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const ams::socket::InAddr &in) {
|
||||||
|
return SizeOfImpl(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const struct in_addr **in, u32 &out_count) {
|
||||||
|
return SizeOfImpl(in, out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const ams::socket::InAddr **in, u32 &out_count) {
|
||||||
|
return SizeOfImpl(in, out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const struct in_addr &in) {
|
||||||
|
return ToBufferImpl(dst, dst_size, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const ams::socket::InAddr &in) {
|
||||||
|
return ToBufferImpl(dst, dst_size, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(struct in_addr &out, const u8 *src, size_t src_size) {
|
||||||
|
return FromBufferImpl(out, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::InAddr &out, const u8 *src, size_t src_size) {
|
||||||
|
return FromBufferImpl(out, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, struct in_addr **arr) {
|
||||||
|
return ToBufferImpl(dst, dst_size, arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, ams::socket::InAddr **arr) {
|
||||||
|
return ToBufferImpl(dst, dst_size, arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(struct in_addr **&out, const u8 *src, size_t src_size) {
|
||||||
|
return FromBufferImpl(out, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(struct ams::socket::InAddr **&out, const u8 *src, size_t src_size) {
|
||||||
|
return FromBufferImpl(out, src, src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* 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 "serializer.hpp"
|
||||||
|
|
||||||
|
namespace ams::mitm::socket::resolver::serializer {
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const u16 &in) {
|
||||||
|
/* Convert the value. */
|
||||||
|
u8 *cur = dst;
|
||||||
|
const u16 val = InternalHton(in);
|
||||||
|
|
||||||
|
/* Check arguments. */
|
||||||
|
ssize_t rc = -1;
|
||||||
|
if ((rc = CheckToBufferArguments(cur, dst_size, sizeof(u16), __LINE__)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(cur, std::addressof(val), sizeof(u16));
|
||||||
|
rc += sizeof(u16);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(u16 &out, const u8 *src, size_t src_size) {
|
||||||
|
if (src_size < sizeof(u16)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = InternalNtoh(*reinterpret_cast<const u16 *>(src));
|
||||||
|
return sizeof(u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, const u32 &in) {
|
||||||
|
/* Convert the value. */
|
||||||
|
u8 *cur = dst;
|
||||||
|
const u32 val = InternalHton(in);
|
||||||
|
|
||||||
|
/* Check arguments. */
|
||||||
|
ssize_t rc = -1;
|
||||||
|
if ((rc = CheckToBufferArguments(cur, dst_size, sizeof(u32), __LINE__)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(cur, std::addressof(val), sizeof(u32));
|
||||||
|
rc += sizeof(u32);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(u32 &out, const u8 *src, size_t src_size) {
|
||||||
|
if (src_size < sizeof(u32)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = InternalNtoh(*reinterpret_cast<const u32 *>(src));
|
||||||
|
return sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const char *str) {
|
||||||
|
if (str == nullptr) {
|
||||||
|
return sizeof(char);
|
||||||
|
}
|
||||||
|
return std::strlen(str) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> size_t DNSSerializer::SizeOf(const char **str, u32 &out_count) {
|
||||||
|
size_t rc = sizeof(u32);
|
||||||
|
out_count = 0;
|
||||||
|
|
||||||
|
if (str != nullptr) {
|
||||||
|
for (const char **cur = str; *cur != nullptr; ++cur) {
|
||||||
|
++out_count;
|
||||||
|
rc += SizeOf(*cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, char *str) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
|
||||||
|
if (str == nullptr && dst_size == 0) {
|
||||||
|
return -1;
|
||||||
|
} else if (str == nullptr) {
|
||||||
|
*cur = '\x00';
|
||||||
|
return 1;
|
||||||
|
} else if ((rc = SizeOf(static_cast<const char *>(str))) == 0) {
|
||||||
|
*cur = '\x00';
|
||||||
|
return 1;
|
||||||
|
} else if (CheckToBufferArguments(cur, dst_size, rc + 1, __LINE__) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memmove(cur, str, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(char *&out, const u8 *src, size_t src_size) {
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
if (src == nullptr) {
|
||||||
|
return 0;
|
||||||
|
} else if (src_size == 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (src_size < (len = SizeOf(reinterpret_cast<const char *>(src)))) {
|
||||||
|
return 1;
|
||||||
|
} else if (src[0] == '\x00') {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out = static_cast<char *>(ams::socket::impl::Alloc(len));
|
||||||
|
if (out == nullptr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memmove(out, src, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::ToBuffer(u8 * const dst, size_t dst_size, char **str) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
u8 *cur = dst;
|
||||||
|
u32 count = 0;
|
||||||
|
|
||||||
|
if (dst_size == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t total_size = SizeOf(const_cast<const char **>(str), count);
|
||||||
|
AMS_UNUSED(total_size);
|
||||||
|
|
||||||
|
if ((rc = CheckToBufferArguments(cur, dst_size, sizeof(u32), __LINE__)) == -1) {
|
||||||
|
return rc;
|
||||||
|
} else if ((rc = ToBuffer(cur, dst_size, count)) == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
dst_size -= rc;
|
||||||
|
|
||||||
|
if (str != nullptr) {
|
||||||
|
for (char **cur_str = str; *cur_str != nullptr; ++cur_str) {
|
||||||
|
const auto tmp = ToBuffer(cur, dst_size, *cur_str);
|
||||||
|
if (tmp == -1) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur += tmp;
|
||||||
|
dst_size -= tmp;
|
||||||
|
rc += tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cur - dst;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> ssize_t DNSSerializer::FromBuffer(char **&out, const u8 *src, size_t src_size) {
|
||||||
|
ssize_t rc = -1;
|
||||||
|
const u8 *cur = src;
|
||||||
|
u32 count = 0;
|
||||||
|
|
||||||
|
out = nullptr;
|
||||||
|
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
if (rc < 0 && out != nullptr) {
|
||||||
|
u32 i = 0;
|
||||||
|
for (char *str = *out; str != nullptr; str = out[++i]) {
|
||||||
|
ams::socket::impl::Free(str);
|
||||||
|
}
|
||||||
|
ams::socket::impl::Free(out);
|
||||||
|
out = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (src == nullptr) {
|
||||||
|
rc = 0;
|
||||||
|
return rc;
|
||||||
|
} else if (src_size == 0) {
|
||||||
|
rc = 0;
|
||||||
|
return rc;
|
||||||
|
} else if ((rc = FromBuffer(count, cur, src_size)) == -1) {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
cur += rc;
|
||||||
|
|
||||||
|
out = static_cast<char **>(ams::socket::impl::Alloc((count + 1) * sizeof(char *)));
|
||||||
|
if (out == nullptr) {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
std::memset(out, 0, (count + 1) * sizeof(char *));
|
||||||
|
|
||||||
|
u32 i;
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
const size_t len = std::strlen(reinterpret_cast<const char *>(cur));
|
||||||
|
out[i] = static_cast<char *>(ams::socket::impl::Alloc(len + 1));
|
||||||
|
if (out[i] == nullptr) {
|
||||||
|
rc = -1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memmove(out[i], cur, len + 1);
|
||||||
|
cur += len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[i] = nullptr;
|
||||||
|
rc = cur - src;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
54
stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.c
Normal file
54
stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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 "sfdnsres_shim.h"
|
||||||
|
#include <stratosphere/sf/sf_mitm_dispatch.h>
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
const struct {
|
||||||
|
u32 options_version;
|
||||||
|
u32 num_options;
|
||||||
|
u64 process_id;
|
||||||
|
} in = { options_version, num_options, process_id };
|
||||||
|
struct {
|
||||||
|
u32 size;
|
||||||
|
s32 host_error;
|
||||||
|
s32 errno;
|
||||||
|
} out;
|
||||||
|
|
||||||
|
Result rc = serviceMitmDispatchInOut(s, 10, in, out,
|
||||||
|
.buffer_attrs = {
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In,
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out,
|
||||||
|
SfBufferAttr_HipcAutoSelect | SfBufferAttr_In
|
||||||
|
},
|
||||||
|
.buffers = {
|
||||||
|
{ name, name_size },
|
||||||
|
{ out_hostent, out_hostent_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_host_error) *out_host_error = out.host_error;
|
||||||
|
if (out_errno) *out_errno = out.errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
19
stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.h
Normal file
19
stratosphere/ams_mitm/source/dns_mitm/sfdnsres_shim.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* @file sfdnsres_shim.h
|
||||||
|
* @brief IPC wrapper for dns.mitm.
|
||||||
|
* @author SciresM
|
||||||
|
* @copyright libnx Authors
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
25
stratosphere/ams_mitm/source/dns_mitm/socket_allocator.hpp
Normal file
25
stratosphere/ams_mitm/source/dns_mitm/socket_allocator.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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 <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::socket::impl {
|
||||||
|
|
||||||
|
void *Alloc(size_t size);
|
||||||
|
void *Calloc(size_t num, size_t size);
|
||||||
|
void Free(void *ptr);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue