aboutsummaryrefslogtreecommitdiffstats
path: root/dirmngr/dns-stuff.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2017-01-16 18:03:39 +0000
committerWerner Koch <[email protected]>2017-01-16 18:12:03 +0000
commit9850124c7bdf0a0e7c1866abc85f3437257d7095 (patch)
tree40ec1305b936f0af27b37eaed6f04ba68c8b7475 /dirmngr/dns-stuff.c
parentdirmngr: Avoid network queries for literal IP addresses. (diff)
downloadgnupg-9850124c7bdf0a0e7c1866abc85f3437257d7095.tar.gz
gnupg-9850124c7bdf0a0e7c1866abc85f3437257d7095.zip
dirmngr: Allow reverse DNS lookups in Tor-mode.
* dirmngr/dns-stuff.c (resolve_dns_name): Move up in the file. (resolve_addr_libdns): New. (resolve_dns_addr): Divert to resolve_dns_addr. -- In the old code reverse lookups where disabled in Tor mode. By implementing the reverse lookups via libdns it is now possible to do them also in Tor mode. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'dirmngr/dns-stuff.c')
-rw-r--r--dirmngr/dns-stuff.c213
1 files changed, 182 insertions, 31 deletions
diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c
index 2debdcad0..28ecb1857 100644
--- a/dirmngr/dns-stuff.c
+++ b/dirmngr/dns-stuff.c
@@ -892,6 +892,177 @@ resolve_name_standard (const char *name, unsigned short port,
}
+/* This a wrapper around getaddrinfo with slightly different semantics.
+ NAME is the name to resolve.
+ PORT is the requested port or 0.
+ WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
+ WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
+
+ On success the result is stored in a linked list with the head
+ stored at the address R_AI; the caller must call gpg_addrinfo_free
+ on this. If R_CANONNAME is not NULL the official name of the host
+ is stored there as a malloced string; if that name is not available
+ NULL is stored. */
+gpg_error_t
+resolve_dns_name (const char *name, unsigned short port,
+ int want_family, int want_socktype,
+ dns_addrinfo_t *r_ai, char **r_canonname)
+{
+ gpg_error_t err;
+
+#ifdef USE_LIBDNS
+ if (!standard_resolver)
+ {
+ err = resolve_name_libdns (name, port, want_family, want_socktype,
+ r_ai, r_canonname);
+ if (err && libdns_switch_port_p (err))
+ err = resolve_name_libdns (name, port, want_family, want_socktype,
+ r_ai, r_canonname);
+ }
+ else
+#endif /*USE_LIBDNS*/
+ err = resolve_name_standard (name, port, want_family, want_socktype,
+ r_ai, r_canonname);
+ if (opt_debug)
+ log_debug ("dns: resolve_dns_name(%s): %s\n", name, gpg_strerror (err));
+ return err;
+}
+
+
+#ifdef USE_LIBDNS
+/* Resolve an address using libdns. */
+static gpg_error_t
+resolve_addr_libdns (const struct sockaddr *addr, int addrlen,
+ unsigned int flags, char **r_name)
+{
+ gpg_error_t err;
+ char host[DNS_D_MAXNAME + 1];
+ struct dns_resolver *res;
+ struct dns_packet *ans = NULL;
+ struct dns_ptr ptr;
+ int derr;
+
+ *r_name = NULL;
+
+ /* First we turn ADDR into a DNS name (with ".arpa" suffix). */
+ err = 0;
+ if (addr->sa_family == AF_INET6)
+ {
+ const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)addr;
+ if (!dns_aaaa_arpa (host, sizeof host, (void*)&a6->sin6_addr))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ }
+ else if (addr->sa_family == AF_INET)
+ {
+ const struct sockaddr_in *a4 = (const struct sockaddr_in *)addr;
+ if (!dns_a_arpa (host, sizeof host, (void*)&a4->sin_addr))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ }
+ else
+ err = gpg_error (GPG_ERR_EAFNOSUPPORT);
+ if (err)
+ goto leave;
+
+
+ err = libdns_res_open (&res);
+ if (err)
+ goto leave;
+
+ err = libdns_res_submit (res, host, DNS_T_PTR, DNS_C_IN);
+ if (err)
+ goto leave;
+
+ err = libdns_res_wait (res);
+ if (err)
+ goto leave;
+
+ ans = dns_res_fetch (res, &derr);
+ if (!ans)
+ {
+ err = libdns_error_to_gpg_error (derr);
+ goto leave;
+ }
+
+ /* Check the rcode. */
+ switch (dns_p_rcode (ans))
+ {
+ case DNS_RC_NOERROR:
+ break;
+ case DNS_RC_NXDOMAIN:
+ err = gpg_error (GPG_ERR_NO_NAME);
+ break;
+ default:
+ err = GPG_ERR_SERVER_FAILED;
+ goto leave;
+ }
+
+ /* Parse the result. */
+ if (!err)
+ {
+ struct dns_rr rr;
+ struct dns_rr_i rri;
+
+ memset (&rri, 0, sizeof rri);
+ dns_rr_i_init (&rri, ans);
+ rri.section = DNS_S_ALL & ~DNS_S_QD;
+ rri.name = host;
+ rri.type = DNS_T_PTR;
+
+ if (!dns_rr_grep (&rr, 1, &rri, ans, &derr))
+ {
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+ goto leave;
+ }
+
+ err = libdns_error_to_gpg_error (dns_ptr_parse (&ptr, &rr, ans));
+ if (err)
+ goto leave;
+
+ /* Copy result. */
+ *r_name = xtrystrdup (ptr.host);
+ if (!*r_name)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ /* Libdns appends the root zone part which is problematic
+ * for most other functions - strip it. */
+ if (**r_name && (*r_name)[strlen (*r_name)-1] == '.')
+ (*r_name)[strlen (*r_name)-1] = 0;
+ }
+ else /* GPG_ERR_NO_NAME */
+ {
+ char *buffer, *p;
+ int buflen;
+ int ec;
+
+ buffer = ptr.host;
+ buflen = sizeof ptr.host;
+
+ p = buffer;
+ if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+ {
+ *p++ = '[';
+ buflen -= 2;
+ }
+ ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
+ if (ec)
+ {
+ err = map_eai_to_gpg_error (ec);
+ goto leave;
+ }
+ if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
+ strcat (buffer, "]");
+ }
+
+ leave:
+ dns_free (ans);
+ dns_res_close (res);
+ return err;
+}
+#endif /*USE_LIBDNS*/
+
+
/* Resolve an address using the standard system function. */
static gpg_error_t
resolve_addr_standard (const struct sockaddr *addr, int addrlen,
@@ -952,51 +1123,31 @@ resolve_addr_standard (const struct sockaddr *addr, int addrlen,
}
-/* This a wrapper around getaddrinfo with slightly different semantics.
- NAME is the name to resolve.
- PORT is the requested port or 0.
- WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
- WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
-
- On success the result is stored in a linked list with the head
- stored at the address R_AI; the caller must call gpg_addrinfo_free
- on this. If R_CANONNAME is not NULL the official name of the host
- is stored there as a malloced string; if that name is not available
- NULL is stored. */
+/* A wrapper around getnameinfo. */
gpg_error_t
-resolve_dns_name (const char *name, unsigned short port,
- int want_family, int want_socktype,
- dns_addrinfo_t *r_ai, char **r_canonname)
+resolve_dns_addr (const struct sockaddr *addr, int addrlen,
+ unsigned int flags, char **r_name)
{
gpg_error_t err;
#ifdef USE_LIBDNS
- if (!standard_resolver)
+ /* Note that we divert to the standard resolver for NUMERICHOST. */
+ if (!standard_resolver && !(flags & DNS_NUMERICHOST))
{
- err = resolve_name_libdns (name, port, want_family, want_socktype,
- r_ai, r_canonname);
+ err = resolve_addr_libdns (addr, addrlen, flags, r_name);
if (err && libdns_switch_port_p (err))
- err = resolve_name_libdns (name, port, want_family, want_socktype,
- r_ai, r_canonname);
+ err = resolve_addr_libdns (addr, addrlen, flags, r_name);
}
else
#endif /*USE_LIBDNS*/
- err = resolve_name_standard (name, port, want_family, want_socktype,
- r_ai, r_canonname);
+ err = resolve_addr_standard (addr, addrlen, flags, r_name);
+
if (opt_debug)
- log_debug ("dns: resolve_dns_name(%s): %s\n", name, gpg_strerror (err));
+ log_debug ("dns: resolve_dns_addr(): %s\n", gpg_strerror (err));
return err;
}
-gpg_error_t
-resolve_dns_addr (const struct sockaddr *addr, int addrlen,
- unsigned int flags, char **r_name)
-{
- return resolve_addr_standard (addr, addrlen, flags, r_name);
-}
-
-
/* Check whether NAME is an IP address. Returns a true if it is
* either an IPv6 or a IPv4 numerical address. The actual return
* values can also be used to identify whether it is v4 or v6: The
@@ -1096,7 +1247,7 @@ get_dns_cert_libdns (const char *name, int want_certtype,
int derr;
int qtype;
- /* Gte the query type from WANT_CERTTYPE (which in general indicates
+ /* Get the query type from WANT_CERTTYPE (which in general indicates
* the subtype we want). */
qtype = (want_certtype < DNS_CERTTYPE_RRBASE
? T_CERT