Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20220921154134.GT9709@brightrain.aerifal.cx>
Date: Wed, 21 Sep 2022 11:41:34 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Re: EAI_NODATA in musl

On Mon, Sep 19, 2022 at 07:31:04PM -0400, Rich Felker wrote:
> On Mon, Sep 19, 2022 at 06:26:07PM -0400, Rich Felker wrote:
> > [...]
> > 
> > Some details to work out:
> > 
> > 1. getaddrinfo errors out with EAI_NONAME early when AI_ADDRCONFIG
> >    finds that the requested address family is not configured. The
> >    logic here probably needs to be changed to still perform a lookup
> >    but suppress the results if all requested families were precluded
> >    by AI_ADDRCONFIG.
> > 
> > 2. gethostbyname* need to process EAI_NODATA and convert to (already
> >    existing) NO_DATA.
> > 
> > 3. There was one other point where EAI_NONAME appeared in
> >    lookup_name.c but it was wrong and just fixed by 1e7fb12f77.
> > 
> > Anything else?
> 
> Updated patch attached addressing the above.

> diff --git a/include/netdb.h b/include/netdb.h
> index d096c781..3af065e2 100644
> --- a/include/netdb.h
> +++ b/include/netdb.h
> @@ -44,6 +44,7 @@ struct addrinfo {
>  #define EAI_NONAME     -2
>  #define EAI_AGAIN      -3
>  #define EAI_FAIL       -4
> +#define EAI_NODATA     -5
>  #define EAI_FAMILY     -6
>  #define EAI_SOCKTYPE   -7
>  #define EAI_SERVICE    -8
> diff --git a/src/network/gai_strerror.c b/src/network/gai_strerror.c
> index 9596580e..56b71503 100644
> --- a/src/network/gai_strerror.c
> +++ b/src/network/gai_strerror.c
> @@ -6,7 +6,7 @@ static const char msgs[] =
>  	"Name does not resolve\0"
>  	"Try again\0"
>  	"Non-recoverable error\0"
> -	"Unknown error\0"
> +	"Name has no usable address\0"
>  	"Unrecognized address family or invalid length\0"
>  	"Unrecognized socket type\0"
>  	"Unrecognized service\0"
> diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c
> index 9df045f6..64ad259a 100644
> --- a/src/network/getaddrinfo.c
> +++ b/src/network/getaddrinfo.c
> @@ -16,6 +16,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
>  	char canon[256], *outcanon;
>  	int nservs, naddrs, nais, canon_len, i, j, k;
>  	int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
> +	int no_family = 0;
>  	struct aibuf *out;
>  
>  	if (!host && !serv) return EAI_NONAME;
> @@ -82,7 +83,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
>  			default:
>  				return EAI_SYSTEM;
>  			}
> -			if (family == tf[i]) return EAI_NONAME;
> +			if (family == tf[i]) no_family = 1;
>  			family = tf[1-i];
>  		}
>  	}
> @@ -93,6 +94,8 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
>  	naddrs = __lookup_name(addrs, canon, host, family, flags);
>  	if (naddrs < 0) return naddrs;
>  
> +	if (no_family) return EAI_NODATA;
> +
>  	nais = nservs * naddrs;
>  	canon_len = strlen(canon);
>  	out = calloc(1, nais * sizeof(*out) + canon_len + 1);
> diff --git a/src/network/gethostbyname2_r.c b/src/network/gethostbyname2_r.c
> index c9f3acc4..a5eb67fe 100644
> --- a/src/network/gethostbyname2_r.c
> +++ b/src/network/gethostbyname2_r.c
> @@ -23,6 +23,9 @@ int gethostbyname2_r(const char *name, int af,
>  	case EAI_NONAME:
>  		*err = HOST_NOT_FOUND;
>  		return 0;
> +	case EAI_NODATA:
> +		*err = NO_DATA;
> +		return 0;
>  	case EAI_AGAIN:
>  		*err = TRY_AGAIN;
>  		return EAGAIN;
> diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
> index bec6ba22..37d481f9 100644
> --- a/src/network/lookup_name.c
> +++ b/src/network/lookup_name.c
> @@ -79,7 +79,7 @@ static int name_from_hosts(struct address buf[static MAXADDRS], char canon[stati
>  		case 0:
>  			continue;
>  		default:
> -			badfam = EAI_NONAME;
> +			badfam = EAI_NODATA;
>  			break;
>  		}
>  
> @@ -175,7 +175,7 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static
>  		__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
>  
>  	if (ctx.cnt) return ctx.cnt;
> -	return EAI_NONAME;
> +	return EAI_NODATA;
>  }
>  
>  static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)

One more thing: presently IP literals with address family mismatching
the request error with EAI_NONAME. glibc has an error EAI_ADDRFAMILY
for this, but semantically it's equivalent to the above proposed
EAI_NODATA: "Name has no usable address" and I think we should just
use EAI_NODATA here.

In principle EAI_ADDRFAMILY would be nice if it could tell the caller
(definitively) "this name *does* have an address of some sort, but not
in the requested address family or as limited by AI_ADDRCONFIG". But
doing this requires always looking up both v4 and v6 even when the
caller did not ask for them. That is, it introduces a distinction that
requires more work just to give a more specific error. IMO this is not
a good thing unless the specificity would actually have some use,
which it doesn't seem to here. And indeed glibc doesn't do that
either. It only uses EAI_ADDRFAMILY for IP literals.

So, in addition to the above patch, for now I propose just changing
__lookup_ipliteral to return EAI_NODATA for mismatching family instead
of EAI_NONANE. We could add EAI_ADDRFAMILY with behavior matching
glibc later if we really want to.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.