Keep source sockaddr for every cached DNS record
authorRafał Miłecki <rafal@milecki.pl>
Mon, 20 Mar 2017 23:00:15 +0000 (00:00 +0100)
committerRafał Miłecki <rafal@milecki.pl>
Tue, 21 Mar 2017 21:55:54 +0000 (22:55 +0100)
This will be required for sending questions on TTL timeouts. When that
happens we want to send unicast question but it's currently broken as we
don't know original IP address.

This change stores whole sockaddr (using struct sockaddr_storage). In
theory it'd be sufficient to store struct in_addr or struct in6_addr but
1) There isn't helper struct for storing IP version agnostic address
2) interface_send_packet already expects struct sockaddr

It hopefully won't hurt memory usage that bad to store a bit more info.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
cache.c
cache.h
dns.c

diff --git a/cache.c b/cache.c
index 0658e7e..fea9035 100644 (file)
--- a/cache.c
+++ b/cache.c
@@ -242,8 +242,9 @@ cache_host_is_known(char *record)
        return 0;
 }
 
-void
-cache_answer(struct interface *iface, uint8_t *base, int blen, char *name, struct dns_answer *a, uint8_t *rdata, int flush)
+void cache_answer(struct interface *iface, struct sockaddr *from, uint8_t *base,
+                 int blen, char *name, struct dns_answer *a, uint8_t *rdata,
+                 int flush)
 {
        struct dns_srv_data *dsd = (struct dns_srv_data *) rdata;
        struct cache_record *r;
@@ -362,6 +363,10 @@ cache_answer(struct interface *iface, uint8_t *base, int blen, char *name, struc
        r->rdlength = dlen;
        r->time = now;
        r->iface = iface;
+       if (iface->v6)
+               memcpy(&r->from, from, sizeof(struct sockaddr_in6));
+       else
+               memcpy(&r->from, from, sizeof(struct sockaddr_in));
        r->refresh = 50;
 
        if (tlen)
diff --git a/cache.h b/cache.h
index 10859a5..897d01b 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -44,6 +44,7 @@ struct cache_record {
        uint16_t rdlength;
        time_t time;
        struct interface *iface;
+       struct sockaddr_storage from;
        int refresh;
 };
 
@@ -53,8 +54,9 @@ extern struct avl_tree records;
 int cache_init(void);
 void cache_update(void);
 void cache_cleanup(struct interface *iface);
-void cache_answer(struct interface *iface, uint8_t *base, int blen,
-                 char *name, struct dns_answer *a, uint8_t *rdata, int flush);
+void cache_answer(struct interface *iface, struct sockaddr *from, uint8_t *base,
+                 int blen, char *name, struct dns_answer *a, uint8_t *rdata,
+                 int flush);
 int cache_host_is_known(char *record);
 void cache_dump_records(struct blob_buf *buf, const char *name);
 void cache_dump_recursive(struct blob_buf *b, const char *name, uint16_t type, struct interface *iface);
diff --git a/dns.c b/dns.c
index 51a0150..899b124 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -312,8 +312,9 @@ dns_consume_name(const uint8_t *base, int blen, uint8_t **data, int *len)
        return name_buffer;
 }
 
-static int
-parse_answer(struct interface *iface, uint8_t *buffer, int len, uint8_t **b, int *rlen, int cache)
+static int parse_answer(struct interface *iface, struct sockaddr *from,
+                       uint8_t *buffer, int len, uint8_t **b, int *rlen,
+                       int cache)
 {
        char *name = dns_consume_name(buffer, len, b, rlen);
        struct dns_answer *a;
@@ -343,7 +344,7 @@ parse_answer(struct interface *iface, uint8_t *buffer, int len, uint8_t **b, int
        *b += a->rdlength;
 
        if (cache)
-               cache_answer(iface, buffer, len, name, a, rdata, a->class & CLASS_FLUSH);
+               cache_answer(iface, from, buffer, len, name, a, rdata, a->class & CLASS_FLUSH);
 
        return 0;
 }
@@ -400,7 +401,7 @@ parse_question(struct interface *iface, struct sockaddr *from, char *name, struc
 }
 
 void
-dns_handle_packet(struct interface *iface, struct sockaddr *s, uint16_t port, uint8_t *buffer, int len)
+dns_handle_packet(struct interface *iface, struct sockaddr *from, uint16_t port, uint8_t *buffer, int len)
 {
        struct dns_header *h;
        uint8_t *b = buffer;
@@ -432,22 +433,22 @@ dns_handle_packet(struct interface *iface, struct sockaddr *s, uint16_t port, ui
                }
 
                if (!(h->flags & FLAG_RESPONSE))
-                       parse_question(iface, s, name, q);
+                       parse_question(iface, from, name, q);
        }
 
        if (!(h->flags & FLAG_RESPONSE))
                return;
 
        while (h->answers-- > 0)
-               if (parse_answer(iface, buffer, len, &b, &rlen, 1))
+               if (parse_answer(iface, from, buffer, len, &b, &rlen, 1))
                        return;
 
        while (h->authority-- > 0)
-               if (parse_answer(iface, buffer, len, &b, &rlen, 1))
+               if (parse_answer(iface, from, buffer, len, &b, &rlen, 1))
                        return;
 
        while (h->additional-- > 0)
-               if (parse_answer(iface, buffer, len, &b, &rlen, 1))
+               if (parse_answer(iface, from, buffer, len, &b, &rlen, 1))
                        return;
 
 }