libnm-core: add new functions for DNS parsing
Introduce new functions to parse and normalize name servers. Their name contains "dns_uri" because they also support a URI-like syntax as: "dns+tls://192.0.2.0:553#example.org".
This commit is contained in:
@@ -810,6 +810,299 @@ nm_utils_dnsname_normalize(int addr_family, const char *dns, char **out_free)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nm_dns_uri_parse:
|
||||||
|
* @addr_family: the address family, or AF_UNSPEC to autodetect it
|
||||||
|
* @str: the name server URI string to parse
|
||||||
|
* @dns: the name server descriptor to fill, or %NULL
|
||||||
|
*
|
||||||
|
* Parses the given name server URI string. Each name server is represented
|
||||||
|
* by the following grammar:
|
||||||
|
*
|
||||||
|
* NAMESERVER := { PLAIN | TLS_URI | UDP_URI }
|
||||||
|
* PLAIN := { ipv4address | ipv6address } [ '#' SERVERNAME ]
|
||||||
|
* TLS_URI := 'dns+tls://' URI_ADDRESS [ ':' PORT ] [ '#' SERVERNAME ]
|
||||||
|
* UDP_URI := 'dns+udp://' URI_ADDRESS [ ':' PORT ]
|
||||||
|
* URI_ADDRESS := { ipv4address | '[' ipv6address [ '%' ifname ] ']' }
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* 192.0.2.0
|
||||||
|
* 192.0.2.0#example.com
|
||||||
|
* 2001:db8::1
|
||||||
|
* dns+tls://192.0.2.0
|
||||||
|
* dns+tls://[2001:db8::1]
|
||||||
|
* dns+tls://192.0.2.0:53#example.com
|
||||||
|
* dns+udp://[fe80::1%enp1s0]
|
||||||
|
*
|
||||||
|
* Note that on return, the lifetime of the members in the @dns struct is
|
||||||
|
* the same as the input string @str.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE on success, %FALSE on failure
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns)
|
||||||
|
{
|
||||||
|
NMDnsServer dns_stack;
|
||||||
|
gs_free char *addr_port_heap = NULL;
|
||||||
|
gs_free char *addr_heap = NULL;
|
||||||
|
const char *addr_port;
|
||||||
|
const char *addr;
|
||||||
|
const char *name;
|
||||||
|
const char *port;
|
||||||
|
|
||||||
|
nm_assert_addr_family_or_unspec(addr_family);
|
||||||
|
|
||||||
|
if (!dns)
|
||||||
|
dns = &dns_stack;
|
||||||
|
|
||||||
|
if (!str)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
*dns = (NMDnsServer) {
|
||||||
|
.port = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (NM_STR_HAS_PREFIX(str, "dns+tls://")) {
|
||||||
|
dns->scheme = NM_DNS_URI_SCHEME_TLS;
|
||||||
|
str += NM_STRLEN("dns+tls://");
|
||||||
|
} else if (NM_STR_HAS_PREFIX(str, "dns+udp://")) {
|
||||||
|
dns->scheme = NM_DNS_URI_SCHEME_UDP;
|
||||||
|
str += NM_STRLEN("dns+udp://");
|
||||||
|
} else {
|
||||||
|
name = strchr(str, '#');
|
||||||
|
if (name) {
|
||||||
|
str = nm_strndup_a(200, str, name - str, &addr_heap);
|
||||||
|
name++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name && name[0] == '\0') {
|
||||||
|
/* empty DoT server name is not allowed */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nm_inet_parse_bin(addr_family, str, &dns->addr_family, &dns->addr))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
dns->servername = name;
|
||||||
|
dns->scheme = NM_DNS_URI_SCHEME_NONE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_port = str;
|
||||||
|
name = strrchr(addr_port, '#');
|
||||||
|
if (name) {
|
||||||
|
addr_port = nm_strndup_a(100, addr_port, name - addr_port, &addr_port_heap);
|
||||||
|
name++;
|
||||||
|
if (*name == '\0') {
|
||||||
|
/* empty DoT server name not allowed */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
dns->servername = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr_family != AF_INET && *addr_port == '[') {
|
||||||
|
const char *end;
|
||||||
|
char *perc;
|
||||||
|
|
||||||
|
addr_family = AF_INET6;
|
||||||
|
addr_port++;
|
||||||
|
end = strchr(addr_port, ']');
|
||||||
|
if (!end)
|
||||||
|
return FALSE;
|
||||||
|
addr = nm_strndup_a(100, addr_port, end - addr_port, &addr_heap);
|
||||||
|
|
||||||
|
/* IPv6 link-local scope-id */
|
||||||
|
perc = strchr(addr, '%');
|
||||||
|
if (perc) {
|
||||||
|
*perc = '\0';
|
||||||
|
if (g_strlcpy(dns->interface, perc + 1, sizeof(dns->interface))
|
||||||
|
>= sizeof(dns->interface))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* port */
|
||||||
|
end++;
|
||||||
|
if (*end == ':') {
|
||||||
|
end++;
|
||||||
|
dns->port = _nm_utils_ascii_str_to_int64(end, 10, 0, 65535, G_MAXINT32);
|
||||||
|
if (dns->port == G_MAXINT32)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else if (addr_family != AF_INET6) {
|
||||||
|
/* square brackets are mandatory for IPv6, so it must be IPv4 */
|
||||||
|
|
||||||
|
addr_family = AF_INET;
|
||||||
|
addr = addr_port;
|
||||||
|
|
||||||
|
/* port */
|
||||||
|
port = strchr(addr_port, ':');
|
||||||
|
if (port) {
|
||||||
|
addr = nm_strndup_a(100, addr_port, port - addr_port, &addr_heap);
|
||||||
|
port++;
|
||||||
|
dns->port = _nm_utils_ascii_str_to_int64(port, 10, 0, 65535, G_MAXINT32);
|
||||||
|
if (dns->port == G_MAXINT32)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nm_inet_parse_bin(addr_family, addr, &dns->addr_family, &dns->addr))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (dns->scheme != NM_DNS_URI_SCHEME_TLS && dns->servername)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* For now, allow the interface only for IPv6 link-local addresses */
|
||||||
|
if (dns->interface[0]
|
||||||
|
&& (dns->addr_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&dns->addr.addr6)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @nm_dns_uri_parse_plain:
|
||||||
|
* @addr_family: the address family, or AF_UNSPEC to autodetect it
|
||||||
|
* @str: the name server URI string
|
||||||
|
* @out_addrstr: the buffer to fill with the address string on return,
|
||||||
|
* or %NULL. Must be of size at least NM_INET_ADDRSTRLEN.
|
||||||
|
* @out_addr: the %NMIPAddr struct to fill on return, or %NULL
|
||||||
|
*
|
||||||
|
* Returns whether the string contains a "plain" (DNS over UDP on port 53)
|
||||||
|
* name server. In such case, it fills the arguments with the address
|
||||||
|
* of the name server.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE on success, %FALSE if the string can't be parsed or
|
||||||
|
* if it's not a plain name server.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
nm_dns_uri_parse_plain(int addr_family, const char *str, char *out_addrstr, NMIPAddr *out_addr)
|
||||||
|
{
|
||||||
|
NMDnsServer dns;
|
||||||
|
|
||||||
|
if (!nm_dns_uri_parse(addr_family, str, &dns))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (dns.scheme) {
|
||||||
|
case NM_DNS_URI_SCHEME_TLS:
|
||||||
|
return FALSE;
|
||||||
|
case NM_DNS_URI_SCHEME_NONE:
|
||||||
|
NM_SET_OUT(out_addr, dns.addr);
|
||||||
|
if (out_addrstr) {
|
||||||
|
nm_inet_ntop(dns.addr_family, &dns.addr, out_addrstr);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
case NM_DNS_URI_SCHEME_UDP:
|
||||||
|
if (dns.port != -1 && dns.port != 53)
|
||||||
|
return FALSE;
|
||||||
|
if (dns.interface[0])
|
||||||
|
return FALSE;
|
||||||
|
NM_SET_OUT(out_addr, dns.addr);
|
||||||
|
if (out_addrstr) {
|
||||||
|
nm_inet_ntop(dns.addr_family, &dns.addr, out_addrstr);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
case NM_DNS_URI_SCHEME_UNKNOWN:
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @nm_dns_uri_normalize:
|
||||||
|
* @addr_family: the address family, or AF_UNSPEC to autodetect it
|
||||||
|
* @str: the name server URI string
|
||||||
|
* @out_free: the newly-allocated string to set on return, or %NULL
|
||||||
|
*
|
||||||
|
* Returns the "normal" representation for the given name server URI.
|
||||||
|
* Note that a plain name server (DNS over UDP on port 53) is always
|
||||||
|
* represented in the "legacy" (non-URI) form.
|
||||||
|
*
|
||||||
|
* Returns: the normalized DNS URI
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
nm_dns_uri_normalize(int addr_family, const char *str, char **out_free)
|
||||||
|
{
|
||||||
|
NMDnsServer dns;
|
||||||
|
char addrstr[NM_INET_ADDRSTRLEN];
|
||||||
|
char portstr[32];
|
||||||
|
char *ret;
|
||||||
|
gsize len;
|
||||||
|
|
||||||
|
nm_assert_addr_family_or_unspec(addr_family);
|
||||||
|
nm_assert(str);
|
||||||
|
nm_assert(out_free && !*out_free);
|
||||||
|
|
||||||
|
if (!nm_dns_uri_parse(addr_family, str, &dns))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nm_inet_ntop(dns.addr_family, &dns.addr, addrstr);
|
||||||
|
|
||||||
|
if (dns.port != -1) {
|
||||||
|
nm_assert(dns.port >= 0 && dns.port <= 65535);
|
||||||
|
g_snprintf(portstr, sizeof(portstr), "%d", dns.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dns.scheme) {
|
||||||
|
case NM_DNS_URI_SCHEME_NONE:
|
||||||
|
len = strlen(addrstr);
|
||||||
|
/* In the vast majority of cases, the name is in fact normalized. Check
|
||||||
|
* whether it is, and don't duplicate the string. */
|
||||||
|
if (strncmp(str, addrstr, len) == 0) {
|
||||||
|
if (dns.servername) {
|
||||||
|
if (str[len] == '#' && nm_streq(&str[len + 1], dns.servername))
|
||||||
|
return str;
|
||||||
|
} else {
|
||||||
|
if (str[len] == '\0')
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dns.servername)
|
||||||
|
ret = g_strdup(addrstr);
|
||||||
|
else
|
||||||
|
ret = g_strconcat(addrstr, "#", dns.servername, NULL);
|
||||||
|
break;
|
||||||
|
case NM_DNS_URI_SCHEME_UDP:
|
||||||
|
if (dns.interface[0] || dns.port != -1) {
|
||||||
|
ret = g_strdup_printf("dns+udp://%s%s%s%s%s%s%s",
|
||||||
|
dns.addr_family == AF_INET6 ? "[" : "",
|
||||||
|
addrstr,
|
||||||
|
dns.interface[0] ? "%" : "",
|
||||||
|
dns.interface[0] ? dns.interface : "",
|
||||||
|
dns.addr_family == AF_INET6 ? "]" : "",
|
||||||
|
dns.port != -1 ? ":" : "",
|
||||||
|
dns.port != -1 ? portstr : "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = g_strdup_printf("%s%s%s", addrstr, dns.servername ? "#" : "", dns.servername ?: "");
|
||||||
|
break;
|
||||||
|
case NM_DNS_URI_SCHEME_TLS:
|
||||||
|
ret = g_strdup_printf("dns+tls://%s%s%s%s%s%s%s%s%s",
|
||||||
|
dns.addr_family == AF_INET6 ? "[" : "",
|
||||||
|
addrstr,
|
||||||
|
dns.interface[0] ? "%%" : "",
|
||||||
|
dns.interface[0] ? dns.interface : "",
|
||||||
|
dns.addr_family == AF_INET6 ? "]" : "",
|
||||||
|
dns.port != -1 ? ":" : "",
|
||||||
|
dns.port != -1 ? portstr : "",
|
||||||
|
dns.servername ? "#" : "",
|
||||||
|
dns.servername ?: "");
|
||||||
|
break;
|
||||||
|
case NM_DNS_URI_SCHEME_UNKNOWN:
|
||||||
|
default:
|
||||||
|
nm_assert_not_reached();
|
||||||
|
ret = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_free = ret;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nm_setting_ovs_other_config_check_key:
|
* nm_setting_ovs_other_config_check_key:
|
||||||
* @key: (nullable): the key to check
|
* @key: (nullable): the key to check
|
||||||
|
@@ -341,6 +341,29 @@ const char *nm_utils_dnsname_normalize(int addr_family, const char *dns, char **
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NM_DNS_URI_SCHEME_UNKNOWN,
|
||||||
|
NM_DNS_URI_SCHEME_NONE,
|
||||||
|
NM_DNS_URI_SCHEME_UDP,
|
||||||
|
NM_DNS_URI_SCHEME_TLS,
|
||||||
|
} NMDnsUriScheme;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NMIPAddr addr;
|
||||||
|
const char *servername;
|
||||||
|
char interface[NM_IFNAMSIZ];
|
||||||
|
NMDnsUriScheme scheme;
|
||||||
|
int addr_family;
|
||||||
|
int port;
|
||||||
|
} NMDnsServer;
|
||||||
|
|
||||||
|
gboolean nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *out_dns);
|
||||||
|
gboolean
|
||||||
|
nm_dns_uri_parse_plain(int addr_family, const char *str, char *out_addrstr, NMIPAddr *out_addr);
|
||||||
|
const char *nm_dns_uri_normalize(int addr_family, const char *str, char **out_free);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
gboolean nm_setting_ovs_other_config_check_key(const char *key, GError **error);
|
gboolean nm_setting_ovs_other_config_check_key(const char *key, GError **error);
|
||||||
gboolean nm_setting_ovs_other_config_check_val(const char *val, GError **error);
|
gboolean nm_setting_ovs_other_config_check_val(const char *val, GError **error);
|
||||||
|
|
||||||
|
@@ -11571,6 +11571,184 @@ test_dnsname(void)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
t_dns_0(const char *str)
|
||||||
|
{
|
||||||
|
NMDnsServer server = {};
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
ret = nm_dns_uri_parse(AF_UNSPEC, str, &server);
|
||||||
|
|
||||||
|
g_assert(!ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dns_uri_parse_ok(const char *str,
|
||||||
|
int addr_family,
|
||||||
|
NMDnsUriScheme scheme,
|
||||||
|
const char *addr,
|
||||||
|
int port,
|
||||||
|
const char *sname,
|
||||||
|
const char *ifname)
|
||||||
|
{
|
||||||
|
NMDnsServer dns = {};
|
||||||
|
char addrstr[NM_INET_ADDRSTRLEN];
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
gboolean af_unspec = i;
|
||||||
|
|
||||||
|
ret = nm_dns_uri_parse(af_unspec ? AF_UNSPEC : addr_family, str, &dns);
|
||||||
|
g_assert(ret);
|
||||||
|
|
||||||
|
g_assert_cmpint(addr_family, ==, dns.addr_family);
|
||||||
|
g_assert_cmpint(port, ==, dns.port);
|
||||||
|
g_assert_cmpstr(sname, ==, dns.servername);
|
||||||
|
g_assert_cmpstr(ifname ?: "", ==, dns.interface);
|
||||||
|
|
||||||
|
nm_inet_ntop(dns.addr_family, &dns.addr, addrstr);
|
||||||
|
g_assert_cmpstr(addrstr, ==, addr);
|
||||||
|
|
||||||
|
/* Parse with the wrong address family must fail */
|
||||||
|
ret = nm_dns_uri_parse(addr_family == AF_INET ? AF_INET6 : AF_INET, str, &dns);
|
||||||
|
g_assert(!ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define t_dns_1(str, af, scheme, addr, port, sname, ifname) \
|
||||||
|
dns_uri_parse_ok((str), \
|
||||||
|
(AF_##af), \
|
||||||
|
(NM_DNS_URI_SCHEME_##scheme), \
|
||||||
|
(addr), \
|
||||||
|
(port), \
|
||||||
|
(sname), \
|
||||||
|
(ifname))
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_dns_uri_parse(void)
|
||||||
|
{
|
||||||
|
/* clang-format off */
|
||||||
|
t_dns_1("dns+tls://8.8.8.8", INET, TLS, "8.8.8.8", -1, NULL, NULL);
|
||||||
|
t_dns_1("dns+tls://8.8.8.8", INET, TLS, "8.8.8.8", -1, NULL, NULL);
|
||||||
|
t_dns_1("dns+tls://1.2.3.4#name", INET, TLS, "1.2.3.4", -1, "name", NULL);
|
||||||
|
t_dns_1("dns+tls://1.2.3.4#a.b.c", INET, TLS, "1.2.3.4", -1, "a.b.c", NULL);
|
||||||
|
t_dns_1("dns+tls://1.2.3.4:53", INET, TLS, "1.2.3.4", 53, NULL, NULL);
|
||||||
|
t_dns_1("dns+tls://1.2.3.4:53#foobar", INET, TLS, "1.2.3.4", 53, "foobar", NULL);
|
||||||
|
t_dns_1("dns+tls://192.168.120.250:99", INET, TLS, "192.168.120.250", 99, NULL, NULL);
|
||||||
|
t_dns_1("dns+udp://8.8.8.8:65535", INET, UDP, "8.8.8.8", 65535, NULL, NULL);
|
||||||
|
|
||||||
|
t_dns_1("dns+udp://[fd01::1]", INET6, UDP, "fd01::1", -1, NULL, NULL);
|
||||||
|
t_dns_1("dns+tls://[fd01::2]:5353", INET6, UDP, "fd01::2", 5353, NULL, NULL);
|
||||||
|
t_dns_1("dns+tls://[::1]#name", INET6, UDP, "::1", -1, "name", NULL);
|
||||||
|
t_dns_1("dns+tls://[::2]:65535#name", INET6, UDP, "::2", 65535, "name", NULL);
|
||||||
|
t_dns_1("dns+udp://[::ffff:1.2.3.4]", INET6, UDP, "::ffff:1.2.3.4", -1, NULL, NULL);
|
||||||
|
t_dns_1("dns+tls://[fe80::1%eth0]", INET6, UDP, "fe80::1", -1, NULL, "eth0");
|
||||||
|
t_dns_1("dns+tls://[fe80::2%en1]:53#a", INET6, UDP, "fe80::2", 53, "a", "en1");
|
||||||
|
t_dns_1("dns+tls://[fe80::1%en3456789012345]", INET6, UDP, "fe80::1", -1, NULL, "en3456789012345");
|
||||||
|
|
||||||
|
t_dns_1("1.2.3.4", INET, NONE, "1.2.3.4", -1, NULL, NULL);
|
||||||
|
t_dns_1("1.2.3.4#foo", INET, NONE, "1.2.3.4", -1, "foo", NULL);
|
||||||
|
t_dns_1("1::#x", INET6, NONE, "1::", -1, "x", NULL);
|
||||||
|
t_dns_1("1::0#x", INET6, NONE, "1::", -1, "x", NULL);
|
||||||
|
t_dns_1("192.168.0.1", INET, NONE, "192.168.0.1", -1, NULL, NULL);
|
||||||
|
t_dns_1("192.168.0.1#tst.com", INET, NONE, "192.168.0.1", -1, "tst.com", NULL);
|
||||||
|
t_dns_1("fe80::18", INET6, NONE, "fe80::18", -1, NULL, NULL);
|
||||||
|
t_dns_1("fe80::18#foo.com", INET6, NONE, "fe80::18", -1, "foo.com", NULL);
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
t_dns_0("http://8.8.8.8"); /* unsupported schema */
|
||||||
|
t_dns_0("dns+udp://1.2.3.4#name"); /* servername not supported for plain UDP */
|
||||||
|
t_dns_0("dns+tls://1.2.3"); /* invalid address */
|
||||||
|
t_dns_0("dns+tls://fd01::1"); /* IPv6 requires brackets */
|
||||||
|
t_dns_0("dns+tls://[fd13:a:aaaa]"); /* invalid address */
|
||||||
|
t_dns_0("dns+tls://1.2.3.4:1:1"); /* invalid syntax */
|
||||||
|
t_dns_0("dns+tls://1.2.3.4#name#name"); /* invalid syntax */
|
||||||
|
t_dns_0("dns+tls://1.2.3.4%eth0"); /* interface only allowed for IPv6 */
|
||||||
|
t_dns_0("dns+tls://[2001::1%eth0]"); /* interface only allowed for IPv6 link-local */
|
||||||
|
t_dns_0("dns+tls://[fe80::1%en34567890123456]"); /* interface name too long */
|
||||||
|
t_dns_0("1.2.3.4#");
|
||||||
|
t_dns_0("1::0#");
|
||||||
|
t_dns_0("192.168.0.1:53");
|
||||||
|
t_dns_0("192.168.0.1:53#example.com");
|
||||||
|
t_dns_0("fe80::18%19");
|
||||||
|
t_dns_0("fe80::18%lo");
|
||||||
|
t_dns_0("[fe80::18]:53");
|
||||||
|
t_dns_0("[fe80::18]:53%19");
|
||||||
|
t_dns_0("[fe80::18]:53%lo");
|
||||||
|
t_dns_0("fe80::18%19#hoge.com");
|
||||||
|
t_dns_0("[fe80::18]:53#hoge.com");
|
||||||
|
t_dns_0("[fe80::18]:53%19");
|
||||||
|
t_dns_0("[fe80::18]:53%19#hoge.com");
|
||||||
|
t_dns_0("[fe80::18]:53%lo");
|
||||||
|
t_dns_0("[fe80::18]:53%lo#hoge.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_dns_uri_parse_plain(void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
const char *input;
|
||||||
|
int input_af;
|
||||||
|
gboolean result;
|
||||||
|
const char *addrstr;
|
||||||
|
} values[] = {
|
||||||
|
{"1.2.3.4", AF_INET, TRUE, "1.2.3.4"},
|
||||||
|
{"1.2.3.4", AF_INET6, FALSE, NULL},
|
||||||
|
{"1.2.3.4", AF_UNSPEC, TRUE, "1.2.3.4"},
|
||||||
|
{"1234:5555:ffff:dddd::4321", AF_INET, FALSE, NULL},
|
||||||
|
{"1234:5555:ffff:dddd::4321", AF_INET6, TRUE, "1234:5555:ffff:dddd::4321"},
|
||||||
|
{"1234:5555:ffff:dddd::4321", AF_UNSPEC, TRUE, "1234:5555:ffff:dddd::4321"},
|
||||||
|
{"192.0.2.1#example.com", AF_INET, TRUE, "192.0.2.1"},
|
||||||
|
{"192.0.2.1#example.com", AF_UNSPEC, TRUE, "192.0.2.1"},
|
||||||
|
{"192.0.2.1#example.com", AF_INET6, FALSE, NULL},
|
||||||
|
{"dns+tls://1.2.3.4", AF_INET, FALSE, NULL},
|
||||||
|
{"dns+tls://[fd01::1]", AF_INET, FALSE, NULL},
|
||||||
|
{"dns+udp://1.2.3.4:53", AF_INET, TRUE, "1.2.3.4"},
|
||||||
|
{"dns+udp://1.2.3.4:54", AF_INET, FALSE, NULL},
|
||||||
|
{"dns+udp://[fd01::1]", AF_INET6, TRUE, "fd01::1"},
|
||||||
|
{"dns+udp://[fd01::1]:53", AF_INET6, TRUE, "fd01::1"},
|
||||||
|
{"dns+udp://[fd01::1]:60000", AF_INET, FALSE, NULL},
|
||||||
|
};
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS(values); i++) {
|
||||||
|
char addrstr[NM_INET_ADDRSTRLEN];
|
||||||
|
gboolean result;
|
||||||
|
NMIPAddr addr;
|
||||||
|
|
||||||
|
result = nm_dns_uri_parse_plain(values[i].input_af, values[i].input, addrstr, &addr);
|
||||||
|
g_assert_cmpint(result, ==, values[i].result);
|
||||||
|
if (result) {
|
||||||
|
char buf[NM_INET_ADDRSTRLEN];
|
||||||
|
|
||||||
|
nm_inet_ntop(strchr(addrstr, ':') ? AF_INET6 : AF_INET, addr.addr_ptr, buf);
|
||||||
|
g_assert_cmpstr(buf, ==, addrstr);
|
||||||
|
g_assert_cmpstr(addrstr, ==, values[i].addrstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
t_dns_uri_normalize(const char *input, const char *expected)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
gs_free char *str_free = NULL;
|
||||||
|
|
||||||
|
str = nm_dns_uri_normalize(AF_UNSPEC, input, &str_free);
|
||||||
|
g_assert_cmpstr(str, ==, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_dns_uri_normalize(void)
|
||||||
|
{
|
||||||
|
t_dns_uri_normalize("8.8.8.8", "8.8.8.8");
|
||||||
|
t_dns_uri_normalize("dns+tls://[2001:0:0::1234]:999#name", "dns+tls://[2001::1234]:999#name");
|
||||||
|
t_dns_uri_normalize("dns+udp://[0::1]:0123", "dns+udp://[::1]:123");
|
||||||
|
t_dns_uri_normalize("8.8.8.888", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_dhcp_iaid_hexstr(void)
|
test_dhcp_iaid_hexstr(void)
|
||||||
{
|
{
|
||||||
@@ -11946,6 +12124,9 @@ main(int argc, char **argv)
|
|||||||
g_test_add_func("/core/general/test_direct_string_is_refstr", test_direct_string_is_refstr);
|
g_test_add_func("/core/general/test_direct_string_is_refstr", test_direct_string_is_refstr);
|
||||||
g_test_add_func("/core/general/test_connection_path", test_connection_path);
|
g_test_add_func("/core/general/test_connection_path", test_connection_path);
|
||||||
g_test_add_func("/core/general/test_dnsname", test_dnsname);
|
g_test_add_func("/core/general/test_dnsname", test_dnsname);
|
||||||
|
g_test_add_func("/core/general/test_dns_uri_parse", test_dns_uri_parse);
|
||||||
|
g_test_add_func("/core/general/test_dns_uri_get_legacy", test_dns_uri_parse_plain);
|
||||||
|
g_test_add_func("/core/general/test_dns_uri_normalize", test_dns_uri_normalize);
|
||||||
g_test_add_func("/core/general/test_dhcp_iaid_hexstr", test_dhcp_iaid_hexstr);
|
g_test_add_func("/core/general/test_dhcp_iaid_hexstr", test_dhcp_iaid_hexstr);
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
|
Reference in New Issue
Block a user