From 107323352d3d3a062c831e21c450efe5efd6dbab Mon Sep 17 00:00:00 2001 From: "Alfred E. Heggestad" Date: Tue, 21 Jun 2016 14:58:15 +0000 Subject: [PATCH] patch from richard sort multiple DNS records using a key --- include/re_dns.h | 3 +- src/dns/rrlist.c | 83 +++++++++++++++++++++++++++++++++++++--------- src/sip/request.c | 13 +++++--- src/stun/dnsdisc.c | 2 +- 4 files changed, 79 insertions(+), 22 deletions(-) diff --git a/include/re_dns.h b/include/re_dns.h index 6e1465e..73ecd08 100644 --- a/include/re_dns.h +++ b/include/re_dns.h @@ -172,7 +172,8 @@ int dns_dname_encode(struct mbuf *mb, const char *name, int dns_dname_decode(struct mbuf *mb, char **name, size_t start); int dns_cstr_encode(struct mbuf *mb, const char *str); int dns_cstr_decode(struct mbuf *mb, char **str); -void dns_rrlist_sort(struct list *rrl, uint16_t type); +void dns_rrlist_sort(struct list *rrl, uint16_t type, size_t key); +void dns_rrlist_sort_addr(struct list *rrl, size_t key); struct dnsrr *dns_rrlist_apply(struct list *rrl, const char *name, uint16_t type, uint16_t dnsclass, bool recurse, dns_rrlist_h *rrlh, void *arg); diff --git a/src/dns/rrlist.c b/src/dns/rrlist.c index 69bf211..6e7c572 100644 --- a/src/dns/rrlist.c +++ b/src/dns/rrlist.c @@ -3,8 +3,10 @@ * * Copyright (C) 2010 Creytiv.com */ +#include #include #include +#include #include #include #include @@ -15,31 +17,56 @@ enum { }; +struct sort { + uint16_t type; + uint32_t key; +}; + + +static uint32_t sidx(const struct dnsrr *rr, uint32_t key) +{ + uint32_t addr[4]; + + switch (rr->type) { + + case DNS_TYPE_A: + return rr->rdata.a.addr ^ key; + + case DNS_TYPE_AAAA: + memcpy(addr, rr->rdata.aaaa.addr, 16); + + return addr[0] ^ addr[1] ^ addr[2] ^ addr[3] ^ key; + + case DNS_TYPE_SRV: + return ((hash_fast_str(rr->rdata.srv.target) & 0xfff) ^ key) + + rr->rdata.srv.weight; + + default: + return 0; + } +} + + static bool std_sort_handler(struct le *le1, struct le *le2, void *arg) { struct dnsrr *rr1 = le1->data; struct dnsrr *rr2 = le2->data; - const uint16_t type = *(uint16_t *)arg; + struct sort *sort = arg; - if (type != rr1->type) - return type != rr2->type; + if (sort->type != rr1->type) + return sort->type != rr2->type; - if (type != rr2->type) + if (sort->type != rr2->type) return true; - switch (type) { + switch (sort->type) { case DNS_TYPE_MX: return rr1->rdata.mx.pref <= rr2->rdata.mx.pref; case DNS_TYPE_SRV: - if (rr1->rdata.srv.pri == rr2->rdata.srv.pri) { - - if (rr1->rdata.srv.weight) - return 0 != rr2->rdata.srv.weight; - - return true; - } + if (rr1->rdata.srv.pri == rr2->rdata.srv.pri) + return sidx(rr1, sort->key) >= sidx(rr2, sort->key); return rr1->rdata.srv.pri < rr2->rdata.srv.pri; @@ -57,16 +84,42 @@ static bool std_sort_handler(struct le *le1, struct le *le2, void *arg) } +static bool addr_sort_handler(struct le *le1, struct le *le2, void *arg) +{ + struct dnsrr *rr1 = le1->data; + struct dnsrr *rr2 = le2->data; + struct sort *sort = arg; + + return sidx(rr1, sort->key) >= sidx(rr2, sort->key); +} + + /** * Sort a list of DNS Resource Records * * @param rrl DNS Resource Record list * @param type DNS Record type + * @param key Sort key */ -void dns_rrlist_sort(struct list *rrl, uint16_t type) +void dns_rrlist_sort(struct list *rrl, uint16_t type, size_t key) { - list_sort(rrl, std_sort_handler, &type); - /* todo add SRV postprocessing for weighted load balancing. */ + struct sort sort = {type, (uint32_t)key>>5}; + + list_sort(rrl, std_sort_handler, &sort); +} + + +/** + * Sort a list of A/AAAA DNS Resource Records + * + * @param rrl DNS Resource Record list + * @param key Sort key + */ +void dns_rrlist_sort_addr(struct list *rrl, size_t key) +{ + struct sort sort = {0, (uint32_t)key>>5}; + + list_sort(rrl, addr_sort_handler, &sort); } diff --git a/src/sip/request.c b/src/sip/request.c index b2deb5b..921ad89 100644 --- a/src/sip/request.c +++ b/src/sip/request.c @@ -227,6 +227,7 @@ static int request_next(struct sip_request *req) list_unlink(&rr->le); if (req->addrl.head) { + dns_rrlist_sort_addr(&req->addrl, (size_t)req->arg); mem_deref(rr); goto again; } @@ -392,7 +393,7 @@ static void naptr_handler(int err, const struct dnshdr *hdr, struct list *ansl, (void)hdr; (void)authl; - dns_rrlist_sort(ansl, DNS_TYPE_NAPTR); + dns_rrlist_sort(ansl, DNS_TYPE_NAPTR, (size_t)req->arg); rr = dns_rrlist_apply(ansl, NULL, DNS_TYPE_NAPTR, DNS_CLASS_IN, false, rr_naptr_handler, req); @@ -410,8 +411,6 @@ static void naptr_handler(int err, const struct dnshdr *hdr, struct list *ansl, return; } - dns_rrlist_sort(addl, DNS_TYPE_SRV); - dns_rrlist_apply(addl, rr->rdata.naptr.replace, DNS_TYPE_SRV, DNS_CLASS_IN, true, rr_append_handler, &req->srvl); @@ -425,6 +424,8 @@ static void naptr_handler(int err, const struct dnshdr *hdr, struct list *ansl, return; } + dns_rrlist_sort(&req->srvl, DNS_TYPE_SRV, (size_t)req->arg); + dns_rrlist_apply(addl, NULL, DNS_QTYPE_ANY, DNS_CLASS_IN, false, rr_cache_handler, req); @@ -447,8 +448,6 @@ static void srv_handler(int err, const struct dnshdr *hdr, struct list *ansl, (void)hdr; (void)authl; - dns_rrlist_sort(ansl, DNS_TYPE_SRV); - dns_rrlist_apply(ansl, NULL, DNS_TYPE_SRV, DNS_CLASS_IN, false, rr_append_handler, &req->srvl); @@ -479,6 +478,8 @@ static void srv_handler(int err, const struct dnshdr *hdr, struct list *ansl, return; } + dns_rrlist_sort(&req->srvl, DNS_TYPE_SRV, (size_t)req->arg); + dns_rrlist_apply(addl, NULL, DNS_QTYPE_ANY, DNS_CLASS_IN, false, rr_cache_handler, req); @@ -514,6 +515,8 @@ static void addr_handler(int err, const struct dnshdr *hdr, struct list *ansl, goto fail; } + dns_rrlist_sort_addr(&req->addrl, (size_t)req->arg); + err = request_next(req); if (err) goto fail; diff --git a/src/stun/dnsdisc.c b/src/stun/dnsdisc.c index 4bead19..c79b2c4 100644 --- a/src/stun/dnsdisc.c +++ b/src/stun/dnsdisc.c @@ -138,7 +138,7 @@ static void srv_handler(int err, const struct dnshdr *hdr, struct list *ansl, (void)hdr; (void)authl; - dns_rrlist_sort(ansl, DNS_TYPE_SRV); + dns_rrlist_sort(ansl, DNS_TYPE_SRV, (size_t)dns->arg); /* Find SRV answers */ rr = dns_rrlist_find(ansl, NULL, DNS_TYPE_SRV, DNS_CLASS_IN, false);