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
Copyright (C) 2006 Gerald Carter
+ Copyright (C) 2008 James Peach

** 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
+#include
#include

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