contrib: add WoL application to menuconfig
[project/luci.git] / contrib / fwd / src / fwd_config.c
1 /*
2 * fwd - OpenWrt firewall daemon - config parsing
3 *
4 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * The fwd program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * The fwd program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with the fwd program. If not, see http://www.gnu.org/licenses/.
17 */
18
19
20 #include "fwd.h"
21 #include "fwd_addr.h"
22 #include "fwd_config.h"
23 #include "fwd_utils.h"
24
25 #include "ucix.h"
26
27
28 #define fwd_read_error(...) do { \
29 fwd_log_err(__VA_ARGS__); \
30 return; \
31 } while(0)
32
33
34 /*
35 * Parse helpers
36 */
37 static int
38 fwd_read_policy(struct uci_context *uci, const char *s, const char *o)
39 {
40 const char *val = ucix_get_option(uci, "firewall", s, o);
41
42 if( val != NULL )
43 {
44 switch( val[0] )
45 {
46 case 'D':
47 case 'd':
48 return FWD_P_DROP;
49
50 case 'R':
51 case 'r':
52 return FWD_P_REJECT;
53
54 case 'A':
55 case 'a':
56 return FWD_P_ACCEPT;
57 }
58 }
59
60 return FWD_P_UNSPEC;
61 }
62
63 static int
64 fwd_read_bool(struct uci_context *uci, const char *s, const char *o, int d)
65 {
66 const char *val = ucix_get_option(uci, "firewall", s, o);
67
68 if( val != NULL )
69 {
70 if( !strcmp(val, "yes") || !strcmp(val, "true") || !strcmp(val, "1") )
71 return 1;
72 else
73 return 0;
74 }
75
76 return d;
77 }
78
79 static unsigned int
80 fwd_read_uint(struct uci_context *uci, const char *s, const char *o, unsigned int d)
81 {
82 const char *val = ucix_get_option(uci, "firewall", s, o);
83
84 if( val != NULL )
85 {
86 return atoi(val);
87 }
88
89 return d;
90 }
91
92 static int
93 fwd_read_cidr(struct uci_context *uci, const char *s, const char *o, struct fwd_cidr **c)
94 {
95 const char *val = ucix_get_option(uci, "firewall", s, o);
96 char ip[32], prefix[32];
97 struct in_addr ina;
98
99 memset(ip, 0, 32);
100 memset(prefix, 0, 32);
101
102 if( val == NULL )
103 {
104 return 0;
105 }
106 else if( (strlen(val) < 32) && (sscanf(val, "%[^/]/%s", ip, prefix) > 0) )
107 {
108 if( !(*c = fwd_alloc_ptr(struct fwd_cidr)) )
109 goto inval;
110
111 if( inet_aton(ip, &ina) )
112 {
113 (*c)->addr.s_addr = ina.s_addr;
114
115 if( strchr(prefix, '.') )
116 {
117 if( inet_aton(prefix, &ina) )
118 {
119 (*c)->prefix = 32;
120 ina.s_addr = ntohl(ina.s_addr);
121
122 while( !(ina.s_addr & 1) )
123 {
124 ina.s_addr >>= 1;
125 (*c)->prefix--;
126 }
127 }
128 else
129 {
130 goto inval;
131 }
132 }
133 else
134 {
135 (*c)->prefix = prefix[0] ? atoi(prefix) : 32;
136
137 if( ((*c)->prefix < 0) || ((*c)->prefix > 32) )
138 {
139 goto inval;
140 }
141 }
142
143 return 0;
144 }
145 }
146
147 inval:
148 fwd_free_ptr(*c);
149 return -1;
150 }
151
152 static int
153 fwd_read_mac(struct uci_context *uci, const char *s, const char *o, struct fwd_mac **m)
154 {
155 const char *val = ucix_get_option(uci, "firewall", s, o);
156
157 if( val == NULL )
158 {
159 return 0;
160 }
161 else
162 {
163 if( (*m = fwd_alloc_ptr(struct fwd_mac)) != NULL )
164 {
165 unsigned int i1, i2, i3, i4, i5, i6;
166
167 if( sscanf(val, "%2x:%2x:%2x:%2x:%2x:%2x",
168 &i1, &i2, &i3, &i4, &i5, &i6) == 6
169 ) {
170 (*m)->mac[0] = (unsigned char)i1;
171 (*m)->mac[1] = (unsigned char)i2;
172 (*m)->mac[2] = (unsigned char)i3;
173 (*m)->mac[3] = (unsigned char)i4;
174 (*m)->mac[4] = (unsigned char)i5;
175 (*m)->mac[5] = (unsigned char)i6;
176 return 0;
177 }
178 }
179 }
180
181 fwd_free_ptr(*m);
182 return -1;
183 }
184
185 static int
186 fwd_read_portrange(struct uci_context *uci, const char *s, const char *o, struct fwd_portrange **p)
187 {
188 const char *val = ucix_get_option(uci, "firewall", s, o);
189 int min = -1;
190 int max = -1;
191 unsigned int tmp;
192
193 if( val == NULL )
194 {
195 return 0;
196 }
197 else if( sscanf(val, "%u%*[:-]%u", &min, &max) > 0 )
198 {
199 if( max == -1 )
200 {
201 max = min;
202 }
203 else if( min > max )
204 {
205 tmp = max;
206 max = min;
207 min = tmp;
208 }
209
210 if( (min >= 0) && (min <= 65535) && (max >= 0) && (max <= 65535) )
211 {
212 if( (*p = fwd_alloc_ptr(struct fwd_portrange)) != NULL )
213 {
214 (*p)->min = min;
215 (*p)->max = max;
216 return 0;
217 }
218 }
219 }
220
221 fwd_free_ptr(*p);
222 return -1;
223 }
224
225 static int
226 fwd_read_proto(struct uci_context *uci, const char *s, const char *o, struct fwd_proto **p)
227 {
228 const char *val = ucix_get_option(uci, "firewall", s, o);
229 int proto;
230
231 if( val == NULL )
232 {
233 return 0;
234 }
235 else
236 {
237 if( (*p = fwd_alloc_ptr(struct fwd_proto)) != NULL )
238 {
239 proto = atoi(val);
240
241 if( !strcasecmp(val, "all") )
242 {
243 (*p)->type = FWD_PR_ALL;
244 (*p)->proto = 0;
245 }
246 else if( !strcasecmp(val, "icmp") )
247 {
248 (*p)->type = FWD_PR_ICMP;
249 (*p)->proto = 0;
250 }
251 else if( !strcasecmp(val, "udp") )
252 {
253 (*p)->type = FWD_PR_UDP;
254 (*p)->proto = 0;
255 }
256 else if( !strcasecmp(val, "tcp") )
257 {
258 (*p)->type = FWD_PR_TCP;
259 (*p)->proto = 0;
260 }
261 else if( !strcasecmp(val, "tcpudp") )
262 {
263 (*p)->type = FWD_PR_TCPUDP;
264 (*p)->proto = 0;
265 }
266 else if( proto > 0 )
267 {
268 (*p)->type = FWD_PR_CUSTOM;
269 (*p)->proto = proto;
270 }
271 else
272 {
273 goto inval;
274 }
275
276 return 0;
277 }
278 }
279
280 inval:
281 fwd_free_ptr(*p);
282 return -1;
283 }
284
285 static int
286 fwd_read_icmptype(struct uci_context *uci, const char *s, const char *o, struct fwd_icmptype **i)
287 {
288 const char *val = ucix_get_option(uci, "firewall", s, o);
289 unsigned int type, code;
290
291 if( val == NULL )
292 {
293 return 0;
294 }
295 else
296 {
297 if( (*i = fwd_alloc_ptr(struct fwd_icmptype)) != NULL )
298 {
299 if( sscanf(val, "%u/%u", &type, &code) == 2 )
300 {
301 if( (type > 255) || (code > 255) )
302 goto inval;
303
304 (*i)->type = type;
305 (*i)->code = code;
306
307 return 0;
308 }
309
310 else if( sscanf(val, "%u", &type) == 1 )
311 {
312 if( type > 255 )
313 goto inval;
314
315 (*i)->type = type;
316 (*i)->code = -1;
317
318 return 0;
319 }
320
321 /* XXX: no validity check here but I do not want to
322 duplicate libipt_icmp.c ... */
323 else if( sscanf(val, "%31s", (*i)->name) == 1 )
324 {
325 return 0;
326 }
327 }
328 }
329
330 inval:
331 fwd_free_ptr(*i);
332 return -1;
333 }
334
335 static const char *
336 fwd_read_string(struct uci_context *uci, const char *s, const char *o)
337 {
338 return ucix_get_option(uci, "firewall", s, o);
339 }
340
341
342 static void
343 fwd_append_config(struct fwd_data *h, struct fwd_data *a)
344 {
345 while( h->next )
346 h = h->next;
347
348 h->next = a;
349 }
350
351
352 /*
353 * config defaults
354 */
355 static void fwd_read_defaults_cb(
356 struct uci_context *uci,
357 const char *s, struct fwd_defaults *d
358 ) {
359 d->input = fwd_read_policy(uci, s, "input");
360 d->forward = fwd_read_policy(uci, s, "forward");
361 d->output = fwd_read_policy(uci, s, "output");
362 d->syn_flood = fwd_read_bool(uci, s, "syn_flood", 1);
363 d->syn_rate = fwd_read_uint(uci, s, "syn_rate", 25);
364 d->syn_burst = fwd_read_uint(uci, s, "syn_burst", 50);
365 d->drop_invalid = fwd_read_bool(uci, s, "drop_invalid", 1);
366 }
367
368 static struct fwd_data *
369 fwd_read_defaults(struct uci_context *uci)
370 {
371 struct fwd_data *dt;
372 struct fwd_defaults d;
373
374 if( (dt = fwd_alloc_ptr(struct fwd_data)) != NULL )
375 {
376 memset(&d, 0, sizeof(d));
377
378 ucix_for_each_section_type(uci, "firewall", "defaults",
379 (void *)fwd_read_defaults_cb, &d);
380
381 memcpy(&dt->section.defaults, &d, sizeof(d));
382
383 dt->type = FWD_S_DEFAULTS;
384 dt->next = NULL;
385
386 return dt;
387 }
388
389 return NULL;
390 }
391
392
393 /*
394 * config zone
395 */
396 static void fwd_read_zone_networks_cb(
397 const char *net, struct fwd_network **np
398 ) {
399 struct fwd_network *nn;
400
401 if( (nn = fwd_alloc_ptr(struct fwd_network)) != NULL )
402 {
403 nn->name = strdup(net);
404 nn->next = *np;
405 *np = nn;
406 }
407 }
408
409 static void fwd_read_zones_cb(
410 struct uci_context *uci,
411 const char *s, struct fwd_data_conveyor *cv
412 ) {
413 struct fwd_data *dtn;
414 struct fwd_network *net = NULL;
415 const char *name;
416
417 if( !(name = fwd_read_string(uci, s, "name")) )
418 fwd_read_error("section '%s' is missing 'name' option!", s);
419
420 if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
421 {
422 dtn->section.zone.name = strdup(name);
423 dtn->section.zone.masq = fwd_read_bool(uci, s, "masq", 0);
424 dtn->section.zone.mtu_fix = fwd_read_bool(uci, s, "mtu_fix", 0);
425 dtn->section.zone.conntrack = fwd_read_bool(uci, s, "conntrack", 0);
426
427 dtn->section.zone.input = fwd_read_policy(uci, s, "input")
428 ?: cv->head->section.defaults.input ?: FWD_P_DROP;
429
430 dtn->section.zone.forward = fwd_read_policy(uci, s, "forward")
431 ?: cv->head->section.defaults.forward ?: FWD_P_DROP;
432
433 dtn->section.zone.output = fwd_read_policy(uci, s, "output")
434 ?: cv->head->section.defaults.output ?: FWD_P_DROP;
435
436 /* try to parse option/list network ... */
437 if( ucix_for_each_list(uci, "firewall", s, "network",
438 (void *)&fwd_read_zone_networks_cb, &net) < 0 )
439 {
440 /* ... didn't work, fallback to option name */
441 fwd_read_zone_networks_cb(name, &net);
442 }
443
444 dtn->section.zone.networks = net;
445 dtn->type = FWD_S_ZONE;
446 dtn->next = cv->cursor;
447 cv->cursor = dtn;
448 }
449 }
450
451 static struct fwd_data *
452 fwd_read_zones(struct uci_context *uci, struct fwd_data *def)
453 {
454 struct fwd_data_conveyor cv;
455
456 cv.cursor = NULL;
457 cv.head = def;
458
459 ucix_for_each_section_type(uci, "firewall", "zone",
460 (void *)fwd_read_zones_cb, &cv);
461
462 return cv.cursor;
463 }
464
465
466 /*
467 * config forwarding
468 */
469 static void fwd_read_forwards_cb(
470 struct uci_context *uci,
471 const char *s, struct fwd_data_conveyor *cv
472 ) {
473 const char *src, *dest;
474 struct fwd_data *dtn;
475 struct fwd_zone *zsrc = NULL;
476 struct fwd_zone *zdest = NULL;
477
478 if( !(src = fwd_read_string(uci, s, "src")) )
479 fwd_read_error("section '%s' is missing 'src' option!", s);
480 else if( !(zsrc = fwd_lookup_zone(cv->head, src)) )
481 fwd_read_error("section '%s' references unknown src zone '%s'!", s, src);
482 else if( !(dest = fwd_read_string(uci, s, "dest")) )
483 fwd_read_error("section '%s' is missing 'dest' option!", s);
484 else if( !(zdest = fwd_lookup_zone(cv->head, dest)) )
485 fwd_read_error("section '%s' references unknown dest zone '%s'!", s, dest);
486
487 if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
488 {
489 dtn->section.forwarding.src = zsrc;
490 dtn->section.forwarding.dest = zdest;
491 dtn->section.forwarding.mtu_fix = fwd_read_bool(uci, s, "mtu_fix", 0);
492 dtn->section.forwarding.masq = fwd_read_bool(uci, s, "masq", 0);
493
494 dtn->type = FWD_S_FORWARD;
495
496 if( zsrc )
497 {
498 dtn->next = zsrc->forwardings;
499 zsrc->forwardings = dtn;
500 }
501 else
502 {
503 dtn->next = cv->cursor;
504 cv->cursor = dtn;
505 }
506 }
507 else
508 {
509 fwd_read_error("out of memory while parsing config!");
510 }
511 }
512
513 static struct fwd_data *
514 fwd_read_forwards(struct uci_context *uci, struct fwd_data *zones)
515 {
516 struct fwd_data_conveyor cv;
517
518 cv.cursor = NULL;
519 cv.head = zones;
520
521 ucix_for_each_section_type(uci, "firewall", "forwarding",
522 (void *)fwd_read_forwards_cb, &cv);
523
524 return cv.cursor;
525 }
526
527
528 /*
529 * config redirect
530 */
531 static void fwd_read_redirects_cb(
532 struct uci_context *uci,
533 const char *s, struct fwd_data_conveyor *cv
534 ) {
535 const char *src;
536 struct fwd_data *dtn = NULL;
537 struct fwd_data *dtn2 = NULL;
538 struct fwd_zone *zsrc = NULL;
539
540 /* check zone */
541 if( !(src = fwd_read_string(uci, s, "src")) )
542 fwd_read_error(
543 "section '%s' is missing 'src' option!",
544 s
545 );
546
547 else if( !(zsrc = fwd_lookup_zone(cv->head, src)) )
548 fwd_read_error(
549 "section '%s' references unknown src zone '%s'!",
550 s, src
551 );
552
553 /* uci context, section, name, type */
554 fwd_check_option(uci, s, src_ip, cidr);
555 fwd_check_option(uci, s, src_mac, mac);
556 fwd_check_option(uci, s, src_port, portrange);
557 fwd_check_option(uci, s, src_dport, portrange);
558 fwd_check_option(uci, s, dest_ip, cidr);
559 fwd_check_option(uci, s, dest_port, portrange);
560 fwd_check_option(uci, s, proto, proto);
561
562 if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
563 {
564 dtn->section.redirect.proto = proto;
565 dtn->section.redirect.src = zsrc;
566 dtn->section.redirect.src_ip = src_ip;
567 dtn->section.redirect.src_mac = src_mac;
568 dtn->section.redirect.src_port = src_port;
569 dtn->section.redirect.src_dport = src_dport;
570 dtn->section.redirect.dest_ip = dest_ip;
571 dtn->section.redirect.dest_port = dest_port;
572
573 dtn->type = FWD_S_REDIRECT;
574 dtn->next = zsrc->redirects;
575 zsrc->redirects = dtn;
576
577 if( (proto != NULL) && (proto->type == FWD_PR_TCPUDP) )
578 {
579 if( !(dtn2 = fwd_alloc_ptr(struct fwd_data)) ||
580 !(dtn2->section.redirect.proto = fwd_alloc_ptr(struct fwd_proto))
581 ) {
582 fwd_free_ptr(dtn2);
583 fwd_read_error("out of memory while parsing config!");
584 }
585
586 dtn->section.redirect.proto->type = FWD_PR_UDP;
587 dtn2->section.redirect.proto->type = FWD_PR_TCP;
588
589 dtn2->section.redirect.src = zsrc;
590 dtn2->section.redirect.src_ip = src_ip;
591 dtn2->section.redirect.src_mac = src_mac;
592 dtn2->section.redirect.src_port = src_port;
593 dtn2->section.redirect.src_dport = src_dport;
594 dtn2->section.redirect.dest_ip = dest_ip;
595 dtn2->section.redirect.dest_port = dest_port;
596 dtn2->section.redirect.clone = 1;
597
598 dtn2->type = FWD_S_REDIRECT;
599 dtn2->next = zsrc->redirects;
600 zsrc->redirects = dtn2;
601 }
602 }
603 else
604 {
605 fwd_read_error("out of memory while parsing config!");
606 }
607 }
608
609 static struct fwd_data *
610 fwd_read_redirects(struct uci_context *uci, struct fwd_data *zones)
611 {
612 struct fwd_data_conveyor cv;
613
614 cv.cursor = NULL;
615 cv.head = zones;
616
617 ucix_for_each_section_type(uci, "firewall", "redirect",
618 (void *)fwd_read_redirects_cb, &cv);
619
620 return cv.cursor;
621 }
622
623
624 /*
625 * config rule
626 */
627 static void fwd_read_rules_cb(
628 struct uci_context *uci,
629 const char *s, struct fwd_data_conveyor *cv
630 ) {
631 const char *src, *dest;
632 struct fwd_data *dtn = NULL;
633 struct fwd_data *dtn2 = NULL;
634 struct fwd_zone *zsrc = NULL;
635 struct fwd_zone *zdest = NULL;
636
637 /* check zones */
638 if( !(src = fwd_read_string(uci, s, "src")) )
639 fwd_read_error(
640 "section '%s' is missing 'src' option!",
641 s
642 );
643
644 else if( !(zsrc = fwd_lookup_zone(cv->head, src)) )
645 fwd_read_error(
646 "section '%s' references unknown src zone '%s'!",
647 s, src
648 );
649
650 if( (dest = fwd_read_string(uci, s, "dest")) != NULL )
651 if( !(zdest = fwd_lookup_zone(cv->head, dest)) )
652 fwd_read_error(
653 "section '%s' references unknown dest zone '%s'!",
654 s, dest
655 );
656
657 /* uci context, section, name, type */
658 fwd_check_option(uci, s, src_ip, cidr);
659 fwd_check_option(uci, s, src_mac, mac);
660 fwd_check_option(uci, s, src_port, portrange);
661 fwd_check_option(uci, s, dest_ip, cidr);
662 fwd_check_option(uci, s, dest_port, portrange);
663 fwd_check_option(uci, s, proto, proto);
664 fwd_check_option(uci, s, icmptype, icmptype);
665
666 if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
667 {
668 dtn->section.rule.proto = proto;
669 dtn->section.rule.icmp_type = icmptype;
670 dtn->section.rule.src = zsrc;
671 dtn->section.rule.src_ip = src_ip;
672 dtn->section.rule.src_mac = src_mac;
673 dtn->section.rule.src_port = src_port;
674 dtn->section.rule.dest = zdest;
675 dtn->section.rule.dest_ip = dest_ip;
676 dtn->section.rule.dest_port = dest_port;
677 dtn->section.rule.target = fwd_read_policy(uci, s, "target");
678
679 dtn->type = FWD_S_RULE;
680 dtn->next = zsrc->rules;
681 zsrc->rules = dtn;
682
683 if( (proto != NULL) && (proto->type == FWD_PR_TCPUDP) )
684 {
685 if( !(dtn2 = fwd_alloc_ptr(struct fwd_data)) ||
686 !(dtn2->section.rule.proto = fwd_alloc_ptr(struct fwd_proto))
687 ) {
688 fwd_free_ptr(dtn2);
689 fwd_read_error("out of memory while parsing config!");
690 }
691
692 dtn->section.rule.proto->type = FWD_PR_UDP;
693 dtn2->section.rule.proto->type = FWD_PR_TCP;
694
695 dtn2->section.rule.src = zsrc;
696 dtn2->section.rule.src_ip = src_ip;
697 dtn2->section.rule.src_mac = src_mac;
698 dtn2->section.rule.src_port = src_port;
699 dtn2->section.rule.dest = zdest;
700 dtn2->section.rule.dest_ip = dest_ip;
701 dtn2->section.rule.dest_port = dest_port;
702 dtn2->section.rule.target = dtn->section.rule.target;
703 dtn2->section.rule.clone = 1;
704
705 dtn2->type = FWD_S_RULE;
706 dtn2->next = zsrc->rules;
707 zsrc->rules = dtn2;
708 }
709 }
710 else
711 {
712 fwd_read_error("out of memory while parsing config!");
713 }
714 }
715
716 static struct fwd_data *
717 fwd_read_rules(struct uci_context *uci, struct fwd_data *zones)
718 {
719 struct fwd_data_conveyor cv;
720
721 cv.cursor = NULL;
722 cv.head = zones;
723
724 ucix_for_each_section_type(uci, "firewall", "rule",
725 (void *)fwd_read_rules_cb, &cv);
726
727 return cv.cursor;
728 }
729
730
731 /*
732 * config include
733 */
734 static void fwd_read_includes_cb(
735 struct uci_context *uci,
736 const char *s, struct fwd_data_conveyor *cv
737 ) {
738 const char *path = fwd_read_string(uci, s, "path");
739 struct fwd_data *dtn = NULL;
740
741 if( path != NULL )
742 {
743 if( (dtn = fwd_alloc_ptr(struct fwd_data)) != NULL )
744 {
745 dtn->section.include.path = strdup(path);
746
747 dtn->type = FWD_S_INCLUDE;
748 dtn->next = cv->cursor;
749 cv->cursor = dtn;
750 }
751 else
752 {
753 fwd_read_error("out of memory while parsing config!");
754 }
755 }
756 }
757
758 static struct fwd_data *
759 fwd_read_includes(struct uci_context *uci)
760 {
761 struct fwd_data_conveyor cv;
762
763 cv.cursor = NULL;
764 cv.head = NULL;
765
766 ucix_for_each_section_type(uci, "firewall", "include",
767 (void *)fwd_read_includes_cb, &cv);
768
769 return cv.cursor;
770 }
771
772
773 /*
774 * config interface
775 */
776 static void fwd_read_network_data(
777 struct uci_context *uci, struct fwd_network *net
778 ) {
779 struct fwd_network *e;
780 const char *type, *ifname;
781
782 for( e = net; e; e = e->next )
783 {
784 if( (type = ucix_get_option(uci, "network", e->name, NULL)) != NULL )
785 {
786 if( !(ifname = ucix_get_option(uci, "network", e->name, "ifname")) )
787 fwd_read_error(
788 "section '%s' is missing 'ifname' option!",
789 e->name
790 );
791
792 e->isalias = (strcmp(type, "alias") ? 0 : 1);
793 e->ifname = strdup(ifname);
794 }
795 }
796 }
797
798 static void fwd_read_networks(
799 struct uci_context *uci, struct fwd_data *zones
800 ) {
801 struct fwd_data *e;
802
803 for( e = zones; e; e = e->next )
804 if( e->type == FWD_S_ZONE )
805 fwd_read_network_data(uci, e->section.zone.networks);
806 }
807
808 static void fwd_free_networks(struct fwd_network *h)
809 {
810 struct fwd_network *e = h;
811
812 while( h != NULL )
813 {
814 e = h->next;
815
816 fwd_free_ptr(h->name);
817 fwd_free_ptr(h->ifname);
818 fwd_free_ptr(h->addr);
819
820 free(h);
821 h = e;
822 }
823
824 e = h = NULL;
825 }
826
827 static struct fwd_cidr * fwd_alloc_cidr(struct fwd_cidr *addr)
828 {
829 struct fwd_cidr *cidr;
830
831 if( (cidr = fwd_alloc_ptr(struct fwd_cidr)) != NULL )
832 {
833 if( addr != NULL )
834 {
835 cidr->addr.s_addr = addr->addr.s_addr;
836 cidr->prefix = addr->prefix;
837 }
838
839 return cidr;
840 }
841
842 return NULL;
843 }
844
845
846
847 struct fwd_data * fwd_read_config(struct fwd_handle *h)
848 {
849 struct uci_context *ctx;
850 struct fwd_data *defaults, *zones, *e;
851 struct fwd_addr *addrs;
852 struct fwd_network *net;
853 struct fwd_zone *zone;
854
855 if( (ctx = ucix_init("firewall")) != NULL )
856 {
857 if( !(defaults = fwd_read_defaults(ctx)) )
858 goto error;
859
860 if( !(zones = fwd_read_zones(ctx, defaults)) )
861 goto error;
862
863 fwd_append_config(defaults, zones);
864 fwd_append_config(defaults, fwd_read_forwards(ctx, zones));
865 fwd_append_config(defaults, fwd_read_redirects(ctx, zones));
866 fwd_append_config(defaults, fwd_read_rules(ctx, zones));
867 fwd_append_config(defaults, fwd_read_includes(ctx));
868
869 ucix_cleanup(ctx);
870
871 if( (ctx = ucix_init("network")) != NULL )
872 {
873 fwd_read_networks(ctx, zones);
874 ucix_cleanup(ctx);
875
876 if( !(addrs = fwd_get_addrs(h->rtnl_socket, AF_INET)) )
877 goto error;
878
879 for( e = zones; e && (zone = &e->section.zone); e = e->next )
880 {
881 if( e->type != FWD_S_ZONE )
882 break;
883
884 for( net = zone->networks; net; net = net->next )
885 {
886 net->addr = fwd_alloc_cidr(
887 fwd_lookup_addr(addrs, net->ifname)
888 );
889 }
890 }
891
892 fwd_free_addrs(addrs);
893 return defaults;
894 }
895 }
896
897 error:
898 if( ctx ) ucix_cleanup(ctx);
899 fwd_free_config(defaults);
900 fwd_free_config(zones);
901 return NULL;
902 }
903
904
905 void fwd_free_config(struct fwd_data *h)
906 {
907 struct fwd_data *e = h;
908
909 while( h != NULL )
910 {
911 e = h->next;
912
913 switch(h->type)
914 {
915 case FWD_S_INCLUDE:
916 fwd_free_ptr(h->section.include.path);
917 break;
918
919 case FWD_S_ZONE:
920 fwd_free_ptr(h->section.zone.name);
921 fwd_free_networks(h->section.zone.networks);
922 fwd_free_config(h->section.zone.rules);
923 fwd_free_config(h->section.zone.redirects);
924 fwd_free_config(h->section.zone.forwardings);
925 break;
926
927 case FWD_S_REDIRECT:
928 /* Clone rules share all pointers except proto.
929 Prevent a double-free here */
930 if( ! h->section.redirect.clone )
931 {
932 fwd_free_ptr(h->section.redirect.src_ip);
933 fwd_free_ptr(h->section.redirect.src_mac);
934 fwd_free_ptr(h->section.redirect.src_port);
935 fwd_free_ptr(h->section.redirect.src_dport);
936 fwd_free_ptr(h->section.redirect.dest_ip);
937 fwd_free_ptr(h->section.redirect.dest_port);
938 }
939 fwd_free_ptr(h->section.redirect.proto);
940 break;
941
942 case FWD_S_RULE:
943 /* Clone rules share all pointers except proto.
944 Prevent a double-free here */
945 if( ! h->section.rule.clone )
946 {
947 fwd_free_ptr(h->section.rule.src_ip);
948 fwd_free_ptr(h->section.rule.src_mac);
949 fwd_free_ptr(h->section.rule.src_port);
950 fwd_free_ptr(h->section.rule.dest_ip);
951 fwd_free_ptr(h->section.rule.dest_port);
952 fwd_free_ptr(h->section.rule.icmp_type);
953 }
954 fwd_free_ptr(h->section.rule.proto);
955 break;
956
957 case FWD_S_DEFAULTS:
958 case FWD_S_FORWARD:
959 /* Make gcc happy */
960 break;
961 }
962
963 fwd_free_ptr(h);
964 h = e;
965 }
966
967 e = h = NULL;
968 }
969
970
971 struct fwd_zone *
972 fwd_lookup_zone(struct fwd_data *h, const char *n)
973 {
974 struct fwd_data *e;
975
976 if( n != NULL )
977 {
978 for( e = h; e; e = e->next )
979 {
980 if( (e->type = FWD_S_ZONE) && !strcmp(e->section.zone.name, n) )
981 return &e->section.zone;
982 }
983 }
984
985 return NULL;
986 }
987