1 /**
2 * @file rrlist.c DNS Resource Records list
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <string.h>
7 #include <re_types.h>
8 #include <re_list.h>
9 #include <re_hash.h>
10 #include <re_mbuf.h>
11 #include <re_fmt.h>
12 #include <re_dns.h>
13
14
15 enum {
16 CNAME_RECURSE_MAX = 16,
17 };
18
19
20 struct sort {
21 uint16_t type;
22 uint32_t key;
23 };
24
25
sidx(const struct dnsrr * rr,uint32_t key)26 static uint32_t sidx(const struct dnsrr *rr, uint32_t key)
27 {
28 uint32_t addr[4];
29
30 switch (rr->type) {
31
32 case DNS_TYPE_A:
33 return rr->rdata.a.addr ^ key;
34
35 case DNS_TYPE_AAAA:
36 memcpy(addr, rr->rdata.aaaa.addr, 16);
37
38 return addr[0] ^ addr[1] ^ addr[2] ^ addr[3] ^ key;
39
40 case DNS_TYPE_SRV:
41 return ((hash_fast_str(rr->rdata.srv.target) & 0xfff) ^ key) +
42 rr->rdata.srv.weight;
43
44 default:
45 return 0;
46 }
47 }
48
49
std_sort_handler(struct le * le1,struct le * le2,void * arg)50 static bool std_sort_handler(struct le *le1, struct le *le2, void *arg)
51 {
52 struct dnsrr *rr1 = le1->data;
53 struct dnsrr *rr2 = le2->data;
54 struct sort *sort = arg;
55
56 if (sort->type != rr1->type)
57 return sort->type != rr2->type;
58
59 if (sort->type != rr2->type)
60 return true;
61
62 switch (sort->type) {
63
64 case DNS_TYPE_MX:
65 return rr1->rdata.mx.pref <= rr2->rdata.mx.pref;
66
67 case DNS_TYPE_SRV:
68 if (rr1->rdata.srv.pri == rr2->rdata.srv.pri)
69 return sidx(rr1, sort->key) >= sidx(rr2, sort->key);
70
71 return rr1->rdata.srv.pri < rr2->rdata.srv.pri;
72
73 case DNS_TYPE_NAPTR:
74 if (rr1->rdata.naptr.order == rr2->rdata.naptr.order)
75 return rr1->rdata.naptr.pref <= rr2->rdata.naptr.pref;
76
77 return rr1->rdata.naptr.order < rr2->rdata.naptr.order;
78
79 default:
80 break;
81 }
82
83 return true;
84 }
85
86
addr_sort_handler(struct le * le1,struct le * le2,void * arg)87 static bool addr_sort_handler(struct le *le1, struct le *le2, void *arg)
88 {
89 struct dnsrr *rr1 = le1->data;
90 struct dnsrr *rr2 = le2->data;
91 struct sort *sort = arg;
92
93 return sidx(rr1, sort->key) >= sidx(rr2, sort->key);
94 }
95
96
97 /**
98 * Sort a list of DNS Resource Records
99 *
100 * @param rrl DNS Resource Record list
101 * @param type DNS Record type
102 * @param key Sort key
103 */
dns_rrlist_sort(struct list * rrl,uint16_t type,size_t key)104 void dns_rrlist_sort(struct list *rrl, uint16_t type, size_t key)
105 {
106 struct sort sort = {type, (uint32_t)key>>5};
107
108 list_sort(rrl, std_sort_handler, &sort);
109 }
110
111
112 /**
113 * Sort a list of A/AAAA DNS Resource Records
114 *
115 * @param rrl DNS Resource Record list
116 * @param key Sort key
117 */
dns_rrlist_sort_addr(struct list * rrl,size_t key)118 void dns_rrlist_sort_addr(struct list *rrl, size_t key)
119 {
120 struct sort sort = {0, (uint32_t)key>>5};
121
122 list_sort(rrl, addr_sort_handler, &sort);
123 }
124
125
rrlist_apply(struct list * rrl,const char * name,uint16_t type1,uint16_t type2,uint16_t dnsclass,bool recurse,uint32_t depth,dns_rrlist_h * rrlh,void * arg)126 static struct dnsrr *rrlist_apply(struct list *rrl, const char *name,
127 uint16_t type1, uint16_t type2,
128 uint16_t dnsclass,
129 bool recurse, uint32_t depth,
130 dns_rrlist_h *rrlh, void *arg)
131 {
132 struct le *le = list_head(rrl);
133
134 if (depth > CNAME_RECURSE_MAX)
135 return NULL;
136
137 while (le) {
138
139 struct dnsrr *rr = le->data;
140
141 le = le->next;
142
143 if (name && str_casecmp(name, rr->name))
144 continue;
145
146 if (type1 != DNS_QTYPE_ANY && type2 != DNS_QTYPE_ANY &&
147 rr->type != type1 && rr->type != type2 &&
148 (rr->type != DNS_TYPE_CNAME || !recurse))
149 continue;
150
151 if (dnsclass != DNS_QCLASS_ANY && rr->dnsclass != dnsclass)
152 continue;
153
154 if (!rrlh || rrlh(rr, arg))
155 return rr;
156
157 if (recurse &&
158 DNS_QTYPE_ANY != type1 && DNS_QTYPE_ANY != type2 &&
159 DNS_TYPE_CNAME != type1 && DNS_TYPE_CNAME != type2 &&
160 DNS_TYPE_CNAME == rr->type) {
161 rr = rrlist_apply(rrl, rr->rdata.cname.cname, type1,
162 type2, dnsclass, recurse, ++depth,
163 rrlh, arg);
164 if (rr)
165 return rr;
166 }
167 }
168
169 return NULL;
170 }
171
172
173 /**
174 * Apply a function handler to a list of DNS Resource Records
175 *
176 * @param rrl DNS Resource Record list
177 * @param name If set, filter on domain name
178 * @param type If not DNS_QTYPE_ANY, filter on record type
179 * @param dnsclass If not DNS_QCLASS_ANY, filter on DNS class
180 * @param recurse Cname recursion
181 * @param rrlh Resource record handler
182 * @param arg Handler argument
183 *
184 * @return Matching Resource Record or NULL
185 */
dns_rrlist_apply(struct list * rrl,const char * name,uint16_t type,uint16_t dnsclass,bool recurse,dns_rrlist_h * rrlh,void * arg)186 struct dnsrr *dns_rrlist_apply(struct list *rrl, const char *name,
187 uint16_t type, uint16_t dnsclass,
188 bool recurse, dns_rrlist_h *rrlh, void *arg)
189 {
190 return rrlist_apply(rrl, name, type, type, dnsclass,
191 recurse, 0, rrlh, arg);
192 }
193
194
195 /**
196 * Apply a function handler to a list of DNS Resource Records (two types)
197 *
198 * @param rrl DNS Resource Record list
199 * @param name If set, filter on domain name
200 * @param type1 If not DNS_QTYPE_ANY, filter on record type
201 * @param type2 If not DNS_QTYPE_ANY, filter on record type
202 * @param dnsclass If not DNS_QCLASS_ANY, filter on DNS class
203 * @param recurse Cname recursion
204 * @param rrlh Resource record handler
205 * @param arg Handler argument
206 *
207 * @return Matching Resource Record or NULL
208 */
dns_rrlist_apply2(struct list * rrl,const char * name,uint16_t type1,uint16_t type2,uint16_t dnsclass,bool recurse,dns_rrlist_h * rrlh,void * arg)209 struct dnsrr *dns_rrlist_apply2(struct list *rrl, const char *name,
210 uint16_t type1, uint16_t type2,
211 uint16_t dnsclass, bool recurse,
212 dns_rrlist_h *rrlh, void *arg)
213 {
214 return rrlist_apply(rrl, name, type1, type2, dnsclass,
215 recurse, 0, rrlh, arg);
216 }
217
218
find_handler(struct dnsrr * rr,void * arg)219 static bool find_handler(struct dnsrr *rr, void *arg)
220 {
221 uint16_t type = *(uint16_t *)arg;
222
223 return rr->type == type;
224 }
225
226
227 /**
228 * Find a DNS Resource Record in a list
229 *
230 * @param rrl Resource Record list
231 * @param name If set, filter on domain name
232 * @param type If not DNS_QTYPE_ANY, filter on record type
233 * @param dnsclass If not DNS_QCLASS_ANY, filter on DNS class
234 * @param recurse Cname recursion
235 *
236 * @return Matching Resource Record or NULL
237 */
dns_rrlist_find(struct list * rrl,const char * name,uint16_t type,uint16_t dnsclass,bool recurse)238 struct dnsrr *dns_rrlist_find(struct list *rrl, const char *name,
239 uint16_t type, uint16_t dnsclass, bool recurse)
240 {
241 return rrlist_apply(rrl, name, type, type, dnsclass,
242 recurse, 0, find_handler, &type);
243 }
244