malcontent/nss/helpers.cc

123 lines
4.0 KiB
C++

// SPDX-FileCopyrightText: Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "helpers.hh"
#include <new>
#include <nss.h>
#include <netdb.h>
#include <cstring>
#include <memory>
auto malcontent::copy_hostent(const hostent& src, hostent& dst, void *buffer, size_t buflen) -> void {
dst.h_addrtype = src.h_addrtype;
dst.h_length = src.h_length;
// copy name
{
auto name_len = std::strlen(src.h_name) + 1;
buffer = std::align(alignof(char), name_len, buffer, buflen);
if (buffer == nullptr) {
throw std::bad_alloc{};
}
dst.h_name = static_cast<char *>(std::memcpy(buffer, src.h_name, name_len));
reinterpret_cast<char *&>(buffer) += name_len;
buflen -= name_len;
}
// copy addresses
{
auto begin_it = src.h_addr_list;
auto end_it = begin_it;
for (; *end_it != nullptr; ++end_it);
auto n = std::distance(begin_it, end_it);
auto needs_bytes = (n + 1) * sizeof(char *);
buffer = std::align(alignof(char *), needs_bytes, buffer, buflen);
if (buffer == nullptr) {
throw std::bad_alloc {};
}
dst.h_addr_list = static_cast<char **>(buffer);
reinterpret_cast<char **&>(buffer) += n + 1;
for (auto i = 0; i < n; ++i) {
buffer = std::align(alignof(char), src.h_length, buffer, buflen);
if (buffer == nullptr) {
throw std::bad_alloc {};
}
dst.h_addr_list[i] = static_cast<char *>(
std::memcpy(buffer, src.h_addr_list[i], src.h_length));
reinterpret_cast<char *&>(buffer) += src.h_length;
buflen -= src.h_length;
}
dst.h_addr_list[n] = nullptr;
}
// copy aliases
{
auto begin_it = src.h_aliases;
auto end_it = begin_it;
for (; *end_it != nullptr; ++end_it);
auto n = std::distance(begin_it, end_it);
auto needs_bytes = (n + 1) * sizeof(char *);
buffer = std::align(alignof(char *), needs_bytes, buffer, buflen);
if (buffer == nullptr) {
throw std::bad_alloc {};
}
dst.h_aliases = static_cast<char **>(buffer);
reinterpret_cast<char **&>(buffer) += n + 1;
buflen -= needs_bytes;
for (int i = 0; i < n; ++i) {
auto alias_len = strlen(*begin_it) + 1;
buffer = std::align(alignof(char), alias_len, buffer, buflen);
if (buffer == nullptr) {
throw std::bad_alloc{};
}
dst.h_addr_list[i] = static_cast<char *>(
std::memcpy(buffer, src.h_aliases[i], n));
reinterpret_cast<char *&>(buffer) += alias_len;
buflen -= alias_len;
}
dst.h_aliases[n] = nullptr;
}
}
auto malcontent::copy_hostent_to_gaih_addrtuple(const hostent& src, gaih_addrtuple *head, void *& buffer, size_t& buflen) -> gaih_addrtuple * {
auto name_len = std::strlen(src.h_name) + 1;
buffer = std::align(alignof(char), name_len, buffer, buflen);
if (buffer == nullptr) {
throw std::bad_alloc{};
}
auto namep = static_cast<char *>(std::memcpy(buffer, src.h_name, name_len));
reinterpret_cast<char *&>(buffer) += name_len;
buflen -= name_len;
for (auto addr = src.h_addr_list; *addr != nullptr; ++addr) {
buffer = std::align(alignof(gaih_addrtuple), sizeof(gaih_addrtuple), buffer, buflen);
if (buffer == nullptr) {
throw std::bad_alloc{};
}
auto tuple = static_cast<gaih_addrtuple *>(buffer);
tuple->family = src.h_addrtype;
tuple->name = namep;
std::memcpy(tuple->addr, *addr, src.h_length);
tuple->next = head; // <-- We are reversing result order here, but it shouldn't be a problem, right?
tuple->scopeid = 0; // FIXME: I have no clue how to determine this
head = tuple;
buflen -= sizeof(gaih_addrtuple);
}
return head;
}