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 0658e7e2f44c127b167db8f76bb87bff2e9686de..fea9035609253b67172e332e2aca3ac6a70e51a3 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 10859a593a735611aac72ec5c9035075bb2d1024..897d01b2bbc353cce7560d795386734e08e2210b 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 51a015056d3a4d41d9c80e56488ff97f090905a7..899b1245f61c4e8d1877d614d5b1921454c44389 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;
 
 }