You are here because in one or another way you are resolving an IP address and that takes a long time (5 to 15 or even 30 seconds). Let me guess. You are using Ubuntu and you use gethostbyaddr(), getnameinfo(), or any such function in a programming language like C, C++, Python, Perl, etc. It’s not your fault. To be precise, the problem arises (at least in my case) whenever you are trying to resolve IP 0.0.0.0. This IP, which is also referred to with the code name INADDR_ANY (actually a macro declaration in C) is very helpful when you write a server process and you would like to make it listen to all network interfaces of the machine it resides. For example, it is very common to have two or more external IP addresses for a machine. If you would like your server to accept connections on all such interfaces, then you have to create a socket and afterwards bind it to the IP address 0.0.0.0. A sample program written in C that does exactly this is the following:
#include #include #include #include #include #include #include int main(void) { int sock; struct sockaddr_in addr; struct hostent *hoste; char *host; printf("Creating socket..."); // create socket sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { perror("create socket"); exit(-1); } printf("OK\n"); // initialize structure memset((void *) &addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); printf("Binding..."); // bind if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind"); close(sock); exit(-1); } printf("OK\n"); // resolving printf("Resolving 0.0.0.0 ...\n"); hoste = gethostbyaddr(&addr.sin_addr.s_addr, 4, addr.sin_family); if (hoste == NULL) { fprintf(stderr, "\tWARNING: gethostbyaddr returned NULL\n"); } else { host = hoste->h_name; printf("OK"); printf("Host: %s\n", host); } printf("Closing socket...\n"); close(sock); printf("Socket closed.\n"); printf("Exit\n"); return 0; }
Running the above code in my system (Ubuntu 10.04) takes about 5 seconds.
$ time ./test_gethostbyaddr Creating socket...OK Binding...OK Resolving 0.0.0.0 ... WARNING: gethostbyaddr returned NULL Closing socket... Socket closed. Exit real 0m5.005s user 0m0.010s sys 0m0.000s
But why does the lookup take so long? Let’s try to resolve 0.0.0.0 manually.
$ time host 0.0.0.0 Host 0.0.0.0.in-addr.arpa. not found: 3(NXDOMAIN) real 0m0.006s user 0m0.020s sys 0m0.000s
Nice timing. But what about using nslookup?
$ time nslookup 0.0.0.0 Server: 195.134.100.90 Address: 195.134.100.90#53 ** server can't find 0.0.0.0.in-addr.arpa.: NXDOMAIN real 0m0.007s user 0m0.010s sys 0m0.000s
Nice timing as well. But why my program executes in 5 seconds? Well, the reason is that it does not use these commands to resolve the IP. More correctly, it does not use the underlying services that these two commands use, i.e., named, bind, /etc/hosts, etc., which are also mentioned in the respective man pages.
What service does it use then? It uses avahi. Come on, it can’t use the woolly lemur of Madagaskar. Don’t blame me because the author of avahi baptized it after that animal. Avahi is a daemon service that is included in distributions like Ubuntu, Debian, Fedora, SuSe, etc. and implements the mDNS (multicast DNS) protocol initially proposed by Apple. With mDNS a system can play the role of a DNS server for other computers on the same sub-network. It can also publish services like printing so as other computers find and use them.
Returning back to our problem, for some (configuration-centric) reason that I hadn’t had the time (and probably the mood) to further investigate, when the avahi-daemon is used in Ubuntu, it takes over all resolve lookups coming from such calls as gethostbyaddr() and getnameinfo(). Let’s test it manually:
$ time avahi-resolve --address 0.0.0.0 Failed to resolve address '0.0.0.0': Timeout reached real 0m5.007s user 0m0.010s sys 0m0.000s
And this is exactly the amount of time that our program takes to execute. The hard way is to disable avahi-daemon. This can be done by first stopping the daemon
$ sudo service avahi-daemon stop avahi-daemon stop/waiting
and then removing it from loading during system startup
$ sudo update-rc.d -f avahi-daemon remove Removing any system startup links for /etc/init.d/avahi-daemon ... /etc/rc0.d/K20avahi-daemon /etc/rc1.d/K20avahi-daemon /etc/rc2.d/S20avahi-daemon /etc/rc3.d/S20avahi-daemon /etc/rc4.d/S20avahi-daemon /etc/rc5.d/S20avahi-daemon /etc/rc6.d/K20avahi-daemon
Of course, this has the disadvantage that you lose the useful service of discovery of printers, etc. No big deal for me. But if it counts much for you, then I suggest you read the documentation about how to configure avahi making not responding to lookup requests for INADDR_ANY (0.0.0.0). I bet that it is a configuration issue because running the same program in Fedora 16 it does not incur any time penalty. And if you find yourself searching and finally overcoming it, just drop a line here.
In case that you would like to re-enable it, just type
$ sudo update-rc.d avahi-daemon defaultsTiming, now, our initial program we get the following
$ time ./test_gethostbyaddr Creating socket...OK Binding...OK Resolving 0.0.0.0 ... WARNING: gethostbyaddr returned NULL Closing socket... Socket closed. Exit real 0m0.007s user 0m0.010s sys 0m0.000s
Music Listened: Isn’t She Lovely on Songs in the Key of Life by Stevie Wonder
0 Responses to “Resolving IP addresses takes a long time (not anymore)”