mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
dirmngr: Implement a getnameinfo wrapper.
* dirmngr/dns-stuff.h (DNS_NUMERICHOST): New. (DNS_WITHBRACKET): New. * dirmngr/dns-stuff.c (resolve_name_standard): Factor code out to... (map_eai_to_gpg_error): new. (resolve_addr_standard): New. (resolve_dns_addr): New. * dirmngr/ks-engine-hkp.c (is_ip_address): Move to ... * dirmngr/dns-stuff.c (is_ip_address): here. Add support for non bracketed v6 addresses. * dirmngr/t-dns-stuff.c: Remove header netdb.h. (main): Add option --bracket. Use resolve_dns_name instead of getnameinfo. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
7f65e84ac0
commit
816505958a
@ -54,6 +54,11 @@
|
||||
#include "host2net.h"
|
||||
#include "dns-stuff.h"
|
||||
|
||||
|
||||
#if AF_UNSPEC != 0
|
||||
# error AF_UNSPEC does not have the value 0
|
||||
#endif
|
||||
|
||||
/* Not every installation has gotten around to supporting SRVs or
|
||||
CERTs yet... */
|
||||
#ifndef T_SRV
|
||||
@ -96,6 +101,30 @@ free_dns_addrinfo (dns_addrinfo_t ai)
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
map_eai_to_gpg_error (int ec)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
switch (ec)
|
||||
{
|
||||
case EAI_AGAIN: err = gpg_error (GPG_ERR_EAGAIN); break;
|
||||
case EAI_BADFLAGS: err = gpg_error (GPG_ERR_INV_FLAG); break;
|
||||
case EAI_FAIL: err = gpg_error (GPG_ERR_SERVER_FAILED); break;
|
||||
case EAI_MEMORY: err = gpg_error (GPG_ERR_ENOMEM); break;
|
||||
case EAI_NODATA: err = gpg_error (GPG_ERR_NO_DATA); break;
|
||||
case EAI_NONAME: err = gpg_error (GPG_ERR_NO_NAME); break;
|
||||
case EAI_SERVICE: err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
|
||||
case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
|
||||
case EAI_FAMILY: err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
|
||||
case EAI_SOCKTYPE: err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
|
||||
case EAI_SYSTEM: err = gpg_error_from_syserror (); break;
|
||||
default: err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Resolve a name using the standard system function. */
|
||||
static gpg_error_t
|
||||
resolve_name_standard (const char *name, unsigned short port,
|
||||
@ -132,21 +161,7 @@ resolve_name_standard (const char *name, unsigned short port,
|
||||
if (ret)
|
||||
{
|
||||
aibuf = NULL;
|
||||
switch (ret)
|
||||
{
|
||||
case EAI_AGAIN: err = gpg_error (GPG_ERR_EAGAIN); break;
|
||||
case EAI_BADFLAGS: err = gpg_error (GPG_ERR_INV_FLAG); break;
|
||||
case EAI_FAIL: err = gpg_error (GPG_ERR_SERVER_FAILED); break;
|
||||
case EAI_MEMORY: err = gpg_error (GPG_ERR_ENOMEM); break;
|
||||
case EAI_NODATA: err = gpg_error (GPG_ERR_NO_DATA); break;
|
||||
case EAI_NONAME: err = gpg_error (GPG_ERR_NO_NAME); break;
|
||||
case EAI_SERVICE: err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
|
||||
case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
|
||||
case EAI_FAMILY: err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
|
||||
case EAI_SOCKTYPE: err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
|
||||
case EAI_SYSTEM: err = gpg_error_from_syserror (); break;
|
||||
default: err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
|
||||
}
|
||||
err = map_eai_to_gpg_error (ret);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
@ -193,6 +208,66 @@ resolve_name_standard (const char *name, unsigned short port,
|
||||
}
|
||||
|
||||
|
||||
/* Resolve an address using the standard system function. */
|
||||
static gpg_error_t
|
||||
resolve_addr_standard (const struct sockaddr *addr, int addrlen,
|
||||
unsigned int flags, char **r_name)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int ec;
|
||||
char *buffer, *p;
|
||||
int buflen;
|
||||
|
||||
*r_name = NULL;
|
||||
|
||||
buflen = NI_MAXHOST;
|
||||
buffer = xtrymalloc (buflen + 2 + 1);
|
||||
if (!buffer)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
if ((flags & DNS_NUMERICHOST) || tor_mode)
|
||||
ec = EAI_NONAME;
|
||||
else
|
||||
ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
|
||||
|
||||
if (!ec && *buffer == '[')
|
||||
ec = EAI_FAIL; /* A name may never start with a bracket. */
|
||||
else if (ec == EAI_NONAME)
|
||||
{
|
||||
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 && addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
|
||||
strcat (buffer, "]");
|
||||
}
|
||||
|
||||
if (ec)
|
||||
err = map_eai_to_gpg_error (ec);
|
||||
else
|
||||
{
|
||||
p = xtryrealloc (buffer, strlen (buffer)+1);
|
||||
if (!p)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
buffer = p;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
xfree (buffer);
|
||||
else
|
||||
*r_name = buffer;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* This a wrapper around getaddrinfo with slighly different semantics.
|
||||
NAME is the name to resolve.
|
||||
PORT is the requested port or 0.
|
||||
@ -219,6 +294,85 @@ resolve_dns_name (const char *name, unsigned short port,
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
resolve_dns_addr (const struct sockaddr *addr, int addrlen,
|
||||
unsigned int flags, char **r_name)
|
||||
{
|
||||
#ifdef USE_ADNS_disabled_for_now
|
||||
return resolve_addr_adns (addr, addrlen, flags, r_name);
|
||||
#else
|
||||
return resolve_addr_standard (addr, addrlen, flags, r_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Check whether NAME is an IP address. Returns true if it is either
|
||||
an IPv6 or IPv4 numerical address. */
|
||||
int
|
||||
is_ip_address (const char *name)
|
||||
{
|
||||
const char *s;
|
||||
int ndots, dblcol, n;
|
||||
|
||||
if (*name == '[')
|
||||
return 1; /* yes: A legal DNS name may not contain this character;
|
||||
this mut be bracketed v6 address. */
|
||||
if (*name == '.')
|
||||
return 0; /* No. A leading dot is not a valid IP address. */
|
||||
|
||||
/* Check whether this is a v6 address. */
|
||||
ndots = n = dblcol = 0;
|
||||
for (s=name; *s; s++)
|
||||
{
|
||||
if (*s == ':')
|
||||
{
|
||||
ndots++;
|
||||
if (s[1] == ':')
|
||||
{
|
||||
ndots++;
|
||||
if (dblcol)
|
||||
return 0; /* No: Only one "::" allowed. */
|
||||
dblcol++;
|
||||
if (s[1])
|
||||
s++;
|
||||
}
|
||||
n = 0;
|
||||
}
|
||||
else if (*s == '.')
|
||||
goto legacy;
|
||||
else if (!strchr ("0123456789abcdefABCDEF", *s))
|
||||
return 0; /* No: Not a hex digit. */
|
||||
else if (++n > 4)
|
||||
return 0; /* To many digits in a group. */
|
||||
}
|
||||
if (ndots > 7)
|
||||
return 0; /* No: Too many colons. */
|
||||
else if (ndots > 1)
|
||||
return 1; /* Yes: At least 2 colons indicate an v6 address. */
|
||||
|
||||
legacy:
|
||||
/* Check whether it is legacy IP address. */
|
||||
ndots = n = 0;
|
||||
for (s=name; *s; s++)
|
||||
{
|
||||
if (*s == '.')
|
||||
{
|
||||
if (s[1] == '.')
|
||||
return 0; /* No: Douple dot. */
|
||||
if (atoi (s+1) > 255)
|
||||
return 0; /* No: Ipv4 byte value too large. */
|
||||
ndots++;
|
||||
n = 0;
|
||||
}
|
||||
else if (!strchr ("0123456789", *s))
|
||||
return 0; /* No: Not a digit. */
|
||||
else if (++n > 3)
|
||||
return 0; /* No: More than 3 digits. */
|
||||
}
|
||||
return !!(ndots == 3);
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_ADNS
|
||||
/* Init ADNS and store the new state at R_STATE. Returns 0 on
|
||||
success; prints an error message and returns an error code on
|
||||
|
@ -40,7 +40,16 @@
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flags used with resolve_dns_addr.
|
||||
*/
|
||||
#define DNS_NUMERICHOST 1 /* Force numeric output format. */
|
||||
#define DNS_WITHBRACKET 2 /* Put brackets around numeric v6
|
||||
addresses. */
|
||||
|
||||
/*
|
||||
* Constants for use with get_dns_cert.
|
||||
*/
|
||||
#define DNS_CERTTYPE_ANY 0 /* Internal catch all type. */
|
||||
/* Certificate types according to RFC-4398: */
|
||||
#define DNS_CERTTYPE_PKIX 1 /* X.509 as per PKIX. */
|
||||
@ -58,6 +67,8 @@
|
||||
#define DNS_CERTTYPE_RRBASE 1024 /* Base of special constants. */
|
||||
#define DNS_CERTTYPE_RR61 (DNS_CERTTYPE_RRBASE + 61)
|
||||
|
||||
|
||||
|
||||
struct dns_addrinfo_s;
|
||||
typedef struct dns_addrinfo_s *dns_addrinfo_t;
|
||||
struct dns_addrinfo_s
|
||||
@ -87,17 +98,25 @@ gpg_error_t enable_dns_tormode (void);
|
||||
|
||||
void free_dns_addrinfo (dns_addrinfo_t ai);
|
||||
|
||||
/* Provide function similar to getaddrinfo. */
|
||||
/* Function similar to getaddrinfo. */
|
||||
gpg_error_t resolve_dns_name (const char *name, unsigned short port,
|
||||
int want_family, int want_socktype,
|
||||
dns_addrinfo_t *r_dai, char **r_canonname);
|
||||
|
||||
/* Function similar to getnameinfo. */
|
||||
gpg_error_t resolve_dns_addr (const struct sockaddr *addr, int addrlen,
|
||||
unsigned int flags, char **r_name);
|
||||
|
||||
/* Return true if NAME is a numerical IP address. */
|
||||
int is_ip_address (const char *name);
|
||||
|
||||
/* Return a CERT record or an arbitray RR. */
|
||||
gpg_error_t get_dns_cert (const char *name, int want_certtype,
|
||||
void **r_key, size_t *r_keylen,
|
||||
unsigned char **r_fpr, size_t *r_fprlen,
|
||||
char **r_url);
|
||||
|
||||
|
||||
int getsrv (const char *name,struct srventry **list);
|
||||
|
||||
|
||||
|
@ -280,38 +280,6 @@ my_getnameinfo (dns_addrinfo_t ai, char *host, size_t hostlen,
|
||||
}
|
||||
|
||||
|
||||
/* Check whether NAME is an IP address. */
|
||||
static int
|
||||
is_ip_address (const char *name)
|
||||
{
|
||||
int ndots, n;
|
||||
|
||||
if (*name == '[')
|
||||
return 1;
|
||||
/* Check whether it is legacy IP address. */
|
||||
if (*name == '.')
|
||||
return 0; /* No. */
|
||||
ndots = n = 0;
|
||||
for (; *name; name++)
|
||||
{
|
||||
if (*name == '.')
|
||||
{
|
||||
if (name[1] == '.')
|
||||
return 0; /* No. */
|
||||
if (atoi (name+1) > 255)
|
||||
return 0; /* Value too large. */
|
||||
ndots++;
|
||||
n = 0;
|
||||
}
|
||||
else if (!strchr ("012345678", *name))
|
||||
return 0; /* Not a digit. */
|
||||
else if (++n > 3)
|
||||
return 0; /* More than 3 digits. */
|
||||
}
|
||||
return !!(ndots == 3);
|
||||
}
|
||||
|
||||
|
||||
/* Map the host name NAME to the actual to be used host name. This
|
||||
allows us to manage round robin DNS names. We use our own strategy
|
||||
to choose one of the hosts. For example we skip those hosts which
|
||||
|
@ -22,9 +22,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "util.h"
|
||||
#include "dns-stuff.h"
|
||||
@ -45,6 +43,7 @@ main (int argc, char **argv)
|
||||
int opt_tor = 0;
|
||||
int opt_cert = 0;
|
||||
int opt_srv = 0;
|
||||
int opt_bracket = 0;
|
||||
char const *name = NULL;
|
||||
|
||||
gpgrt_init ();
|
||||
@ -66,6 +65,7 @@ main (int argc, char **argv)
|
||||
" --verbose print timings etc.\n"
|
||||
" --debug flyswatter\n"
|
||||
" --use-tor use Tor\n"
|
||||
" --bracket enclose v6 addresses in brackets\n"
|
||||
" --cert lookup a CERT RR\n"
|
||||
" --srv lookup a SRV RR\n"
|
||||
, stdout);
|
||||
@ -87,6 +87,11 @@ main (int argc, char **argv)
|
||||
opt_tor = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--bracket"))
|
||||
{
|
||||
opt_bracket = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--cert"))
|
||||
{
|
||||
any_options = opt_cert = 1;
|
||||
@ -194,8 +199,7 @@ main (int argc, char **argv)
|
||||
{
|
||||
char *cname;
|
||||
dns_addrinfo_t aibuf, ai;
|
||||
int ret;
|
||||
char hostbuf[1025];
|
||||
char *host;
|
||||
|
||||
printf ("Lookup on '%s'\n", name);
|
||||
|
||||
@ -216,14 +220,30 @@ main (int argc, char **argv)
|
||||
ai->family == AF_INET? "inet4" : "? ",
|
||||
ai->socktype, ai->protocol);
|
||||
|
||||
ret = getnameinfo (ai->addr, ai->addrlen,
|
||||
hostbuf, sizeof hostbuf,
|
||||
NULL, 0,
|
||||
NI_NUMERICHOST);
|
||||
if (ret)
|
||||
printf ("[getnameinfo failed: %s]\n", gai_strerror (ret));
|
||||
err = resolve_dns_addr (ai->addr, ai->addrlen,
|
||||
(DNS_NUMERICHOST
|
||||
| (opt_bracket? DNS_WITHBRACKET:0)),
|
||||
&host);
|
||||
if (err)
|
||||
printf ("[getnameinfo failed: %s]", gpg_strerror (err));
|
||||
else
|
||||
printf ("%s\n", hostbuf);
|
||||
{
|
||||
printf ("%s", host);
|
||||
xfree (host);
|
||||
}
|
||||
|
||||
err = resolve_dns_addr (ai->addr, ai->addrlen,
|
||||
(opt_bracket? DNS_WITHBRACKET:0),
|
||||
&host);
|
||||
if (err)
|
||||
printf ("[getnameinfo failed (2): %s]", gpg_strerror (err));
|
||||
else
|
||||
{
|
||||
if (!is_ip_address (host))
|
||||
printf (" (%s)", host);
|
||||
xfree (host);
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
xfree (cname);
|
||||
free_dns_addrinfo (aibuf);
|
||||
|
Loading…
x
Reference in New Issue
Block a user