PERFORCE change 108739 for review
Michael Bushkov
bushman at FreeBSD.org
Mon Oct 30 12:54:53 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=108739
Change 108739 by bushman at bushman_nss_ldap_cached on 2006/10/30 12:53:52
IFC
Affected files ...
.. //depot/projects/soc2006/nss_ldap_cached_no_nss_ldap/src/lib/Makefile#3 integrate
.. //depot/projects/soc2006/nss_ldap_cached_no_nss_ldap/src/lib/nss_icmp/icmp_hosts_namadr.c#2 integrate
.. //depot/projects/soc2006/nss_ldap_cached_no_nss_ldap/src/share/mk/bsd.own.mk#2 integrate
Differences ...
==== //depot/projects/soc2006/nss_ldap_cached_no_nss_ldap/src/lib/Makefile#3 (text+ko) ====
@@ -33,7 +33,7 @@
libradius librpcsvc libsbuf libtacplus libutil \
${_libypclnt} libalias libarchive ${_libatm} \
libbegemot ${_libbluetooth} libbsnmp libbz2 \
- nss_compat nss_dns nss_files nss_icmp ${_nss_nis} libc \
+ nss_compat nss_dns nss_files ${_nss_icmp} ${_nss_nis} libc \
libcalendar libcam libcompat libdevinfo libdevstat libdisk \
libedit libexpat libfetch libform libftpio libgeom ${_libgpib} \
libgssapi libipsec \
@@ -120,6 +120,10 @@
_libusbhid= libusbhid
.endif
+.if ${MK_NSS_ICMP} != "no"
+_nss_icmp= nss_icmp
+.endif
+
.if ${MK_NIS} != "no"
_libypclnt= libypclnt
_nss_nis= nss_nis
==== //depot/projects/soc2006/nss_ldap_cached_no_nss_ldap/src/lib/nss_icmp/icmp_hosts_namadr.c#2 (text+ko) ====
@@ -156,151 +156,119 @@
/*
* experimental:
- * draft-ietf-ipngwg-icmp-namelookups-02.txt
+ * draft-ietf-ipngwg-icmp-namelookups-09.txt
* ifindex is assumed to be encoded in addr.
*/
#include <sys/uio.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
+#include <ctype.h>
-struct _icmp_host_cache {
- struct _icmp_host_cache *hc_next;
- int hc_ifindex;
- struct in6_addr hc_addr;
- char *hc_name;
-};
+#ifndef NI_QTYPE_NODENAME
+#define NI_QTYPE_NODENAME NI_QTYPE_DNSNAME
+#endif
-/* setting the query/reply structures according to
- * draft-ietf-ipngwg-icmp-namelookups-02.txt */
-
-struct icmp6_fqdn_query {
- u_int8_t icmp6_fqdn_type; /* type field */
- u_int8_t icmp6_fqdn_code; /* code field */
- u_int16_t icmp6_fqdn_cksum; /* checksum field */
- u_short icmp6_fqdn_id;
- u_int16_t icmp6_fqdn_nonce[4];
-};
-
-#define MAX_ICMP6_NAMELEN 255
-
-struct icmp6_fqdn_reply {
- u_int8_t icmp6_fqdn_type; /* type field */
- u_int8_t icmp6_fqdn_code; /* code field */
- u_int16_t icmp6_fqdn_cksum; /* checksum field */
- u_short icmp6_fqdn_id;
- u_int16_t icmp6_fqdn_nonce[4];
- int16_t icmp6_fqdn_ttl;
- uint8_t icmp6_fqdn_namelen;
- char icmp6_fqdn_name[MAX_ICMP6_NAMELEN];
-};
-
-static int
-__copy_hostent(struct hostent *he, struct hostent *hptr, char *buf,
- size_t buflen)
+static char *
+dnsdecode(sp, ep, base, buf, bufsiz)
+ const u_char **sp;
+ const u_char *ep;
+ const u_char *base; /*base for compressed name*/
+ u_char *buf;
+ size_t bufsiz;
{
- char *cp;
- char **ptr;
- int i, n;
- int nptr, len;
+ int i;
+ const u_char *cp;
+ char cresult[MAXDNAME + 1];
+ const u_char *comp;
+ int l;
- /* Find out the amount of space required to store the answer. */
- nptr = 2; /* NULL ptrs */
- len = (char *)ALIGN(buf) - buf;
- for (i = 0; he->h_addr_list[i]; i++, nptr++) {
- len += he->h_length;
- }
- for (i = 0; he->h_aliases[i]; i++, nptr++) {
- len += strlen(he->h_aliases[i]) + 1;
- }
- len += strlen(he->h_name) + 1;
- len += nptr * sizeof(char*);
+ cp = *sp;
+ *buf = '\0';
- if (len > buflen) {
- errno = ERANGE;
- return (-1);
- }
+ if (cp >= ep)
+ return NULL;
+ while (cp < ep) {
+ i = *cp;
+ if (i == 0 || cp != *sp) {
+ if (strlcat(buf, ".", bufsiz) >= bufsiz)
+ return NULL; /* result overrun */
+ }
+ if (i == 0)
+ break;
+ cp++;
- /* copy address size and type */
- hptr->h_addrtype = he->h_addrtype;
- n = hptr->h_length = he->h_length;
+ if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) {
+ /* DNS compression */
+ if (!base)
+ return NULL;
- ptr = (char **)ALIGN(buf);
- cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
-
- /* copy address list */
- hptr->h_addr_list = ptr;
- for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
- memcpy(cp, he->h_addr_list[i], n);
- hptr->h_addr_list[i] = cp;
- cp += n;
+ comp = base + (i & 0x3f);
+ if (dnsdecode(&comp, cp, base, cresult,
+ sizeof(cresult)) == NULL)
+ return NULL;
+ if (strlcat(buf, cresult, bufsiz) >= bufsiz)
+ return NULL; /* result overrun */
+ break;
+ } else if ((i & 0x3f) == i) {
+ if (i > ep - cp)
+ return NULL; /* source overrun */
+ while (i-- > 0 && cp < ep) {
+ l = snprintf(cresult, sizeof(cresult),
+ isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
+ if (l >= sizeof(cresult) || l < 0)
+ return NULL;
+ if (strlcat(buf, cresult, bufsiz) >= bufsiz)
+ return NULL; /* result overrun */
+ cp++;
+ }
+ } else
+ return NULL; /* invalid label */
}
- hptr->h_addr_list[i] = NULL;
- ptr++;
-
- /* copy official name */
- n = strlen(he->h_name) + 1;
- strcpy(cp, he->h_name);
- hptr->h_name = cp;
- cp += n;
-
- /* copy aliases */
- hptr->h_aliases = ptr;
- for (i = 0 ; he->h_aliases[i]; i++) {
- n = strlen(he->h_aliases[i]) + 1;
- strcpy(cp, he->h_aliases[i]);
- hptr->h_aliases[i] = cp;
- cp += n;
- }
- hptr->h_aliases[i] = NULL;
-
- return (0);
+ if (i != 0)
+ return NULL; /* not terminated */
+ cp++;
+ *sp = cp;
+ return buf;
}
static char *
-_icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
+_icmp_nodeinfo_query(const struct in6_addr *addr, int ifindex, char *dnsname)
{
int s;
struct icmp6_filter filter;
struct msghdr msg;
struct cmsghdr *cmsg;
struct in6_pktinfo *pkt;
- char cbuf[256];
- char buf[1024];
+ char cbuf[256], buf[1024], *cp, *end;
int cc;
- struct icmp6_fqdn_query *fq;
- struct icmp6_fqdn_reply *fr;
- struct _icmp_host_cache *hc;
+ struct icmp6_nodeinfo niq, *nir;
struct sockaddr_in6 sin6;
struct iovec iov;
fd_set s_fds, fds;
struct timeval tout;
int len;
- char *name;
- static struct _icmp_host_cache *hc_head;
+ static int pid;
+ u_int32_t r1, r2;
- THREAD_LOCK();
- for (hc = hc_head; hc; hc = hc->hc_next) {
- if (hc->hc_ifindex == ifindex
- && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) {
- THREAD_UNLOCK();
- return hc->hc_name; /* XXX: never freed */
- }
- }
- THREAD_UNLOCK();
+ if (pid == 0)
+ pid = getpid();
ICMP6_FILTER_SETBLOCKALL(&filter);
- ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
+ ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filter);
FD_ZERO(&s_fds);
tout.tv_sec = 0;
- tout.tv_usec = 200000; /*XXX: 200ms*/
+ tout.tv_usec = 500000; /* 500ms */
- fq = (struct icmp6_fqdn_query *)buf;
- fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
- fq->icmp6_fqdn_code = 0;
- fq->icmp6_fqdn_cksum = 0;
- fq->icmp6_fqdn_id = (u_short)getpid();
- memset(&fq->icmp6_fqdn_nonce, 0, sizeof(fq->icmp6_fqdn_nonce));
+ memset(&niq, 0, sizeof(niq));
+ niq.ni_type = ICMP6_NI_QUERY;
+ niq.ni_code = ICMP6_NI_SUBJ_IPV6;
+ niq.ni_qtype = htons(NI_QTYPE_NODENAME);
+ niq.ni_flags = 0;
+ r1 = arc4random();
+ r2 = arc4random();
+ memcpy(&niq.icmp6_ni_nonce[0], &r1, sizeof(r1));
+ memcpy(&niq.icmp6_ni_nonce[4], &r2, sizeof(r2));
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
@@ -313,8 +281,8 @@
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
- iov.iov_base = (caddr_t)buf;
- iov.iov_len = sizeof(struct icmp6_fqdn_query);
+ iov.iov_base = (caddr_t)&niq;
+ iov.iov_len = sizeof(struct icmp6_nodeinfo);
if (ifindex) {
msg.msg_control = cbuf;
@@ -330,68 +298,85 @@
msg.msg_controllen = (char *)cmsg - cbuf;
}
- if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
+ /* XXX: we need root privilege here */
+ if ((s = _socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
return NULL;
(void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
(char *)&filter, sizeof(filter));
cc = _sendmsg(s, &msg, 0);
if (cc < 0) {
_close(s);
- return NULL;
+ return (NULL);
}
FD_SET(s, &s_fds);
for (;;) {
fds = s_fds;
if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
_close(s);
- return NULL;
+ return (NULL);
}
len = sizeof(sin6);
cc = _recvfrom(s, buf, sizeof(buf), 0,
(struct sockaddr *)&sin6, &len);
if (cc <= 0) {
_close(s);
- return NULL;
+ return (NULL);
}
- if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
+ if (cc < sizeof(struct icmp6_hdr))
+ continue;
+ nir = (struct icmp6_nodeinfo *)buf;
+ if (nir->ni_type != ICMP6_NI_REPLY)
+ continue;
+ if (nir->ni_qtype != htons(NI_QTYPE_NODENAME))
continue;
- if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
+ if (memcmp(nir->icmp6_ni_nonce, niq.icmp6_ni_nonce,
+ sizeof(nir->icmp6_ni_nonce)) != 0) {
continue;
- fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
- if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
- break;
+ }
+ if (nir->ni_code != htons(ICMP6_NI_SUCCESS))
+ continue; /* or should we fail? */
+
+ /* this is an expected reply. */
+ break;
}
_close(s);
- /* TODO: this check confuses me a bit */
- /* if (fr->icmp6_fqdn_cookie[1] != 0) { */
- /* rfc1788 type */
- /* name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
- * len = (buf + cc) - name;
- * } else { */
- len = fr->icmp6_fqdn_namelen;
- name = fr->icmp6_fqdn_name;
- /* } */
+
+ memset(dnsname, 0, MAXDNAME + 1);
+ cp = (char *)(nir + 1);
+ end = ((char *)nir) + cc;
+ if (end - cp < sizeof(int32_t)) /* for TTL. we don't use it. */
+ return (NULL);
+ cp += sizeof(int32_t);
+ if (*cp == end - cp - 1) { /* an old version */
+ int nlen;
+
+ cp++; /* skip length */
+ nlen = end - cp;
+ if (nlen > MAXDNAME)
+ return (NULL); /* XXX: use it anyway? */
+ memcpy(dnsname, cp, nlen);
+ } else {
+ /* XXX: should we use a generic function? */
+ if (dnsdecode((const u_char **)(void *)&cp, end,
+ (const u_char *)(nir + 1), dnsname, MAXDNAME + 1)
+ == NULL) {
+ return (NULL); /* bogus name */
+ }
+ /* Name-lookup special handling for truncated name. */
+ if (cp + 1 <= end && !*cp && strlen(dnsname) > 0)
+ dnsname[strlen(dnsname) - 1] = '\0';
- if (len <= 0)
- return NULL;
- name[len] = 0;
+ /* There may be other names, but we ignore them. */
+ }
- if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
- return NULL;
- /* XXX: limit number of cached entries */
- hc->hc_ifindex = ifindex;
- hc->hc_addr = *addr;
- hc->hc_name = strdup(name);
- THREAD_LOCK();
- hc->hc_next = hc_head;
- hc_head = hc;
- THREAD_UNLOCK();
- return hc->hc_name;
+ return (dnsname);
}
+
static struct hostent *
_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
{
+ char dnsname[MAXDNAME + 1];
struct icmp_hostent_data *hed;
struct hostent *he;
@@ -405,29 +390,23 @@
return (NULL);
}
- if (af != AF_INET6) {
+ if (af != AF_INET6 || addrlen != sizeof(addr6)) {
/*
* Note: rfc1788 defines Who Are You for IPv4,
* but no one implements it.
*/
- return NULL;
+ return (NULL);
}
memcpy(&addr6, addr, addrlen);
- ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
- addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
+ if (IN6_IS_ADDR_LINKLOCAL(&addr6)) {
+ ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
+ addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
+ }
- if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
- return (NULL); /*XXX*/
-
- if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
+ if ((hname = _icmp_nodeinfo_query(&addr6, ifindex, dnsname)) == NULL)
return (NULL);
- if (strlen(hname) > sizeof(hed->hostbuf) - 1) {
- *errp = NO_RECOVERY;
- return (NULL);
- }
-
he->h_name = hed->hostbuf;
he->h_aliases = NULL;
he->h_addrtype = af;
==== //depot/projects/soc2006/nss_ldap_cached_no_nss_ldap/src/share/mk/bsd.own.mk#2 (text+ko) ====
@@ -367,7 +367,8 @@
.for var in \
BIND_LIBS \
HESIOD \
- IDEA
+ IDEA \
+ NSS_ICMP \
.if defined(WITH_${var}) && defined(WITHOUT_${var})
.error WITH_${var} and WITHOUT_${var} can't both be set.
.endif
More information about the p4-projects
mailing list