mailing list of musl libc
 help / color / mirror / code / Atom feed
* [musl] EAI_NODATA in musl
@ 2022-09-19 22:14 Rich Felker
  2022-09-19 22:26 ` Rich Felker
  0 siblings, 1 reply; 4+ messages in thread
From: Rich Felker @ 2022-09-19 22:14 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 852 bytes --]

I just posted on libc-coord about an idea that sounded good, and it
turns out glibc and nearly everyone else have had it for a long time:

https://www.openwall.com/lists/libc-coord/2022/09/19/2

I'd like to bring the same to musl, even though it's not standardized
yet, since it's a clear candidate for standardization and solves a
major problem with the libc DNS API, namely inability to distinguish
NxDomain from NODATA.

Aside from that, it should help justify musl's distinguishing of these
two (very different) results in how search domain fallbacks work and
how results for one of the A or AAAA erroring out get handled. Our
misleadingly reporting "name exists but has no address" as "name
doesn't exist" has made it hard for folks to understand why we don't
keep going on the search when "name does not exist".

Draft patch attached, untested.


[-- Attachment #2: nodata.diff --]
[-- Type: text/plain, Size: 1525 bytes --]

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/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)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [musl] EAI_NODATA in musl
  2022-09-19 22:14 [musl] EAI_NODATA in musl Rich Felker
@ 2022-09-19 22:26 ` Rich Felker
  2022-09-19 23:31   ` Rich Felker
  0 siblings, 1 reply; 4+ messages in thread
From: Rich Felker @ 2022-09-19 22:26 UTC (permalink / raw)
  To: musl

On Mon, Sep 19, 2022 at 06:14:03PM -0400, Rich Felker wrote:
> I just posted on libc-coord about an idea that sounded good, and it
> turns out glibc and nearly everyone else have had it for a long time:
> 
> https://www.openwall.com/lists/libc-coord/2022/09/19/2
> 
> I'd like to bring the same to musl, even though it's not standardized
> yet, since it's a clear candidate for standardization and solves a
> major problem with the libc DNS API, namely inability to distinguish
> NxDomain from NODATA.
> 
> Aside from that, it should help justify musl's distinguishing of these
> two (very different) results in how search domain fallbacks work and
> how results for one of the A or AAAA erroring out get handled. Our
> misleadingly reporting "name exists but has no address" as "name
> doesn't exist" has made it hard for folks to understand why we don't
> keep going on the search when "name does not exist".
> 
> Draft patch attached, untested.
> 

> 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/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)

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?

Rich

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [musl] EAI_NODATA in musl
  2022-09-19 22:26 ` Rich Felker
@ 2022-09-19 23:31   ` Rich Felker
  2022-09-21 15:41     ` Rich Felker
  0 siblings, 1 reply; 4+ messages in thread
From: Rich Felker @ 2022-09-19 23:31 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 698 bytes --]

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.

[-- Attachment #2: nodata2.diff --]
[-- Type: text/plain, Size: 3027 bytes --]

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)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [musl] EAI_NODATA in musl
  2022-09-19 23:31   ` Rich Felker
@ 2022-09-21 15:41     ` Rich Felker
  0 siblings, 0 replies; 4+ messages in thread
From: Rich Felker @ 2022-09-21 15:41 UTC (permalink / raw)
  To: 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

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-09-21 15:41 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-19 22:14 [musl] EAI_NODATA in musl Rich Felker
2022-09-19 22:26 ` Rich Felker
2022-09-19 23:31   ` Rich Felker
2022-09-21 15:41     ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).