- switch(qtype) {
- case NI_QTYPE_NOOP:
- break; /* no reply data */
- case NI_QTYPE_SUPTYPES:
- goto bad; /* xxx: to be implemented */
- break;
- case NI_QTYPE_FQDN:
- replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
- hostnamelen;
- break;
- case NI_QTYPE_NODEADDR:
- addrs = ni6_addrs(ni6, m, &ifp);
- if ((replylen += addrs * sizeof(struct in6_addr)) > MCLBYTES)
- replylen = MCLBYTES; /* XXX: we'll truncate later */
-
- break;
- default:
- /*
- * XXX: We must return a reply with the ICMP6 code
- * `unknown Qtype' in this case. However we regard the case
- * as an FQDN query for backward compatibility.
- * Older versions set a random value to this field,
- * so it rarely varies in the defined qtypes.
- * But the mechanism is not reliable...
- * maybe we should obsolete older versions.
- */
- qtype = NI_QTYPE_FQDN;
- replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_name) +
- hostnamelen;
- break;
- }
-
- /* allocate a mbuf to reply. */
- MGETHDR(n, M_DONTWAIT, m->m_type);
+ if (subjlen != sizeof(sin6.sin6_addr))
+ goto bad;
+
+ /*
+ * Validate Subject address.
+ *
+ * Not sure what exactly "address belongs to the node"
+ * means in the spec, is it just unicast, or what?
+ *
+ * At this moment we consider Subject address as
+ * "belong to the node" if the Subject address equals
+ * to the IPv6 destination address; validation for
+ * IPv6 destination address should have done enough
+ * check for us.
+ *
+ * We do not do proxy at this moment.
+ */
+ /* m_pulldown instead of copy? */
+ m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
+ subjlen, (caddr_t)&sin6.sin6_addr);
+ sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ &sin6.sin6_addr);
+#ifndef SCOPEDROUTING
+ in6_embedscope(&sin6.sin6_addr, &sin6, NULL, NULL);
+#endif
+ bzero(&sin6_d, sizeof(sin6_d));
+ sin6_d.sin6_family = AF_INET6; /* not used, actually */
+ sin6_d.sin6_len = sizeof(sin6_d); /* ditto */
+ sin6_d.sin6_addr = ip6->ip6_dst;
+ sin6_d.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
+ &ip6->ip6_dst);
+#ifndef SCOPEDROUTING
+ in6_embedscope(&sin6_d.sin6_addr, &sin6_d, NULL, NULL);
+#endif
+ subj = (char *)&sin6;
+ if (SA6_ARE_ADDR_EQUAL(&sin6, &sin6_d))
+ break;
+
+ /*
+ * XXX if we are to allow other cases, we should really
+ * be careful about scope here.
+ * basically, we should disallow queries toward IPv6
+ * destination X with subject Y, if scope(X) > scope(Y).
+ * if we allow scope(X) > scope(Y), it will result in
+ * information leakage across scope boundary.
+ */
+ goto bad;
+
+ case ICMP6_NI_SUBJ_FQDN:
+ /*
+ * Validate Subject name with gethostname(3).
+ *
+ * The behavior may need some debate, since:
+ * - we are not sure if the node has FQDN as
+ * hostname (returned by gethostname(3)).
+ * - the code does wildcard match for truncated names.
+ * however, we are not sure if we want to perform
+ * wildcard match, if gethostname(3) side has
+ * truncated hostname.
+ */
+ n = ni6_nametodns(hostname, hostnamelen, 0);
+ if (!n || n->m_next || n->m_len == 0)
+ goto bad;
+ IP6_EXTHDR_GET(subj, char *, m,
+ off + sizeof(struct icmp6_nodeinfo), subjlen);
+ if (subj == NULL)
+ goto bad;
+ if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
+ n->m_len)) {
+ goto bad;
+ }
+ m_freem(n);
+ n = NULL;
+ break;
+
+ case ICMP6_NI_SUBJ_IPV4: /* XXX: to be implemented? */
+ default:
+ goto bad;
+ }
+ break;
+ }
+
+ /* refuse based on configuration. XXX ICMP6_NI_REFUSED? */
+ switch (qtype) {
+ case NI_QTYPE_FQDN:
+ if ((icmp6_nodeinfo & 1) == 0)
+ goto bad;
+ break;
+ case NI_QTYPE_NODEADDR:
+ if ((icmp6_nodeinfo & 2) == 0)
+ goto bad;
+ break;
+ }
+
+ /* guess reply length */
+ switch (qtype) {
+ case NI_QTYPE_NOOP:
+ break; /* no reply data */
+ case NI_QTYPE_SUPTYPES:
+ replylen += sizeof(u_int32_t);
+ break;
+ case NI_QTYPE_FQDN:
+ /* XXX will append an mbuf */
+ replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
+ break;
+ case NI_QTYPE_NODEADDR:
+ addrs = ni6_addrs(ni6, &ifp, subj);
+ if ((replylen += addrs * (sizeof(struct in6_addr) +
+ sizeof(u_int32_t))) > MCLBYTES)
+ replylen = MCLBYTES; /* XXX: will truncate pkt later */
+ break;
+ default:
+ /*
+ * XXX: We must return a reply with the ICMP6 code
+ * `unknown Qtype' in this case. However we regard the case
+ * as an FQDN query for backward compatibility.
+ * Older versions set a random value to this field,
+ * so it rarely varies in the defined qtypes.
+ * But the mechanism is not reliable...
+ * maybe we should obsolete older versions.
+ */
+ qtype = NI_QTYPE_FQDN;
+ /* XXX will append an mbuf */
+ replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
+ oldfqdn++;
+ break;
+ }
+
+ /* allocate an mbuf to reply. */
+ MGETHDR(n, M_DONTWAIT, m->m_type); /* MAC-OK */