summaryrefslogtreecommitdiff
path: root/src/dnsproxy.c
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2012-06-20 13:38:35 +0300
committerPatrik Flykt <patrik.flykt@linux.intel.com>2012-06-20 14:11:00 +0300
commit28c0f56aaf3f74c78f16b9443de4333ffdc398d6 (patch)
tree325bf3e675d7c6fa4e13f822f3b32a2bb3eaacaa /src/dnsproxy.c
parent14ca0eb028af61717f5a5fbfef2d97d60f8699e6 (diff)
downloadconnman-28c0f56aaf3f74c78f16b9443de4333ffdc398d6.tar.gz
connman-28c0f56aaf3f74c78f16b9443de4333ffdc398d6.tar.bz2
connman-28c0f56aaf3f74c78f16b9443de4333ffdc398d6.zip
dnsproxy: Save DNS packet in cache always in TCP format
The cached DNS packet will always contain two prefix bytes. For UDP we do not send these two extra bytes. This way we do not need to know if the cached message is from UDP or TCP query.
Diffstat (limited to 'src/dnsproxy.c')
-rw-r--r--src/dnsproxy.c70
1 files changed, 57 insertions, 13 deletions
diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index ee7cbf37..03d334ff 100644
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -376,15 +376,32 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
int protocol, int id, uint16_t answers, int ttl)
{
struct domain_hdr *hdr;
- int err, offset = protocol_offset(protocol);
+ unsigned char *ptr = buf;
+ int err, offset, dns_len, adj_len = len - 2;
- if (offset < 0)
+ /*
+ * The cached packet contains always the TCP offset (two bytes)
+ * so skip them for UDP.
+ */
+ switch (protocol) {
+ case IPPROTO_UDP:
+ ptr += 2;
+ len -= 2;
+ dns_len = len;
+ offset = 0;
+ break;
+ case IPPROTO_TCP:
+ offset = 2;
+ dns_len = ptr[0] * 256 + ptr[1];
+ break;
+ default:
return;
+ }
if (len < 12)
return;
- hdr = (void *) (buf + offset);
+ hdr = (void *) (ptr + offset);
hdr->id = id;
hdr->qr = 1;
@@ -397,16 +414,22 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
if (answers == 0)
hdr->aa = 1;
else
- update_cached_ttl(buf, len, ttl);
+ update_cached_ttl((unsigned char *)hdr, adj_len, ttl);
- DBG("id 0x%04x answers %d", hdr->id, answers);
+ DBG("sk %d id 0x%04x answers %d ptr %p length %d dns %d",
+ sk, hdr->id, answers, ptr, len, dns_len);
- err = sendto(sk, buf, len, MSG_NOSIGNAL, to, tolen);
+ err = sendto(sk, ptr, len, MSG_NOSIGNAL, to, tolen);
if (err < 0) {
connman_error("Cannot send cached DNS response: %s",
strerror(errno));
return;
}
+
+ if (err != len || (dns_len != (len - 2) && protocol == IPPROTO_TCP) ||
+ (dns_len != len && protocol == IPPROTO_UDP))
+ DBG("Packet length mismatch, sent %d wanted %d dns %d",
+ err, len, dns_len);
}
static void send_response(int sk, unsigned char *buf, int len,
@@ -1354,7 +1377,12 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
data->type = type;
data->answers = answers;
data->timeout = ttl;
- data->data_len = 12 + qlen + 1 + 2 + 2 + rsplen;
+ /*
+ * The "2" in start of the length is the TCP offset. We allocate it
+ * here even for UDP packet because it simplifies the sending
+ * of cached packet.
+ */
+ data->data_len = 2 + 12 + qlen + 1 + 2 + 2 + rsplen;
data->data = ptr = g_malloc(data->data_len);
data->valid_until = current_time + ttl;
@@ -1374,13 +1402,24 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
return -ENOMEM;
}
- memcpy(ptr, msg, 12);
- memcpy(ptr + 12, question, qlen + 1); /* copy also the \0 */
+ /*
+ * We cache the two extra bytes at the start of the message
+ * in a TCP packet. When sending UDP packet, we skip the first
+ * two bytes. This way we do not need to know the format
+ * (UDP/TCP) of the cached message.
+ */
+ ptr[0] = (data->data_len - 2) / 256;
+ ptr[1] = (data->data_len - 2) - ptr[0] * 256;
+ if (srv->protocol == IPPROTO_UDP)
+ ptr += 2;
+
+ memcpy(ptr, msg, offset + 12);
+ memcpy(ptr + offset + 12, question, qlen + 1); /* copy also the \0 */
- q = (void *) (ptr + 12 + qlen + 1);
+ q = (void *) (ptr + offset + 12 + qlen + 1);
q->type = htons(type);
q->class = htons(class);
- memcpy(ptr + 12 + qlen + 1 + sizeof(struct domain_question),
+ memcpy(ptr + offset + 12 + qlen + 1 + sizeof(struct domain_question),
response, rsplen);
if (new_entry == TRUE) {
@@ -1388,10 +1427,15 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
cache_size++;
}
- DBG("cache %d %squestion \"%s\" type %d ttl %d size %zd",
+ DBG("cache %d %squestion \"%s\" type %d ttl %d size %zd packet %u "
+ "dns len %u",
cache_size, new_entry ? "new " : "old ",
question, type, ttl,
- sizeof(*entry) + sizeof(*data) + data->data_len + qlen);
+ sizeof(*entry) + sizeof(*data) + data->data_len + qlen,
+ data->data_len,
+ srv->protocol == IPPROTO_TCP ?
+ (unsigned int)(data->data[0] * 256 + data->data[1]) :
+ data->data_len);
return 0;
}