[PATCH 3/4] dns: Use writev(2) to send DNS requests in a single TCP segment.

James Peach jpeach at apple.com
Fri May 30 17:44:43 GMT 2008


The Wireshark DNS dissector does not reassemble DNS requests
particularly well.  If we send a request in a single TCP segment,
it's much easier to display in Wireshark.
---
  source/libaddns/dnssock.c |   50 ++++++++++++++++++++++++++++++++++++ 
+-------
  1 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/source/libaddns/dnssock.c b/source/libaddns/dnssock.c
index 7c8bd41..68e7645 100644
--- a/source/libaddns/dnssock.c
+++ b/source/libaddns/dnssock.c
@@ -3,6 +3,7 @@

    Copyright (C) 2006 Krishna Ganugapati <krishnag at centeris.com>
    Copyright (C) 2006 Gerald Carter <jerry at samba.org>
+  Copyright (C) 2008 James Peach <jpeach at samba.org>

       ** NOTE! The following LGPL license applies to the libaddns
       ** library. This does NOT imply that all of Samba is released
@@ -24,6 +25,7 @@

  #include "dns.h"
  #include <sys/time.h>
+#include <sys/uio.h>
  #include <unistd.h>

  static int destroy_dns_connection(struct dns_connection *conn)
@@ -171,13 +173,35 @@ static DNS_ERROR write_all(int fd, uint8 *data,  
size_t len)
  static DNS_ERROR dns_send_tcp(struct dns_connection *conn,
  			      const struct dns_buffer *buf)
  {
+	ssize_t ret;
+	struct iovec iov[2];
  	uint16 len = htons(buf->offset);
-	DNS_ERROR err;

-	err = write_all(conn->s, (uint8 *)&len, sizeof(len));
-	if (!ERR_DNS_IS_OK(err)) return err;
+	/* The Wireshark DNS dissector can't reassemble DNS requests when they
+	 * are split over multiple TCP segments. Sending the length prefix and
+	 * the actual request in the same system call prevents this.
+	 */
+	iov[0].iov_base = &len;
+	iov[0].iov_len = sizeof(len);
+	iov[1].iov_base = buf->data;
+	iov[1].iov_len = buf->offset;
+
+	ret = writev(conn->s, iov, 2);
+	if (ret <= 2) {
+		/* Either the write failed or we didn't get to write the
+		 * length prefix. Either way, it's bad.
+		 */
+		return ERROR_DNS_SOCKET_ERROR;
+	}
+
+	/* Partial write. */
+	if (ret <= (buf->offset + sizeof(len))) {
+		size_t buffer_bytes_written = ret - 2;
+		return write_all(conn->s, buf->data + buffer_bytes_written,
+			buf->offset - buffer_bytes_written);
+	}

-	return write_all(conn->s, buf->data, buf->offset);
+	return ERROR_DNS_SUCCESS;
  }

  static DNS_ERROR dns_send_udp(struct dns_connection *conn,
@@ -233,11 +257,15 @@ static DNS_ERROR read_all(int fd, uint8 *data,  
size_t len)
  		}

  		ret = read(fd, data + total, len - total);
-		if (ret <= 0) {
+		if (ret < 0) {
  			/* EOF or error */
  			return ERROR_DNS_SOCKET_ERROR;
  		}

+		if (ret == 0 && total != len) {
+			return ERROR_DNS_SOCKET_ERROR;
+		}
+
  		total += ret;
  	}

@@ -346,11 +374,15 @@ DNS_ERROR dns_transaction(TALLOC_CTX *mem_ctx,  
struct dns_connection *conn,
  	if (!ERR_DNS_IS_OK(err)) goto error;

  	err = dns_send(conn, buf);
-	if (!ERR_DNS_IS_OK(err)) goto error;
+	if (!ERR_DNS_IS_OK(err)) {
+	    goto error;
+	}
  	TALLOC_FREE(buf);

  	err = dns_receive(mem_ctx, conn, &buf);
-	if (!ERR_DNS_IS_OK(err)) goto error;
+	if (!ERR_DNS_IS_OK(err)) {
+	    goto error;
+	}

  	err = dns_unmarshall_request(mem_ctx, buf, resp);

@@ -370,7 +402,9 @@ DNS_ERROR dns_update_transaction(TALLOC_CTX  
*mem_ctx,
  	err = dns_transaction(mem_ctx, conn, dns_update2request(up_req),
  			      &resp);

-	if (!ERR_DNS_IS_OK(err)) return err;
+	if (!ERR_DNS_IS_OK(err)) {
+	    return err;
+	}

  	*up_resp = dns_request2update(resp);
  	return ERROR_DNS_SUCCESS;
-- 
1.5.5.1




More information about the samba-technical mailing list