|Deletions are marked like this.||Additions are marked like this.|
|Line 2:||Line 2:|
|On this page we are trying to describe what the correct behavior should be for a resolver function, i.e., for a function translating a hostname to an address, when it should return which error code, and so on.||On this page we are trying to describe what the correct behavior should be for a resolver function, i.e., for a function translating a hostname to an address. What is the correct order of looking things up? Which status codes should be returned and when?|
|Line 4:||Line 4:|
|There are several sources of information that can be used to translate a hostname to an address. This includes "hosts" files, DNS and mDNS. If needed information is not found in one source the information might be sought in other sources.||There are several sources of information that can be used to translate a hostname to an address. This includes "hosts" files, NIS, DNS and mDNS. If needed information is not found in one source the information might be sought in other sources.|
|Line 10:||Line 10:|
|So this comes down to needing to look up multiple hostnames and in multiple sources looking for different address types. It's important to know what the correct order of looking things up is, and when to return an error code and which one.||In short, the resolver needs to look up multiple qualified hostnames and in multiple sources looking for different address types.|
Behavior of a name resolver
On this page we are trying to describe what the correct behavior should be for a resolver function, i.e., for a function translating a hostname to an address. What is the correct order of looking things up? Which status codes should be returned and when?
There are several sources of information that can be used to translate a hostname to an address. This includes "hosts" files, NIS, DNS and mDNS. If needed information is not found in one source the information might be sought in other sources.
The resolver might also need to look up various qualified hostnames based on a short hostname it is asked to look up.
It might also have to look up different address types. This is currently about IPv4 and IPv6.
In short, the resolver needs to look up multiple qualified hostnames and in multiple sources looking for different address types.
The functions implementing this in the GNU C library are getaddrinfo() and gethostbyname(), but gethostbyname() is deprecated and applications should switch to getaddrinfo(). The behavior of these functions is governed by POSIX but the relevant RFCs are not very clear — hence the need for this page.
Order of lookups
The resolver should probably look up the service name before looking up the hostname.
The correct order of looking a hostname up is first to look at the first source of information and look up all the different hostnames in that source. For each hostname it should look up the different address types in that source. So this is basically 3 nested loops.
For example, if a "hosts" file is the first source, the resolver should first look for all different hostnames in the hosts file before trying to do something like DNS.
If a hostname is found in a source (positive answer) then the resolver should look up all the address types that were requested and then not search any further. Some sources might be able to confirm that a hostname exists but has no addresses assigned to it, we called that the no address answer.
Some sources might also contain the information that the hostname does not exist (negative answer). In that case the resolver should stop searching.
If there is neither a positive or negative answer (no answer), it should continue searching until all source / hostname combinations have been tried.
The following results are possible.
We got a positive answer that the hostname exists. The hostname could have an address assigned to it or not.
We got a negative answer that the hostname does not exist.
We still have no answer after searching all sources.
- Some error occurred preventing us from completing the source. The error can be either local, reported perhaps by a local subsystem such as the memory allocator, or remote, reported by a remote service such as a nameserver.
If there was a confirmation that the hostname exists, it should either:
- Return success. For getaddrinfo() this means: return 0. Or,
Return a value indicating that no address is assigned. For getaddrinfo() there used to be a EAI_NODATA return value for that, which is not mentioned in later versions of the standard. Either EIA_FAIL or EAI_NONAME could be used instead. Note that if getaddrinfo() returns success there should be at least 1 address, so we can't return 0 in this case.
getaddrinfo() should return the following error values in the following cases:
There was no answer: EAI_AGAIN
- There was neither a positive nor a negative acknowledgment of the existence of the service name: EAI_AGAIN
- AI_NUMERICHOST was used and the hostname wasn't a valid numeric string representation of the address: EAI_NONAME
- AI_NUMERICSERV was used and the service name wasn't a valid number in string form: EAI_NONAME
- Both nodename and servname are NULL: EAI_NONAME
- Unknown bits where set in the ai_flags: EAI_BADFLAGS
- Unknown or unsupported family was used: EAI_FAMILY
- Unknown or unsupported socket type: EAI_SOCKTYPE
- There was a failure to allocate memory: EAI_MEMORY
- There was a answer that indicates that the service name doesn't exist for the given socket type: EAI_SERVICE
- Some system error occurred and errno is set: EAI_SYSTEM.
- The source information doesn't make sense, like failing to parse a file, dns returned an invalid packet: EAI_FAIL
It's unclear when EAI_SYSTEM should be returned and that getaddrinfo() shouldn't do something else in stead in case the system return an error. Some reasons why system could return an error and set errno:
- We tried to open a file and got an error like EACCES, EMFILE, ... It should probably return EAI_SYSTEM in that case.
- We tried to create a socket and got an error like EACCES, EINVAL, ... It should probably only return that error in case all the different sockets it tried to create failed.
- We tried to do network communication (send, sendto, recv, recvfrom) and got an error. It should probably all be treated as non-permanent error and might then result in an EAI_AGAIN
- EINTR should always be handled by getaddrinfo() itself. It should not return EAI_SYSTEM in this case.
In case there was a negative answer it's unclear what should be returned. Some implementations return EAI_FAIL, others EAI_NONAME.
When looking in files to do the resolving it can only return a positive acknowledgment. If it's not found it the file it doesn't mean it doesn't exist and it has no answer.
The /etc/hosts files is listed by IP address, and we're looking up the hostname. A hostname might have multiple addresses or address types assigned to it, so the hole file should be checked. In case the hostname exists but doesn't have the address type that is asked for it should return the positive answer no address.
Both FQDN and non-FQDNs can be looked up in this source.
When looking things up in DNS, there could be more than 1 server which we can ask address of the hostname. If we don't get a answer from the server or get a communication error we should move to the next server. This should be not be treated as a negative answer. In case there are no answers it should retry it since this goes over UDP and the packet could be lost. There should be some timeout before it gives up trying to look up the host. It should probably also increase the time between sending packets to the same server in case of no answer. Only after the timeout has been reached it the answer is no answer.
It's unclear what we should do in case of an invalid packet: same as no answer and retry until timeout?
If the DNSSEC verification fails for whatever reason, it should not be treated as no answer.
DNS can return both positive and negative answers.
DNS can return the case of no address by returning SUCCESS but with an empty answer. In case of DNSSEC we should retry this until we have a signed reply saying this.
Both FQDNs and non-FQDNs can be looked up in this source, but most non-FQDNs will either result no address or a negative answer.
If no nameserver is configured it should either default to localhost or to an empty list of servers. If an empty list of servers is used there is no answer.
mDNS can only do lookups in the .local domain, and so the hostname should always be a FQDN. Asking about any other domain or a non-FQDN should result in no answer.
mDNS queries should be retried until there is an answer, error or a timeout is reached. There should probably be an increase in time between packets.
It's unclear what the best behavior is in case their was no reply since it might currently be down or otherwise unreachable. It should probably return no answer.
Since this is based on DNS, it can also return the case of no address.
There is a problem with the .local domain since both DNS and mDNS claim to be authoritative over it, and DNS will always return a negative answer for it if root nameserver can be reached. Changing the order of the sources doesn't solve this. Therefor in case of mDNS returning no answer for a host in the .local domain it should prevent the next source from being tried, and DNS should come after mDNS.
There are various reasons while the configuration files can be changed while a process is running. getaddrinfo() should re-read those files if they got changed.