|
|
|
/* MIT License
|
|
|
|
*
|
|
|
|
* Copyright (c) The c-ares project and its contributors
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
* Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*/
|
|
|
|
#include "ares-test.h"
|
|
|
|
#include "dns-proto.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
Autotools: rework to simplify and fix recent issues (#674)
Completely rework the autotools build system, issues have cropped up due to the complexity and could cause issues on even semi-modern Linux systems (Ubuntu 20.04 for example).
Changes include:
Remove all curl/xc/cares m4 helper files, they go overboard on detections of functions and datatypes. Go back to more plain autoconf macros as they've come a long way over the years.
Use known systems and heuristics to determine datatypes for functions like send() and recv(), rather than the error prone detection which required thousands of permutations and might still get it wrong.
Remove unneeded configure arguments like --enable-debug or --enable-optimize, its more common for people to simply pass their own CFLAGS on the command line.
Only require CARES_STATICLIB definition on Windows static builds, its not necessary ever for other systems, even when hiding non-public symbols.
Remove some function and definition detections that were never used in c-ares
The test framework is now embedded into the toplevel configure system, there was no need to chain build the test system as it is never built externally to c-ares.
As a side-effect of the changes, a configure run completes in about 25% of the original time.
This has been tested on various Linux distributions (of varying age), FreeBSD, MacOS, Windows (via MSYS2 with Mingw), and Solaris10/11 (by @dfandrich), AIX 7.3 (by @dfandrich). It is not unlikely that this may have broken more esoteric or legacy systems, and we'll likely need to be ready to accept bug reports and patches, but it has removed over 10k lines of build system code. It is very likely any issues that crop up will add far fewer lines of code to fix such systems.
Fixes Bug: #670
Fix By: Brad House (@bradh352)
11 months ago
|
|
|
#ifdef HAVE_SYS_IOCTL_H
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
#endif
|
|
|
|
extern "C" {
|
|
|
|
// Remove command-line defines of package variables for the test project...
|
|
|
|
#undef PACKAGE_NAME
|
|
|
|
#undef PACKAGE_BUGREPORT
|
|
|
|
#undef PACKAGE_STRING
|
|
|
|
#undef PACKAGE_TARNAME
|
|
|
|
// ... so we can include the library's config without symbol redefinitions.
|
|
|
|
#include "ares_private.h"
|
|
|
|
#include "ares_inet_net_pton.h"
|
|
|
|
#include "ares_data.h"
|
|
|
|
#include "str/ares_strsplit.h"
|
|
|
|
#include "dsa/ares_htable.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_UIO_H
|
|
|
|
# include <sys/uio.h>
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace ares {
|
|
|
|
namespace test {
|
|
|
|
|
|
|
|
#ifndef CARES_SYMBOL_HIDING
|
|
|
|
void CheckPtoN4(int size, unsigned int value, const char *input) {
|
|
|
|
struct in_addr a4;
|
|
|
|
a4.s_addr = 0;
|
|
|
|
uint32_t expected = htonl(value);
|
|
|
|
EXPECT_EQ(size, ares_inet_net_pton(AF_INET, input, &a4, sizeof(a4)))
|
|
|
|
<< " for input " << input;
|
|
|
|
EXPECT_EQ(expected, a4.s_addr) << " for input " << input;
|
|
|
|
}
|
|
|
|
|
bug fix: new ares_strsplit (#492)
* add ares_strsplit unit test
The test reveals a bug in the implementation of ares_strsplit when the
make_set parameter is set to 1, as distinct domains are confused for
equal:
out = ares_strsplit("example.com, example.co", ", ", 1, &n);
evaluates to n = 1 with out = { "example.com" }.
* bugfix and cleanup of ares_strsplit
The purpose of ares_strsplit in c-ares is to split a comma-delimited
string of unique (up to letter case) domains. However, because the
terminating NUL byte was not checked in the substrings when comparing
for uniqueness, the function would sometimes drop domains it should
not. For example,
ares_strsplit("example.com, example.co", ",")
would only result in a single domain "example.com".
Aside from this bugfix, the following cleanup is performed:
1. The tokenization now happens with the help of strcspn instead of the
custom function is_delim.
2. The function list_contains has been inlined.
3. The interface of ares_strsplit has been simplified by removing the
parameter make_set since in practice it was always 1.
4. There are fewer passes over the input string.
5. We resize the table using realloc() down to its minimum size.
6. The docstring of ares_strsplit is updated and also a couple typos
are fixed.
There occurs a single use of ares_strsplit and since the make_set
parameter has been removed, the call in ares_init.c is modified
accordingly. The unit test for ares_strsplit is also updated.
Fix By: Nikolaos Chatzikonstantinou (@createyourpersonalaccount)
2 years ago
|
|
|
TEST_F(LibraryTest, Strsplit) {
|
|
|
|
using std::vector;
|
|
|
|
using std::string;
|
|
|
|
size_t n;
|
|
|
|
struct {
|
|
|
|
vector<string> inputs;
|
|
|
|
vector<string> delimiters;
|
|
|
|
vector<vector<string>> expected;
|
|
|
|
} data = {
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
" ",
|
|
|
|
" ",
|
|
|
|
"example.com, example.co",
|
|
|
|
" a, b, A,c, d, e,,,D,e,e,E",
|
|
|
|
},
|
|
|
|
{ ", ", ", ", ", ", ", ", ", " },
|
|
|
|
{
|
|
|
|
{}, {}, {},
|
|
|
|
{ "example.com", "example.co" },
|
|
|
|
{ "a", "b", "c", "d", "e" },
|
|
|
|
},
|
|
|
|
};
|
|
|
|
for(size_t i = 0; i < data.inputs.size(); i++) {
|
|
|
|
char **out = ares_strsplit(data.inputs.at(i).c_str(),
|
bug fix: new ares_strsplit (#492)
* add ares_strsplit unit test
The test reveals a bug in the implementation of ares_strsplit when the
make_set parameter is set to 1, as distinct domains are confused for
equal:
out = ares_strsplit("example.com, example.co", ", ", 1, &n);
evaluates to n = 1 with out = { "example.com" }.
* bugfix and cleanup of ares_strsplit
The purpose of ares_strsplit in c-ares is to split a comma-delimited
string of unique (up to letter case) domains. However, because the
terminating NUL byte was not checked in the substrings when comparing
for uniqueness, the function would sometimes drop domains it should
not. For example,
ares_strsplit("example.com, example.co", ",")
would only result in a single domain "example.com".
Aside from this bugfix, the following cleanup is performed:
1. The tokenization now happens with the help of strcspn instead of the
custom function is_delim.
2. The function list_contains has been inlined.
3. The interface of ares_strsplit has been simplified by removing the
parameter make_set since in practice it was always 1.
4. There are fewer passes over the input string.
5. We resize the table using realloc() down to its minimum size.
6. The docstring of ares_strsplit is updated and also a couple typos
are fixed.
There occurs a single use of ares_strsplit and since the make_set
parameter has been removed, the call in ares_init.c is modified
accordingly. The unit test for ares_strsplit is also updated.
Fix By: Nikolaos Chatzikonstantinou (@createyourpersonalaccount)
2 years ago
|
|
|
data.delimiters.at(i).c_str(), &n);
|
|
|
|
if(data.expected.at(i).size() == 0) {
|
|
|
|
EXPECT_EQ(out, nullptr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
EXPECT_EQ(n, data.expected.at(i).size());
|
|
|
|
for(size_t j = 0; j < n && j < data.expected.at(i).size(); j++) {
|
|
|
|
EXPECT_STREQ(out[j], data.expected.at(i).at(j).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ares_strsplit_free(out, n);
|
bug fix: new ares_strsplit (#492)
* add ares_strsplit unit test
The test reveals a bug in the implementation of ares_strsplit when the
make_set parameter is set to 1, as distinct domains are confused for
equal:
out = ares_strsplit("example.com, example.co", ", ", 1, &n);
evaluates to n = 1 with out = { "example.com" }.
* bugfix and cleanup of ares_strsplit
The purpose of ares_strsplit in c-ares is to split a comma-delimited
string of unique (up to letter case) domains. However, because the
terminating NUL byte was not checked in the substrings when comparing
for uniqueness, the function would sometimes drop domains it should
not. For example,
ares_strsplit("example.com, example.co", ",")
would only result in a single domain "example.com".
Aside from this bugfix, the following cleanup is performed:
1. The tokenization now happens with the help of strcspn instead of the
custom function is_delim.
2. The function list_contains has been inlined.
3. The interface of ares_strsplit has been simplified by removing the
parameter make_set since in practice it was always 1.
4. There are fewer passes over the input string.
5. We resize the table using realloc() down to its minimum size.
6. The docstring of ares_strsplit is updated and also a couple typos
are fixed.
There occurs a single use of ares_strsplit and since the make_set
parameter has been removed, the call in ares_init.c is modified
accordingly. The unit test for ares_strsplit is also updated.
Fix By: Nikolaos Chatzikonstantinou (@createyourpersonalaccount)
2 years ago
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, InetNetPtoN) {
|
|
|
|
uint32_t expected;
|
|
|
|
struct in_addr a4;
|
|
|
|
struct in6_addr a6;
|
|
|
|
CheckPtoN4(4 * 8, 0x01020304, "1.2.3.4");
|
|
|
|
CheckPtoN4(4 * 8, 0x81010101, "129.1.1.1");
|
|
|
|
CheckPtoN4(4 * 8, 0xC0010101, "192.1.1.1");
|
|
|
|
CheckPtoN4(4 * 8, 0xE0010101, "224.1.1.1");
|
|
|
|
CheckPtoN4(4 * 8, 0xE1010101, "225.1.1.1");
|
|
|
|
CheckPtoN4(4, 0xE0000000, "224");
|
|
|
|
CheckPtoN4(4 * 8, 0xFD000000, "253");
|
|
|
|
CheckPtoN4(4 * 8, 0xF0010101, "240.1.1.1");
|
|
|
|
CheckPtoN4(4 * 8, 0x02030405, "02.3.4.5");
|
|
|
|
CheckPtoN4(3 * 8, 0x01020304, "1.2.3.4/24");
|
|
|
|
CheckPtoN4(3 * 8, 0x01020300, "1.2.3/24");
|
|
|
|
CheckPtoN4(2 * 8, 0xa0000000, "0xa");
|
|
|
|
CheckPtoN4(0, 0x02030405, "2.3.4.5/000");
|
|
|
|
CheckPtoN4(1 * 8, 0x01020000, "1.2/8");
|
|
|
|
CheckPtoN4(2 * 8, 0x01020000, "0x0102/16");
|
|
|
|
CheckPtoN4(4 * 8, 0x02030405, "02.3.4.5");
|
|
|
|
|
|
|
|
EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "::", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "::1", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "1234:5678::", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ff", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(23, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4/23", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(3 * 8, ares_inet_net_pton(AF_INET6, "12:34::ff/24", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "12:34::ff/0", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ffff:0.2", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(2, ares_inet_net_pton(AF_INET6, "0::00:00:00/2", &a6, sizeof(a6)));
|
|
|
|
|
|
|
|
// Various malformed versions
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, " ", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x ", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "x0", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0xXYZZY", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "xyzzy", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET+AF_INET6, "1.2.3.4", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "257.2.3.4", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "002.3.4.x", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "00.3.4.x", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.x", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5.6", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5.6/12", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4:5", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/120", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/1x", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "2.3.4.5/x", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/240", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/02", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/2y", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/y", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff/", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":x", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ": :1234", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "::12345", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234::2345:3456::0011", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234::", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1.2.3.4", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234:", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678:5678", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:257.2.3.4", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5.6", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.z", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3001.4", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3..4", &a6, sizeof(a6)));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.", &a6, sizeof(a6)));
|
|
|
|
|
|
|
|
// Hex constants are allowed.
|
|
|
|
EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x01020304", &a4, sizeof(a4)));
|
|
|
|
expected = htonl(0x01020304);
|
|
|
|
EXPECT_EQ(expected, a4.s_addr);
|
|
|
|
EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x0a0b0c0d", &a4, sizeof(a4)));
|
|
|
|
expected = htonl(0x0a0b0c0d);
|
|
|
|
EXPECT_EQ(expected, a4.s_addr);
|
|
|
|
EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x0A0B0C0D", &a4, sizeof(a4)));
|
|
|
|
expected = htonl(0x0a0b0c0d);
|
|
|
|
EXPECT_EQ(expected, a4.s_addr);
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0xyz", &a4, sizeof(a4)));
|
|
|
|
EXPECT_EQ(4 * 8, ares_inet_net_pton(AF_INET, "0x1122334", &a4, sizeof(a4)));
|
|
|
|
expected = htonl(0x11223340);
|
|
|
|
EXPECT_EQ(expected, a4.s_addr); // huh?
|
|
|
|
|
|
|
|
// No room, no room.
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "1.2.3.4", &a4, sizeof(a4) - 1));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ff", &a6, sizeof(a6) - 1));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x01020304", &a4, 2));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x01020304", &a4, 0));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0a0b0c0d", &a4, 0));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x0xyz", &a4, 0));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "0x1122334", &a4, sizeof(a4) - 1));
|
|
|
|
EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "253", &a4, sizeof(a4) - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, FreeLongChain) {
|
|
|
|
struct ares_addr_node *data = nullptr;
|
|
|
|
for (int ii = 0; ii < 100000; ii++) {
|
|
|
|
struct ares_addr_node *prev = (struct ares_addr_node*)ares_malloc_data(ARES_DATATYPE_ADDR_NODE);
|
|
|
|
prev->next = data;
|
|
|
|
data = prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
ares_free_data(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, MallocDataFail) {
|
|
|
|
EXPECT_EQ(nullptr, ares_malloc_data((ares_datatype)99));
|
|
|
|
SetAllocSizeFail(sizeof(struct ares_data));
|
|
|
|
EXPECT_EQ(nullptr, ares_malloc_data(ARES_DATATYPE_MX_REPLY));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Misc, OnionDomain) {
|
|
|
|
EXPECT_EQ(0, ares_is_onion_domain("onion.no"));
|
|
|
|
EXPECT_EQ(0, ares_is_onion_domain(".onion.no"));
|
|
|
|
EXPECT_EQ(1, ares_is_onion_domain(".onion"));
|
|
|
|
EXPECT_EQ(1, ares_is_onion_domain(".onion."));
|
|
|
|
EXPECT_EQ(1, ares_is_onion_domain("yes.onion"));
|
|
|
|
EXPECT_EQ(1, ares_is_onion_domain("yes.onion."));
|
|
|
|
EXPECT_EQ(1, ares_is_onion_domain("YES.ONION"));
|
|
|
|
EXPECT_EQ(1, ares_is_onion_domain("YES.ONION."));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, CatDomain) {
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
ares_cat_domain("foo", "example.net", &s);
|
|
|
|
EXPECT_STREQ("foo.example.net", s);
|
|
|
|
ares_free(s);
|
|
|
|
|
|
|
|
ares_cat_domain("foo", ".", &s);
|
|
|
|
EXPECT_STREQ("foo.", s);
|
|
|
|
ares_free(s);
|
|
|
|
|
|
|
|
ares_cat_domain("foo", "example.net.", &s);
|
|
|
|
EXPECT_STREQ("foo.example.net.", s);
|
|
|
|
ares_free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, SlistMisuse) {
|
|
|
|
EXPECT_EQ(NULL, ares_slist_create(NULL, NULL, NULL));
|
|
|
|
ares_slist_replace_destructor(NULL, NULL);
|
|
|
|
EXPECT_EQ(NULL, ares_slist_insert(NULL, NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_find(NULL, NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_first(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_last(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_next(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_prev(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_val(NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_slist_len(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_parent(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_first_val(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_last_val(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_slist_node_claim(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, IfaceIPs) {
|
|
|
|
ares_status_t status;
|
|
|
|
ares_iface_ips_t *ips = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
status = ares_iface_ips(&ips, ARES_IFACE_IP_DEFAULT, NULL);
|
|
|
|
EXPECT_TRUE(status == ARES_SUCCESS || status == ARES_ENOTIMP);
|
|
|
|
|
|
|
|
/* Not implemented, can't run tests */
|
|
|
|
if (status == ARES_ENOTIMP)
|
|
|
|
return;
|
|
|
|
|
|
|
|
EXPECT_NE(nullptr, ips);
|
|
|
|
|
|
|
|
for (i=0; i<ares_iface_ips_cnt(ips); i++) {
|
|
|
|
const char *name = ares_iface_ips_get_name(ips, i);
|
|
|
|
EXPECT_NE(nullptr, name);
|
|
|
|
int flags = (int)ares_iface_ips_get_flags(ips, i);
|
|
|
|
EXPECT_NE(0, (int)flags);
|
|
|
|
EXPECT_NE(nullptr, ares_iface_ips_get_addr(ips, i));
|
|
|
|
EXPECT_NE(0, ares_iface_ips_get_netmask(ips, i));
|
|
|
|
if (flags & ARES_IFACE_IP_LINKLOCAL && flags & ARES_IFACE_IP_V6) {
|
|
|
|
/* Hmm, seems not to work at least on MacOS
|
|
|
|
* EXPECT_NE(0, ares_iface_ips_get_ll_scope(ips, i));
|
|
|
|
*/
|
|
|
|
} else {
|
|
|
|
EXPECT_EQ(0, ares_iface_ips_get_ll_scope(ips, i));
|
|
|
|
}
|
|
|
|
unsigned int idx = ares_os_if_nametoindex(name);
|
|
|
|
EXPECT_NE(0, idx);
|
|
|
|
char namebuf[256];
|
|
|
|
EXPECT_EQ(std::string(ares_os_if_indextoname(idx, namebuf, sizeof(namebuf))), std::string(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Negative checking */
|
|
|
|
ares_iface_ips_get_name(ips, ares_iface_ips_cnt(ips));
|
|
|
|
ares_iface_ips_get_flags(ips, ares_iface_ips_cnt(ips));
|
|
|
|
ares_iface_ips_get_addr(ips, ares_iface_ips_cnt(ips));
|
|
|
|
ares_iface_ips_get_netmask(ips, ares_iface_ips_cnt(ips));
|
|
|
|
ares_iface_ips_get_ll_scope(ips, ares_iface_ips_cnt(ips));
|
|
|
|
|
|
|
|
ares_iface_ips(NULL, ARES_IFACE_IP_DEFAULT, NULL);
|
|
|
|
ares_iface_ips_cnt(NULL);
|
|
|
|
ares_iface_ips_get_name(NULL, 0);
|
|
|
|
ares_iface_ips_get_flags(NULL, 0);
|
|
|
|
ares_iface_ips_get_addr(NULL, 0);
|
|
|
|
ares_iface_ips_get_netmask(NULL, 0);
|
|
|
|
ares_iface_ips_get_ll_scope(NULL, 0);
|
|
|
|
ares_iface_ips_destroy(NULL);
|
|
|
|
ares_os_if_nametoindex(NULL);
|
|
|
|
ares_os_if_indextoname(0, NULL, 0);
|
|
|
|
|
|
|
|
ares_iface_ips_destroy(ips);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableMisuse) {
|
|
|
|
EXPECT_EQ(NULL, ares_htable_create(NULL, NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_insert(NULL, NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_htable_get(NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_remove(NULL, NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_htable_num_keys(NULL));
|
|
|
|
}
|
URI parser/writer for ares_set_servers_csv()/ares_get_servers_csv() (#882)
The DNS server format is insufficient for future configurations, such as
supporting DNS over TLS (DoT) and DNS over HTTPS (DoH), as well as
additional functionality such as domain-specific servers. Already, in
the case where different UDP and TCP ports are used, it is impossible to
represent in the current format.
In order to try to use some standardized format, we are going to define
our own URI schemes that should be parse-able by any URI parser. The new
scheme will only be used when the configuration cannot otherwise be
expressed using the current `ipaddr%iface:port` format, which is the
format used as the nameserver configuration in `/etc/resolv.conf`.
However, the parser `ares_set_servers_csv()` shall accept the new URI
scheme format even when it is not necessary.
This PR implements a URI parser and writer and hooks the basic usage
into `ares_set_servers_csv()` and `ares_get_servers_csv()` as well as
provides updated documentation in the relevant manpages.
We will define these URI schemes:
* `dns://` - Normal DNS server (UDP + TCP). We need to be careful not to
conflict with query params defined in
https://datatracker.ietf.org/doc/html/rfc4501 since we'd technically be
extending this URI scheme. Port defaults to `53`.
* `dns+tls://` - DNS over TLS. Port defaults to `853`.
* `dns+https://` - DNS over HTTPS. Port defaults to `443`.
We initially will define these query parameters (additional arguments
may be required in the future to specify options such as TLS certificate
validation rules):
* `tcpport` - TCP port to use, only for `dns://` scheme. The `port`
specified as part of the `authority` component of the URI will be used
for both UDP and TCP by default, this option will override the TCP port.
* `ipaddr` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains a hostname, this is used to
specify the ip address of the hostname. If not specified, will need to
use a non-secure server to perform a DNS lookup to retrieve this
information. It is always recommended to have both the ip address and
fully qualified domain name specified.
* `hostname` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains an ip address, this is used to
specify the fully qualified domain name of the server. If not specified,
will need to use a non-secure server to perform a DNS reverse lookup to
retrieve this information. It is always recommended to have both the ip
address and fully qualified domain name specified.
* `domain` - If specified, this server is a domain-specific server. Any
queries for this domain will be routed to this server. Multiple servers
may be tagged with the same domain.
Examples:
```
dns://8.8.8.8
dns://[2001:4860:4860::8888]
dns://[fe80::b542:84df:1719:65e3%en0]
dns://192.168.1.1:55
dns://192.168.1.1?tcpport=1153
dns://10.0.1.1?domain=myvpn.com
dns+tls://8.8.8.8?hostname=dns.google
dns+tls://one.one.one.one?ipaddr=1.1.1.1
```
NOTE: While we are defining the scheme for things like domain-specific
servers, DNS over TLS and DNS over HTTPS, the underlying implementations
for those features do not yet exist and therefore will result in errors
if they are attempted to be used.
### Non-compliance in implementation
All these could be easily implemented/fixed if desired, however any such
changes would be of no use to the current c-ares usage of URIs:
* Does not currently support relative references
* Requires use of the authority section, blank is not allowed
* The query string is interpreted to be in
[application/x-www-form-urlencoded](https://en.wikipedia.org/wiki/Application/x-www-form-urlencoded)
format only and will result in parse errors if it is not. This is the
most common format used, however technically not valid to mandate this
format is used. We could add flags in the future to treat the query
string as opaque and leave it to the user to process. Or we could
internally have a list of schemes that use this format.
* [IDNA](https://en.wikipedia.org/wiki/Internationalized_domain_name) is
not supported.
* Does not support hex-encoded IPv4 addresses (this is compliant with RFC3986, but not WHATWG)
Authored-By: Brad House (@bradh352)
3 months ago
|
|
|
|
|
|
|
TEST_F(LibraryTest, URI) {
|
|
|
|
struct {
|
|
|
|
ares_bool_t success;
|
|
|
|
const char *uri;
|
|
|
|
const char *alt_match_uri;
|
|
|
|
} tests[] = {
|
|
|
|
{ ARES_TRUE, "https://www.example.com", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com:8443", NULL },
|
|
|
|
{ ARES_TRUE, "https://user:password@www.example.com", NULL },
|
|
|
|
{ ARES_TRUE, "https://user%25:password@www.example.com", NULL },
|
|
|
|
{ ARES_TRUE, "https://user:password%25@www.example.com", NULL },
|
|
|
|
{ ARES_TRUE, "https://user@www.example.com", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com/path", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com/path/", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com/a/../", "https://www.example.com/" },
|
|
|
|
{ ARES_TRUE, "https://www.example.com/../a/", "https://www.example.com/a/" },
|
|
|
|
{ ARES_TRUE, "https://www.example.com/.././../a/", "https://www.example.com/a/" },
|
|
|
|
{ ARES_TRUE, "https://www.example.com/.././../a//b/c/d/../../", "https://www.example.com/a/b/" },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key=val", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key=", "https://www.example.com?key" },
|
|
|
|
{ ARES_TRUE, "https://www.example.com#fragment", NULL },
|
|
|
|
{ ARES_TRUE, "https://user:password@www.example.com/path", NULL },
|
|
|
|
{ ARES_TRUE, "https://user:password@www.example.com/path#fragment", NULL },
|
|
|
|
{ ARES_TRUE, "https://user:password@www.example.com/path?key=val", NULL },
|
|
|
|
{ ARES_TRUE, "https://user:password@www.example.com/path?key=val#fragment", NULL },
|
|
|
|
{ ARES_TRUE, "https://user:password@www.example.com/path?key=val#fragment/with?chars", NULL },
|
URI parser/writer for ares_set_servers_csv()/ares_get_servers_csv() (#882)
The DNS server format is insufficient for future configurations, such as
supporting DNS over TLS (DoT) and DNS over HTTPS (DoH), as well as
additional functionality such as domain-specific servers. Already, in
the case where different UDP and TCP ports are used, it is impossible to
represent in the current format.
In order to try to use some standardized format, we are going to define
our own URI schemes that should be parse-able by any URI parser. The new
scheme will only be used when the configuration cannot otherwise be
expressed using the current `ipaddr%iface:port` format, which is the
format used as the nameserver configuration in `/etc/resolv.conf`.
However, the parser `ares_set_servers_csv()` shall accept the new URI
scheme format even when it is not necessary.
This PR implements a URI parser and writer and hooks the basic usage
into `ares_set_servers_csv()` and `ares_get_servers_csv()` as well as
provides updated documentation in the relevant manpages.
We will define these URI schemes:
* `dns://` - Normal DNS server (UDP + TCP). We need to be careful not to
conflict with query params defined in
https://datatracker.ietf.org/doc/html/rfc4501 since we'd technically be
extending this URI scheme. Port defaults to `53`.
* `dns+tls://` - DNS over TLS. Port defaults to `853`.
* `dns+https://` - DNS over HTTPS. Port defaults to `443`.
We initially will define these query parameters (additional arguments
may be required in the future to specify options such as TLS certificate
validation rules):
* `tcpport` - TCP port to use, only for `dns://` scheme. The `port`
specified as part of the `authority` component of the URI will be used
for both UDP and TCP by default, this option will override the TCP port.
* `ipaddr` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains a hostname, this is used to
specify the ip address of the hostname. If not specified, will need to
use a non-secure server to perform a DNS lookup to retrieve this
information. It is always recommended to have both the ip address and
fully qualified domain name specified.
* `hostname` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains an ip address, this is used to
specify the fully qualified domain name of the server. If not specified,
will need to use a non-secure server to perform a DNS reverse lookup to
retrieve this information. It is always recommended to have both the ip
address and fully qualified domain name specified.
* `domain` - If specified, this server is a domain-specific server. Any
queries for this domain will be routed to this server. Multiple servers
may be tagged with the same domain.
Examples:
```
dns://8.8.8.8
dns://[2001:4860:4860::8888]
dns://[fe80::b542:84df:1719:65e3%en0]
dns://192.168.1.1:55
dns://192.168.1.1?tcpport=1153
dns://10.0.1.1?domain=myvpn.com
dns+tls://8.8.8.8?hostname=dns.google
dns+tls://one.one.one.one?ipaddr=1.1.1.1
```
NOTE: While we are defining the scheme for things like domain-specific
servers, DNS over TLS and DNS over HTTPS, the underlying implementations
for those features do not yet exist and therefore will result in errors
if they are attempted to be used.
### Non-compliance in implementation
All these could be easily implemented/fixed if desired, however any such
changes would be of no use to the current c-ares usage of URIs:
* Does not currently support relative references
* Requires use of the authority section, blank is not allowed
* The query string is interpreted to be in
[application/x-www-form-urlencoded](https://en.wikipedia.org/wiki/Application/x-www-form-urlencoded)
format only and will result in parse errors if it is not. This is the
most common format used, however technically not valid to mandate this
format is used. We could add flags in the future to treat the query
string as opaque and leave it to the user to process. Or we could
internally have a list of schemes that use this format.
* [IDNA](https://en.wikipedia.org/wiki/Internationalized_domain_name) is
not supported.
* Does not support hex-encoded IPv4 addresses (this is compliant with RFC3986, but not WHATWG)
Authored-By: Brad House (@bradh352)
3 months ago
|
|
|
{ ARES_TRUE, "HTTPS://www.example.com", "https://www.example.com" },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key=hello+world", "https://www.example.com?key=hello%20world" },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key=val%26", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key%26=val", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key=Aa2-._~/?!$'()*,;:@", NULL },
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key1=val1&key2=val2&key3=val3&key4=val4", "ignore" }, /* keys get randomized, can't match */
|
|
|
|
{ ARES_TRUE, "https://www.example.com?key=%41%61%32%2D%2E%5f%7e%2F%3F%21%24%27%28%29%2a%2C%3b%3a%40", "https://www.example.com?key=Aa2-._~/?!$'()*,;:@" },
|
|
|
|
{ ARES_TRUE, "dns+tls://192.168.1.1:53", NULL },
|
|
|
|
{ ARES_TRUE, "dns+tls://[fe80::1]:53", NULL },
|
|
|
|
{ ARES_TRUE, "dns://[fe80::b542:84df:1719:65e3%en0]", NULL },
|
|
|
|
{ ARES_TRUE, "dns+tls://[fe80:00::00:1]:53", "dns+tls://[fe80::1]:53" },
|
|
|
|
{ ARES_TRUE, "d.n+s-tls://www.example.com", NULL },
|
|
|
|
{ ARES_FALSE, "dns*tls://www.example.com", NULL }, /* invalid scheme character */
|
|
|
|
{ ARES_FALSE, "0dns://www.example.com", NULL }, /* dns can't start with digits */
|
URI parser/writer for ares_set_servers_csv()/ares_get_servers_csv() (#882)
The DNS server format is insufficient for future configurations, such as
supporting DNS over TLS (DoT) and DNS over HTTPS (DoH), as well as
additional functionality such as domain-specific servers. Already, in
the case where different UDP and TCP ports are used, it is impossible to
represent in the current format.
In order to try to use some standardized format, we are going to define
our own URI schemes that should be parse-able by any URI parser. The new
scheme will only be used when the configuration cannot otherwise be
expressed using the current `ipaddr%iface:port` format, which is the
format used as the nameserver configuration in `/etc/resolv.conf`.
However, the parser `ares_set_servers_csv()` shall accept the new URI
scheme format even when it is not necessary.
This PR implements a URI parser and writer and hooks the basic usage
into `ares_set_servers_csv()` and `ares_get_servers_csv()` as well as
provides updated documentation in the relevant manpages.
We will define these URI schemes:
* `dns://` - Normal DNS server (UDP + TCP). We need to be careful not to
conflict with query params defined in
https://datatracker.ietf.org/doc/html/rfc4501 since we'd technically be
extending this URI scheme. Port defaults to `53`.
* `dns+tls://` - DNS over TLS. Port defaults to `853`.
* `dns+https://` - DNS over HTTPS. Port defaults to `443`.
We initially will define these query parameters (additional arguments
may be required in the future to specify options such as TLS certificate
validation rules):
* `tcpport` - TCP port to use, only for `dns://` scheme. The `port`
specified as part of the `authority` component of the URI will be used
for both UDP and TCP by default, this option will override the TCP port.
* `ipaddr` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains a hostname, this is used to
specify the ip address of the hostname. If not specified, will need to
use a non-secure server to perform a DNS lookup to retrieve this
information. It is always recommended to have both the ip address and
fully qualified domain name specified.
* `hostname` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains an ip address, this is used to
specify the fully qualified domain name of the server. If not specified,
will need to use a non-secure server to perform a DNS reverse lookup to
retrieve this information. It is always recommended to have both the ip
address and fully qualified domain name specified.
* `domain` - If specified, this server is a domain-specific server. Any
queries for this domain will be routed to this server. Multiple servers
may be tagged with the same domain.
Examples:
```
dns://8.8.8.8
dns://[2001:4860:4860::8888]
dns://[fe80::b542:84df:1719:65e3%en0]
dns://192.168.1.1:55
dns://192.168.1.1?tcpport=1153
dns://10.0.1.1?domain=myvpn.com
dns+tls://8.8.8.8?hostname=dns.google
dns+tls://one.one.one.one?ipaddr=1.1.1.1
```
NOTE: While we are defining the scheme for things like domain-specific
servers, DNS over TLS and DNS over HTTPS, the underlying implementations
for those features do not yet exist and therefore will result in errors
if they are attempted to be used.
### Non-compliance in implementation
All these could be easily implemented/fixed if desired, however any such
changes would be of no use to the current c-ares usage of URIs:
* Does not currently support relative references
* Requires use of the authority section, blank is not allowed
* The query string is interpreted to be in
[application/x-www-form-urlencoded](https://en.wikipedia.org/wiki/Application/x-www-form-urlencoded)
format only and will result in parse errors if it is not. This is the
most common format used, however technically not valid to mandate this
format is used. We could add flags in the future to treat the query
string as opaque and leave it to the user to process. Or we could
internally have a list of schemes that use this format.
* [IDNA](https://en.wikipedia.org/wiki/Internationalized_domain_name) is
not supported.
* Does not support hex-encoded IPv4 addresses (this is compliant with RFC3986, but not WHATWG)
Authored-By: Brad House (@bradh352)
3 months ago
|
|
|
{ ARES_FALSE, "https://www.example.com?key=val%01", NULL }, /* non-printable character */
|
|
|
|
{ ARES_FALSE, "abcdef0123456789://www.example.com", NULL }, /* scheme too long */
|
|
|
|
{ ARES_FALSE, "www.example.com", NULL }, /* missing scheme */
|
|
|
|
{ ARES_FALSE, "https://www.example.com?key=val%0", NULL }, /* truncated uri-encoding */
|
|
|
|
{ ARES_FALSE, "https://www.example.com?key=val%AZ", NULL }, /* invalid uri-encoding sequence */
|
|
|
|
{ ARES_FALSE, "https://www.example.com?key=hello world", NULL }, /* invalid character in query value */
|
|
|
|
{ ARES_FALSE, "https://:password@www.example.com", NULL }, /* can't have password without username */
|
|
|
|
{ ARES_FALSE, "dns+tls://[fe8G::1]", NULL }, /* invalid ipv6 address */
|
|
|
|
|
|
|
|
{ ARES_FALSE, NULL, NULL }
|
|
|
|
};
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i=0; tests[i].uri != NULL; i++) {
|
|
|
|
ares_uri_t *uri = NULL;
|
|
|
|
ares_status_t status;
|
|
|
|
|
|
|
|
if (verbose) std::cerr << "Testing " << tests[i].uri << std::endl;
|
|
|
|
status = ares_uri_parse(&uri, tests[i].uri);
|
|
|
|
if (tests[i].success) {
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, status);
|
|
|
|
} else {
|
|
|
|
EXPECT_NE(ARES_SUCCESS, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status == ARES_SUCCESS) {
|
|
|
|
char *out = NULL;
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_uri_write(&out, uri));
|
|
|
|
if (tests[i].alt_match_uri == NULL || strcmp(tests[i].alt_match_uri, "ignore") != 0) {
|
|
|
|
EXPECT_STRCASEEQ(tests[i].alt_match_uri == NULL?tests[i].uri:tests[i].alt_match_uri, out);
|
|
|
|
}
|
|
|
|
ares_free(out);
|
|
|
|
}
|
|
|
|
ares_uri_destroy(uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid tests */
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_scheme(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_scheme(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_username(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_username(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_password(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_password(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_host(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_host(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_port(NULL, 0));
|
|
|
|
EXPECT_EQ(0, ares_uri_get_port(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_path(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_path(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_query_key(NULL, NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_del_query_key(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_query_key(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_query_keys(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_set_fragment(NULL, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_uri_get_fragment(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_write_buf(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_write(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_parse_buf(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_uri_parse_buf(NULL, NULL));
|
URI parser/writer for ares_set_servers_csv()/ares_get_servers_csv() (#882)
The DNS server format is insufficient for future configurations, such as
supporting DNS over TLS (DoT) and DNS over HTTPS (DoH), as well as
additional functionality such as domain-specific servers. Already, in
the case where different UDP and TCP ports are used, it is impossible to
represent in the current format.
In order to try to use some standardized format, we are going to define
our own URI schemes that should be parse-able by any URI parser. The new
scheme will only be used when the configuration cannot otherwise be
expressed using the current `ipaddr%iface:port` format, which is the
format used as the nameserver configuration in `/etc/resolv.conf`.
However, the parser `ares_set_servers_csv()` shall accept the new URI
scheme format even when it is not necessary.
This PR implements a URI parser and writer and hooks the basic usage
into `ares_set_servers_csv()` and `ares_get_servers_csv()` as well as
provides updated documentation in the relevant manpages.
We will define these URI schemes:
* `dns://` - Normal DNS server (UDP + TCP). We need to be careful not to
conflict with query params defined in
https://datatracker.ietf.org/doc/html/rfc4501 since we'd technically be
extending this URI scheme. Port defaults to `53`.
* `dns+tls://` - DNS over TLS. Port defaults to `853`.
* `dns+https://` - DNS over HTTPS. Port defaults to `443`.
We initially will define these query parameters (additional arguments
may be required in the future to specify options such as TLS certificate
validation rules):
* `tcpport` - TCP port to use, only for `dns://` scheme. The `port`
specified as part of the `authority` component of the URI will be used
for both UDP and TCP by default, this option will override the TCP port.
* `ipaddr` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains a hostname, this is used to
specify the ip address of the hostname. If not specified, will need to
use a non-secure server to perform a DNS lookup to retrieve this
information. It is always recommended to have both the ip address and
fully qualified domain name specified.
* `hostname` - Only for `dns+tls://` and `dns+https://`. If the
`authority` component of the URI contains an ip address, this is used to
specify the fully qualified domain name of the server. If not specified,
will need to use a non-secure server to perform a DNS reverse lookup to
retrieve this information. It is always recommended to have both the ip
address and fully qualified domain name specified.
* `domain` - If specified, this server is a domain-specific server. Any
queries for this domain will be routed to this server. Multiple servers
may be tagged with the same domain.
Examples:
```
dns://8.8.8.8
dns://[2001:4860:4860::8888]
dns://[fe80::b542:84df:1719:65e3%en0]
dns://192.168.1.1:55
dns://192.168.1.1?tcpport=1153
dns://10.0.1.1?domain=myvpn.com
dns+tls://8.8.8.8?hostname=dns.google
dns+tls://one.one.one.one?ipaddr=1.1.1.1
```
NOTE: While we are defining the scheme for things like domain-specific
servers, DNS over TLS and DNS over HTTPS, the underlying implementations
for those features do not yet exist and therefore will result in errors
if they are attempted to be used.
### Non-compliance in implementation
All these could be easily implemented/fixed if desired, however any such
changes would be of no use to the current c-ares usage of URIs:
* Does not currently support relative references
* Requires use of the authority section, blank is not allowed
* The query string is interpreted to be in
[application/x-www-form-urlencoded](https://en.wikipedia.org/wiki/Application/x-www-form-urlencoded)
format only and will result in parse errors if it is not. This is the
most common format used, however technically not valid to mandate this
format is used. We could add flags in the future to treat the query
string as opaque and leave it to the user to process. Or we could
internally have a list of schemes that use this format.
* [IDNA](https://en.wikipedia.org/wiki/Internationalized_domain_name) is
not supported.
* Does not support hex-encoded IPv4 addresses (this is compliant with RFC3986, but not WHATWG)
Authored-By: Brad House (@bradh352)
3 months ago
|
|
|
}
|
|
|
|
#endif /* !CARES_SYMBOL_HIDING */
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, InetPtoN) {
|
|
|
|
struct in_addr a4;
|
|
|
|
struct in6_addr a6;
|
|
|
|
EXPECT_EQ(1, ares_inet_pton(AF_INET, "1.2.3.4", &a4));
|
|
|
|
EXPECT_EQ(1, ares_inet_pton(AF_INET6, "12:34::ff", &a6));
|
|
|
|
EXPECT_EQ(1, ares_inet_pton(AF_INET6, "12:34::ffff:1.2.3.4", &a6));
|
|
|
|
EXPECT_EQ(0, ares_inet_pton(AF_INET, "xyzzy", &a4));
|
|
|
|
EXPECT_EQ(-1, ares_inet_pton(AF_INET+AF_INET6, "1.2.3.4", &a4));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, FreeCorruptData) {
|
|
|
|
// ares_free_data(p) expects that there is a type field and a marker
|
|
|
|
// field in the memory before p. Feed it incorrect versions of each.
|
|
|
|
struct ares_data *data = (struct ares_data *)malloc(sizeof(struct ares_data));
|
|
|
|
void* p = &(data->data);
|
|
|
|
|
|
|
|
// Invalid type
|
|
|
|
data->type = (ares_datatype)ARES_DATATYPE_LAST;
|
|
|
|
data->mark = ARES_DATATYPE_MARK;
|
|
|
|
ares_free_data(p);
|
|
|
|
|
|
|
|
// Invalid marker
|
|
|
|
data->type = (ares_datatype)ARES_DATATYPE_MX_REPLY;
|
|
|
|
data->mark = ARES_DATATYPE_MARK + 1;
|
|
|
|
ares_free_data(p);
|
|
|
|
|
|
|
|
// Null pointer
|
|
|
|
ares_free_data(nullptr);
|
|
|
|
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(LibraryInit, StrdupFailures) {
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL));
|
|
|
|
char* copy = ares_strdup("string");
|
|
|
|
EXPECT_NE(nullptr, copy);
|
|
|
|
ares_free(copy);
|
|
|
|
ares_library_cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, StrdupFailures) {
|
|
|
|
SetAllocFail(1);
|
|
|
|
char* copy = ares_strdup("string");
|
|
|
|
EXPECT_EQ(nullptr, copy);
|
|
|
|
}
|
|
|
|
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
TEST_F(FileChannelTest, GetAddrInfoHostsPositive) {
|
|
|
|
TempFile hostsfile("1.2.3.4 example.com \n"
|
|
|
|
" 2.3.4.5\tgoogle.com www.google.com\twww2.google.com\n"
|
|
|
|
"#comment\n"
|
|
|
|
"4.5.6.7\n"
|
|
|
|
"1.3.5.7 \n"
|
|
|
|
"::1 ipv6.com");
|
|
|
|
EnvValue with_env("CARES_HOSTS", hostsfile.filename());
|
|
|
|
struct ares_addrinfo_hints hints = {0, 0, 0, 0};
|
|
|
|
AddrInfoResult result = {};
|
|
|
|
hints.ai_family = AF_INET;
|
|
|
|
hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT;
|
|
|
|
ares_getaddrinfo(channel_, "example.com", NULL, &hints, AddrInfoCallback, &result);
|
|
|
|
Process();
|
|
|
|
EXPECT_TRUE(result.done_);
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << result.ai_;
|
|
|
|
EXPECT_EQ("{example.com addr=[1.2.3.4]}", ss.str());
|
|
|
|
}
|
|
|
|
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
TEST_F(FileChannelTest, GetAddrInfoHostsSpaces) {
|
|
|
|
TempFile hostsfile("1.2.3.4 example.com \n"
|
|
|
|
" 2.3.4.5\tgoogle.com www.google.com\twww2.google.com\n"
|
|
|
|
"#comment\n"
|
|
|
|
"4.5.6.7\n"
|
|
|
|
"1.3.5.7 \n"
|
|
|
|
"::1 ipv6.com");
|
|
|
|
EnvValue with_env("CARES_HOSTS", hostsfile.filename());
|
|
|
|
struct ares_addrinfo_hints hints = {0, 0, 0, 0};
|
|
|
|
AddrInfoResult result = {};
|
|
|
|
hints.ai_family = AF_INET;
|
|
|
|
hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT;
|
|
|
|
ares_getaddrinfo(channel_, "google.com", NULL, &hints, AddrInfoCallback, &result);
|
|
|
|
Process();
|
|
|
|
EXPECT_TRUE(result.done_);
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << result.ai_;
|
|
|
|
EXPECT_EQ("{www.google.com->google.com, www2.google.com->google.com addr=[2.3.4.5]}", ss.str());
|
|
|
|
}
|
|
|
|
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
TEST_F(FileChannelTest, GetAddrInfoHostsByALias) {
|
|
|
|
TempFile hostsfile("1.2.3.4 example.com \n"
|
|
|
|
" 2.3.4.5\tgoogle.com www.google.com\twww2.google.com\n"
|
|
|
|
"#comment\n"
|
|
|
|
"4.5.6.7\n"
|
|
|
|
"1.3.5.7 \n"
|
|
|
|
"::1 ipv6.com");
|
|
|
|
EnvValue with_env("CARES_HOSTS", hostsfile.filename());
|
|
|
|
struct ares_addrinfo_hints hints = {0, 0, 0, 0};
|
|
|
|
AddrInfoResult result = {};
|
|
|
|
hints.ai_family = AF_INET;
|
|
|
|
hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT;
|
|
|
|
ares_getaddrinfo(channel_, "www2.google.com", NULL, &hints, AddrInfoCallback, &result);
|
|
|
|
Process();
|
|
|
|
EXPECT_TRUE(result.done_);
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << result.ai_;
|
|
|
|
EXPECT_EQ("{www.google.com->google.com, www2.google.com->google.com addr=[2.3.4.5]}", ss.str());
|
|
|
|
}
|
|
|
|
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
TEST_F(FileChannelTest, GetAddrInfoHostsIPV6) {
|
|
|
|
TempFile hostsfile("1.2.3.4 example.com \n"
|
|
|
|
" 2.3.4.5\tgoogle.com www.google.com\twww2.google.com\n"
|
|
|
|
"#comment\n"
|
|
|
|
"4.5.6.7\n"
|
|
|
|
"1.3.5.7 \n"
|
|
|
|
"::1 ipv6.com");
|
|
|
|
EnvValue with_env("CARES_HOSTS", hostsfile.filename());
|
|
|
|
struct ares_addrinfo_hints hints = {0, 0, 0, 0};
|
|
|
|
AddrInfoResult result = {};
|
|
|
|
hints.ai_family = AF_INET6;
|
|
|
|
hints.ai_flags = ARES_AI_CANONNAME | ARES_AI_ENVHOSTS | ARES_AI_NOSORT;
|
|
|
|
ares_getaddrinfo(channel_, "ipv6.com", NULL, &hints, AddrInfoCallback, &result);
|
|
|
|
Process();
|
|
|
|
EXPECT_TRUE(result.done_);
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << result.ai_;
|
|
|
|
EXPECT_EQ("{ipv6.com addr=[[0000:0000:0000:0000:0000:0000:0000:0001]]}", ss.str());
|
|
|
|
}
|
|
|
|
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
|
|
|
|
TEST_F(FileChannelTest, GetAddrInfoAllocFail) {
|
|
|
|
TempFile hostsfile("1.2.3.4 example.com alias1 alias2\n");
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
EnvValue with_env("CARES_HOSTS", hostsfile.filename());
|
|
|
|
struct ares_addrinfo_hints hints;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = AF_INET;
|
|
|
|
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
// Fail a variety of different memory allocations, and confirm
|
|
|
|
// that the operation either fails with ENOMEM or succeeds
|
|
|
|
// with the expected result.
|
|
|
|
const int kCount = 34;
|
|
|
|
AddrInfoResult results[kCount];
|
|
|
|
for (int ii = 1; ii <= kCount; ii++) {
|
|
|
|
AddrInfoResult* result = &(results[ii - 1]);
|
|
|
|
ClearFails();
|
|
|
|
SetAllocFail(ii);
|
Replace hosts parser, add caching capabilities (#591)
HOSTS FILE PROCESSING OVERVIEW
==============================
The hosts file on the system contains static entries to be processed locally
rather than querying the nameserver. Each row is an IP address followed by
a list of space delimited hostnames that match the ip address. This is used
for both forward and reverse lookups.
We are caching the entire parsed hosts file for performance reasons. Some
files may be quite sizable and as per Issue #458 can approach 1/2MB in size,
and the parse overhead on a rapid succession of queries can be quite large.
The entries are stored in forwards and backwards hashtables so we can get
O(1) performance on lookup. The file is cached until the file modification
timestamp changes (or 60s if there is no implemented stat() capability).
The hosts file processing is quite unique. It has to merge all related hosts
and ips into a single entry due to file formatting requirements. For
instance take the below:
```
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 host.example.com host
192.168.1.5 host.example.com host
2620:1234::1 host.example.com host6.example.com host6 host
```
This will yield 2 entries.
1) ips: `127.0.0.1,::1`
hosts: `localhost.localdomain,localhost`
2) ips: `192.168.1.1,192.168.1.5,2620:1234::1`
hosts: `host.example.com,host,host6.example.com,host6`
It could be argued that if searching for `192.168.1.1` that the `host6`
hostnames should not be returned, but this implementation will return them
since they are related (both ips have the fqdn of host.example.com). It is
unlikely this will matter in the real world.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
ares_getaddrinfo(channel_, "example.com", NULL, &hints, AddrInfoCallback, result);
|
|
|
|
Process();
|
|
|
|
EXPECT_TRUE(result->done_);
|
|
|
|
if (result->status_ == ARES_SUCCESS) {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << result->ai_;
|
|
|
|
EXPECT_EQ("{alias1->example.com, alias2->example.com addr=[1.2.3.4]}", ss.str()) << " failed alloc #" << ii;
|
|
|
|
if (verbose) std::cerr << "Succeeded despite failure of alloc #" << ii << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, DNSRecord) {
|
|
|
|
ares_dns_record_t *dnsrec = NULL;
|
|
|
|
ares_dns_rr_t *rr = NULL;
|
|
|
|
struct in_addr addr;
|
|
|
|
struct ares_in6_addr addr6;
|
|
|
|
unsigned char *msg = NULL;
|
|
|
|
size_t msglen = 0;
|
|
|
|
size_t qdcount = 0;
|
|
|
|
size_t ancount = 0;
|
|
|
|
size_t nscount = 0;
|
|
|
|
size_t arcount = 0;
|
|
|
|
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_create(&dnsrec, 0x1234,
|
|
|
|
ARES_FLAG_QR|ARES_FLAG_AA|ARES_FLAG_RD|ARES_FLAG_RA,
|
|
|
|
ARES_OPCODE_QUERY, ARES_RCODE_NOERROR));
|
|
|
|
|
|
|
|
/* == Question == */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_query_add(dnsrec, "example.com",
|
|
|
|
ARES_REC_TYPE_ANY,
|
|
|
|
ARES_CLASS_IN));
|
|
|
|
|
|
|
|
/* == Answer == */
|
|
|
|
/* A */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
|
|
|
|
ARES_REC_TYPE_A, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_LT(0, ares_inet_pton(AF_INET, "1.1.1.1", &addr));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_addr(rr, ARES_RR_A_ADDR, &addr));
|
|
|
|
/* AAAA */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
|
|
|
|
ARES_REC_TYPE_AAAA, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_LT(0, ares_inet_pton(AF_INET6, "2600::4", &addr6));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_addr6(rr, ARES_RR_AAAA_ADDR, &addr6));
|
|
|
|
/* MX */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
|
|
|
|
ARES_REC_TYPE_MX, ARES_CLASS_IN, 3600));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_MX_PREFERENCE, 10));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_MX_EXCHANGE, "mail.example.com"));
|
|
|
|
/* CNAME */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
|
|
|
|
ARES_REC_TYPE_CNAME, ARES_CLASS_IN, 3600));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_CNAME_CNAME, "b.example.com"));
|
|
|
|
/* TXT */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
|
|
|
|
ARES_REC_TYPE_TXT, ARES_CLASS_IN, 3600));
|
|
|
|
const char txt1[] = "blah=here blah=there anywhere";
|
|
|
|
const char txt2[] = "some other record";
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_add_abin(rr, ARES_RR_TXT_DATA, (unsigned char *)txt1,
|
|
|
|
sizeof(txt1)-1));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_add_abin(rr, ARES_RR_TXT_DATA, (unsigned char *)txt2,
|
|
|
|
sizeof(txt2)-1));
|
|
|
|
/* SIG */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
|
|
|
|
ARES_REC_TYPE_SIG, ARES_CLASS_ANY, 0));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_SIG_TYPE_COVERED, ARES_REC_TYPE_TXT));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_SIG_ALGORITHM, 1));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_SIG_LABELS, 1));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SIG_ORIGINAL_TTL, 3200));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SIG_EXPIRATION, (unsigned int)time(NULL)));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SIG_INCEPTION, (unsigned int)time(NULL) - (86400 * 365)));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_SIG_KEY_TAG, 0x1234));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_SIG_SIGNERS_NAME, "signer.example.com"));
|
|
|
|
const unsigned char sig[] = {
|
|
|
|
0xd2, 0xab, 0xde, 0x24, 0x0d, 0x7c, 0xd3, 0xee, 0x6b, 0x4b, 0x28, 0xc5,
|
|
|
|
0x4d, 0xf0, 0x34, 0xb9, 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e,
|
|
|
|
0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71 };
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_bin(rr, ARES_RR_SIG_SIGNATURE, sig, sizeof(sig)));
|
|
|
|
|
|
|
|
|
|
|
|
/* == Authority == */
|
|
|
|
/* NS */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com",
|
|
|
|
ARES_REC_TYPE_NS, ARES_CLASS_IN, 38400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_NS_NSDNAME, "ns1.example.com"));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com",
|
|
|
|
ARES_REC_TYPE_NS, ARES_CLASS_IN, 38400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_NS_NSDNAME, "ns2.example.com"));
|
|
|
|
/* SOA */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com",
|
|
|
|
ARES_REC_TYPE_SOA, ARES_CLASS_IN, 86400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_SOA_MNAME, "ns1.example.com"));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_SOA_RNAME, "tech\\.support.example.com"));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SOA_SERIAL, 2023110701));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SOA_REFRESH, 28800));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SOA_RETRY, 7200));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SOA_EXPIRE, 604800));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u32(rr, ARES_RR_SOA_MINIMUM, 86400));
|
|
|
|
|
|
|
|
/* == Additional */
|
|
|
|
/* OPT */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "",
|
|
|
|
ARES_REC_TYPE_OPT, ARES_CLASS_IN, 0));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_OPT_UDP_SIZE, 1280));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_OPT_VERSION, 0));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_OPT_FLAGS, 0));
|
|
|
|
unsigned char optval[] = { 'c', '-', 'a', 'r', 'e', 's' };
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_opt(rr, ARES_RR_OPT_OPTIONS, 3 /* NSID */, optval, sizeof(optval)));
|
|
|
|
/* PTR -- doesn't make sense, but ok */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com",
|
|
|
|
ARES_REC_TYPE_PTR, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_PTR_DNAME, "b.example.com"));
|
|
|
|
/* HINFO */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com",
|
|
|
|
ARES_REC_TYPE_HINFO, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_HINFO_CPU, "Virtual"));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_HINFO_OS, "Linux"));
|
|
|
|
/* SRV */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL,
|
|
|
|
"_ldap.example.com", ARES_REC_TYPE_SRV, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_SRV_PRIORITY, 100));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_SRV_WEIGHT, 1));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_SRV_PORT, 389));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_SRV_TARGET, "ldap.example.com"));
|
|
|
|
/* TLSA */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL,
|
|
|
|
"_443._tcp.example.com", ARES_REC_TYPE_TLSA, ARES_CLASS_IN, 86400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_CERT_USAGE, ARES_TLSA_USAGE_CA));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_SELECTOR, ARES_TLSA_SELECTOR_FULL));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_MATCH, ARES_TLSA_MATCH_SHA256));
|
|
|
|
const unsigned char tlsa[] = {
|
|
|
|
0xd2, 0xab, 0xde, 0x24, 0x0d, 0x7c, 0xd3, 0xee, 0x6b, 0x4b, 0x28, 0xc5,
|
|
|
|
0x4d, 0xf0, 0x34, 0xb9, 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e,
|
|
|
|
0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71 };
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_bin(rr, ARES_RR_TLSA_DATA, tlsa, sizeof(tlsa)));
|
|
|
|
/* SVCB */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL,
|
|
|
|
"_1234._bar.example.com", ARES_REC_TYPE_SVCB, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_SVCB_PRIORITY, 1));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_SVCB_TARGET, "svc1.example.net"));
|
|
|
|
/* IPV6 hint is a list of IPV6 addresses in network byte order, concatenated */
|
|
|
|
struct ares_addr svcb_addr;
|
|
|
|
svcb_addr.family = AF_UNSPEC;
|
|
|
|
size_t svcb_ipv6hint_len = 0;
|
|
|
|
const unsigned char *svcb_ipv6hint = (const unsigned char *)ares_dns_pton("2001:db8::1", &svcb_addr, &svcb_ipv6hint_len);
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_opt(rr, ARES_RR_SVCB_PARAMS, ARES_SVCB_PARAM_IPV6HINT,
|
|
|
|
svcb_ipv6hint, svcb_ipv6hint_len));
|
|
|
|
/* Port is 16bit big endian format */
|
|
|
|
unsigned short svcb_port = htons(1234);
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_opt(rr, ARES_RR_SVCB_PARAMS, ARES_SVCB_PARAM_PORT,
|
|
|
|
(const unsigned char *)&svcb_port, sizeof(svcb_port)));
|
|
|
|
/* HTTPS */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL,
|
|
|
|
"example.com", ARES_REC_TYPE_HTTPS, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_HTTPS_PRIORITY, 1));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_HTTPS_TARGET, ""));
|
|
|
|
|
|
|
|
/* In DNS string format which is 1 octet length indicator followed by string */
|
|
|
|
const unsigned char https_alpn[] = { 0x02, 'h', '3' };
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_opt(rr, ARES_RR_HTTPS_PARAMS, ARES_SVCB_PARAM_ALPN,
|
|
|
|
https_alpn, sizeof(https_alpn)));
|
|
|
|
/* URI */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL,
|
|
|
|
"_ftp._tcp.example.com", ARES_REC_TYPE_URI, ARES_CLASS_IN, 3600));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_URI_PRIORITY, 10));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_URI_WEIGHT, 1));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_URI_TARGET, "ftp://ftp.example.com/public"));
|
|
|
|
/* CAA */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL,
|
|
|
|
"example.com", ARES_REC_TYPE_CAA, ARES_CLASS_IN, 86400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_CAA_CRITICAL, 0));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_CAA_TAG, "issue"));
|
|
|
|
unsigned char caa[] = "letsencrypt.org";
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_bin(rr, ARES_RR_CAA_VALUE, caa, sizeof(caa)));
|
|
|
|
/* NAPTR */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL,
|
|
|
|
"example.com", ARES_REC_TYPE_NAPTR, ARES_CLASS_IN, 86400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_NAPTR_ORDER, 100));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_NAPTR_PREFERENCE, 10));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_NAPTR_FLAGS, "S"));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_NAPTR_SERVICES, "SIP+D2U"));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_NAPTR_REGEXP,
|
|
|
|
"!^.*$!sip:customer-service@example.com!"));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_NAPTR_REPLACEMENT,
|
|
|
|
"_sip._udp.example.com."));
|
|
|
|
/* RAW_RR */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "",
|
|
|
|
ARES_REC_TYPE_RAW_RR, ARES_CLASS_IN, 0));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u16(rr, ARES_RR_RAW_RR_TYPE, 65432));
|
|
|
|
unsigned char data[] = { 0x00 };
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_bin(rr, ARES_RR_RAW_RR_DATA, data, sizeof(data)));
|
|
|
|
|
|
|
|
qdcount = ares_dns_record_query_cnt(dnsrec);
|
|
|
|
ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
|
|
|
|
nscount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY);
|
|
|
|
arcount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL);
|
|
|
|
|
|
|
|
/* Write */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_dns_write(dnsrec, &msg, &msglen));
|
|
|
|
|
|
|
|
ares_buf_t *hexdump = ares_buf_create();
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_buf_hexdump(hexdump, msg, msglen));
|
|
|
|
char *hexdata = ares_buf_finish_str(hexdump, NULL);
|
|
|
|
//printf("HEXDUMP\n%s", hexdata);
|
|
|
|
ares_free(hexdata);
|
|
|
|
|
|
|
|
ares_dns_record_destroy(dnsrec); dnsrec = NULL;
|
|
|
|
|
|
|
|
/* Parse */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_dns_parse(msg, msglen, 0, &dnsrec));
|
|
|
|
ares_free_string(msg); msg = NULL;
|
|
|
|
|
|
|
|
/* Re-write */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_dns_write(dnsrec, &msg, &msglen));
|
|
|
|
|
|
|
|
EXPECT_EQ(qdcount, ares_dns_record_query_cnt(dnsrec));
|
|
|
|
EXPECT_EQ(ancount, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER));
|
|
|
|
EXPECT_EQ(nscount, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY));
|
|
|
|
EXPECT_EQ(arcount, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL));
|
|
|
|
|
|
|
|
/* Iterate and print */
|
|
|
|
ares_buf_t *printmsg = ares_buf_create();
|
|
|
|
ares_buf_append_str(printmsg, ";; ->>HEADER<<- opcode: ");
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec)));
|
|
|
|
ares_buf_append_str(printmsg, ", status: ");
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_rcode_tostr(ares_dns_record_get_rcode(dnsrec)));
|
|
|
|
ares_buf_append_str(printmsg, ", id: ");
|
|
|
|
ares_buf_append_num_dec(printmsg, (size_t)ares_dns_record_get_id(dnsrec), 0);
|
|
|
|
ares_buf_append_str(printmsg, "\n;; flags: ");
|
|
|
|
ares_buf_append_num_hex(printmsg, (size_t)ares_dns_record_get_flags(dnsrec), 0);
|
|
|
|
ares_buf_append_str(printmsg, "; QUERY: ");
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_record_query_cnt(dnsrec), 0);
|
|
|
|
ares_buf_append_str(printmsg, ", ANSWER: ");
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER), 0);
|
|
|
|
ares_buf_append_str(printmsg, ", AUTHORITY: ");
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY), 0);
|
|
|
|
ares_buf_append_str(printmsg, ", ADDITIONAL: ");
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL), 0);
|
|
|
|
ares_buf_append_str(printmsg, "\n\n");
|
|
|
|
ares_buf_append_str(printmsg, ";; QUESTION SECTION:\n");
|
|
|
|
for (size_t i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) {
|
|
|
|
const char *name;
|
|
|
|
ares_dns_rec_type_t qtype;
|
|
|
|
ares_dns_class_t qclass;
|
|
|
|
ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass);
|
|
|
|
ares_buf_append_str(printmsg, ";");
|
|
|
|
ares_buf_append_str(printmsg, name);
|
|
|
|
ares_buf_append_str(printmsg, ".\t\t\t");
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_class_tostr(qclass));
|
|
|
|
ares_buf_append_str(printmsg, "\t");
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_rec_type_tostr(qtype));
|
|
|
|
ares_buf_append_str(printmsg, "\n");
|
|
|
|
}
|
|
|
|
ares_buf_append_str(printmsg, "\n");
|
|
|
|
for (size_t i = ARES_SECTION_ANSWER; i < ARES_SECTION_ADDITIONAL + 1; i++) {
|
|
|
|
ares_buf_append_str(printmsg, ";; ");
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_section_tostr((ares_dns_section_t)i));
|
|
|
|
ares_buf_append_str(printmsg, " SECTION:\n");
|
|
|
|
for (size_t j = 0; j < ares_dns_record_rr_cnt(dnsrec, (ares_dns_section_t)i); j++) {
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, (ares_dns_section_t)i, j);
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_rr_get_name(rr));
|
|
|
|
ares_buf_append_str(printmsg, ".\t\t\t");
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_class_tostr(ares_dns_rr_get_class(rr)));
|
|
|
|
ares_buf_append_str(printmsg, "\t");
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_rec_type_tostr(ares_dns_rr_get_type(rr)));
|
|
|
|
ares_buf_append_str(printmsg, "\t");
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_rr_get_ttl(rr), 0);
|
|
|
|
ares_buf_append_str(printmsg, "\t");
|
|
|
|
|
|
|
|
size_t keys_cnt;
|
|
|
|
const ares_dns_rr_key_t *keys = ares_dns_rr_get_keys(ares_dns_rr_get_type(rr), &keys_cnt);
|
|
|
|
for (size_t k = 0; k<keys_cnt; k++) {
|
|
|
|
char buf[256] = "";
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_rr_key_tostr(keys[k]));
|
|
|
|
ares_buf_append_str(printmsg, "=");
|
|
|
|
switch (ares_dns_rr_key_datatype(keys[k])) {
|
|
|
|
case ARES_DATATYPE_INADDR:
|
|
|
|
ares_inet_ntop(AF_INET, ares_dns_rr_get_addr(rr, keys[k]), buf, sizeof(buf));
|
|
|
|
ares_buf_append_str(printmsg, buf);
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_INADDR6:
|
|
|
|
ares_inet_ntop(AF_INET6, ares_dns_rr_get_addr6(rr, keys[k]), buf, sizeof(buf));
|
|
|
|
ares_buf_append_str(printmsg, buf);
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_U8:
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u8(rr, keys[k]), 0);
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_U16:
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u16(rr, keys[k]), 0);
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_U32:
|
|
|
|
ares_buf_append_num_dec(printmsg, ares_dns_rr_get_u32(rr, keys[k]), 0);
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_NAME:
|
|
|
|
case ARES_DATATYPE_STR:
|
|
|
|
ares_buf_append_byte(printmsg, '"');
|
|
|
|
ares_buf_append_str(printmsg, ares_dns_rr_get_str(rr, keys[k]));
|
|
|
|
ares_buf_append_byte(printmsg, '"');
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_BIN:
|
|
|
|
/* TODO */
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_BINP:
|
|
|
|
{
|
|
|
|
ares_buf_append_byte(printmsg, '"');
|
|
|
|
size_t templen;
|
|
|
|
ares_buf_append_str(printmsg, (const char *)ares_dns_rr_get_bin(rr, keys[k], &templen));
|
|
|
|
ares_buf_append_byte(printmsg, '"');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_ABINP:
|
|
|
|
for (size_t a=0; a<ares_dns_rr_get_abin_cnt(rr, keys[k]); a++) {
|
|
|
|
if (a != 0) {
|
|
|
|
ares_buf_append_byte(printmsg, ' ');
|
|
|
|
}
|
|
|
|
ares_buf_append_byte(printmsg, '"');
|
|
|
|
size_t templen;
|
|
|
|
ares_buf_append_str(printmsg, (const char *)ares_dns_rr_get_abin(rr, keys[k], a, &templen));
|
|
|
|
ares_buf_append_byte(printmsg, '"');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ARES_DATATYPE_OPT:
|
|
|
|
/* TODO */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ares_buf_append_str(printmsg, " ");
|
|
|
|
}
|
|
|
|
ares_buf_append_str(printmsg, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ares_buf_append_str(printmsg, ";; SIZE: ");
|
|
|
|
ares_buf_append_num_dec(printmsg, msglen, 0);
|
|
|
|
ares_buf_append_str(printmsg, "\n\n");
|
|
|
|
|
|
|
|
char *printdata = ares_buf_finish_str(printmsg, NULL);
|
|
|
|
//printf("%s", printdata);
|
|
|
|
ares_free(printdata);
|
|
|
|
|
|
|
|
ares_dns_record_destroy(dnsrec);
|
|
|
|
ares_free_string(msg);
|
|
|
|
|
|
|
|
// Invalid
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_parse(NULL, 0, 0, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_record_create(NULL, 0, 0, ARES_OPCODE_QUERY, ARES_RCODE_NOERROR));
|
|
|
|
EXPECT_EQ(0, ares_dns_record_get_id(NULL));
|
|
|
|
EXPECT_EQ(0, ares_dns_record_get_flags(NULL));
|
|
|
|
EXPECT_EQ(0, (int)ares_dns_record_get_opcode(NULL));
|
|
|
|
EXPECT_EQ(0, (int)ares_dns_record_get_rcode(NULL));
|
|
|
|
EXPECT_EQ(0, (int)ares_dns_record_query_cnt(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_record_query_set_name(NULL, 0, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_record_query_set_type(NULL, 0, ARES_REC_TYPE_A));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_record_query_get(NULL, 0, NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(0, ares_dns_record_rr_cnt(NULL, ARES_SECTION_ANSWER));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_record_rr_add(NULL, NULL, ARES_SECTION_ANSWER, NULL, ARES_REC_TYPE_A, ARES_CLASS_IN, 0));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_record_rr_del(NULL, ARES_SECTION_ANSWER, 0));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_record_rr_get(NULL, ARES_SECTION_ANSWER, 0));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_name(NULL));
|
|
|
|
EXPECT_EQ(0, (int)ares_dns_rr_get_type(NULL));
|
|
|
|
EXPECT_EQ(0, (int)ares_dns_rr_get_class(NULL));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_ttl(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_dns_write(NULL, NULL, NULL));
|
|
|
|
#ifndef CARES_SYMBOL_HIDING
|
|
|
|
ares_dns_record_ttl_decrement(NULL, 0);
|
|
|
|
#endif
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_addr(NULL, ARES_RR_A_ADDR));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_addr(NULL, ARES_RR_NS_NSDNAME));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_addr6(NULL, ARES_RR_AAAA_ADDR));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_addr6(NULL, ARES_RR_NS_NSDNAME));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_u8(NULL, ARES_RR_SIG_ALGORITHM));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_u8(NULL, ARES_RR_NS_NSDNAME));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_u16(NULL, ARES_RR_MX_PREFERENCE));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_u16(NULL, ARES_RR_NS_NSDNAME));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_u32(NULL, ARES_RR_SOA_SERIAL));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_u32(NULL, ARES_RR_NS_NSDNAME));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_bin(NULL, ARES_RR_TXT_DATA, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_bin(NULL, ARES_RR_NS_NSDNAME, NULL));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_str(NULL, ARES_RR_NS_NSDNAME));
|
|
|
|
EXPECT_EQ(nullptr, ares_dns_rr_get_str(NULL, ARES_RR_MX_PREFERENCE));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_opt_cnt(NULL, ARES_RR_OPT_OPTIONS));
|
|
|
|
EXPECT_EQ(0, ares_dns_rr_get_opt_cnt(NULL, ARES_RR_A_ADDR));
|
|
|
|
EXPECT_EQ(65535, ares_dns_rr_get_opt(NULL, ARES_RR_OPT_OPTIONS, 0, NULL, NULL));
|
|
|
|
EXPECT_EQ(65535, ares_dns_rr_get_opt(NULL, ARES_RR_A_ADDR, 0, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_dns_rr_get_opt_byid(NULL, ARES_RR_OPT_OPTIONS, 1, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_dns_rr_get_opt_byid(NULL, ARES_RR_A_ADDR, 1, NULL, NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, DNSParseFlags) {
|
|
|
|
ares_dns_record_t *dnsrec = NULL;
|
|
|
|
ares_dns_rr_t *rr = NULL;
|
|
|
|
struct in_addr addr;
|
|
|
|
unsigned char *msg = NULL;
|
|
|
|
size_t msglen = 0;
|
|
|
|
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_create(&dnsrec, 0x1234,
|
|
|
|
ARES_FLAG_QR|ARES_FLAG_AA|ARES_FLAG_RD|ARES_FLAG_RA,
|
|
|
|
ARES_OPCODE_QUERY, ARES_RCODE_NOERROR));
|
|
|
|
|
|
|
|
/* == Question == */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_query_add(dnsrec, "example.com",
|
|
|
|
ARES_REC_TYPE_ANY,
|
|
|
|
ARES_CLASS_IN));
|
|
|
|
|
|
|
|
/* == Answer == */
|
|
|
|
/* A */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER, "example.com",
|
|
|
|
ARES_REC_TYPE_A, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_LT(0, ares_inet_pton(AF_INET, "1.1.1.1", &addr));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_addr(rr, ARES_RR_A_ADDR, &addr));
|
|
|
|
/* TLSA */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ANSWER,
|
|
|
|
"_443._tcp.example.com", ARES_REC_TYPE_TLSA, ARES_CLASS_IN, 86400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_CERT_USAGE, ARES_TLSA_USAGE_CA));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_SELECTOR, ARES_TLSA_SELECTOR_FULL));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_u8(rr, ARES_RR_TLSA_MATCH, ARES_TLSA_MATCH_SHA256));
|
|
|
|
const unsigned char tlsa[] = {
|
|
|
|
0xd2, 0xab, 0xde, 0x24, 0x0d, 0x7c, 0xd3, 0xee, 0x6b, 0x4b, 0x28, 0xc5,
|
|
|
|
0x4d, 0xf0, 0x34, 0xb9, 0x79, 0x83, 0xa1, 0xd1, 0x6e, 0x8a, 0x41, 0x0e,
|
|
|
|
0x45, 0x61, 0xcb, 0x10, 0x66, 0x18, 0xe9, 0x71 };
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_bin(rr, ARES_RR_TLSA_DATA, tlsa, sizeof(tlsa)));
|
|
|
|
|
|
|
|
/* == Authority == */
|
|
|
|
/* NS */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_AUTHORITY, "example.com",
|
|
|
|
ARES_REC_TYPE_NS, ARES_CLASS_IN, 38400));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_NS_NSDNAME, "ns1.example.com"));
|
|
|
|
|
|
|
|
/* == Additional */
|
|
|
|
/* PTR -- doesn't make sense, but ok */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_record_rr_add(&rr, dnsrec, ARES_SECTION_ADDITIONAL, "example.com",
|
|
|
|
ARES_REC_TYPE_PTR, ARES_CLASS_IN, 300));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS,
|
|
|
|
ares_dns_rr_set_str(rr, ARES_RR_PTR_DNAME, "b.example.com"));
|
|
|
|
|
|
|
|
/* Write */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_dns_write(dnsrec, &msg, &msglen));
|
|
|
|
|
|
|
|
/* Cleanup - before reuse */
|
|
|
|
ares_dns_record_destroy(dnsrec);
|
|
|
|
|
|
|
|
/* Parse "base" type records (1035) */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_dns_parse(msg, msglen, ARES_DNS_PARSE_AN_BASE_RAW |
|
|
|
|
ARES_DNS_PARSE_NS_BASE_RAW | ARES_DNS_PARSE_AR_BASE_RAW, &dnsrec));
|
|
|
|
|
|
|
|
EXPECT_EQ(1, ares_dns_record_query_cnt(dnsrec));
|
|
|
|
EXPECT_EQ(2, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER));
|
|
|
|
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY));
|
|
|
|
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 0);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 1);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_TLSA, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_AUTHORITY, 0);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ADDITIONAL, 0);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
/* Cleanup - before reuse */
|
|
|
|
|
|
|
|
ares_dns_record_destroy(dnsrec);
|
|
|
|
|
|
|
|
/* Parse later RFCs (no name compression) type records */
|
|
|
|
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_dns_parse(msg, msglen, ARES_DNS_PARSE_AN_EXT_RAW |
|
|
|
|
ARES_DNS_PARSE_NS_EXT_RAW | ARES_DNS_PARSE_AR_EXT_RAW, &dnsrec));
|
|
|
|
|
|
|
|
EXPECT_EQ(1, ares_dns_record_query_cnt(dnsrec));
|
|
|
|
EXPECT_EQ(2, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER));
|
|
|
|
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY));
|
|
|
|
EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ADDITIONAL));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 0);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_A, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 1);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_AUTHORITY, 0);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_NS, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ADDITIONAL, 0);
|
|
|
|
EXPECT_EQ(ARES_REC_TYPE_PTR, ares_dns_rr_get_type(rr));
|
|
|
|
|
|
|
|
ares_dns_record_destroy(dnsrec);
|
|
|
|
ares_free_string(msg); msg = NULL;
|
|
|
|
}
|
|
|
|
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
TEST_F(LibraryTest, ArrayMisuse) {
|
|
|
|
EXPECT_EQ(NULL, ares_array_create(0, NULL));
|
|
|
|
ares_array_destroy(NULL);
|
|
|
|
EXPECT_EQ(NULL, ares_array_finish(NULL, NULL));
|
|
|
|
EXPECT_EQ(0, ares_array_len(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_insert_at(NULL, NULL, 0));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_insertdata_at(NULL, 0, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_insert_last(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_insertdata_last(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_insert_first(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_insertdata_first(NULL, NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_array_at(NULL, 0));
|
|
|
|
EXPECT_EQ(NULL, ares_array_first(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_array_last(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_claim_at(NULL, 0, NULL, 0));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_remove_at(NULL, 0));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_remove_first(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_remove_last(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_sort(NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_set_size(NULL, 0));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, BufMisuse) {
|
|
|
|
EXPECT_EQ(NULL, ares_buf_create_const(NULL, 0));
|
|
|
|
ares_buf_reclaim(NULL);
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_append(NULL, NULL, 55));
|
|
|
|
size_t len = 10;
|
|
|
|
EXPECT_EQ(NULL, ares_buf_append_start(NULL, &len));
|
|
|
|
EXPECT_EQ(NULL, ares_buf_append_start(NULL, NULL));
|
|
|
|
ares_buf_append_finish(NULL, 0);
|
|
|
|
EXPECT_EQ(NULL, ares_buf_finish_bin(NULL, NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_buf_finish_str(NULL, NULL));
|
|
|
|
ares_buf_tag(NULL);
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_tag_rollback(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_tag_clear(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_buf_tag_fetch(NULL, NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_buf_tag_length(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_tag_fetch_bytes(NULL, NULL, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_tag_fetch_string(NULL, NULL, 0));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_fetch_bytes_dup(NULL, 0, ARES_FALSE, NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_fetch_str_dup(NULL, 0, NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_buf_consume_whitespace(NULL, ARES_FALSE));
|
|
|
|
EXPECT_EQ((size_t)0, ares_buf_consume_nonwhitespace(NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_buf_consume_line(NULL, ARES_FALSE));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_buf_begins_with(NULL, NULL, 0));
|
|
|
|
EXPECT_EQ((size_t)0, ares_buf_get_position(NULL));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_set_position(NULL, 0));
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_buf_parse_dns_binstr(NULL, 0, NULL, NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableAsvpMisuse) {
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_asvp_insert(NULL, ARES_SOCKET_BAD, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_asvp_get(NULL, ARES_SOCKET_BAD, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_asvp_remove(NULL, ARES_SOCKET_BAD));
|
|
|
|
EXPECT_EQ((size_t)0, ares_htable_asvp_num_keys(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableStrvpMisuse) {
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_strvp_insert(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_strvp_get(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_strvp_remove(NULL, NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_htable_strvp_num_keys(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableVpStrMisuse) {
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_vpstr_insert(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_vpstr_get(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_vpstr_remove(NULL, NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_htable_vpstr_num_keys(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableDictMisuse) {
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_dict_insert(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_dict_get(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_dict_remove(NULL, NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_htable_dict_num_keys(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableSzvpMisuse) {
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_szvp_insert(NULL, 0, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_szvp_get(NULL, 0, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_szvp_remove(NULL, 0));
|
|
|
|
EXPECT_EQ((size_t)0, ares_htable_szvp_num_keys(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableVpvpMisuse) {
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_vpvp_insert(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_vpvp_get(NULL, NULL, NULL));
|
|
|
|
EXPECT_EQ(ARES_FALSE, ares_htable_vpvp_remove(NULL, NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_htable_vpvp_num_keys(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, LlistMisuse) {
|
|
|
|
ares_llist_replace_destructor(NULL, NULL);
|
|
|
|
EXPECT_EQ(NULL, ares_llist_insert_before(NULL, NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_llist_insert_after(NULL, NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_llist_node_last(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_llist_node_next(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_llist_node_prev(NULL));
|
|
|
|
EXPECT_EQ((size_t)0, ares_llist_len(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_llist_node_parent(NULL));
|
|
|
|
EXPECT_EQ(NULL, ares_llist_node_claim(NULL));
|
|
|
|
ares_llist_node_replace(NULL, NULL);
|
|
|
|
}
|
|
|
|
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
typedef struct {
|
|
|
|
unsigned int id;
|
|
|
|
ares_buf_t *buf;
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
} array_member_t;
|
|
|
|
|
|
|
|
static void array_member_init(void *mb, unsigned int id)
|
|
|
|
{
|
|
|
|
array_member_t *m = (array_member_t *)mb;
|
|
|
|
m->id = id;
|
|
|
|
m->buf = ares_buf_create();
|
|
|
|
ares_buf_append_be32(m->buf, id);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
}
|
|
|
|
|
|
|
|
static void array_member_destroy(void *mb)
|
|
|
|
{
|
|
|
|
array_member_t *m = (array_member_t *)mb;
|
|
|
|
ares_buf_destroy(m->buf);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
}
|
|
|
|
|
|
|
|
static int array_sort_cmp(const void *data1, const void *data2)
|
|
|
|
{
|
|
|
|
const array_member_t *m1 = (const array_member_t *)data1;
|
|
|
|
const array_member_t *m2 = (const array_member_t *)data2;
|
|
|
|
if (m1->id > m2->id)
|
|
|
|
return 1;
|
|
|
|
if (m1->id < m2->id)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, Array) {
|
|
|
|
ares_array_t *a = NULL;
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
array_member_t *m = NULL;
|
|
|
|
array_member_t mbuf;
|
|
|
|
unsigned int cnt = 0;
|
|
|
|
unsigned int removed = 0;
|
|
|
|
void *ptr = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
a = ares_array_create(sizeof(array_member_t), array_member_destroy);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
EXPECT_NE(nullptr, a);
|
|
|
|
|
|
|
|
/* Try to sort with no elements, should break out */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_sort(a, array_sort_cmp));
|
|
|
|
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
/* Add 8 elements */
|
|
|
|
for ( ; cnt < 8 ; cnt++) {
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_insert_last(&ptr, a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
array_member_init(ptr, cnt+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert at invalid index */
|
|
|
|
EXPECT_NE(ARES_SUCCESS, ares_array_insert_at(&ptr, a, 12345678));
|
|
|
|
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
/* Verify count */
|
|
|
|
EXPECT_EQ(cnt, ares_array_len(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
|
|
|
|
/* Remove the first 2 elements */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_remove_first(a));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_remove_first(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
removed += 2;
|
|
|
|
|
|
|
|
/* Verify count */
|
|
|
|
EXPECT_EQ(cnt-removed, ares_array_len(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
|
|
|
|
/* Verify id of first element */
|
|
|
|
m = (array_member_t *)ares_array_first(a);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
EXPECT_NE(nullptr, m);
|
|
|
|
EXPECT_EQ(3, m->id);
|
|
|
|
|
|
|
|
|
|
|
|
/* Add 100 total elements, this should force a shift of memory at some
|
|
|
|
* to make sure moves are working */
|
|
|
|
for ( ; cnt < 100 ; cnt++) {
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_insert_last(&ptr, a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
array_member_init(ptr, cnt+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify count */
|
|
|
|
EXPECT_EQ(cnt-removed, ares_array_len(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
|
|
|
|
/* Remove 2 from the end */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_remove_last(a));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_remove_last(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
removed += 2;
|
|
|
|
|
|
|
|
/* Verify count */
|
|
|
|
EXPECT_EQ(cnt-removed, ares_array_len(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
|
|
|
|
/* Verify expected id of last member */
|
|
|
|
m = (array_member_t *)ares_array_last(a);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
EXPECT_NE(nullptr, m);
|
|
|
|
EXPECT_EQ(cnt-2, m->id);
|
|
|
|
|
|
|
|
/* Remove 3 middle members */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_remove_at(a, ares_array_len(a)/2));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_remove_at(a, ares_array_len(a)/2));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_remove_at(a, ares_array_len(a)/2));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
removed += 3;
|
|
|
|
|
|
|
|
/* Verify count */
|
|
|
|
EXPECT_EQ(cnt-removed, ares_array_len(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
|
|
|
|
/* Claim a middle member then re-add it at the same position */
|
|
|
|
i = ares_array_len(a) / 2;
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_claim_at(&mbuf, sizeof(mbuf), a, i));
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_insert_at(&ptr, a, i));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
array_member_init(ptr, mbuf.id);
|
|
|
|
array_member_destroy((void *)&mbuf);
|
|
|
|
/* Verify count */
|
|
|
|
EXPECT_EQ(cnt-removed, ares_array_len(a));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
|
|
|
|
/* Iterate across the array, make sure each entry is greater than the last and
|
|
|
|
* the data in the buffer matches the id in the array */
|
|
|
|
unsigned int last_id = 0;
|
|
|
|
for (i=0; i<ares_array_len(a); i++) {
|
|
|
|
m = (array_member_t *)ares_array_at(a, i);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
EXPECT_NE(nullptr, m);
|
|
|
|
EXPECT_GT(m->id, last_id);
|
|
|
|
last_id = m->id;
|
|
|
|
|
|
|
|
unsigned int bufval = 0;
|
|
|
|
ares_buf_tag(m->buf);
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_buf_fetch_be32(m->buf, &bufval));
|
|
|
|
ares_buf_tag_rollback(m->buf);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
EXPECT_EQ(bufval, m->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add a new element in the middle to the beginning with a high id */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_insert_at(&ptr, a, ares_array_len(a)/2));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
array_member_init(ptr, 100000);
|
|
|
|
|
|
|
|
/* Sort the array */
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_array_sort(a, array_sort_cmp));
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
|
|
|
|
/* Iterate across the array, make sure each entry is greater than the last and
|
|
|
|
* the data in the buffer matches the id in the array */
|
|
|
|
last_id = 0;
|
|
|
|
for (i=0; i<ares_array_len(a); i++) {
|
|
|
|
m = (array_member_t *)ares_array_at(a, i);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
EXPECT_NE(nullptr, m);
|
|
|
|
EXPECT_GT(m->id, last_id);
|
|
|
|
last_id = m->id;
|
|
|
|
|
|
|
|
unsigned int bufval = 0;
|
|
|
|
ares_buf_tag(m->buf);
|
|
|
|
EXPECT_EQ(ARES_SUCCESS, ares_buf_fetch_be32(m->buf, &bufval));
|
|
|
|
ares_buf_tag_rollback(m->buf);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
EXPECT_EQ(bufval, m->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
ares_array_destroy(a);
|
Data Structure: Dynamic Array (#841)
Create a new data structure for a basic growable indexable array,
supporting the features you'd normally expect such as insert (at, last,
first), remove (at, last, first), and get (at, last, first). Internally
all data is stored in an appropriately sized array that can directly be
returned to the caller as a C array of the data type provided. The array
grows by powers of two, and has optimizations for head and tail
removals.
Array modifications can be risky (e.g. wrong reallocation sizes,
mis-sized memory moves, out-of-bounds access), so it makes sense to have
standardized code that is well tested.
The arrays used by the dns record parser / writer have been converted to
the new array data structure as have a few other instances.
Authored-By: Brad House (@bradh352)
4 months ago
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableVpvp) {
|
|
|
|
ares_llist_t *l = NULL;
|
|
|
|
ares_htable_vpvp_t *h = NULL;
|
|
|
|
ares_llist_node_t *n = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
#define VPVP_TABLE_SIZE 1000
|
|
|
|
|
|
|
|
l = ares_llist_create(NULL);
|
|
|
|
EXPECT_NE((void *)NULL, l);
|
|
|
|
|
|
|
|
h = ares_htable_vpvp_create(NULL, ares_free);
|
|
|
|
EXPECT_NE((void *)NULL, h);
|
|
|
|
|
|
|
|
for (i=0; i<VPVP_TABLE_SIZE; i++) {
|
|
|
|
void *p = ares_malloc_zero(4);
|
|
|
|
EXPECT_NE((void *)NULL, p);
|
|
|
|
EXPECT_NE((void *)NULL, ares_llist_insert_last(l, p));
|
|
|
|
EXPECT_TRUE(ares_htable_vpvp_insert(h, p, p));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(VPVP_TABLE_SIZE, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(VPVP_TABLE_SIZE, ares_htable_vpvp_num_keys(h));
|
|
|
|
|
|
|
|
n = ares_llist_node_first(l);
|
|
|
|
EXPECT_NE((void *)NULL, n);
|
|
|
|
while (n != NULL) {
|
|
|
|
ares_llist_node_t *next = ares_llist_node_next(n);
|
|
|
|
void *p = ares_llist_node_val(n);
|
|
|
|
EXPECT_NE((void *)NULL, p);
|
|
|
|
EXPECT_EQ(p, ares_htable_vpvp_get_direct(h, p));
|
|
|
|
EXPECT_TRUE(ares_htable_vpvp_get(h, p, NULL));
|
|
|
|
EXPECT_TRUE(ares_htable_vpvp_remove(h, p));
|
|
|
|
ares_llist_node_destroy(n);
|
|
|
|
n = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(0, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(0, ares_htable_vpvp_num_keys(h));
|
|
|
|
|
|
|
|
ares_llist_destroy(l);
|
|
|
|
ares_htable_vpvp_destroy(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, BufSplitStr) {
|
|
|
|
ares_buf_t *buf = NULL;
|
|
|
|
char **strs = NULL;
|
|
|
|
size_t nstrs = 0;
|
|
|
|
|
|
|
|
buf = ares_buf_create();
|
|
|
|
ares_buf_append_str(buf, "string1\nstring2 string3\t \nstring4");
|
|
|
|
ares_buf_split_str(buf, (const unsigned char *)"\n \t", 2, ARES_BUF_SPLIT_TRIM, 0, &strs, &nstrs);
|
|
|
|
ares_buf_destroy(buf);
|
|
|
|
|
|
|
|
EXPECT_EQ(4, nstrs);
|
|
|
|
EXPECT_TRUE(ares_streq(strs[0], "string1"));
|
|
|
|
EXPECT_TRUE(ares_streq(strs[1], "string2"));
|
|
|
|
EXPECT_TRUE(ares_streq(strs[2], "string3"));
|
|
|
|
EXPECT_TRUE(ares_streq(strs[3], "string4"));
|
|
|
|
ares_free_array(strs, nstrs, ares_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ares_socket_t s;
|
|
|
|
} test_htable_asvp_t;
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableAsvp) {
|
|
|
|
ares_llist_t *l = NULL;
|
|
|
|
ares_htable_asvp_t *h = NULL;
|
|
|
|
ares_llist_node_t *n = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
#define ASVP_TABLE_SIZE 1000
|
|
|
|
|
|
|
|
l = ares_llist_create(NULL);
|
|
|
|
EXPECT_NE((void *)NULL, l);
|
|
|
|
|
|
|
|
h = ares_htable_asvp_create(ares_free);
|
|
|
|
EXPECT_NE((void *)NULL, h);
|
|
|
|
|
|
|
|
for (i=0; i<ASVP_TABLE_SIZE; i++) {
|
|
|
|
test_htable_asvp_t *a = (test_htable_asvp_t *)ares_malloc_zero(sizeof(*a));
|
|
|
|
EXPECT_NE((void *)NULL, a);
|
|
|
|
a->s = (ares_socket_t)i+1;
|
|
|
|
EXPECT_NE((void *)NULL, ares_llist_insert_last(l, a));
|
|
|
|
EXPECT_TRUE(ares_htable_asvp_insert(h, a->s, a));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(ASVP_TABLE_SIZE, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(ASVP_TABLE_SIZE, ares_htable_asvp_num_keys(h));
|
|
|
|
|
|
|
|
n = ares_llist_node_first(l);
|
|
|
|
EXPECT_NE((void *)NULL, n);
|
|
|
|
while (n != NULL) {
|
|
|
|
ares_llist_node_t *next = ares_llist_node_next(n);
|
|
|
|
test_htable_asvp_t *a = (test_htable_asvp_t *)ares_llist_node_val(n);
|
|
|
|
EXPECT_NE((void *)NULL, a);
|
|
|
|
EXPECT_EQ(a, ares_htable_asvp_get_direct(h, a->s));
|
|
|
|
EXPECT_TRUE(ares_htable_asvp_get(h, a->s, NULL));
|
|
|
|
EXPECT_TRUE(ares_htable_asvp_remove(h, a->s));
|
|
|
|
ares_llist_node_destroy(n);
|
|
|
|
n = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(0, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(0, ares_htable_asvp_num_keys(h));
|
|
|
|
|
|
|
|
ares_llist_destroy(l);
|
|
|
|
ares_htable_asvp_destroy(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
size_t s;
|
|
|
|
} test_htable_szvp_t;
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableSzvp) {
|
|
|
|
ares_llist_t *l = NULL;
|
|
|
|
ares_htable_szvp_t *h = NULL;
|
|
|
|
ares_llist_node_t *n = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
#define SZVP_TABLE_SIZE 1000
|
|
|
|
|
|
|
|
l = ares_llist_create(NULL);
|
|
|
|
EXPECT_NE((void *)NULL, l);
|
|
|
|
|
|
|
|
h = ares_htable_szvp_create(ares_free);
|
|
|
|
EXPECT_NE((void *)NULL, h);
|
|
|
|
|
|
|
|
for (i=0; i<SZVP_TABLE_SIZE; i++) {
|
|
|
|
test_htable_szvp_t *s = (test_htable_szvp_t *)ares_malloc_zero(sizeof(*s));
|
|
|
|
EXPECT_NE((void *)NULL, s);
|
|
|
|
s->s = i+1;
|
|
|
|
EXPECT_NE((void *)NULL, ares_llist_insert_last(l, s));
|
|
|
|
EXPECT_TRUE(ares_htable_szvp_insert(h, s->s, s));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(SZVP_TABLE_SIZE, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(SZVP_TABLE_SIZE, ares_htable_szvp_num_keys(h));
|
|
|
|
|
|
|
|
n = ares_llist_node_first(l);
|
|
|
|
EXPECT_NE((void *)NULL, n);
|
|
|
|
while (n != NULL) {
|
|
|
|
ares_llist_node_t *next = ares_llist_node_next(n);
|
|
|
|
test_htable_szvp_t *s = (test_htable_szvp_t *)ares_llist_node_val(n);
|
|
|
|
EXPECT_NE((void *)NULL, s);
|
|
|
|
EXPECT_EQ(s, ares_htable_szvp_get_direct(h, s->s));
|
|
|
|
EXPECT_TRUE(ares_htable_szvp_get(h, s->s, NULL));
|
|
|
|
EXPECT_TRUE(ares_htable_szvp_remove(h, s->s));
|
|
|
|
ares_llist_node_destroy(n);
|
|
|
|
n = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(0, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(0, ares_htable_szvp_num_keys(h));
|
|
|
|
|
|
|
|
ares_llist_destroy(l);
|
|
|
|
ares_htable_szvp_destroy(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char s[32];
|
|
|
|
} test_htable_vpstr_t;
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableVpstr) {
|
|
|
|
ares_llist_t *l = NULL;
|
|
|
|
ares_htable_vpstr_t *h = NULL;
|
|
|
|
ares_llist_node_t *n = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
#define VPSTR_TABLE_SIZE 1000
|
|
|
|
|
|
|
|
l = ares_llist_create(ares_free);
|
|
|
|
EXPECT_NE((void *)NULL, l);
|
|
|
|
|
|
|
|
h = ares_htable_vpstr_create();
|
|
|
|
EXPECT_NE((void *)NULL, h);
|
|
|
|
|
|
|
|
for (i=0; i<VPSTR_TABLE_SIZE; i++) {
|
|
|
|
test_htable_vpstr_t *s = (test_htable_vpstr_t *)ares_malloc_zero(sizeof(*s));
|
|
|
|
EXPECT_NE((void *)NULL, s);
|
|
|
|
snprintf(s->s, sizeof(s->s), "%d", (int)i);
|
|
|
|
EXPECT_NE((void *)NULL, ares_llist_insert_last(l, s));
|
|
|
|
EXPECT_TRUE(ares_htable_vpstr_insert(h, s, s->s));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(VPSTR_TABLE_SIZE, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(VPSTR_TABLE_SIZE, ares_htable_vpstr_num_keys(h));
|
|
|
|
|
|
|
|
n = ares_llist_node_first(l);
|
|
|
|
EXPECT_NE((void *)NULL, n);
|
|
|
|
while (n != NULL) {
|
|
|
|
ares_llist_node_t *next = ares_llist_node_next(n);
|
|
|
|
test_htable_vpstr_t *s = (test_htable_vpstr_t *)ares_llist_node_val(n);
|
|
|
|
EXPECT_NE((void *)NULL, s);
|
|
|
|
EXPECT_STREQ(s->s, ares_htable_vpstr_get_direct(h, s));
|
|
|
|
EXPECT_TRUE(ares_htable_vpstr_get(h, s, NULL));
|
|
|
|
EXPECT_TRUE(ares_htable_vpstr_remove(h, s));
|
|
|
|
ares_llist_node_destroy(n);
|
|
|
|
n = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(0, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(0, ares_htable_vpstr_num_keys(h));
|
|
|
|
|
|
|
|
ares_llist_destroy(l);
|
|
|
|
ares_htable_vpstr_destroy(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char s[32];
|
|
|
|
} test_htable_strvp_t;
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableStrvp) {
|
|
|
|
ares_llist_t *l = NULL;
|
|
|
|
ares_htable_strvp_t *h = NULL;
|
|
|
|
ares_llist_node_t *n = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
#define STRVP_TABLE_SIZE 1000
|
|
|
|
|
|
|
|
l = ares_llist_create(NULL);
|
|
|
|
EXPECT_NE((void *)NULL, l);
|
|
|
|
|
|
|
|
h = ares_htable_strvp_create(ares_free);
|
|
|
|
EXPECT_NE((void *)NULL, h);
|
|
|
|
|
|
|
|
for (i=0; i<STRVP_TABLE_SIZE; i++) {
|
|
|
|
test_htable_strvp_t *s = (test_htable_strvp_t *)ares_malloc_zero(sizeof(*s));
|
|
|
|
EXPECT_NE((void *)NULL, s);
|
|
|
|
snprintf(s->s, sizeof(s->s), "%d", (int)i);
|
|
|
|
EXPECT_NE((void *)NULL, ares_llist_insert_last(l, s));
|
|
|
|
EXPECT_TRUE(ares_htable_strvp_insert(h, s->s, s));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(STRVP_TABLE_SIZE, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(STRVP_TABLE_SIZE, ares_htable_strvp_num_keys(h));
|
|
|
|
|
|
|
|
n = ares_llist_node_first(l);
|
|
|
|
EXPECT_NE((void *)NULL, n);
|
|
|
|
while (n != NULL) {
|
|
|
|
ares_llist_node_t *next = ares_llist_node_next(n);
|
|
|
|
test_htable_strvp_t *s = (test_htable_strvp_t *)ares_llist_node_val(n);
|
|
|
|
EXPECT_NE((void *)NULL, s);
|
|
|
|
EXPECT_EQ(s, ares_htable_strvp_get_direct(h, s->s));
|
|
|
|
EXPECT_TRUE(ares_htable_strvp_get(h, s->s, NULL));
|
|
|
|
EXPECT_TRUE(ares_htable_strvp_remove(h, s->s));
|
|
|
|
ares_llist_node_destroy(n);
|
|
|
|
n = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(0, ares_llist_len(l));
|
|
|
|
EXPECT_EQ(0, ares_htable_strvp_num_keys(h));
|
|
|
|
|
|
|
|
ares_llist_destroy(l);
|
|
|
|
ares_htable_strvp_destroy(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryTest, HtableDict) {
|
|
|
|
ares_htable_dict_t *h = NULL;
|
|
|
|
size_t i;
|
|
|
|
char **keys;
|
|
|
|
size_t nkeys;
|
|
|
|
|
|
|
|
#define DICT_TABLE_SIZE 1000
|
|
|
|
|
|
|
|
h = ares_htable_dict_create();
|
|
|
|
EXPECT_NE((void *)NULL, h);
|
|
|
|
|
|
|
|
for (i=0; i<DICT_TABLE_SIZE; i++) {
|
|
|
|
char key[32];
|
|
|
|
char val[32];
|
|
|
|
snprintf(key, sizeof(key), "%d", (int)i);
|
|
|
|
snprintf(val, sizeof(val), "val%d", (int)i);
|
|
|
|
EXPECT_TRUE(ares_htable_dict_insert(h, key, val));
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_EQ(DICT_TABLE_SIZE, ares_htable_dict_num_keys(h));
|
|
|
|
|
|
|
|
keys = ares_htable_dict_keys(h, &nkeys);
|
|
|
|
for (i=0; i<nkeys; i++) {
|
|
|
|
char val[32];
|
|
|
|
snprintf(val, sizeof(val), "val%s", keys[i]);
|
|
|
|
EXPECT_STREQ(val, ares_htable_dict_get_direct(h, keys[i]));
|
|
|
|
EXPECT_TRUE(ares_htable_dict_get(h, keys[i], NULL));
|
|
|
|
EXPECT_TRUE(ares_htable_dict_remove(h, keys[i]));
|
|
|
|
}
|
|
|
|
ares_free_array(keys, nkeys, ares_free);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, ares_htable_dict_num_keys(h));
|
|
|
|
|
|
|
|
ares_htable_dict_destroy(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DefaultChannelTest, SaveInvalidChannel) {
|
|
|
|
ares_slist_t *saved = channel_->servers;
|
Dynamic Server List (#594)
This PR makes the server list a dynamic sorted list of servers. The sort order is [ consecutive failures, system config index ]. The server list can be updated via ares_set_servers_*(). Any queries currently directed to servers that are no longer in the list will be automatically re-queued to a different server.
Also, any time a failure occurs on the server, the sort order of the servers will be updated so that the one with the fewest consecutive failures is chosen for the next query that goes on the wire, this way bad or non-responsive servers are automatically isolated.
Since the server list is now dynamic, the tracking of query failures per server has been removed and instead is relying on the server sort order as previously described. This simplifies the logic while also reducing the amount of memory required per query. However, because of this dynamic nature, it may not be easy to determine the server attempt order for enqueued queries if there have been any failures.
If using the ARES_OPT_ROTATE, this is now implemented to be a random selection of the configured servers. Since the server list is dynamic, its not possible to go to the next server as configuration could have changed between queries or attempts for the same query.
Finally, this PR moved some existing functions into new files to logically separate them.
This should address issues #550 and #440, while also setting the framework to implement #301. #301 needs a little more effort since it configures things other than the servers themselves (domains, search, sortlist, lookups), which need to make sure they can be safely updated.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
channel_->servers = NULL;
|
|
|
|
struct ares_options opts;
|
|
|
|
int optmask = 0;
|
|
|
|
EXPECT_EQ(ARES_ENODATA, ares_save_options(channel_, &opts, &optmask));
|
Dynamic Server List (#594)
This PR makes the server list a dynamic sorted list of servers. The sort order is [ consecutive failures, system config index ]. The server list can be updated via ares_set_servers_*(). Any queries currently directed to servers that are no longer in the list will be automatically re-queued to a different server.
Also, any time a failure occurs on the server, the sort order of the servers will be updated so that the one with the fewest consecutive failures is chosen for the next query that goes on the wire, this way bad or non-responsive servers are automatically isolated.
Since the server list is now dynamic, the tracking of query failures per server has been removed and instead is relying on the server sort order as previously described. This simplifies the logic while also reducing the amount of memory required per query. However, because of this dynamic nature, it may not be easy to determine the server attempt order for enqueued queries if there have been any failures.
If using the ARES_OPT_ROTATE, this is now implemented to be a random selection of the configured servers. Since the server list is dynamic, its not possible to go to the next server as configuration could have changed between queries or attempts for the same query.
Finally, this PR moved some existing functions into new files to logically separate them.
This should address issues #550 and #440, while also setting the framework to implement #301. #301 needs a little more effort since it configures things other than the servers themselves (domains, search, sortlist, lookups), which need to make sure they can be safely updated.
Fix By: Brad House (@bradh352)
1 year ago
|
|
|
channel_->servers = saved;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to put this in own function due to nested lambda bug
|
|
|
|
// in VS2013. (C2888)
|
|
|
|
static int configure_socket(ares_socket_t s) {
|
|
|
|
// transposed from ares-process, simplified non-block setter.
|
|
|
|
#if defined(USE_BLOCKING_SOCKETS)
|
|
|
|
return 0; /* returns success */
|
|
|
|
#elif defined(HAVE_FCNTL_O_NONBLOCK)
|
|
|
|
/* most recent unix versions */
|
|
|
|
int flags;
|
|
|
|
flags = fcntl(s, F_GETFL, 0);
|
|
|
|
return fcntl(s, F_SETFL, flags | O_NONBLOCK);
|
|
|
|
#elif defined(HAVE_IOCTL_FIONBIO)
|
|
|
|
/* older unix versions */
|
|
|
|
int flags = 1;
|
|
|
|
return ioctl(s, FIONBIO, &flags);
|
|
|
|
#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
|
|
|
|
#ifdef WATT32
|
|
|
|
char flags = 1;
|
|
|
|
#else
|
|
|
|
/* Windows */
|
|
|
|
unsigned long flags = 1UL;
|
|
|
|
#endif
|
|
|
|
return ioctlsocket(s, (long)FIONBIO, &flags);
|
|
|
|
#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
|
|
|
|
/* Amiga */
|
|
|
|
long flags = 1L;
|
|
|
|
return IoctlSocket(s, FIONBIO, flags);
|
|
|
|
#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
|
|
|
|
/* BeOS */
|
|
|
|
long b = 1L;
|
|
|
|
return setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
|
|
|
|
#else
|
|
|
|
# error "no non-blocking method was found/used/set"
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: This should not really be in this file, but we need ares config
|
|
|
|
// flags, and here they are available.
|
|
|
|
const struct ares_socket_functions VirtualizeIO::default_functions = {
|
|
|
|
[](int af, int type, int protocol, void *) -> ares_socket_t {
|
|
|
|
auto s = ::socket(af, type, protocol);
|
|
|
|
if (s == ARES_SOCKET_BAD) {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
if (configure_socket(s) != 0) {
|
|
|
|
sclose(s);
|
|
|
|
return ares_socket_t(-1);
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
},
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace test
|
|
|
|
} // namespace ares
|