chiark / gitweb /
SECURITY: adns: Do not corrupt pointer when nameserver speaks first
[adns.git] / src / event.c
index 3621bc8b2ece48d2b03dd16dad955dbe2a217cce..b36288ddfab610e305a4205d659f963bdaabb4d4 100644 (file)
@@ -6,7 +6,8 @@
  */
 /*
  *  This file is part of adns, which is
- *    Copyright (C) 1997-2000,2003,2006,2014  Ian Jackson
+ *    Copyright (C) 1997-2000,2003,2006,2014-2016  Ian Jackson
+ *    Copyright (C) 2014  Mark Wooding
  *    Copyright (C) 1999-2000,2003,2006  Tony Finch
  *    Copyright (C) 1991 Massachusetts Institute of Technology
  *  (See the file INSTALL for full details.)
@@ -338,7 +339,8 @@ int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {
 }
 
 int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
-  int want, dgramlen, r, i, udpaddrlen, serv, old_skip;
+  int want, dgramlen, r, i, serv, old_skip;
+  socklen_t udpaddrlen;
   byte udpbuf[DNS_MAXUDP];
   char addrbuf[ADNS_ADDR2TEXT_BUFLEN];
   struct udpsocket *udp;
@@ -442,8 +444,24 @@ int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) {
     assert(ads->tcprecv.used==0);
     assert(ads->tcprecv_skip==0);
     for (;;) {
+      /* This function can be called even if the fd wasn't actually
+       * flagged as writeable.  For asynch tcp connect we have to
+       * actually use the writeability to tell us the connect has
+       * completed (or failed), so we need to double check. */
+      fd_set writeable;
+      struct timeval timeout = { 0,0 };
+      FD_ZERO(&writeable);
+      FD_SET(ads->tcpsocket,&writeable);
+      r= select(ads->tcpsocket+1,0,&writeable,0,&timeout);
+      if (r==0) break;
+      if (r<0) {
+       if (errno==EINTR) continue;
+       adns__tcp_broken(ads,"select","failed connecting writeability check");
+       r= 0; goto xit;
+      }
+      assert(FD_ISSET(ads->tcpsocket,&writeable));
       if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
-      r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
+      r= read(ads->tcpsocket,ads->tcprecv.buf,1);
       if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
        tcp_connected(ads,*now);
        r= 0; goto xit;