#include <nscd.h>
-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);
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. */
{
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);
{
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)
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;
-
- if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s, &rc,
- &herrno)) == NSS_STATUS_SUCCESS)
- canon = s;
+ /* 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;
+ 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);
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;
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
{
}
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,
int *h_errnop)
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)
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
{
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)
{
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)
{
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;