diff --git a/ChangeLog b/ChangeLog index 9478b280f4..e562bcc0d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2004-09-15 Ulrich Drepper + * nscd/aicache.c: Prefer using gethostbyname3_r NSS callback to also + get ttl and canonical name. Use these two values. + * resolv/Versions: Export _nss_dns_gethostbyname3_r from libnss_dns. + * resolv/nss_dns/dns-host.c (getanswer_r): Take two new parameters. + If nonnull fill with TTL and pointer to canonical name respectively. + (_nss_dns_gethostbyaddr_r): Pass NULL in new parameters of getanswer_r. + (_nss_dns_gethostbyname2_r): Just wrapper around + _nss_dns_gethostbyname3_r. + (_nss_dns_gethostbyname3_r): Renamed from _nss_dns_gethostbyname2_r. + Take two new parameters which as passed to getanswer_r. + * nscd/Makefile (rountines): Add nscd_getai. (nscd-modules): Add aicache. * nscd/aicache.c: New file. diff --git a/nscd/aicache.c b/nscd/aicache.c index e7489065d4..7fddd7d98c 100644 --- a/nscd/aicache.c +++ b/nscd/aicache.c @@ -30,10 +30,10 @@ #include -typedef enum nss_status (*nss_gethostbyname2_r) +typedef enum nss_status (*nss_gethostbyname3_r) (const char *name, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, - int *h_errnop); + int *h_errnop, int32_t *, char **); typedef enum nss_status (*nss_getcanonname_r) (const char *name, char *buffer, size_t buflen, char **result, int *errnop, int *h_errnop); @@ -114,19 +114,23 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, size_t tmpbuf4len = 0; char *tmpbuf4 = NULL; char *canon = NULL; + int32_t ttl = UINT32_MAX; ssize_t total = 0; char *key_copy = NULL; bool alloca_used = false; while (!no_more) { - nss_gethostbyname2_r fct = __nss_lookup_function (nip, - "gethostbyname2_r"); int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL }; + /* Prefer the function which also returns the TTL and canonical name. */ + nss_gethostbyname3_r fct = __nss_lookup_function (nip, + "gethostbyname3_r"); + if (fct == NULL) + fct = __nss_lookup_function (nip, "gethostbyname2_r"); + if (fct != NULL) { - printf("fct=%p\n",fct); struct hostent th[2]; /* Collect IPv6 information first. */ @@ -134,7 +138,8 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, { rc6 = 0; status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0], tmpbuf6, - tmpbuf6len, &rc6, &herrno)); + tmpbuf6len, &rc6, &herrno, + &ttl, &canon)); if (rc6 != ERANGE || herrno != NETDB_INTERNAL) break; tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len); @@ -161,10 +166,12 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, { rc4 = 0; status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1], tmpbuf4, - tmpbuf4len, &rc4, &herrno)); + tmpbuf4len, &rc4, &herrno, + ttl == UINT32_MAX ? &ttl : NULL, + canon == NULL ? &canon : NULL)); if (rc4 != ERANGE || herrno != NETDB_INTERNAL) break; - tmpbuf4 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len); + tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len); } if (rc4 != 0 || herrno == NETDB_INTERNAL) @@ -184,26 +191,69 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, addrslen += th[j].h_length; } - /* Determine the canonical name. */ - nss_getcanonname_r cfct; - cfct = __nss_lookup_function (nip, "getcanonname_r"); - if (cfct != NULL) + if (canon == NULL) { - const size_t max_fqdn_len = 256; - char *buf = alloca (max_fqdn_len); - char *s; - int rc; + /* Determine the canonical name. */ + nss_getcanonname_r cfct; + cfct = __nss_lookup_function (nip, "getcanonname_r"); + if (cfct != NULL) + { + const size_t max_fqdn_len = 256; + char *buf = alloca (max_fqdn_len); + char *s; + int rc; - if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s, &rc, - &herrno)) == NSS_STATUS_SUCCESS) - canon = s; + if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s, &rc, + &herrno)) == NSS_STATUS_SUCCESS) + canon = s; + else + /* Set to name now to avoid using gethostbyaddr. */ + canon = key; + } else - /* Set to name now to avoid using gethostbyaddr. */ - canon = key; - } - else - { - // XXX use gethostbyaddr + { + struct hostent *he = NULL; + int herrno; + struct hostent he_mem; + void *addr; + size_t addrlen; + int addrfamily; + + if (status[1] == NSS_STATUS_SUCCESS) + { + addr = th[1].h_addr_list[0]; + addrlen = sizeof (struct in_addr); + addrfamily = AF_INET; + } + else + { + addr = th[0].h_addr_list[0]; + addrlen = sizeof (struct in6_addr); + addrfamily = AF_INET6; + } + + size_t tmpbuflen = 512; + char *tmpbuf = alloca (tmpbuflen); + int rc; + while (1) + { + rc = __gethostbyaddr_r (addr, addrlen, addrfamily, + &he_mem, tmpbuf, tmpbuflen, + &he, &herrno); + if (rc != ERANGE || herrno != NETDB_INTERNAL) + break; + tmpbuf = extend_alloca (tmpbuf, tmpbuflen, + tmpbuflen * 2); + } + + if (rc == 0) + { + if (he != NULL) + canon = he->h_name; + else + canon = key; + } + } } size_t canonlen = canon == NULL ? 0 : (strlen (canon) + 1); @@ -237,7 +287,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, dataset->head.usable = true; /* Compute the timeout time. */ - dataset->head.timeout = time (NULL) + db->postimeout; + dataset->head.timeout = time (NULL) + MIN (db->postimeout, ttl); dataset->resp.version = NSCD_VERSION; dataset->resp.found = 1; diff --git a/posix/Makefile b/posix/Makefile index d0ad95dce1..766c1dd7f7 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -126,7 +126,7 @@ endif endif CFLAGS-regex.c = -Wno-strict-prototypes -CFLAGS-getaddrinfo.c = -DRESOLVER -fexceptions +CFLAGS-getaddrinfo.c = -DRESOLVER -fexceptions -DUSE_NSCD CFLAGS-pread.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-pread64.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-pwrite.c = -fexceptions -fasynchronous-unwind-tables diff --git a/resolv/Versions b/resolv/Versions index 0e4fea5e19..2a67677d8e 100644 --- a/resolv/Versions +++ b/resolv/Versions @@ -77,7 +77,7 @@ libresolv { GLIBC_PRIVATE { # Needed in libnss_dns. __ns_name_unpack; __ns_name_ntop; - __ns_get16; + __ns_get16; __ns_get32; __libc_res_nquery; __libc_res_nsearch; } } @@ -85,6 +85,7 @@ libresolv { libnss_dns { GLIBC_PRIVATE { _nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_r; + _nss_dns_gethostbyname3_r; _nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r; _nss_dns_getnetbyname_r; _nss_dns_getcanonname_r; } diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 91699cc50d..f6a2fa65d6 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -125,12 +125,12 @@ static enum nss_status getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, - int map); + int map, int32_t *ttlp, char **canonp); enum nss_status -_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, +_nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, - int *h_errnop) + int *h_errnop, int32_t *ttlp, char **canonp) { union { @@ -211,13 +211,23 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, } status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen, - errnop, h_errnop, map); + errnop, h_errnop, map, ttlp, canonp); if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); return status; } +enum nss_status +_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop) +{ + return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop, + h_errnop, NULL, NULL); +} + + enum nss_status _nss_dns_gethostbyname_r (const char *name, struct hostent *result, char *buffer, size_t buflen, int *errnop, @@ -355,7 +365,7 @@ _nss_dns_gethostbyaddr_r (const void *addr, socklen_t len, int af, got_it_already: status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen, - errnop, h_errnop, 0 /* XXX */); + errnop, h_errnop, 0 /* XXX */, NULL, NULL); if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); if (status != NSS_STATUS_SUCCESS) @@ -439,7 +449,7 @@ addrsort (char **ap, int num) static enum nss_status getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, struct hostent *result, char *buffer, size_t buflen, - int *errnop, int *h_errnop, int map) + int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp) { struct host_data { @@ -458,6 +468,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, int (*name_ok) (const char *); u_char packtmp[NS_MAXCDNAME]; int have_to_map = 0; + int32_t ttl = 0; if (__builtin_expect (linebuflen, 0) < 0) { @@ -577,7 +588,9 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, type = ns_get16 (cp); cp += INT16SZ; /* type */ class = ns_get16 (cp); - cp += INT16SZ + INT32SZ; /* class, TTL */ + cp += INT16SZ; /* class */ + ttl = ns_get32 (cp); + cp += INT32SZ; /* TTL */ n = ns_get16 (cp); cp += INT16SZ; /* len */ if (class != C_IN) @@ -749,6 +762,10 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype, { register int nn; + if (ttlp != NULL && ttl != 0) + *ttlp = ttl; + if (canonp != NULL) + *canonp = bp; result->h_name = bp; nn = strlen (bp) + 1; /* for the \0 */ bp += nn;