diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2010-12-03 23:29:09 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2010-12-03 23:29:09 +0000 |
commit | e638ad5991a7a0874e3ce707cf60c2d16e939502 (patch) | |
tree | 885157087b8d499e06d9854ef536598e66f24f79 | |
parent | ff8e3087f4a246f4d358528491ec6449b59fdca4 (diff) |
be more strict on socket lifetime (fixes a fd leak).
ok gilles@
-rw-r--r-- | usr.sbin/smtpd/asr.c | 85 |
1 files changed, 48 insertions, 37 deletions
diff --git a/usr.sbin/smtpd/asr.c b/usr.sbin/smtpd/asr.c index 0a878a7ec5b..15011d09816 100644 --- a/usr.sbin/smtpd/asr.c +++ b/usr.sbin/smtpd/asr.c @@ -1174,6 +1174,7 @@ int asr_udp_send(struct asr_query *aq) { ssize_t n; + int errno_save; aq->aq_fd = sockaddr_connect(AQ_NS_SA(aq), SOCK_DGRAM); if (aq->aq_fd == -1) @@ -1183,7 +1184,10 @@ asr_udp_send(struct asr_query *aq) n = send(aq->aq_fd, aq->aq_buf, aq->aq_buflen, 0); if (n == -1) { - if (errno == EAGAIN) + errno_save = errno; + close(aq->aq_fd); + aq->aq_fd = -1; + if (errno_save == EAGAIN) return (-2); /* timeout */ return (-1); } @@ -1195,10 +1199,14 @@ int asr_udp_recv(struct asr_query *aq) { ssize_t n; + int errno_save; n = recv(aq->aq_fd, aq->aq_buf, aq->aq_bufsize, 0); + errno_save = errno; + close(aq->aq_fd); + aq->aq_fd = -1; if (n == -1) { - if (errno == EAGAIN) + if (errno_save == EAGAIN) return (-2); /* timeout */ return (-1); } @@ -1223,9 +1231,8 @@ asr_tcp_write(struct asr_query *aq) struct iovec iov[2]; uint16_t len; ssize_t n; - int i; + int i, ret, se; socklen_t sl; - int se; if (aq->aq_fd == -1) { /* connect */ aq->aq_fd = sockaddr_connect(AQ_NS_SA(aq), SOCK_STREAM); @@ -1235,16 +1242,17 @@ asr_tcp_write(struct asr_query *aq) return (1); } + ret = -1; i = 0; if (aq->aq_datalen == 0) { /* check connection first */ sl = sizeof(se); if (getsockopt(aq->aq_fd, SOL_SOCKET, SO_ERROR, &se, &sl) == -1) { warn("getsockopt"); - return (-1); + goto close; } if (se) - return -1; + goto close; /* need to send datalen first */ len = htons(aq->aq_buflen); @@ -1260,15 +1268,16 @@ asr_tcp_write(struct asr_query *aq) n = writev(aq->aq_fd, iov, i); if (n == -1) { if (errno == EAGAIN) - return (-2); /* timeout */ - warn("writev"); - return (-1); + ret = -2; + else + warn("writev"); + goto close; } if (aq->aq_datalen == 0 && n < 2) { /* we want to write the data len */ warnx("short write"); - return (-1); + goto close; } if (aq->aq_datalen == 0) { @@ -1284,6 +1293,11 @@ asr_tcp_write(struct asr_query *aq) aq->aq_timeout = AQ_DB(aq)->ad_timeout; return (1); + +close: + close(aq->aq_fd); + aq->aq_fd = -1; + return (ret); } int @@ -1291,24 +1305,31 @@ asr_tcp_read(struct asr_query *aq) { uint16_t len; ssize_t n; + int ret; + + ret = -1; if (aq->aq_datalen == 0) { n = read(aq->aq_fd, &len, sizeof(len)); if (n == -1) { if (errno == EAGAIN) /* timeout */ - return (-2); - return (-1); + ret = -2; + else + warn("read"); + goto close; } if (n < 2) { warnx("short read"); - return (-1); + goto close; } aq->aq_datalen = ntohs(len); aq->aq_bufoffset = 0; aq->aq_buflen = 0; - if (asr_ensure_buf(aq, aq->aq_datalen) == -1) - return (-3); /* ENOMEM */ + if (asr_ensure_buf(aq, aq->aq_datalen) == -1) { + ret = -3; + goto close; + } return (1); /* need more data */ } @@ -1316,13 +1337,14 @@ asr_tcp_read(struct asr_query *aq) n = read(aq->aq_fd, AQ_BUF_WPOS(aq), AQ_BUF_LEFT(aq)); if (n == -1) { if (errno == EAGAIN) /* timeout */ - return (-2); - warn("read"); - return (-1); + ret = -2; + else + warn("read"); + goto close; } if (n == 0) { warnx("closed"); - return (-1); + goto close; } aq->aq_buflen += n; @@ -1330,9 +1352,14 @@ asr_tcp_read(struct asr_query *aq) return (1); /* need more data */ if (asr_validate_packet(aq) != 0) - return (-1); + goto close; - return (0); + ret = 0; + +close: + close(aq->aq_fd); + aq->aq_fd = -1; + return (ret); } int @@ -1378,12 +1405,6 @@ asr_run_dns(struct asr_query *aq, struct asr_result *ar) break; case ASR_STATE_NEXT_NS: - /* close the current fd if any */ - if (aq->aq_fd != -1) { - close(aq->aq_fd); - aq->aq_fd = -1; - } - aq->aq_ns_idx += 1; if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) { aq->aq_ns_idx = 0; @@ -1439,8 +1460,6 @@ asr_run_dns(struct asr_query *aq, struct asr_result *ar) aq->aq_state = ASR_STATE_PACKET; break; case 1: /* truncated */ - close(aq->aq_fd); - aq->aq_fd = -1; aq->aq_state = ASR_STATE_TCP_WRITE; break; } @@ -1662,12 +1681,6 @@ asr_run_host(struct asr_query *aq, struct asr_result *ar) break; case ASR_STATE_NEXT_NS: - /* close the current fd if any */ - if (aq->aq_fd != -1) { - close(aq->aq_fd); - aq->aq_fd = -1; - } - aq->aq_ns_idx += 1; if (aq->aq_ns_idx >= AQ_DB(aq)->ad_count) { aq->aq_ns_idx = 0; @@ -1723,8 +1736,6 @@ asr_run_host(struct asr_query *aq, struct asr_result *ar) aq->aq_state = ASR_STATE_PACKET; break; case 1: /* truncated */ - close(aq->aq_fd); - aq->aq_fd = -1; aq->aq_state = ASR_STATE_TCP_WRITE; break; } |