From a0403cde2d5684b63c0ea2c25a5414ede9ac99c3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 21 Mar 2017 00:00:15 +0100 Subject: [PATCH] Keep source sockaddr for every cached DNS record MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- cache.c | 9 +++++++-- cache.h | 6 ++++-- dns.c | 17 +++++++++-------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/cache.c b/cache.c index 0658e7e..fea9035 100644 --- 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 --- 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 --- 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; } -- 2.25.1