diff options
author | Jim Pirzyk <pirzyk@FreeBSD.org> | 2002-08-21 19:57:53 +0000 |
---|---|---|
committer | Jim Pirzyk <pirzyk@FreeBSD.org> | 2002-08-21 19:57:53 +0000 |
commit | 69b0a4b6ac12aef5fbb0f2a58b2ef3ef4249e692 (patch) | |
tree | f75871c0d7a2aad9649768236d41c911b5de5554 /lib | |
parent | f5cd3d67fe0c5ed47e8945d7dfb0874c6de02e83 (diff) | |
download | src-69b0a4b6ac12aef5fbb0f2a58b2ef3ef4249e692.tar.gz src-69b0a4b6ac12aef5fbb0f2a58b2ef3ef4249e692.zip |
Fixed getaddrinfo to honor sortlist in /etc/resolv.conf
PR: bin/27939
Reviewed by: ru, sheldonh (about a year ago)
Obtained from: ume (via KAME, I think)
MFC after: 1 month
Notes
Notes:
svn path=/head/; revision=102237
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/net/getaddrinfo.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index c102d6b3b78a..0f724f9c64be 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -105,6 +105,9 @@ __FBSDID("$FreeBSD$"); #include <unistd.h> #include <stdio.h> #include <errno.h> + +#include "res_config.h" + #ifdef DEBUG #include <syslog.h> #endif @@ -1119,6 +1122,72 @@ ip6_str2scopeid(scope, sin6) } #endif +#ifdef RESOLVSORT +struct addr_ptr { + struct addrinfo *ai; + int aval; +}; + +static int +addr4sort(struct addrinfo *sentinel) +{ + struct addrinfo *ai; + struct addr_ptr *addrs, addr; + struct sockaddr_in *sin; + int naddrs, i, j; + int needsort = 0; + + if (!sentinel) + return -1; + naddrs = 0; + for (ai = sentinel->ai_next; ai; ai = ai->ai_next) + naddrs++; + if (naddrs < 2) + return 0; /* We don't need sorting. */ + if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) + return -1; + i = 0; + for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { + sin = (struct sockaddr_in *)ai->ai_addr; + for (j = 0; (unsigned)j < _res.nsort; j++) { + if (_res.sort_list[j].addr.s_addr == + (sin->sin_addr.s_addr & _res.sort_list[j].mask)) + break; + } + addrs[i].ai = ai; + addrs[i].aval = j; + if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) + needsort = i; + i++; + } + if (!needsort) { + free(addrs); + return 0; + } + + while (needsort < naddrs) { + for (j = needsort - 1; j >= 0; j--) { + if (addrs[j].aval > addrs[j+1].aval) { + addr = addrs[j]; + addrs[j] = addrs[j + 1]; + addrs[j + 1] = addr; + } else + break; + } + needsort++; + } + + ai = sentinel; + for (i = 0; i < naddrs; ++i) { + ai->ai_next = addrs[i].ai; + ai = ai->ai_next; + } + ai->ai_next = NULL; + free(addrs); + return 0; +} +#endif /*RESOLVSORT*/ + #ifdef DEBUG static const char AskedForGot[] = "gethostby*.getanswer: asked for \"%s\", got \"%s\""; @@ -1313,6 +1382,19 @@ getanswer(answer, anslen, qname, qtype, pai) haveanswer++; } if (haveanswer) { +#if defined(RESOLVSORT) + /* + * We support only IPv4 address for backward + * compatibility against gethostbyname(3). + */ + if (_res.nsort && qtype == T_A) { + if (addr4sort(&sentinel) < 0) { + freeaddrinfo(sentinel.ai_next); + h_errno = NO_RECOVERY; + return NULL; + } + } +#endif /*RESOLVSORT*/ if (!canonname) (void)get_canonname(pai, sentinel.ai_next, qname); else |