Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libc/net PR/32373, PR/25827: Add SRV lookup in getaddrin...
details: https://anonhg.NetBSD.org/src/rev/dcc34113d5f2
branches: trunk
changeset: 786615:dcc34113d5f2
user: christos <christos%NetBSD.org@localhost>
date: Fri May 03 19:31:13 2013 +0000
description:
PR/32373, PR/25827: Add SRV lookup in getaddrinfo(3)
Per DNS-SD (RFC 2782), but only enabled if AI_SRV is set.
diffstat:
lib/libc/net/getaddrinfo.c | 516 ++++++++++++++++++++++++++++++++++++--------
1 files changed, 420 insertions(+), 96 deletions(-)
diffs (truncated from 663 to 300 lines):
diff -r d85213e15006 -r dcc34113d5f2 lib/libc/net/getaddrinfo.c
--- a/lib/libc/net/getaddrinfo.c Fri May 03 19:24:52 2013 +0000
+++ b/lib/libc/net/getaddrinfo.c Fri May 03 19:31:13 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: getaddrinfo.c,v 1.102 2013/05/03 19:24:52 christos Exp $ */
+/* $NetBSD: getaddrinfo.c,v 1.103 2013/05/03 19:31:13 christos Exp $ */
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */
/*
@@ -55,7 +55,7 @@
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: getaddrinfo.c,v 1.102 2013/05/03 19:24:52 christos Exp $");
+__RCSID("$NetBSD: getaddrinfo.c,v 1.103 2013/05/03 19:31:13 christos Exp $");
#endif /* LIBC_SCCS and not lint */
#include "namespace.h"
@@ -191,6 +191,13 @@
int n; /* result length */
};
+struct srvinfo {
+ struct srvinfo *next;
+ char name[MAXDNAME];
+ int port, pri, weight;
+};
+
+static int gai_srvok(const char *);
static int str2number(const char *);
static int explore_fqdn(const struct addrinfo *, const char *,
const char *, struct addrinfo **, struct servent_data *);
@@ -217,6 +224,12 @@
static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
const struct addrinfo *);
static void aisort(struct addrinfo *s, res_state res);
+static struct addrinfo * _dns_query(struct res_target *,
+ const struct addrinfo *, res_state, int);
+static struct addrinfo * _dns_srv_lookup(const char *, const char *,
+ const struct addrinfo *);
+static struct addrinfo * _dns_host_lookup(const char *,
+ const struct addrinfo *);
static int _dns_getaddrinfo(void *, void *, va_list);
static void _sethtent(FILE **);
static void _endhtent(FILE **);
@@ -319,6 +332,58 @@
} while (ai);
}
+/*
+ * We don't want localization to affect us
+ */
+#define PERIOD '.'
+#define hyphenchar(c) ((c) == '-')
+#define periodchar(c) ((c) == PERIOD)
+#define underschar(c) ((c) == '_')
+#define alphachar(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+#define digitchar(c) ((c) >= '0' && (c) <= '9')
+
+#define firstchar(c) (alphachar(c) || digitchar(c) || underschar(c))
+#define lastchar(c) (alphachar(c) || digitchar(c))
+#define middlechar(c) (lastchar(c) || hyphenchar(c))
+
+static int
+gai_srvok(const char *dn)
+{
+ int nch, pch, ch;
+
+ for (pch = PERIOD, nch = ch = *dn++; ch != '\0'; pch = ch, ch = nch) {
+ if (periodchar(ch))
+ continue;
+ if (periodchar(pch)) {
+ if (!firstchar(ch))
+ return 0;
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!lastchar(ch))
+ return 0;
+ } else if (!middlechar(ch))
+ return 0;
+ }
+ return 1;
+}
+
+static in_port_t *
+getport(struct addrinfo *ai) {
+ static in_port_t p;
+
+ switch (ai->ai_family) {
+ case AF_INET:
+ return &((struct sockaddr_in *)(void *)ai->ai_addr)->sin_port;
+#ifdef INET6
+ case AF_INET6:
+ return &((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_port;
+#endif
+ default:
+ p = 0;
+ /* XXX: abort()? */
+ return &p;
+ }
+}
+
static int
str2number(const char *p)
{
@@ -589,7 +654,7 @@
return 0;
switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
- default_dns_files, hostname, pai)) {
+ default_dns_files, hostname, pai, servname)) {
case NS_TRYAGAIN:
error = EAI_AGAIN;
goto free;
@@ -602,6 +667,9 @@
case NS_SUCCESS:
error = 0;
for (cur = result; cur; cur = cur->ai_next) {
+ /* Check for already filled port. */
+ if (*getport(cur))
+ continue;
GET_PORT(cur, servname, svd);
/* canonname should be filled already */
}
@@ -990,21 +1058,8 @@
port = sp->s_port;
}
- if (!matchonly) {
- switch (ai->ai_family) {
- case AF_INET:
- ((struct sockaddr_in *)(void *)
- ai->ai_addr)->sin_port = port;
- break;
-#ifdef INET6
- case AF_INET6:
- ((struct sockaddr_in6 *)(void *)
- ai->ai_addr)->sin6_port = port;
- break;
-#endif
- }
- }
-
+ if (!matchonly)
+ *getport(__UNCONST(ai)) = port;
return 0;
}
@@ -1107,7 +1162,7 @@
const struct addrinfo *pai)
{
struct addrinfo sentinel, *cur;
- struct addrinfo ai;
+ struct addrinfo ai, *aip;
const struct afd *afd;
char *canonname;
const HEADER *hp;
@@ -1120,6 +1175,8 @@
char tbuf[MAXDNAME];
int (*name_ok) (const char *);
char hostbuf[8*1024];
+ int port, pri, weight;
+ struct srvinfo *srvlist, *srv, *csrv;
_DIAGASSERT(answer != NULL);
_DIAGASSERT(qname != NULL);
@@ -1136,6 +1193,9 @@
case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
name_ok = res_hnok;
break;
+ case T_SRV:
+ name_ok = gai_srvok;
+ break;
default:
return NULL; /* XXX should be abort(); */
}
@@ -1175,6 +1235,7 @@
}
haveanswer = 0;
had_error = 0;
+ srvlist = NULL;
while (ancount-- > 0 && cp < eom && !had_error) {
n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
if ((n < 0) || !(*name_ok)(bp)) {
@@ -1277,17 +1338,116 @@
cur = cur->ai_next;
cp += n;
break;
+ case T_SRV:
+ /* Add to SRV list. Insertion sort on priority. */
+ pri = _getshort(cp);
+ cp += INT16SZ;
+ weight = _getshort(cp);
+ cp += INT16SZ;
+ port = _getshort(cp);
+ cp += INT16SZ;
+ n = dn_expand(answer->buf, eom, cp, tbuf,
+ (int)sizeof(tbuf));
+ if ((n < 0) || !res_hnok(tbuf)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ if (strlen(tbuf) + 1 >= MAXDNAME) {
+ had_error++;
+ continue;
+ }
+ srv = malloc(sizeof(*srv));
+ if (!srv) {
+ had_error++;
+ continue;
+ }
+ strlcpy(srv->name, tbuf, sizeof(srv->name));
+ srv->pri = pri;
+ srv->weight = weight;
+ srv->port = port;
+ /* Weight 0 is sorted before other weights. */
+ if (!srvlist
+ || srv->pri < srvlist->pri
+ || (srv->pri == srvlist->pri &&
+ (!srv->weight || srvlist->weight))) {
+ srv->next = srvlist;
+ srvlist = srv;
+ } else {
+ for (csrv = srvlist;
+ csrv->next && csrv->next->pri <= srv->pri;
+ csrv = csrv->next) {
+ if (csrv->next->pri == srv->pri
+ && (!srv->weight ||
+ csrv->next->weight))
+ break;
+ }
+ srv->next = csrv->next;
+ csrv->next = srv;
+ }
+ continue; /* Don't add to haveanswer yet. */
default:
abort();
}
if (!had_error)
haveanswer++;
}
+
+ if (srvlist) {
+ res_state res;
+ /*
+ * Check for explicit rejection.
+ */
+ if (!srvlist->next && !srvlist->name[0]) {
+ free(srvlist);
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
+ }
+ res = __res_get_state();
+ if (res == NULL) {
+ h_errno = NETDB_INTERNAL;
+ return NULL;
+ }
+
+ while (srvlist) {
+ struct res_target q, q2;
+
+ srv = srvlist;
+ srvlist = srvlist->next;
+
+ /*
+ * Since res_* doesn't give the additional
+ * section, we always look up.
+ */
+ memset(&q, 0, sizeof(q));
+ memset(&q2, 0, sizeof(q2));
+
+ q.name = srv->name;
+ q.qclass = C_IN;
+ q.qtype = T_AAAA;
+ q.next = &q2;
+ q2.name = srv->name;
+ q2.qclass = C_IN;
+ q2.qtype = T_A;
+
+ aip = _dns_query(&q, pai, res, 0);
+
+ if (aip != NULL) {
+ cur->ai_next = aip;
+ while (cur && cur->ai_next) {
+ cur = cur->ai_next;
+ *getport(cur) = htons(srv->port);
+ haveanswer++;
+ }
+ }
+ free(srv);
+ }
+ __res_put_state(res);
+ }
if (haveanswer) {
- if (!canonname)
- (void)get_canonname(pai, sentinel.ai_next, qname);
- else
- (void)get_canonname(pai, sentinel.ai_next, canonname);
+ if (!sentinel.ai_next->ai_canonname)
+ (void)get_canonname(pai, sentinel.ai_next,
Home |
Main Index |
Thread Index |
Old Index