Subject: Clarifications wanted on Basic API (RFC 2553)

From: Brian Zill <[email-masked]>
Date: Fri, 28 Jan 2000 19:25:34 -0800

When implementing the basic API functions for our 1.4 release, there were a
number of places where I had to guess as to what the proper behavior should
be.  So I'm soliciting clarifications from anyone with an opinion,
especially the RFC authors, and would also like to hear what other existing
implementations do.

I'm primarily interested in answers to the getaddrinfo and getnameinfo
questions, but I'll do this in the order they're presented in the RFC.  If
this whole thing is too long to wade through, please at least look at those.

Section 3.10, sockaddr_storage:
I believe the consensus now is to use ss_family and not __ss_family.
Correct me if I'm wrong.

Section 6.1, getipnodebyname:
What is the namespace for error_num?  Regular system error number space, or
a private one?  Four errors are explicitly listed (HOST_NOT_FOUND,
NO_ADDRESS, NO_RECOVERY, and TRY_AGAIN).  The spec doesn't say that we're
supposed to define these in an include file somewhere, so I assumed that
you're supposed to use the system error codes that are the closest in
meaning.  Is this correct?

Also, the text says "error_num will be set to one of the following values"
and then lists only the above four errors.  Is the intent really that no
other errors are acceptable?  I could see returning errors for invalid
arguments, things that would fault, etc.  We currently return an invalid
argument error if the combination of the "af" and "flags" arguments yield a
name resolution lookup type we don't support.  Likewise we return a fault
error code if the name argument is NULL, and an out of memory error code if
the system can't allocate space to hold the returned hostent structure.  Is
this o.k.?

And is returning a fault error better than just letting the user's code
fault?  For this API, I think it is.

The AI_ADDRCONFIG flag is supposed to indicate that a AAAA query "should
occur only if the node has at least one IPv6 source address configured".  I
assume this definition excludes the loopback address.  Does it also exclude
link-local?  If our stack is present on a machine with interfaces, then
people will have link-local addresses even if they don't have any native
IPv6 connectivity to anywhere off of their local link.  But maybe the
machine they issued the query for is a node on the local link...  How about
automatic tunneling addresses?  We automatically assign one of those for
every IPv4 address, so if you have an IPv4 address, you have an IPv6 address
that can reach any other IPv6 enabled machine on the IPv4 Internet.  And if
you don't have an IPv4 address, then you're probably not issuing a
getaddrinfo call with this flag set.

Section 6.2 getipnodebyaddr:
The same error code issue that I asked about for getipnodebyname applies
here as well.

Again, we return errors that aren't explicitly listed: a fault error instead
of faulting if "src" is a NULL pointer, an invalid arguments error if "len"
isn't the right size for the given "af", and an address family not supported
error if  "af" isn't one of the address families we support.

Section 6.3 freehostent:
I have the same question that Itojun just asked about freeaddrinfo - what to
do if "ptr" is NULL?  You can't return an error, so the options are to take
a fault, or just ignore the call.  I agree with itojun that you should take
the fault -- this is a good way to get the programmer's attention that there
is something wrong with their code.  Changing the call to return an error
code doesn't strike me as any better than just silently ignoring a NULL ptr
since far too many programmers don't bother to check return values from
calls like this.

Section 6.4 freeaddrinfo:
Exact same issue as for freehostent.

Section 6.4 getaddrinfo:
The spec is explicit about getaddrinfo having its own error code namespace
and what the various EAI_* error codes are.  It's not always clear about
which one to use in certain situations, however.  For example, EAI_SERVICE
means "servname not supported for ai_socktype".  But there's also EAI_NONAME
for "nodename nor servname provided, or not known".  So what to return if
someone gives you a service name that isn't valid for the requested socket
type?  Am I actually expected to look up the service name for all other
socket types just so I can return EAI_SERVICE if it exists and EAI_NONAME if
it doesn't?  Also, the spec says that in the "hints" structure, "all members
other than ai_flags, ai_family, ai_socktype, and ai_protocol must be zero or
a NULL pointer".  Okay, but what error code do I return if they aren't?
None really seem to apply, so currently I'm returning EAI_FAIL.

The existence of the EAI_BADFLAGS error implies that there is a combination
of input parameters that would warrant such a return value.  Am I really
supposed to return this if I see a flag I don't recognize?  That would make
it hard to introduce new flags in the future as new programs requesting the
new flag would fail on old systems.  So I don't do that.

The precise meaning of  the AI_CANONNAME flag is unclear to me.  It says
that if this flag is set, then upon return, the first addrinfo struct's
ai_canonname field will point to "a null terminated string containing the
canonical name of the specified nodename".  Someone define canonical name
for me please.  Is this supposed to be the fully qualified domain name for
the host that, in DNS parlance, you get if you follow all the alias
pointers?  But what if someone passes in an IPv6 address literal into
getaddrinfo when this flag is set?  Am I supposed to do a reverse address
lookup just to fill in the ai_canonname field?  I'm thinking yes, although I
currently don't do that.  But what if AI_NUMERICHOST is also set?  The text
describing AI_NUMERICHOST states "this flag prevents any type of name
resolution service from being called", so I'd think I couldn't perform a
reverse address lookup in that case.  Or maybe I can -- does "any type of
name resolution service" include looking in /etc/hosts or a local cache of
previous DNS lookups?  If the only reason to avoid a "name resolution
service" is to prevent the delay of hitting the DNS or equivalent, then that
might be o.k.  If it really means that one is forbidden from finding some
sort of "canonical name" (I assume an address literal doesn't qualify) by
any means, does this make it illegal to set both the AI_CANONNAME and
AI_NUMERICHOST flags?  Currently I return EAI_BADFLAGS in this case -- hey,
a use for that error code after all!

What am I supposed to do if in the "hints" structure, someone passes in a
value for ai_socktype that is at odds with ai_protocol?  (e.g. SOCK_STREAM
with UDP).  Is getaddrinfo supposed to check if the particular triple of
address family, socket type, and protocol is supported on the system?  The
existence of the EAI_ADDRFAMILY error implies that just checking that the
address family is supported is enough (which is all I currently do).

Likewise, the spec isn't clear about whether one should use the value in
ai_socktype or ai_protocol when performing protocol specific service
lookups.  The actual port number to name mappings appear to be assigned via
protocol (specifically, UDP and TCP).  But the EAI_SERVICE error code says
"servname not supported for ai_socktype", it doesn't say "for ai_protocol".
The spec appears to assume that SOCK_STREAM means TCP and vice-versa, and
SOCK_DGRAM means UDP and vice-versa.  Consider this line "if the caller
handles only TCP and not UDP, then the ai_socktype member of the hints
structure should be set to SOCK_STREAM" -- instead of saying that
ai_protocol should be set to IP_PROTOCOL_TCP.  Currently, I use ai_socktype
with hardwired mappings from SOCK_STREAM to TCP and SOCK_DGRAM to UDP to
perform the service lookup, and only use ai_protocol to know what to set the
ai_protocol field in the returned addrinfo structures to.  I do it this way,
because in my experience, programmers typically leave the protocol value
unspecified in socket() calls, instead choosing to specify the socket type.

In the returned addrinfo structures, the spec is silent on what the ai_flags
field should be.  I can think of two possibilities: zero, or whatever was
passed into getaddrinfo in the ai_flags field of the hints structure.
Currently, I always return zero in this field.

Section 6.5 getnameinfo:
The spec says "the salen argument gives the length of the sockaddr_in or
sockaddr_in6 structure".  An overly pedantic member of our team (ok, it was
Rich :-) thinks this means that salen must exactly equal the length of a
sockaddr_in if sa->sa_family == AF_INET or it must exactly equal the length
of a sockaddr_in6 if sa->sa_family == AF_INET6 (i.e. just insisting salen is
large enough to hold a sockaddr of the appropriate type isn't good enough,
it must be exactly the right size).  The rest of us disagree, because that
would mean that you can't call getnameinfo with a pointer to a struct
sockaddr_storage and salen set to sizeof(struct sockaddr_storage).  Losing
that capability loses a lot of the address independence feature that makes
getnameinfo so nice in the first place.  We'd really like to be able to
perform a getpeername call, with the result going into a sockaddr_storage,
and then be able to just pass that to getnameinfo to find out who we're
talking to without having to add any address family specific code.

The spec doesn't say anything about the error code namespace, so I used the
regular system one.

Section 6.6 inet_pton:
Should we check if "src" and/or "dst" is a NULL pointer and return an error
(0?) if so?  Or just let it fault?  For "dst", the spec says that the buffer
it points to must be large enough to hold the expected result, so if we
treat a NULL pointer like any other too-small buffer, faulting would seem
appropriate.  For "src" though, it would seem returning 0 (for an invalid
input string) would be appropriate.

Section 6.6 inet_ntop:
Here the spec says that "dst" must be non-NULL, but doesn't say what error
to set if it isn't.  However, ENOSPC is what is supposed to be set if the
size of the buffer "dst" points to is inadequate.  So would that apply,
should it be EFAULT, or should we just let it fault?

The spec doesn't say anything about what to do if "src" is NULL.  Options
appear to be to set EFAULT and return NULL, or just let it fault.

The spec doesn't say anything about the error code namespace, although the
names appear to be Unix system error codes (strangely different approach
than the generic names used in Section 6.1 and 6.2 -- presumably different
authors), so I used the regular system one.

Well, that's about it,
--Brian

--------------------------------------------------------------------
IETF IPng Working Group Mailing List
IPng Home Page:                      http://playground.sun.com/ipng
FTP archive:                      ftp://playground.sun.com/pub/ipng
Direct all administrative requests to [email-masked]
--------------------------------------------------------------------

---

From: [email-masked]
Date: Sat, 29 Jan 2000 14:41:32 +0900

Here are couple of additions to brian (zill)'s.  I agree with
	brian's comment where I don't quote/comment in the following.

>I believe the consensus now is to use ss_family and not __ss_family.

	This is correct, ss_family was the consensus of the most recent
	discussion.  X/Open spec uses ss_family already.

>Section 6.4 getaddrinfo:

	(addition)
	When host == NULL, loopback addresses and/or wildcard addresses will
	be returned.  At this moment KAME getaddrinfo returns all the
	loopback/wildcard address in address family supported by the kernel.
	For example, if you are on top of IPv6-only kernel, getaddrinfo will
	return :: or ::1.  If you are on dual-stack, getaddrinfo will
	return :: and 0.0.0.0, or ::1 and 127.0.0.1.  Is the behavior okay?

	(addition)
	interaction of NI_NUMERICxxx with AF_LOCAL (AF_UNIX), or other address
	families where hostname/servname cannot become decimal/hexadecimal
	digits.
	(Hideaki YOSHIFUJI pointed this out around Jan 19, 2000)

>for me please.

	(just additional datapoint)
	KAME code copies hp->h_name returned from getipnodebyname(), or
	gethostbyname().  Not sure if this is the right answer to "canonical
	name".  Things gets tricky as
	- KAME getaddrinfo calls name resolution twice, once for IPv4 and 
	  once for IPv6
	- and hp->h_name can be different each time.
	so KAME code puts ai_canonname for every addrinfo entries, if
	AI_CANONNAME is given.

>address family is supported is enough (which is all I currently do).

	(similar to the above)
	The spec does not say how far we need to "glob" the input.
	When KAME getaddrinfo is called with the following parameter:
		host = "foo.internet.host"
		serv = "daytime"
		hints.ai_family = PF_UNSPEC
		hints.ai_socktype = hints.ai_protocol = 0
	the code would return the following four entries:
		AF_INET, port 13, SOCK_STREAM, IPPROTO_TCP
		AF_INET, port 13, SOCK_DGRAM, IPPROTO_UDP
		AF_INET6, port 13, SOCK_STREAM, IPPROTO_TCP
		AF_INET6, port 13, SOCK_DGRAM, IPPROTO_UDP
	Past KAME code returned SOCK_STREAM only (2 entries), like:
		AF_INET, port 13, SOCK_STREAM, IPPROTO_TCP
		AF_INET6, port 13, SOCK_STREAM, IPPROTO_TCP
	Which behavior the spec prefer?

	(addition)
	is SOCK_RAW allowed in hints.ai_socktype?  this is very useful
	when we write "ping" which is less-dependent to AF
	(hints.ai_protocol is opaque in this case).

>Section 6.5 getnameinfo:

	(addition)
	It is not 100% clear how the code should behave when a short buffer
	is passed.  RFC2553 seems to me to raise error.  X/Open says to
	truncate the result and success.  The most recent ipngwg discussion
	preferred RFC2553 (error), if I remember correctly.

>talking to without having to add any address family specific code.

	(comment to brian's)
	by the time you call getnameinfo(), you should have done something like
		getpeername(sock, &ss, &sslen);
	and you have the exact length (like sizeof(sockaddr_in)) in sslen.
	you are not passing sizeof(sockaddr_storage) in 2nd arg in this case.
		getnameinfo(&ss, sslen, ...)

	or, if you have sa_len field, this should be okay:
		getnameinfo(&ss, ss.ss_len, ...)

>The spec doesn't say anything about the error code namespace, so I used the

	KAME code defined NI_xxx and uses them.

itojun

---

From: Francis Dupont <[email-masked]>
Date: Sat, 29 Jan 2000 13:55:43 +0100

In your previous mail you wrote:

   be.

=> some of your questions have answer in any Unix socket support
(RFC 2553 is for this kind of systems then assume you have one,
of course Winsocks are different).
   
   Section 6.1, getipnodebyname:
   What is the namespace for error_num?

=> same than for old gethostbyname, a private one defined in
/usr/include/netdb.h as below:

/*
 * Error return codes from gethostbyname() and gethostbyaddr()
 * (left in extern int h_errno).
 */

#define NETDB_INTERNAL  -1      /* see errno */
#define NETDB_SUCCESS   0       /* no problem */
#define HOST_NOT_FOUND  1 /* Authoritative Answer Host not found */
#define TRY_AGAIN       2 /* Non-Authoritative Host not found, or SERVERFAIL */
#define NO_RECOVERY     3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
#define NO_DATA         4 /* Valid name, no data record of requested type */
#define NO_ADDRESS      NO_DATA         /* no address, look for MX record */

   The AI_ADDRCONFIG flag is supposed to indicate that a AAAA query "should
   occur only if the node has at least one IPv6 source address configured".  I
   assume this definition excludes the loopback address.

=> this has been discussed in the mailing list (we'd like to have
more precisions in the future RFC).

   Section 6.4 getaddrinfo:
   For example, EAI_SERVICE means "servname not supported for ai_socktype".

=> I believe this error code is for service name is valid but not for
this socket type, for instance if you ask for "tftp" with SOCK_STREAM/tcp
socket type.

   Someone define canonical name for me please.

=> this is a standard DNS notion. A not canonical name can only appear
as the left part of a CNAME RR, other names are canonical and MUST NOT
appear as the left part of a CNAME RR. Many softwares pick a name as
the canonical one when there are more than one PTR RR for an address
but this is not a standardized extension.

  Is this supposed to be the fully qualified domain name for
   the host that, in DNS parlance, you get if you follow all the alias
   pointers?

=> names are FQDN (others are garbage :-). You are supposed to support
a (short) alias (aka CNAME RR) chain but they are forbiden.

   But what if someone passes in an IPv6 address literal into
   getaddrinfo when this flag is set?  Am I supposed to do a reverse address
   lookup just to fill in the ai_canonname field?  I'm thinking yes, although I
   currently don't do that.

=> I agree (same reasoning and same implementation, ie. literals go into
the canonical name field :-).

   If it really means that one is forbidden from finding some
   sort of "canonical name" (I assume an address literal doesn't qualify) by
   any means, does this make it illegal to set both the AI_CANONNAME and
   AI_NUMERICHOST flags?

=> I agree, both flags should be exclusive.
   
   lookups.

=> I agree but without a common counter-example is this a real issue?
As you said programmers usually set only the socket type then the current
spec is doing just we expect...

   Section 6.5 getnameinfo:
   it must be exactly the right size).

=> I have no trouble with this because 4.4BSDs just copy sa->sa_len
into salen (sa is the main argument)... (another reason to have
socket structure length! :-)
My proposal is "do what you want and leave the spec as it is".

=> me and KAME use a ENI_ private space (cloned from EAI_ one).
   
   authors),

=> yes, inet_pton/ntop are inherited by an old attempt by Paul Vixie
to get family independent functions which deal with literals.

Regards

[email-masked]