461 lines
12 KiB
Diff
461 lines
12 KiB
Diff
|
--- resolv/res_hconf.c
|
||
|
+++ resolv/res_hconf.c 2004/09/21 12:56:54
|
||
|
@@ -59,6 +59,7 @@
|
||
|
#define ENV_TRIM_ADD "RESOLV_ADD_TRIM_DOMAINS"
|
||
|
#define ENV_MULTI "RESOLV_MULTI"
|
||
|
#define ENV_REORDER "RESOLV_REORDER"
|
||
|
+#define ENV_MDNS "RESOLV_MDNS"
|
||
|
|
||
|
static const char *arg_service_list (const char *, int, const char *,
|
||
|
unsigned int);
|
||
|
@@ -81,7 +82,8 @@
|
||
|
{"multi", arg_bool, HCONF_FLAG_MULTI},
|
||
|
{"nospoof", arg_bool, HCONF_FLAG_SPOOF},
|
||
|
{"spoofalert", arg_bool, HCONF_FLAG_SPOOFALERT},
|
||
|
- {"reorder", arg_bool, HCONF_FLAG_REORDER}
|
||
|
+ {"reorder", arg_bool, HCONF_FLAG_REORDER},
|
||
|
+ {"mdns", arg_bool, HCONF_FLAG_MDNS}
|
||
|
};
|
||
|
|
||
|
/* Structure containing the state. */
|
||
|
@@ -431,6 +433,9 @@
|
||
|
|
||
|
memset (&_res_hconf, '\0', sizeof (_res_hconf));
|
||
|
|
||
|
+ /* Default for mdns is "on". */
|
||
|
+ _res_hconf.flags |= HCONF_FLAG_MDNS;
|
||
|
+
|
||
|
hconf_name = getenv (ENV_HOSTCONF);
|
||
|
if (hconf_name == NULL)
|
||
|
hconf_name = _PATH_HOSTCONF;
|
||
|
@@ -483,6 +488,10 @@
|
||
|
arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval, 0);
|
||
|
}
|
||
|
|
||
|
+ envval = getenv (ENV_MDNS);
|
||
|
+ if (envval)
|
||
|
+ arg_bool (ENV_MDNS, 1, envval, HCONF_FLAG_MDNS);
|
||
|
+
|
||
|
_res_hconf.initialized = 1;
|
||
|
}
|
||
|
|
||
|
--- resolv/res_hconf.h
|
||
|
+++ resolv/res_hconf.h 2004/09/21 12:56:54
|
||
|
@@ -44,6 +44,7 @@
|
||
|
# define HCONF_FLAG_SPOOFALERT (1 << 2) /* syslog warning of spoofed */
|
||
|
# define HCONF_FLAG_REORDER (1 << 3) /* list best address first */
|
||
|
# define HCONF_FLAG_MULTI (1 << 4) /* see comments for gethtbyname() */
|
||
|
+# define HCONF_FLAG_MDNS (1 << 5) /* Disable MDNS support */
|
||
|
};
|
||
|
extern struct hconf _res_hconf;
|
||
|
|
||
|
--- resolv/res_query.c
|
||
|
+++ resolv/res_query.c 2004/09/21 12:57:59
|
||
|
@@ -82,6 +82,8 @@
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
+#include "res_hconf.h"
|
||
|
+
|
||
|
/* Options. Leave them on. */
|
||
|
/* #undef DEBUG */
|
||
|
|
||
|
@@ -278,6 +280,13 @@
|
||
|
*domain && !done;
|
||
|
domain++) {
|
||
|
|
||
|
+ if ((_res_hconf.flags & HCONF_FLAG_MDNS) != 0) {
|
||
|
+ /* don't add "local" domain if query contains a dot */
|
||
|
+ if (dots && (!__strcasecmp(*domain, "local") ||
|
||
|
+ !__strcasecmp(*domain, "local.")))
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
if (domain[0][0] == '\0' ||
|
||
|
(domain[0][0] == '.' && domain[0][1] == '\0'))
|
||
|
root_on_list++;
|
||
|
--- resolv/res_send.c
|
||
|
+++ resolv/res_send.c 2004/09/21 12:58:14
|
||
|
@@ -86,6 +86,9 @@
|
||
|
#include <arpa/nameser.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
+#if defined(_LIBC) && defined(linux)
|
||
|
+#include <net/if.h>
|
||
|
+#endif
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <netdb.h>
|
||
|
@@ -96,6 +99,8 @@
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
+#include "res_hconf.h"
|
||
|
+
|
||
|
#if PACKETSZ > 65536
|
||
|
#define MAXPACKET PACKETSZ
|
||
|
#else
|
||
|
@@ -188,6 +193,9 @@
|
||
|
static int send_dg(res_state, const u_char *, int,
|
||
|
u_char **, int *, int *, int,
|
||
|
int *, int *, u_char **);
|
||
|
+static int send_dg_mdns(res_state, const u_char *, int,
|
||
|
+ u_char **, int *, int *, struct sockaddr_in6 *,
|
||
|
+ int *, int *, u_char **);
|
||
|
#ifdef DEBUG
|
||
|
static void Aerror(const res_state, FILE *, const char *, int,
|
||
|
const struct sockaddr *);
|
||
|
@@ -366,6 +374,35 @@
|
||
|
u_char *ans, int anssiz, u_char **ansp)
|
||
|
{
|
||
|
int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
|
||
|
+ int usemdns;
|
||
|
+ HEADER *qhp = (HEADER *) buf;
|
||
|
+
|
||
|
+ usemdns = 0;
|
||
|
+ if ((_res_hconf.flags & HCONF_FLAG_MDNS) != 0 &&
|
||
|
+ qhp->qr == 0 && qhp->opcode == QUERY && qhp->qdcount == htons(1)) {
|
||
|
+ /* got one simple query */
|
||
|
+ const u_char *bp, *be;
|
||
|
+ be = buf + buflen;
|
||
|
+ for (bp = buf + NS_HFIXEDSZ; bp < be; )
|
||
|
+ if ((*bp & NS_CMPRSFLGS) != 0)
|
||
|
+ break;
|
||
|
+ else if (*bp) {
|
||
|
+ if (*bp == 5 && !strncasecmp(bp, "\005local\000", 7)) {
|
||
|
+ usemdns = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (*bp == 3 && !strncasecmp(bp, "\003254\003169\007in-addr\004arpa\000", 22)) {
|
||
|
+ usemdns = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (*bp == 1 && !strncasecmp(bp, "\0010\0018\001e\001f\003ip6\004arpa\000", 18)) {
|
||
|
+ usemdns = 2;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ bp += *bp + 1;
|
||
|
+ } else
|
||
|
+ break;
|
||
|
+ }
|
||
|
|
||
|
if (statp->nscount == 0) {
|
||
|
__set_errno (ESRCH);
|
||
|
@@ -524,13 +561,28 @@
|
||
|
*/
|
||
|
for (try = 0; try < statp->retry; try++) {
|
||
|
#ifdef _LIBC
|
||
|
- for (ns = 0; ns < MAXNS; ns++)
|
||
|
+ for (ns = 0; ns < (usemdns ? 1 : MAXNS); ns++)
|
||
|
#else
|
||
|
for (ns = 0; ns < statp->nscount; ns++)
|
||
|
#endif
|
||
|
{
|
||
|
#ifdef _LIBC
|
||
|
struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
|
||
|
+ if (usemdns == 1) {
|
||
|
+ static struct sockaddr_in mdns4;
|
||
|
+ mdns4.sin_family = AF_INET;
|
||
|
+ mdns4.sin_port = htons(5353);
|
||
|
+ mdns4.sin_addr.s_addr = htonl(0xe00000fb);
|
||
|
+ nsap = (struct sockaddr_in6 *)&mdns4;
|
||
|
+ }
|
||
|
+ if (usemdns == 2) {
|
||
|
+ static struct sockaddr_in6 mdns6;
|
||
|
+ mdns6.sin6_family = AF_INET6;
|
||
|
+ mdns6.sin6_port = htons(5353);
|
||
|
+ mdns6.sin6_addr.s6_addr32[0] = htonl(0xff020000);
|
||
|
+ mdns6.sin6_addr.s6_addr32[3] = htonl(0x000000fb);
|
||
|
+ nsap = &mdns6;
|
||
|
+ }
|
||
|
|
||
|
if (nsap == NULL)
|
||
|
goto next_ns;
|
||
|
@@ -602,8 +654,11 @@
|
||
|
resplen = n;
|
||
|
} else {
|
||
|
/* Use datagrams. */
|
||
|
- n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno,
|
||
|
- ns, &v_circuit, &gotsomewhere, ansp);
|
||
|
+ if (usemdns)
|
||
|
+ n = send_dg_mdns(statp, buf, buflen, &ans, &anssiz, &terrno, nsap, &v_circuit, &gotsomewhere, ansp);
|
||
|
+ else
|
||
|
+ n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno,
|
||
|
+ ns, &v_circuit, &gotsomewhere, ansp);
|
||
|
if (n < 0)
|
||
|
return (-1);
|
||
|
if (n == 0)
|
||
|
@@ -675,8 +730,15 @@
|
||
|
if (!v_circuit) {
|
||
|
if (!gotsomewhere)
|
||
|
__set_errno (ECONNREFUSED); /* no nameservers found */
|
||
|
- else
|
||
|
+ else if (!usemdns) {
|
||
|
__set_errno (ETIMEDOUT); /* no answer obtained */
|
||
|
+ } else {
|
||
|
+ /* treat timeout as host not found */
|
||
|
+ HEADER *anhp = (HEADER *) ans;
|
||
|
+ memset(ans, 0, HFIXEDSZ);
|
||
|
+ anhp->rcode = NXDOMAIN;
|
||
|
+ return HFIXEDSZ;
|
||
|
+ }
|
||
|
} else
|
||
|
__set_errno (terrno);
|
||
|
return (-1);
|
||
|
@@ -1140,6 +1202,255 @@
|
||
|
return (resplen);
|
||
|
}
|
||
|
|
||
|
+static int
|
||
|
+send_dg_mdns(res_state statp,
|
||
|
+ const u_char *buf, int buflen, u_char **ansp, int *anssizp,
|
||
|
+ int *terrno, struct sockaddr_in6 *nsap, int *v_circuit, int *gotsomewhere, u_char **anscp)
|
||
|
+{
|
||
|
+ const HEADER *hp = (HEADER *) buf;
|
||
|
+ u_char *ans = *ansp;
|
||
|
+ int anssiz = *anssizp;
|
||
|
+ HEADER *anhp = (HEADER *) ans;
|
||
|
+ struct timespec now, timeout, finish;
|
||
|
+ struct pollfd pfd[32];
|
||
|
+ int ptimeout;
|
||
|
+ int fromlen, resplen, seconds, n, s;
|
||
|
+ int on = 1;
|
||
|
+ struct msghdr mhdr;
|
||
|
+ struct iovec iov;
|
||
|
+ u_char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||
|
+ struct cmsghdr *cmsg;
|
||
|
+ int ttl;
|
||
|
+ struct ifconf ifconf;
|
||
|
+ struct ifreq ifreq[64];
|
||
|
+ int ifreqn;
|
||
|
+ int i, j;
|
||
|
+ int ifidx[32], ifidxn;
|
||
|
+ struct ip_mreqn mreqn;
|
||
|
+
|
||
|
+ s = socket(nsap->sin6_family == AF_INET ? PF_INET : PF_INET6, SOCK_DGRAM, 0);
|
||
|
+ if (s < 0) {
|
||
|
+ *terrno = errno;
|
||
|
+ Perror(statp, stderr, "socket(dg)", errno);
|
||
|
+ return (-1);
|
||
|
+ }
|
||
|
+ ifconf.ifc_len = sizeof(ifreq);
|
||
|
+ ifconf.ifc_req = ifreq;
|
||
|
+ ifidxn = 0;
|
||
|
+ if (ioctl(s, SIOCGIFCONF, &ifconf) == 0) {
|
||
|
+ ifreqn = ifconf.ifc_len / sizeof(*ifreq);
|
||
|
+ for (i = 0 ; i < ifreqn; i++) {
|
||
|
+ if (ioctl(s, SIOCGIFFLAGS, ifreq + i))
|
||
|
+ continue;
|
||
|
+ if (!(ifreq[i].ifr_flags & IFF_MULTICAST))
|
||
|
+ continue;
|
||
|
+ if (ioctl(s, SIOCGIFINDEX, ifreq + i))
|
||
|
+ continue;
|
||
|
+ for (j = 0; j < ifidxn; j++)
|
||
|
+ if (ifidx[j] == ifreq[i].ifr_ifindex)
|
||
|
+ break;
|
||
|
+ if (j < ifidxn)
|
||
|
+ continue;
|
||
|
+ ifidx[ifidxn++] = ifreq[i].ifr_ifindex;
|
||
|
+ if (ifidxn == sizeof(ifidx)/sizeof(*ifidx))
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ j = 0;
|
||
|
+ for (i = 0; i < (ifidxn ? ifidxn : 1); i++) {
|
||
|
+ if (i) {
|
||
|
+ s = socket(nsap->sin6_family == AF_INET ? PF_INET : PF_INET6, SOCK_DGRAM, 0);
|
||
|
+ if (!s)
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if (setsockopt(s, SOL_IP, IP_RECVTTL, &on, sizeof(on))) {
|
||
|
+ *terrno = errno;
|
||
|
+ Perror(statp, stderr, "IP_RECVTTL(dg)", errno);
|
||
|
+ close(s);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if (ifidxn) {
|
||
|
+ memset(&mreqn, 0, sizeof(mreqn));
|
||
|
+ mreqn.imr_ifindex = ifidx[i];
|
||
|
+ if (setsockopt(s, SOL_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn))) {
|
||
|
+ *terrno = errno;
|
||
|
+ Perror(statp, stderr, "IP_MULTICAST_IF", errno);
|
||
|
+ close(s);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (sendto(s, (char*)buf, buflen, 0,
|
||
|
+ (struct sockaddr *)nsap, sizeof *nsap) != buflen) {
|
||
|
+ Aerror(statp, stderr, "sendto", errno, *(struct sockaddr_in *)nsap);
|
||
|
+ close(s);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ pfd[j].fd = s;
|
||
|
+ pfd[j].events = POLLIN;
|
||
|
+ j++;
|
||
|
+ }
|
||
|
+ /*
|
||
|
+ * Wait for reply.
|
||
|
+ */
|
||
|
+ seconds = statp->retrans;
|
||
|
+ if (seconds <= 0)
|
||
|
+ seconds = 1;
|
||
|
+ evNowTime(&now);
|
||
|
+ evConsTime(&timeout, seconds, 0);
|
||
|
+ evAddTime(&finish, &now, &timeout);
|
||
|
+ wait:
|
||
|
+ if (j == 0) {
|
||
|
+ return (0);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Convert struct timespec in milliseconds. */
|
||
|
+ ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
|
||
|
+ n = __poll (pfd, j, ptimeout);
|
||
|
+ if (n == 0) {
|
||
|
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
|
||
|
+ *gotsomewhere = 1;
|
||
|
+ for (i = 0; i < j; i++)
|
||
|
+ close(pfd[i].fd);
|
||
|
+ return (0);
|
||
|
+ }
|
||
|
+ if (n < 0) {
|
||
|
+ if (errno == EINTR) {
|
||
|
+ evNowTime(&now);
|
||
|
+ if (evCmpTime(finish, now) > 0) {
|
||
|
+ evSubTime(&timeout, &finish, &now);
|
||
|
+ goto wait;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ Perror(statp, stderr, "select", errno);
|
||
|
+ for (i = 0; i < j; i++)
|
||
|
+ close(pfd[i].fd);
|
||
|
+ res_nclose(statp);
|
||
|
+ return (0);
|
||
|
+ }
|
||
|
+ for (i = 0; i < j - 1; i++)
|
||
|
+ if (pfd[j].revents == POLLIN)
|
||
|
+ break;
|
||
|
+ s = pfd[i].fd;
|
||
|
+ __set_errno (0);
|
||
|
+ fromlen = sizeof(struct sockaddr_in6);
|
||
|
+ if (anssiz < MAXPACKET
|
||
|
+ && anscp
|
||
|
+ && (ioctl (s, FIONREAD, &resplen) < 0
|
||
|
+ || anssiz < resplen)) {
|
||
|
+ ans = malloc (MAXPACKET);
|
||
|
+ if (ans == NULL)
|
||
|
+ ans = *ansp;
|
||
|
+ else {
|
||
|
+ anssiz = MAXPACKET;
|
||
|
+ *anssizp = MAXPACKET;
|
||
|
+ *ansp = ans;
|
||
|
+ *anscp = ans;
|
||
|
+ anhp = (HEADER *) ans;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ iov.iov_base = ans;
|
||
|
+ iov.iov_len = anssiz;
|
||
|
+ mhdr.msg_name = 0;
|
||
|
+ mhdr.msg_namelen = 0;
|
||
|
+ mhdr.msg_iov = &iov;
|
||
|
+ mhdr.msg_iovlen = 1;
|
||
|
+ mhdr.msg_control = cmsgbuf;
|
||
|
+ mhdr.msg_controllen = sizeof(cmsgbuf);
|
||
|
+ mhdr.msg_flags = 0;
|
||
|
+ resplen = recvmsg(s, &mhdr, 0);
|
||
|
+ if (resplen <= 0) {
|
||
|
+ if (errno == EAGAIN)
|
||
|
+ goto wait;
|
||
|
+ Perror(statp, stderr, "recvfrom", errno);
|
||
|
+wait2:
|
||
|
+ close(s);
|
||
|
+ if (i < j)
|
||
|
+ memmove(pfd + i, pfd + i + 1, sizeof(*pfd) * (j - i));
|
||
|
+ j--;
|
||
|
+ goto wait;
|
||
|
+ }
|
||
|
+ cmsg = CMSG_FIRSTHDR(&mhdr);
|
||
|
+ for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; CMSG_NXTHDR(&mhdr, cmsg))
|
||
|
+ if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL)
|
||
|
+ break;
|
||
|
+ if (!cmsg) {
|
||
|
+ Dprint(statp->options & RES_DEBUG,
|
||
|
+ (stdout, ";; no TTL found\n"));
|
||
|
+ goto wait2;
|
||
|
+ }
|
||
|
+ ttl = *(int *)CMSG_DATA(cmsg);
|
||
|
+ if (ttl != 255) {
|
||
|
+ Dprint(statp->options & RES_DEBUG,
|
||
|
+ (stdout, ";; answer with bad TTL: %d \n", ttl));
|
||
|
+ goto wait;
|
||
|
+ }
|
||
|
+ *gotsomewhere = 1;
|
||
|
+ if (resplen < HFIXEDSZ) {
|
||
|
+ /*
|
||
|
+ * Undersized message.
|
||
|
+ */
|
||
|
+ Dprint(statp->options & RES_DEBUG,
|
||
|
+ (stdout, ";; undersized: %d\n",
|
||
|
+ resplen));
|
||
|
+ *terrno = EMSGSIZE;
|
||
|
+ goto wait;
|
||
|
+ }
|
||
|
+ if (hp->id != anhp->id) {
|
||
|
+ /*
|
||
|
+ * response from old query, ignore it.
|
||
|
+ * XXX - potential security hazard could
|
||
|
+ * be detected here.
|
||
|
+ */
|
||
|
+ DprintQ((statp->options & RES_DEBUG) ||
|
||
|
+ (statp->pfcode & RES_PRF_REPLY),
|
||
|
+ (stdout, ";; old answer:\n"),
|
||
|
+ ans, (resplen > anssiz) ? anssiz : resplen);
|
||
|
+ goto wait;
|
||
|
+ }
|
||
|
+ if (!(statp->options & RES_INSECURE2) &&
|
||
|
+ !res_queriesmatch(buf, buf + buflen,
|
||
|
+ ans, ans + anssiz)) {
|
||
|
+ /*
|
||
|
+ * response contains wrong query? ignore it.
|
||
|
+ * XXX - potential security hazard could
|
||
|
+ * be detected here.
|
||
|
+ */
|
||
|
+ DprintQ((statp->options & RES_DEBUG) ||
|
||
|
+ (statp->pfcode & RES_PRF_REPLY),
|
||
|
+ (stdout, ";; wrong query name:\n"),
|
||
|
+ ans, (resplen > anssiz) ? anssiz : resplen);
|
||
|
+ goto wait;
|
||
|
+ }
|
||
|
+ if (anhp->rcode == SERVFAIL ||
|
||
|
+ anhp->rcode == NOTIMP ||
|
||
|
+ anhp->rcode == REFUSED) {
|
||
|
+ DprintQ(statp->options & RES_DEBUG,
|
||
|
+ (stdout, "server rejected query:\n"),
|
||
|
+ ans, (resplen > anssiz) ? anssiz : resplen);
|
||
|
+ goto wait;
|
||
|
+ }
|
||
|
+ for (i = 0; i < j; i++)
|
||
|
+ close(pfd[i].fd);
|
||
|
+#if 0
|
||
|
+ if (!(statp->options & RES_IGNTC) && anhp->tc) {
|
||
|
+ /*
|
||
|
+ * To get the rest of answer,
|
||
|
+ * use TCP with same server.
|
||
|
+ */
|
||
|
+ Dprint(statp->options & RES_DEBUG,
|
||
|
+ (stdout, ";; truncated answer\n"));
|
||
|
+ *v_circuit = 1;
|
||
|
+ res_nclose(statp);
|
||
|
+ return (1);
|
||
|
+ }
|
||
|
+#endif
|
||
|
+ /*
|
||
|
+ * All is well, or the error is fatal. Signal that the
|
||
|
+ * next nameserver ought not be tried.
|
||
|
+ */
|
||
|
+ return (resplen);
|
||
|
+}
|
||
|
+
|
||
|
#ifdef DEBUG
|
||
|
static void
|
||
|
Aerror(const res_state statp, FILE *file, const char *string, int error,
|