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