BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file net_dns.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @section DESCRIPTION
30 *
31 * DNS servers module.
32 *
33 * Synopsis: net.dns(list(string) servers, string priority)
34 * Synopsis: net.dns.resolvconf(list({string type, string value}) lines, string priority)
35 */
36  
37 #include <stdlib.h>
38 #include <string.h>
39 #include <limits.h>
40  
41 #include <misc/offset.h>
42 #include <misc/bsort.h>
43 #include <misc/balloc.h>
44 #include <misc/compare.h>
45 #include <misc/concat_strings.h>
46 #include <misc/expstring.h>
47 #include <misc/ipaddr.h>
48 #include <structure/LinkedList1.h>
49 #include <ncd/extra/NCDIfConfig.h>
50  
51 #include <ncd/module_common.h>
52  
53 #include <generated/blog_channel_ncd_net_dns.h>
54  
55 struct instance {
56 NCDModuleInst *i;
57 LinkedList1 entries;
58 LinkedList1Node instances_node; // node in instances
59 };
60  
61 struct dns_entry {
62 LinkedList1Node list_node; // node in instance.entries
63 char *line;
64 int priority;
65 };
66  
67 struct global {
68 LinkedList1 instances;
69 };
70  
71 static struct dns_entry * add_dns_entry (struct instance *o, const char *type, const char *value, int priority)
72 {
73 // allocate entry
74 struct dns_entry *entry = malloc(sizeof(*entry));
75 if (!entry) {
76 goto fail0;
77 }
78  
79 // generate line
80 entry->line = concat_strings(4, type, " ", value, "\n");
81 if (!entry->line) {
82 goto fail1;
83 }
84  
85 // set info
86 entry->priority = priority;
87  
88 // add to list
89 LinkedList1_Append(&o->entries, &entry->list_node);
90  
91 return entry;
92  
93 fail1:
94 free(entry);
95 fail0:
96 return NULL;
97 }
98  
99 static void remove_dns_entry (struct instance *o, struct dns_entry *entry)
100 {
101 // remove from list
102 LinkedList1_Remove(&o->entries, &entry->list_node);
103  
104 // free line
105 free(entry->line);
106  
107 // free entry
108 free(entry);
109 }
110  
111 static void remove_entries (struct instance *o)
112 {
113 LinkedList1Node *n;
114 while (n = LinkedList1_GetFirst(&o->entries)) {
115 struct dns_entry *e = UPPER_OBJECT(n, struct dns_entry, list_node);
116 remove_dns_entry(o, e);
117 }
118 }
119  
120 static size_t count_entries (struct global *g)
121 {
122 size_t c = 0;
123  
124 for (LinkedList1Node *n = LinkedList1_GetFirst(&g->instances); n; n = LinkedList1Node_Next(n)) {
125 struct instance *o = UPPER_OBJECT(n, struct instance, instances_node);
126 for (LinkedList1Node *en = LinkedList1_GetFirst(&o->entries); en; en = LinkedList1Node_Next(en)) {
127 c++;
128 }
129 }
130  
131 return c;
132 }
133  
134 struct dns_sort_entry {
135 char *line;
136 int priority;
137 };
138  
139 static int dns_sort_comparator (const void *v1, const void *v2)
140 {
141 const struct dns_sort_entry *e1 = v1;
142 const struct dns_sort_entry *e2 = v2;
143 return B_COMPARE(e1->priority, e2->priority);
144 }
145  
146 static int set_servers (struct global *g)
147 {
148 int ret = 0;
149  
150 // count servers
151 size_t num_entries = count_entries(g);
152  
153 // allocate sort array
154 struct dns_sort_entry *sort_entries = BAllocArray(num_entries, sizeof(sort_entries[0]));
155 if (!sort_entries) {
156 goto fail0;
157 }
158  
159 // fill sort array
160 num_entries = 0;
161 for (LinkedList1Node *n = LinkedList1_GetFirst(&g->instances); n; n = LinkedList1Node_Next(n)) {
162 struct instance *o = UPPER_OBJECT(n, struct instance, instances_node);
163 for (LinkedList1Node *en = LinkedList1_GetFirst(&o->entries); en; en = LinkedList1Node_Next(en)) {
164 struct dns_entry *e = UPPER_OBJECT(en, struct dns_entry, list_node);
165 sort_entries[num_entries].line = e->line;
166 sort_entries[num_entries].priority= e->priority;
167 num_entries++;
168 }
169 }
170  
171 // sort by priority
172 // use a custom insertion sort instead of qsort() because we want a stable sort
173 struct dns_sort_entry temp;
174 BInsertionSort(sort_entries, num_entries, sizeof(sort_entries[0]), dns_sort_comparator, &temp);
175  
176 ExpString estr;
177 if (!ExpString_Init(&estr)) {
178 goto fail1;
179 }
180  
181 for (size_t i = 0; i < num_entries; i++) {
182 if (!ExpString_Append(&estr, sort_entries[i].line)) {
183 goto fail2;
184 }
185 }
186  
187 // set servers
188 if (!NCDIfConfig_set_resolv_conf(ExpString_Get(&estr), ExpString_Length(&estr))) {
189 goto fail2;
190 }
191  
192 ret = 1;
193  
194 fail2:
195 ExpString_Free(&estr);
196 fail1:
197 BFree(sort_entries);
198 fail0:
199 return ret;
200 }
201  
202 static int func_globalinit (struct NCDInterpModuleGroup *group, const struct NCDModuleInst_iparams *params)
203 {
204 // allocate global state structure
205 struct global *g = BAlloc(sizeof(*g));
206 if (!g) {
207 BLog(BLOG_ERROR, "BAlloc failed");
208 return 0;
209 }
210  
211 // set group state pointer
212 group->group_state = g;
213  
214 // init instances list
215 LinkedList1_Init(&g->instances);
216  
217 return 1;
218 }
219  
220 static void func_globalfree (struct NCDInterpModuleGroup *group)
221 {
222 struct global *g = group->group_state;
223 ASSERT(LinkedList1_IsEmpty(&g->instances))
224  
225 // free global state structure
226 BFree(g);
227 }
228  
229 static void func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
230 {
231 struct global *g = ModuleGlobal(i);
232 struct instance *o = vo;
233 o->i = i;
234  
235 // init servers list
236 LinkedList1_Init(&o->entries);
237  
238 // get arguments
239 NCDValRef servers_arg;
240 NCDValRef priority_arg;
241 if (!NCDVal_ListRead(params->args, 2, &servers_arg, &priority_arg)) {
242 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
243 goto fail1;
244 }
245 if (!NCDVal_IsList(servers_arg)) {
246 ModuleLog(o->i, BLOG_ERROR, "wrong type");
247 goto fail1;
248 }
249  
250 uintmax_t priority;
251 if (!ncd_read_uintmax(priority_arg, &priority) || priority > INT_MAX) {
252 ModuleLog(o->i, BLOG_ERROR, "wrong priority");
253 goto fail1;
254 }
255  
256 // read servers
257 size_t count = NCDVal_ListCount(servers_arg);
258 for (size_t j = 0; j < count; j++) {
259 NCDValRef server_arg = NCDVal_ListGet(servers_arg, j);
260  
261 if (!NCDVal_IsString(server_arg)) {
262 ModuleLog(o->i, BLOG_ERROR, "wrong type");
263 goto fail1;
264 }
265  
266 uint32_t addr;
267 if (!ipaddr_parse_ipv4_addr(NCDVal_StringMemRef(server_arg), &addr)) {
268 ModuleLog(o->i, BLOG_ERROR, "wrong addr");
269 goto fail1;
270 }
271  
272 char addr_str[IPADDR_PRINT_MAX];
273 ipaddr_print_addr(addr, addr_str);
274  
275 if (!add_dns_entry(o, "nameserver", addr_str, priority)) {
276 ModuleLog(o->i, BLOG_ERROR, "failed to add dns entry");
277 goto fail1;
278 }
279 }
280  
281 // add to instances
282 LinkedList1_Append(&g->instances, &o->instances_node);
283  
284 // set servers
285 if (!set_servers(g)) {
286 ModuleLog(o->i, BLOG_ERROR, "failed to set DNS servers");
287 goto fail2;
288 }
289  
290 // signal up
291 NCDModuleInst_Backend_Up(o->i);
292 return;
293  
294 fail2:
295 LinkedList1_Remove(&g->instances, &o->instances_node);
296 fail1:
297 remove_entries(o);
298 NCDModuleInst_Backend_DeadError(i);
299 }
300  
301 static void func_new_resolvconf (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
302 {
303 struct global *g = ModuleGlobal(i);
304 struct instance *o = vo;
305 o->i = i;
306  
307 // init servers list
308 LinkedList1_Init(&o->entries);
309  
310 // get arguments
311 NCDValRef lines_arg;
312 NCDValRef priority_arg;
313 if (!NCDVal_ListRead(params->args, 2, &lines_arg, &priority_arg)) {
314 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
315 goto fail1;
316 }
317 if (!NCDVal_IsList(lines_arg)) {
318 ModuleLog(o->i, BLOG_ERROR, "wrong type");
319 goto fail1;
320 }
321  
322 uintmax_t priority;
323 if (!ncd_read_uintmax(priority_arg, &priority) || priority > INT_MAX) {
324 ModuleLog(o->i, BLOG_ERROR, "wrong priority");
325 goto fail1;
326 }
327  
328 // read lines
329 size_t count = NCDVal_ListCount(lines_arg);
330 for (size_t j = 0; j < count; j++) {
331 int loop_failed = 1;
332  
333 NCDValRef line = NCDVal_ListGet(lines_arg, j);
334 if (!NCDVal_IsList(line) || NCDVal_ListCount(line) != 2) {
335 ModuleLog(o->i, BLOG_ERROR, "lines element is not a list with two elements");
336 goto loop_fail0;
337 }
338  
339 NCDValRef type = NCDVal_ListGet(line, 0);
340 NCDValRef value = NCDVal_ListGet(line, 1);
341 if (!NCDVal_IsStringNoNulls(type) || !NCDVal_IsStringNoNulls(value)) {
342 ModuleLog(o->i, BLOG_ERROR, "wrong type of type or value");
343 goto loop_fail0;
344 }
345  
346 NCDValNullTermString type_nts;
347 if (!NCDVal_StringNullTerminate(type, &type_nts)) {
348 ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
349 goto loop_fail0;
350 }
351  
352 NCDValNullTermString value_nts;
353 if (!NCDVal_StringNullTerminate(value, &value_nts)) {
354 ModuleLog(o->i, BLOG_ERROR, "NCDVal_StringNullTerminate failed");
355 goto loop_fail1;
356 }
357  
358 if (!add_dns_entry(o, type_nts.data, value_nts.data, priority)) {
359 ModuleLog(o->i, BLOG_ERROR, "failed to add dns entry");
360 goto loop_fail2;
361 }
362  
363 loop_failed = 0;
364 loop_fail2:
365 NCDValNullTermString_Free(&value_nts);
366 loop_fail1:
367 NCDValNullTermString_Free(&type_nts);
368 loop_fail0:
369 if (loop_failed) {
370 goto fail1;
371 }
372 }
373  
374 // add to instances
375 LinkedList1_Append(&g->instances, &o->instances_node);
376  
377 // set servers
378 if (!set_servers(g)) {
379 ModuleLog(o->i, BLOG_ERROR, "failed to set DNS servers");
380 goto fail2;
381 }
382  
383 // signal up
384 NCDModuleInst_Backend_Up(o->i);
385 return;
386  
387 fail2:
388 LinkedList1_Remove(&g->instances, &o->instances_node);
389 fail1:
390 remove_entries(o);
391 NCDModuleInst_Backend_DeadError(i);
392 }
393  
394 static void func_die (void *vo)
395 {
396 struct instance *o = vo;
397 struct global *g = ModuleGlobal(o->i);
398  
399 // remove from instances
400 LinkedList1_Remove(&g->instances, &o->instances_node);
401  
402 // set servers
403 set_servers(g);
404  
405 // free servers
406 remove_entries(o);
407  
408 NCDModuleInst_Backend_Dead(o->i);
409 }
410  
411 static struct NCDModule modules[] = {
412 {
413 .type = "net.dns",
414 .func_new2 = func_new,
415 .func_die = func_die,
416 .alloc_size = sizeof(struct instance)
417 }, {
418 .type = "net.dns.resolvconf",
419 .func_new2 = func_new_resolvconf,
420 .func_die = func_die,
421 .alloc_size = sizeof(struct instance)
422 }, {
423 .type = NULL
424 }
425 };
426  
427 const struct NCDModuleGroup ncdmodule_net_dns = {
428 .func_globalinit = func_globalinit,
429 .func_globalfree = func_globalfree,
430 .modules = modules
431 };