what have i done?
parent
6e0419ecd0
commit
a16cd8619d
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Global constants file.
|
* Global constants file.
|
||||||
* Copyright (C) 2023 Brett Terpstra
|
* Copyright (C) 2023 Brett Terpstra, Et al
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -24,7 +24,35 @@
|
||||||
* | Magic Number Constants |
|
* | Magic Number Constants |
|
||||||
* --------------------------------------------
|
* --------------------------------------------
|
||||||
*/
|
*/
|
||||||
/** DNS header data offset. This is the first byte that isn't a header value (should be question label length octet) */
|
|
||||||
static constexpr size_t DNS_HEADER_END = 12;
|
static constexpr size_t PACKET_BUFFER_SIZE = 65535;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These structs are used in combination with templates to create a form of polymorphism which has significantly reduced the code reuse.
|
||||||
|
* The data set within these structures are specific to the protocol they implement. UDP is exactly as specified in the RFC spec
|
||||||
|
* TCP is what I observed from wireshark (+2 byte offset)
|
||||||
|
*/
|
||||||
|
struct DNS_UDP_INFO_t
|
||||||
|
{
|
||||||
|
/** DNS header data offset. This is the first byte that isn't a header value (should be question label length octet) */
|
||||||
|
size_t HEADER_END = 12;
|
||||||
|
/** DNS questions count data offset. In the standard header this is 4 bytes in */
|
||||||
|
size_t QUESTIONS_BEGIN = 4;
|
||||||
|
/** DNS answer count data offset. */
|
||||||
|
size_t ANSWERS_BEGIN = 6;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The TCP version appears to use a 2 byte unsigned short to represent length. This struct accounts for that.
|
||||||
|
*/
|
||||||
|
struct DNS_TCP_INFO_t
|
||||||
|
{
|
||||||
|
size_t HEADER_END = 14;
|
||||||
|
size_t QUESTIONS_BEGIN = 6;
|
||||||
|
size_t ANSWERS_BEGIN = 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr DNS_UDP_INFO_t DNS_UDP_INFO;
|
||||||
|
static constexpr DNS_TCP_INFO_t DNS_TCP_INFO;
|
||||||
|
|
||||||
#endif //INSANE_DNS_CONSTANTS_H
|
#endif //INSANE_DNS_CONSTANTS_H
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* BLT Memory Util for parsing DNS packets.
|
* BLT Memory Util for parsing DNS packets / BLT + ASIO simple packet sender.
|
||||||
* This software is unlikely to become part of BLT main but is provided under the BLT license (GPL 3).
|
* This software is unlikely to become part of BLT main but is provided under the BLT license (GPL 3).
|
||||||
* Copyright (C) 2023 Brett Terpstra
|
* Copyright (C) 2023 Brett Terpstra, Et al
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,6 +21,14 @@
|
||||||
#define INSANE_DNS_UTIL_H
|
#define INSANE_DNS_UTIL_H
|
||||||
|
|
||||||
#include <insane_dns/constants.h>
|
#include <insane_dns/constants.h>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <asio.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <blt/std/memory.h>
|
||||||
|
|
||||||
|
using asio::ip::udp;
|
||||||
|
using asio::ip::tcp;
|
||||||
|
|
||||||
namespace blt
|
namespace blt
|
||||||
{
|
{
|
||||||
|
@ -28,20 +36,17 @@ namespace blt
|
||||||
/**
|
/**
|
||||||
* Basic parser for processing strings of bytes received from UDP sockets. This class provides a simple interface for efficiently copying the
|
* Basic parser for processing strings of bytes received from UDP sockets. This class provides a simple interface for efficiently copying the
|
||||||
* big endian bytes from the network into the little endian bytes required by x86 processors. The class also provides basic safety guarantees
|
* big endian bytes from the network into the little endian bytes required by x86 processors. The class also provides basic safety guarantees
|
||||||
* in that the program will halt execution if reading the bytes would overflow the internal buffer.
|
* in the sense that the program will halt execution if reading the bytes would overflow the internal buffer.
|
||||||
*/
|
*/
|
||||||
class byte_reader
|
class byte_reader
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
unsigned char* _data;
|
unsigned char* _data;
|
||||||
const size_t _size;
|
const size_t _size;
|
||||||
mutable size_t _current_byte = DNS_HEADER_END;
|
mutable size_t _current_byte;
|
||||||
public:
|
public:
|
||||||
explicit byte_reader(unsigned char* data, size_t size, bool tcp = false): _data(data), _size(size)
|
explicit byte_reader(unsigned char* data, size_t size, size_t start_offset): _data(data), _size(size), _current_byte(start_offset)
|
||||||
{
|
{}
|
||||||
if (tcp)
|
|
||||||
_current_byte += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the next byte in the data stream then increment the internal counter by 1
|
* Read the next byte in the data stream then increment the internal counter by 1
|
||||||
|
@ -109,7 +114,71 @@ namespace blt
|
||||||
return &_data[_current_byte];
|
return &_data[_current_byte];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace network
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sends a simple UDP message to the provided host on the DNS port and outputs the response into the out buffer
|
||||||
|
* @param host host to send the message to
|
||||||
|
* @param in buffer to send
|
||||||
|
* @param in_size size of buffer
|
||||||
|
* @param out buffer to write to
|
||||||
|
* @param out_size size of data that was written. Make sure `out` has enough room for the packet.
|
||||||
|
*/
|
||||||
|
void sendUDPMessage(const std::string& host, const unsigned char*& in, size_t in_size, blt::scoped_buffer<unsigned char>& out,
|
||||||
|
size_t& out_size)
|
||||||
|
{
|
||||||
|
asio::io_context io_context;
|
||||||
|
udp::endpoint receiver_endpoint(asio::ip::address::from_string(host), 53);
|
||||||
|
|
||||||
|
udp::socket socket(io_context);
|
||||||
|
socket.open(udp::v4());
|
||||||
|
|
||||||
|
socket.send_to(asio::const_buffers_1(in, in_size), receiver_endpoint);
|
||||||
|
|
||||||
|
udp::endpoint sender_endpoint;
|
||||||
|
out_size = socket.receive_from(asio::buffer(out.data(), out.size()), sender_endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a simple TCP message to the provided host on the DNS port and outputs the response into the out buffer
|
||||||
|
* @param host host to send the message to
|
||||||
|
* @param in buffer to send
|
||||||
|
* @param in_size size of buffer
|
||||||
|
* @param out buffer to write to
|
||||||
|
* @param out_size size of data that was written. Make sure `out` has enough room for the packet.
|
||||||
|
*/
|
||||||
|
void sendTCPMessage(const std::string& host, const unsigned char*& in, size_t in_size, blt::scoped_buffer<unsigned char>& out,
|
||||||
|
size_t& out_size)
|
||||||
|
{
|
||||||
|
asio::io_context io_context;
|
||||||
|
tcp::resolver resolver(io_context);
|
||||||
|
tcp::resolver::results_type endpoints = resolver.resolve(host, "53");
|
||||||
|
|
||||||
|
tcp::socket socket(io_context);
|
||||||
|
asio::connect(socket, endpoints);
|
||||||
|
|
||||||
|
asio::write(socket, asio::buffer(in, in_size));
|
||||||
|
|
||||||
|
out_size = socket.read_some(asio::buffer(out.data(), out.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //INSANE_DNS_UTIL_H
|
#endif //INSANE_DNS_UTIL_H
|
||||||
|
|
||||||
|
// these are no longer used, but I am keeping them around because they are useful and were not added to git
|
||||||
|
|
||||||
|
// template<class T>
|
||||||
|
// struct is_byte_ptr_type : std::integral_constant<bool,
|
||||||
|
// std::is_same_v<T, std::int8_t*> || std::is_same_v<T, std::uint8_t*> ||
|
||||||
|
// std::is_same_v<T, unsigned char*> || std::is_same_v<T, char*> || std::is_same_v<T, signed char*>>
|
||||||
|
// {
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// template<typename T>
|
||||||
|
// inline constexpr bool is_byte_ptr_type_v = is_byte_ptr_type<T>::value;
|
||||||
|
//
|
||||||
|
// template<typename IN, typename OUT>
|
||||||
|
// using messageFunction = std::function<void(const std::string&, const IN&, size_t, OUT&, size_t&)>;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 16ba4ed192f877d1ea6c9e81c22cb2b04b2014f5
|
Subproject commit 55c497475e15b9a4ff0ac319c2997bd1869c4454
|
88
src/ip.h
88
src/ip.h
|
@ -6,11 +6,10 @@
|
||||||
#define INSANE_DNS_IP_H
|
#define INSANE_DNS_IP_H
|
||||||
|
|
||||||
#include <blt/std/string.h>
|
#include <blt/std/string.h>
|
||||||
|
#include <blt/compatibility.h>
|
||||||
#include <blt/std/assert.h>
|
#include <blt/std/assert.h>
|
||||||
#include <asio.hpp>
|
|
||||||
|
|
||||||
using asio::ip::udp;
|
#include <asio.hpp>
|
||||||
using asio::ip::tcp;
|
|
||||||
|
|
||||||
struct IPAddress
|
struct IPAddress
|
||||||
{
|
{
|
||||||
|
@ -34,33 +33,68 @@ struct IPAddress
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename IN, typename OUT>
|
struct bind_address
|
||||||
void sendUDPMessage(const std::string& host, const IN& in, size_t in_size, OUT& out, size_t& out_size)
|
|
||||||
{
|
{
|
||||||
asio::io_context io_context;
|
unsigned short int port;
|
||||||
udp::endpoint receiver_endpoint(asio::ip::address::from_string(host), 53);
|
bool use_v4 = true;
|
||||||
|
bool use_v6 = true;
|
||||||
udp::socket socket(io_context);
|
// if these are empty it will use ASIO default
|
||||||
socket.open(udp::v4());
|
std::string IP_V4;
|
||||||
|
std::string IP_V6;
|
||||||
socket.send_to(asio::const_buffers_1(in, in_size), receiver_endpoint);
|
};
|
||||||
|
|
||||||
udp::endpoint sender_endpoint;
|
// using a template instead of a macro. Are you proud of me dad?
|
||||||
out_size = socket.receive_from(asio::buffer(out), sender_endpoint);
|
template<typename RET, typename V4, typename V6>
|
||||||
|
inline RET BLT_INTERNAL_ENDPOINT(const bind_address& address, V4 v4, V6 v6)
|
||||||
|
{
|
||||||
|
// this is an ugly mess. Ignore it.
|
||||||
|
BLT_ASSERT(address.use_v4 || address.use_v6);
|
||||||
|
if (address.use_v6)
|
||||||
|
{
|
||||||
|
if (address.IP_V6.empty())
|
||||||
|
return {v6, address.port};
|
||||||
|
else
|
||||||
|
return {asio::ip::address::from_string(address.IP_V6), address.port};
|
||||||
|
}
|
||||||
|
if (address.use_v4)
|
||||||
|
{
|
||||||
|
if (address.IP_V4.empty())
|
||||||
|
return {v4, address.port};
|
||||||
|
else
|
||||||
|
return {asio::ip::address::from_string(address.IP_V4), address.port};
|
||||||
|
}
|
||||||
|
// suppress compiler warnings. Also, could do std::exit() but this is more fun :3
|
||||||
|
return {asio::ip::address::from_string("Unreachable Code"), 42069};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename IN, typename OUT>
|
/**
|
||||||
void sendTCPMessage(const std::string& host, const IN& in, size_t in_size, OUT& out, size_t& out_size){
|
* Convert a bind_address into a ASIO UDP endpoint
|
||||||
asio::io_context io_context;
|
* @param address address to convert
|
||||||
tcp::resolver resolver(io_context);
|
* @return ASIO UDP endpoint
|
||||||
tcp::resolver::results_type endpoints = resolver.resolve(host, "53");
|
*/
|
||||||
|
inline asio::ip::udp::endpoint toUDPEndpoint(const bind_address& address)
|
||||||
tcp::socket socket(io_context);
|
{
|
||||||
asio::connect(socket, endpoints);
|
auto v4 = asio::ip::udp::v4();
|
||||||
|
auto v6 = asio::ip::udp::v6();
|
||||||
asio::write(socket, asio::buffer(in, in_size));
|
return BLT_INTERNAL_ENDPOINT<asio::ip::udp::endpoint>(address, v4, v6);
|
||||||
|
|
||||||
out_size = socket.read_some(asio::buffer(out));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a bind_address into a ASIO TCP endpoint
|
||||||
|
* @param address address to convert
|
||||||
|
* @return ASIO TCP endpoint
|
||||||
|
*/
|
||||||
|
inline asio::ip::tcp::endpoint toTCPEndpoint(const bind_address& address)
|
||||||
|
{
|
||||||
|
auto v4 = asio::ip::tcp::v4();
|
||||||
|
auto v6 = asio::ip::tcp::v6();
|
||||||
|
return BLT_INTERNAL_ENDPOINT<asio::ip::tcp::endpoint>(address, v4, v6);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct request_info
|
||||||
|
{
|
||||||
|
size_t number_of_bytes;
|
||||||
|
size_t number_of_answers;
|
||||||
|
};
|
||||||
|
|
||||||
#endif //INSANE_DNS_IP_H
|
#endif //INSANE_DNS_IP_H
|
||||||
|
|
199
src/main.cpp
199
src/main.cpp
|
@ -28,6 +28,12 @@
|
||||||
/** What port to run the server on */
|
/** What port to run the server on */
|
||||||
static constexpr unsigned short int SERVER_PORT = 5555;
|
static constexpr unsigned short int SERVER_PORT = 5555;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How should we bind to the local machine? By default this will use IPv4 and IPv6 with the default ASIO endpoint.
|
||||||
|
* Only change this if you really need to and know what you are doing.
|
||||||
|
*/
|
||||||
|
static constexpr bind_address address{SERVER_PORT};
|
||||||
|
|
||||||
/** should we strictly match results? ie block `*wikipedia.org*` or just `wikipedia.org`? */
|
/** should we strictly match results? ie block `*wikipedia.org*` or just `wikipedia.org`? */
|
||||||
static constexpr bool STRICT_MATCHING = false;
|
static constexpr bool STRICT_MATCHING = false;
|
||||||
|
|
||||||
|
@ -60,13 +66,14 @@ static const std::unordered_set<std::string> DISALLOWED_DOMAINS{
|
||||||
*/
|
*/
|
||||||
// these features were planned but not added because I realized you guys won't care or give extra marks which broke my obsession with it
|
// these features were planned but not added because I realized you guys won't care or give extra marks which broke my obsession with it
|
||||||
// so uhh don't change em otherwise the code will break :3
|
// so uhh don't change em otherwise the code will break :3
|
||||||
|
// as it is im still adding new features and stuff (TCP) and messing with the code trying to get it cleaner
|
||||||
|
|
||||||
/** true -> only match A records ; false -> match any named record (configure with NON_STRICT_REPLACE_ALL) */
|
/** true -> only match A records ; false -> match any named record (configure with NON_STRICT_REPLACE_ALL) */
|
||||||
static constexpr bool STRICT_FILTERING = true;
|
static constexpr bool STRICT_FILTERING = true;
|
||||||
/** true -> match all records ; false -> match only records we might want to replace (A, AAAA, CNAME) */
|
/** true -> match all records ; false -> match only records we might want to replace (A, AAAA, CNAME) */
|
||||||
static constexpr bool NON_STRICT_REPLACE_ALL = true;
|
static constexpr bool NON_STRICT_REPLACE_ALL = true;
|
||||||
|
|
||||||
// was going to add TCP and ad blocking support
|
// was going to add ~~TCP~~ (this is now a thing for full DIG support. "can you dig it, sucka!?") and ad blocking support
|
||||||
// that also isn't going to happen now.
|
// that also isn't going to happen now.
|
||||||
/** list of web address to download the ad block lists from */
|
/** list of web address to download the ad block lists from */
|
||||||
static BLT_CPP20_CONSTEXPR std::vector<std::string> BLOCK_LISTS{};
|
static BLT_CPP20_CONSTEXPR std::vector<std::string> BLOCK_LISTS{};
|
||||||
|
@ -107,8 +114,8 @@ class question
|
||||||
friend send_buffer;
|
friend send_buffer;
|
||||||
private:
|
private:
|
||||||
std::string domain;
|
std::string domain;
|
||||||
uint16_t QTYPE;
|
uint16_t QTYPE = 0;
|
||||||
uint16_t QCLASS;
|
uint16_t QCLASS = 0;
|
||||||
public:
|
public:
|
||||||
explicit question(const blt::byte_reader& reader)
|
explicit question(const blt::byte_reader& reader)
|
||||||
{
|
{
|
||||||
|
@ -327,75 +334,89 @@ void process_answers(std::vector<answer>& answers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T, typename INFO, typename MESSENGER>
|
||||||
|
request_info handle_forward_request(MESSENGER messenger, const INFO& info, const T& input_recv_buffer, size_t bytes, T& forward_recv_buffer)
|
||||||
|
{
|
||||||
|
// get the number of questions
|
||||||
|
uint16_t questions; // yes I made this part of my library just for this :3
|
||||||
|
blt::mem::fromBytes(&input_recv_buffer[info.QUESTIONS_BEGIN], questions); // i hate little endian
|
||||||
|
|
||||||
|
BLT_INFO("Bytes received: %d with %d questions", bytes, questions);
|
||||||
|
|
||||||
|
// forward to google.
|
||||||
|
size_t out_bytes;
|
||||||
|
auto data = input_recv_buffer.data();
|
||||||
|
messenger(DNS_SERVER_IP(), data, bytes, forward_recv_buffer, out_bytes);
|
||||||
|
|
||||||
|
uint16_t num_of_answers;
|
||||||
|
blt::mem::fromBytes(&forward_recv_buffer[info.ANSWERS_BEGIN], num_of_answers);
|
||||||
|
|
||||||
|
return {out_bytes, num_of_answers};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename INFO>
|
||||||
|
void handle_response(const INFO& info, send_buffer& return_send_buffer, request_info rq_info, T& forward_recv_buffer)
|
||||||
|
{
|
||||||
|
blt::byte_reader reader(forward_recv_buffer.data(), forward_recv_buffer.size(), info.HEADER_END);
|
||||||
|
|
||||||
|
BLT_INFO("Bytes answered: %d with %d answers", rq_info.number_of_bytes, rq_info.number_of_answers);
|
||||||
|
|
||||||
|
// no one actually does multiple questions. trying to do it in dig is not easy
|
||||||
|
// and the standard isn't really designed for this (how do we handle if one question errors but the other doesn't? there is only
|
||||||
|
// one return code.)
|
||||||
|
question q(reader);
|
||||||
|
std::vector<answer> answers;
|
||||||
|
for (size_t i = 0; i < rq_info.number_of_answers; i++)
|
||||||
|
{
|
||||||
|
answer a(reader);
|
||||||
|
answers.push_back(std::move(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
BLT_INFO("DOMAIN: %s", q().c_str());
|
||||||
|
if (STRICT_MATCHING && BLT_CONTAINS(DISALLOWED_DOMAINS, q()))
|
||||||
|
process_answers(answers);
|
||||||
|
else if (!STRICT_MATCHING)
|
||||||
|
{
|
||||||
|
// linear search the domains for contains. Maybe find a better way to do this.
|
||||||
|
for (const auto& v : DISALLOWED_DOMAINS)
|
||||||
|
if (blt::string::contains(q(), v))
|
||||||
|
process_answers(answers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return_send_buffer.write(forward_recv_buffer.data(), info.HEADER_END);
|
||||||
|
auto question_offset = return_send_buffer.size();
|
||||||
|
return_send_buffer.write(q);
|
||||||
|
for (const answer& a : answers)
|
||||||
|
{
|
||||||
|
BLT_TRACE("Writing answer with type of %d", a.type());
|
||||||
|
a.reset(question_offset);
|
||||||
|
return_send_buffer.write(a);
|
||||||
|
}
|
||||||
|
return_send_buffer.write(reader.from(), rq_info.number_of_bytes - reader.last());
|
||||||
|
}
|
||||||
|
|
||||||
void run_udp_server()
|
void run_udp_server()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
asio::io_context io_context;
|
asio::io_context io_context;
|
||||||
|
|
||||||
//udp::socket socket(io_context, udp::endpoint(udp::v6(), 5555));
|
udp::socket socket(io_context, toUDPEndpoint(address));
|
||||||
udp::socket socket(io_context, udp::endpoint(asio::ip::address::from_string("::1"), SERVER_PORT));
|
|
||||||
|
|
||||||
std::array<unsigned char, 65535> recv_buf{};
|
blt::scoped_buffer<unsigned char> input_recv_buffer{PACKET_BUFFER_SIZE};
|
||||||
std::array<unsigned char, 65535> mod_recv_buf{};
|
blt::scoped_buffer<unsigned char> forward_recv_buffer{PACKET_BUFFER_SIZE};
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
udp::endpoint remote_endpoint;
|
udp::endpoint remote_endpoint;
|
||||||
size_t bytes = socket.receive_from(asio::buffer(recv_buf), remote_endpoint);
|
size_t bytes = socket.receive_from(asio::buffer(input_recv_buffer.data(), input_recv_buffer.size()), remote_endpoint);
|
||||||
|
|
||||||
// get the number of questions
|
auto rq_info = handle_forward_request(blt::network::sendUDPMessage, DNS_UDP_INFO, input_recv_buffer, bytes, forward_recv_buffer);
|
||||||
uint16_t questions; // yes I made this part of my library just for this :3
|
|
||||||
blt::mem::fromBytes(&recv_buf[4], questions); // i hate little endian
|
|
||||||
|
|
||||||
BLT_INFO("Bytes received: %d with %d questions", bytes, questions);
|
send_buffer return_send_buffer;
|
||||||
|
handle_response(DNS_UDP_INFO, return_send_buffer, rq_info, forward_recv_buffer);
|
||||||
// forward to google.
|
|
||||||
size_t out_bytes;
|
|
||||||
sendUDPMessage(DNS_SERVER_IP(), recv_buf.data(), bytes, mod_recv_buf, out_bytes);
|
|
||||||
|
|
||||||
uint16_t num_of_answers;
|
|
||||||
blt::mem::fromBytes(&mod_recv_buf[6], num_of_answers);
|
|
||||||
|
|
||||||
blt::byte_reader reader(mod_recv_buf.data(), mod_recv_buf.size());
|
|
||||||
|
|
||||||
BLT_INFO("Bytes answered: %d with %d answers", out_bytes, num_of_answers);
|
|
||||||
|
|
||||||
// no one actually does multiple questions. trying to do it in dig is not easy
|
|
||||||
// and the standard isn't really designed for this (how do we handle if one question errors but the other doesn't? there is only
|
|
||||||
// one return code.)
|
|
||||||
question q(reader);
|
|
||||||
std::vector<answer> answers;
|
|
||||||
for (int i = 0; i < num_of_answers; i++)
|
|
||||||
{
|
|
||||||
answer a(reader);
|
|
||||||
answers.push_back(std::move(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
BLT_INFO("DOMAIN: %s", q().c_str());
|
|
||||||
if (STRICT_MATCHING && BLT_CONTAINS(DISALLOWED_DOMAINS, q()))
|
|
||||||
process_answers(answers);
|
|
||||||
else if (!STRICT_MATCHING)
|
|
||||||
{
|
|
||||||
// linear search the domains for contains. Maybe find a better way to do this.
|
|
||||||
for (const auto& v : DISALLOWED_DOMAINS)
|
|
||||||
if (blt::string::contains(q(), v))
|
|
||||||
process_answers(answers);
|
|
||||||
}
|
|
||||||
|
|
||||||
send_buffer send;
|
|
||||||
send.write(mod_recv_buf.data(), 12);
|
|
||||||
auto question_offset = send.size();
|
|
||||||
send.write(q);
|
|
||||||
for (const answer& a : answers)
|
|
||||||
{
|
|
||||||
BLT_TRACE("Writing answer with type of %d", a.type());
|
|
||||||
a.reset(question_offset);
|
|
||||||
send.write(a);
|
|
||||||
}
|
|
||||||
send.write(reader.from(), out_bytes - reader.last());
|
|
||||||
|
|
||||||
asio::error_code ignored_error;
|
asio::error_code ignored_error;
|
||||||
socket.send_to(send.buffer(), remote_endpoint, 0, ignored_error);
|
socket.send_to(return_send_buffer.buffer(), remote_endpoint, 0, ignored_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
@ -410,74 +431,28 @@ void run_tcp_server()
|
||||||
{
|
{
|
||||||
asio::io_context io_context;
|
asio::io_context io_context;
|
||||||
|
|
||||||
tcp::acceptor acceptor(io_context, tcp::endpoint(asio::ip::address::from_string("::1"), SERVER_PORT));
|
tcp::acceptor acceptor(io_context, toTCPEndpoint(address));
|
||||||
|
|
||||||
std::array<unsigned char, 65535> recv_buf{};
|
blt::scoped_buffer<unsigned char> input_recv_buffer{PACKET_BUFFER_SIZE};
|
||||||
std::array<unsigned char, 65535> mod_recv_buf{};
|
blt::scoped_buffer<unsigned char> forward_recv_buffer{PACKET_BUFFER_SIZE};
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
tcp::socket socket(io_context);
|
tcp::socket socket(io_context);
|
||||||
acceptor.accept(socket);
|
acceptor.accept(socket);
|
||||||
|
|
||||||
asio::error_code error;
|
asio::error_code error;
|
||||||
size_t bytes = socket.read_some(asio::buffer(recv_buf), error);
|
size_t bytes = socket.read_some(asio::buffer(input_recv_buffer.data(), input_recv_buffer.size()), error);
|
||||||
if (error == asio::error::eof)
|
if (error == asio::error::eof)
|
||||||
break;
|
break;
|
||||||
else if (error)
|
else if (error)
|
||||||
throw asio::system_error(error);
|
throw asio::system_error(error);
|
||||||
|
|
||||||
// get the number of questions
|
auto rq_info = handle_forward_request(blt::network::sendTCPMessage, DNS_TCP_INFO, input_recv_buffer, bytes, forward_recv_buffer);
|
||||||
uint16_t questions; // yes I made this part of my library just for this :3
|
|
||||||
blt::mem::fromBytes(&recv_buf[6], questions); // i hate little endian
|
|
||||||
|
|
||||||
BLT_INFO("TCP Bytes received: %d with %d questions", bytes, questions);
|
send_buffer return_send_buffer;
|
||||||
|
handle_response(DNS_TCP_INFO, return_send_buffer, rq_info, forward_recv_buffer);
|
||||||
|
|
||||||
// forward to google.
|
asio::write(socket, return_send_buffer.buffer());
|
||||||
size_t out_bytes;
|
|
||||||
sendTCPMessage(DNS_SERVER_IP(), recv_buf.data(), bytes, mod_recv_buf, out_bytes);
|
|
||||||
|
|
||||||
uint16_t num_of_answers;
|
|
||||||
blt::mem::fromBytes(&mod_recv_buf[8], num_of_answers);
|
|
||||||
|
|
||||||
blt::byte_reader reader(mod_recv_buf.data(), mod_recv_buf.size(), true);
|
|
||||||
|
|
||||||
BLT_INFO("TCP Bytes answered: %d with %d answers", out_bytes, num_of_answers);
|
|
||||||
|
|
||||||
// no one actually does multiple questions. trying to do it in dig is not easy
|
|
||||||
// and the standard isn't really designed for this (how do we handle if one question errors but the other doesn't? there is only
|
|
||||||
// one return code.)
|
|
||||||
question q(reader);
|
|
||||||
std::vector<answer> answers;
|
|
||||||
for (int i = 0; i < num_of_answers; i++)
|
|
||||||
{
|
|
||||||
answer a(reader);
|
|
||||||
answers.push_back(std::move(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
BLT_INFO("TCP DOMAIN: %s", q().c_str());
|
|
||||||
if (STRICT_MATCHING && BLT_CONTAINS(DISALLOWED_DOMAINS, q()))
|
|
||||||
process_answers(answers);
|
|
||||||
else if (!STRICT_MATCHING)
|
|
||||||
{
|
|
||||||
// linear search the domains for contains. Maybe find a better way to do this.
|
|
||||||
for (const auto& v : DISALLOWED_DOMAINS)
|
|
||||||
if (blt::string::contains(q(), v))
|
|
||||||
process_answers(answers);
|
|
||||||
}
|
|
||||||
|
|
||||||
send_buffer send;
|
|
||||||
send.write(mod_recv_buf.data(), 12);
|
|
||||||
auto question_offset = send.size();
|
|
||||||
send.write(q);
|
|
||||||
for (const answer& a : answers)
|
|
||||||
{
|
|
||||||
BLT_TRACE("TCP Writing answer with type of %d", a.type());
|
|
||||||
a.reset(question_offset);
|
|
||||||
send.write(a);
|
|
||||||
}
|
|
||||||
send.write(reader.from(), out_bytes - reader.last());
|
|
||||||
|
|
||||||
asio::write(socket, send.buffer());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
|
Loading…
Reference in New Issue