#include <sys/types.h>
#include <sys/param.h>
+#include <sys/poll.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/uio.h>
# include <../conf/options.h>
#endif
-void _res_close __P((void));
-
static int s = -1; /* socket used for communications */
static int connected = 0; /* is the socket connected */
-static int vc = 0; /* is the socket a virtual ciruit? */
-
-#ifndef FD_SET
-/* XXX - should be in portability.h */
-#define NFDBITS 32
-#define FD_SETSIZE 32
-#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
-#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
-#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
-#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
-#endif
+static int vc = 0; /* is the socket a virtual circuit? */
/* XXX - this should be done in portability.h */
#if (defined(BSD) && (BSD >= 199103)) || defined(linux)
ntohs(address.sin_port),
strerror(error));
}
- errno = save;
+ __set_errno (save);
}
static void
Perror(file, string, error)
fprintf(file, "res_send: %s: %s\n",
string, strerror(error));
}
- errno = save;
+ __set_errno (save);
}
#endif
/* int
* res_nameinquery(name, type, class, buf, eom)
* look for (name,type,class) in the query section of packet (buf,eom)
+ * requires:
+ * buf + HFIXESDZ <= eom
* returns:
* -1 : format error
* 0 : not found
if (n < 0)
return (-1);
cp += n;
+ if (cp + 2 * INT16SZ > eom)
+ return (-1);
ttype = _getshort(cp); cp += INT16SZ;
tclass = _getshort(cp); cp += INT16SZ;
if (ttype == type &&
register const u_char *cp = buf1 + HFIXEDSZ;
int qdcount = ntohs(((HEADER*)buf1)->qdcount);
+ if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
+ return (-1);
+
if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
return (0);
while (qdcount-- > 0) {
if (n < 0)
return (-1);
cp += n;
+ if (cp + 2 * INT16SZ > eom1)
+ return (-1);
ttype = _getshort(cp); cp += INT16SZ;
tclass = _getshort(cp); cp += INT16SZ;
if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
/* errno should have been set by res_init() in this case. */
return (-1);
}
+ if (anssiz < HFIXEDSZ) {
+ __set_errno (EINVAL);
+ return (-1);
+ }
DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
(stdout, ";; res_send()\n"), buf, buflen);
v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
same_ns:
if (badns & (1 << ns)) {
- _res_close();
+ res_close();
goto next_ns;
}
done = 1;
break;
case res_nextns:
- _res_close();
+ res_close();
goto next_ns;
case res_done:
return (resplen);
truncated = 0;
if ((s < 0) || (!vc)) {
if (s >= 0)
- _res_close();
+ res_close();
s = socket(PF_INET, SOCK_STREAM, 0);
if (s < 0) {
Perror(stderr, "socket(vc)", errno);
return (-1);
}
- errno = 0;
+ __set_errno (0);
if (connect(s, (struct sockaddr *)nsap,
sizeof(struct sockaddr)) < 0) {
terrno = errno;
Aerror(stderr, "connect/vc",
errno, *nsap);
badns |= (1 << ns);
- _res_close();
+ res_close();
goto next_ns;
}
vc = 1;
terrno = errno;
Perror(stderr, "write failed", errno);
badns |= (1 << ns);
- _res_close();
+ res_close();
goto next_ns;
}
/*
if (n <= 0) {
terrno = errno;
Perror(stderr, "read failed", errno);
- _res_close();
+ res_close();
/*
* A long running process might get its TCP
* connection reset if the remote server was
*/
if (terrno == ECONNRESET && !connreset) {
connreset = 1;
- _res_close();
+ res_close();
goto same_ns;
}
- _res_close();
+ res_close();
goto next_ns;
}
resplen = _getshort(ans);
len = anssiz;
} else
len = resplen;
+ if (len < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(_res.options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n", len));
+ terrno = EMSGSIZE;
+ badns |= (1 << ns);
+ res_close();
+ goto next_ns;
+ }
cp = ans;
while (len != 0 &&
(n = read(s, (char *)cp, (int)len)) > 0) {
if (n <= 0) {
terrno = errno;
Perror(stderr, "read(vc)", errno);
- _res_close();
+ res_close();
goto next_ns;
}
if (truncated) {
while (len != 0) {
char junk[PACKETSZ];
- n = (len > sizeof(junk)
+ n = ((size_t) len > sizeof(junk)
? sizeof(junk)
: len);
if ((n = read(s, junk, n)) > 0)
/*
* Use datagrams.
*/
- struct timeval timeout;
- fd_set dsmask;
+ int timeout;
+ struct pollfd pfd[1];
struct sockaddr_in from;
- size_t fromlen;
+ socklen_t fromlen;
if ((s < 0) || vc) {
if (vc)
- _res_close();
+ res_close();
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
#if !CAN_RECONNECT
"connect(dg)",
errno, *nsap);
badns |= (1 << ns);
- _res_close();
+ res_close();
goto next_ns;
}
connected = 1;
if (send(s, (char*)buf, buflen, 0) != buflen) {
Perror(stderr, "send", errno);
badns |= (1 << ns);
- _res_close();
+ res_close();
goto next_ns;
}
} else {
(stdout, ";; new DG socket\n"))
#endif
connected = 0;
- errno = 0;
+ __set_errno (0);
}
if (sendto(s, (char*)buf, buflen, 0,
(struct sockaddr *)nsap,
!= buflen) {
Aerror(stderr, "sendto", errno, *nsap);
badns |= (1 << ns);
- _res_close();
+ res_close();
goto next_ns;
}
}
/*
* Wait for reply
*/
- timeout.tv_sec = (_res.retrans << try);
+ timeout = (_res.retrans << try) * 1000;
if (try > 0)
- timeout.tv_sec /= _res.nscount;
- if ((long) timeout.tv_sec <= 0)
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
+ timeout /= _res.nscount;
+ if (timeout <= 0)
+ timeout = 1000;
wait:
- FD_ZERO(&dsmask);
- FD_SET(s, &dsmask);
- n = select(s+1, &dsmask, (fd_set *)NULL,
- (fd_set *)NULL, &timeout);
+ if (s < 0 || s >= FD_SETSIZE) {
+ Perror(stderr, "s out-of-bounds", EMFILE);
+ res_close();
+ goto next_ns;
+ }
+ pfd[0].fd = s;
+ pfd[0].events = POLLIN;
+ n = __poll(pfd, 1, timeout);
if (n < 0) {
if (errno == EINTR)
goto wait;
- Perror(stderr, "select", errno);
- _res_close();
+ Perror(stderr, "poll", errno);
+ res_close();
goto next_ns;
}
if (n == 0) {
Dprint(_res.options & RES_DEBUG,
(stdout, ";; timeout\n"));
gotsomewhere = 1;
- _res_close();
+ res_close();
goto next_ns;
}
- errno = 0;
+ __set_errno (0);
fromlen = sizeof(struct sockaddr_in);
resplen = recvfrom(s, (char*)ans, anssiz, 0,
(struct sockaddr *)&from, &fromlen);
if (resplen <= 0) {
Perror(stderr, "recvfrom", errno);
- _res_close();
+ res_close();
goto next_ns;
}
gotsomewhere = 1;
+ if (resplen < HFIXEDSZ) {
+ /*
+ * Undersized message.
+ */
+ Dprint(_res.options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n",
+ resplen));
+ terrno = EMSGSIZE;
+ badns |= (1 << ns);
+ res_close();
+ goto next_ns;
+ }
if (hp->id != anhp->id) {
/*
* response from old query, ignore it.
(stdout, "server rejected query:\n"),
ans, (resplen>anssiz)?anssiz:resplen);
badns |= (1 << ns);
- _res_close();
+ res_close();
/* don't retry if called from dig */
if (!_res.pfcode)
goto next_ns;
Dprint(_res.options & RES_DEBUG,
(stdout, ";; truncated answer\n"));
v_circuit = 1;
- _res_close();
+ res_close();
goto same_ns;
}
} /*if vc/dg*/
*/
if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
!(_res.options & RES_STAYOPEN)) {
- _res_close();
+ res_close();
}
if (Rhook) {
int done = 0, loops = 0;
done = 1;
break;
case res_nextns:
- _res_close();
+ res_close();
goto next_ns;
case res_modified:
/* give the hook another try */
next_ns: ;
} /*foreach ns*/
} /*foreach retry*/
- _res_close();
- if (!v_circuit)
+ res_close();
+ if (!v_circuit) {
if (!gotsomewhere)
- errno = ECONNREFUSED; /* no nameservers found */
+ __set_errno (ECONNREFUSED); /* no nameservers found */
else
- errno = ETIMEDOUT; /* no answer obtained */
- else
- errno = terrno;
+ __set_errno (ETIMEDOUT); /* no answer obtained */
+ } else
+ __set_errno (terrno);
return (-1);
}
* This routine is not expected to be user visible.
*/
void
-_res_close()
+res_close()
{
if (s >= 0) {
(void) close(s);
* there is more gunk of this kind over in res_debug.c.
*/
+void
+_res_close()
+{
+ res_close();
+}
+
#undef res_send
int
res_send(buf, buflen, ans, anssiz)