mirror of
git://git.gnupg.org/gnupg.git
synced 2025-05-19 09:02:22 +02:00
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 <wk@gnupg.org>
This commit is contained in:
parent
daae97bc14
commit
9850124c7b
@ -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. */
|
/* Resolve an address using the standard system function. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
resolve_addr_standard (const struct sockaddr *addr, int addrlen,
|
resolve_addr_standard (const struct sockaddr *addr, int addrlen,
|
||||||
@ -952,48 +1123,28 @@ resolve_addr_standard (const struct sockaddr *addr, int addrlen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This a wrapper around getaddrinfo with slightly different semantics.
|
/* A wrapper around getnameinfo. */
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
resolve_dns_addr (const struct sockaddr *addr, int addrlen,
|
resolve_dns_addr (const struct sockaddr *addr, int addrlen,
|
||||||
unsigned int flags, char **r_name)
|
unsigned int flags, char **r_name)
|
||||||
{
|
{
|
||||||
return resolve_addr_standard (addr, addrlen, flags, r_name);
|
gpg_error_t err;
|
||||||
|
|
||||||
|
#ifdef USE_LIBDNS
|
||||||
|
/* Note that we divert to the standard resolver for NUMERICHOST. */
|
||||||
|
if (!standard_resolver && !(flags & DNS_NUMERICHOST))
|
||||||
|
{
|
||||||
|
err = resolve_addr_libdns (addr, addrlen, flags, r_name);
|
||||||
|
if (err && libdns_switch_port_p (err))
|
||||||
|
err = resolve_addr_libdns (addr, addrlen, flags, r_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /*USE_LIBDNS*/
|
||||||
|
err = resolve_addr_standard (addr, addrlen, flags, r_name);
|
||||||
|
|
||||||
|
if (opt_debug)
|
||||||
|
log_debug ("dns: resolve_dns_addr(): %s\n", gpg_strerror (err));
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1096,7 +1247,7 @@ get_dns_cert_libdns (const char *name, int want_certtype,
|
|||||||
int derr;
|
int derr;
|
||||||
int qtype;
|
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). */
|
* the subtype we want). */
|
||||||
qtype = (want_certtype < DNS_CERTTYPE_RRBASE
|
qtype = (want_certtype < DNS_CERTTYPE_RRBASE
|
||||||
? T_CERT
|
? T_CERT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user