ubus: use blobmsg_parse to validate data from network.interface:dump
[project/firewall3.git] / options.c
1 /*
2 * firewall3 - 3rd OpenWrt UCI firewall implementation
3 *
4 * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "options.h"
20 #include "ubus.h"
21
22
23 static bool
24 put_value(void *ptr, void *val, int elem_size, bool is_list)
25 {
26 void *copy;
27
28 if (is_list)
29 {
30 copy = malloc(elem_size);
31
32 if (!copy)
33 return false;
34
35 memcpy(copy, val, elem_size);
36 list_add_tail((struct list_head *)copy, (struct list_head *)ptr);
37 return true;
38 }
39
40 memcpy(ptr, val, elem_size);
41 return false;
42 }
43
44 static bool
45 parse_enum(void *ptr, const char *val, const char **values, int min, int max)
46 {
47 int i, l = strlen(val);
48
49 if (l > 0)
50 {
51 for (i = 0; i <= (max - min); i++)
52 {
53 if (!strncasecmp(val, values[i], l))
54 {
55 *((int *)ptr) = min + i;
56 return true;
57 }
58 }
59 }
60
61 return false;
62 }
63
64
65 const char *fw3_flag_names[__FW3_FLAG_MAX] = {
66 "filter",
67 "nat",
68 "mangle",
69 "raw",
70
71 "IPv4",
72 "IPv6",
73
74 "ACCEPT",
75 "REJECT",
76 "DROP",
77 "NOTRACK",
78 "MARK",
79 "DNAT",
80 "SNAT",
81 "MASQUERADE",
82
83 "ACCEPT",
84 "REJECT",
85 "DROP",
86 };
87
88 const char *fw3_limit_units[__FW3_LIMIT_UNIT_MAX] = {
89 "second",
90 "minute",
91 "hour",
92 "day",
93 };
94
95 const char *fw3_ipset_method_names[__FW3_IPSET_METHOD_MAX] = {
96 "(bug)",
97 "bitmap",
98 "hash",
99 "list",
100 };
101
102 const char *fw3_ipset_type_names[__FW3_IPSET_TYPE_MAX] = {
103 "(bug)",
104 "ip",
105 "port",
106 "mac",
107 "net",
108 "set",
109 };
110
111 static const char *weekdays[] = {
112 "monday",
113 "tuesday",
114 "wednesday",
115 "thursday",
116 "friday",
117 "saturday",
118 "sunday",
119 };
120
121 static const char *include_types[] = {
122 "script",
123 "restore",
124 };
125
126 static const char *reflection_sources[] = {
127 "internal",
128 "external",
129 };
130
131
132 bool
133 fw3_parse_bool(void *ptr, const char *val, bool is_list)
134 {
135 if (!strcmp(val, "true") || !strcmp(val, "yes") || !strcmp(val, "1"))
136 *((bool *)ptr) = true;
137 else
138 *((bool *)ptr) = false;
139
140 return true;
141 }
142
143 bool
144 fw3_parse_int(void *ptr, const char *val, bool is_list)
145 {
146 char *e;
147 int n = strtol(val, &e, 0);
148
149 if (e == val || *e)
150 return false;
151
152 *((int *)ptr) = n;
153
154 return true;
155 }
156
157 bool
158 fw3_parse_string(void *ptr, const char *val, bool is_list)
159 {
160 *((char **)ptr) = (char *)val;
161 return true;
162 }
163
164 bool
165 fw3_parse_target(void *ptr, const char *val, bool is_list)
166 {
167 return parse_enum(ptr, val, &fw3_flag_names[FW3_FLAG_ACCEPT],
168 FW3_FLAG_ACCEPT, FW3_FLAG_MASQUERADE);
169 }
170
171 bool
172 fw3_parse_limit(void *ptr, const char *val, bool is_list)
173 {
174 struct fw3_limit *limit = ptr;
175 enum fw3_limit_unit u = FW3_LIMIT_UNIT_SECOND;
176 char *e;
177 int n;
178
179 if (*val == '!')
180 {
181 limit->invert = true;
182 while (isspace(*++val));
183 }
184
185 n = strtol(val, &e, 10);
186
187 if (errno == ERANGE || errno == EINVAL)
188 return false;
189
190 if (*e && *e++ != '/')
191 return false;
192
193 if (!strlen(e))
194 return false;
195
196 if (!parse_enum(&u, e, fw3_limit_units, 0, FW3_LIMIT_UNIT_DAY))
197 return false;
198
199 limit->rate = n;
200 limit->unit = u;
201
202 return true;
203 }
204
205 bool
206 fw3_parse_device(void *ptr, const char *val, bool is_list)
207 {
208 char *p;
209 struct fw3_device dev = { };
210
211 if (*val == '*')
212 {
213 dev.set = true;
214 dev.any = true;
215 put_value(ptr, &dev, sizeof(dev), is_list);
216 return true;
217 }
218
219 if (*val == '!')
220 {
221 dev.invert = true;
222 while (isspace(*++val));
223 }
224
225 if ((p = strchr(val, '@')) != NULL)
226 {
227 *p++ = 0;
228 snprintf(dev.network, sizeof(dev.network), "%s", p);
229 }
230
231 if (*val)
232 snprintf(dev.name, sizeof(dev.name), "%s", val);
233 else
234 return false;
235
236 dev.set = true;
237 put_value(ptr, &dev, sizeof(dev), is_list);
238 return true;
239 }
240
241 bool
242 fw3_parse_address(void *ptr, const char *val, bool is_list)
243 {
244 struct fw3_address addr = { };
245 struct in_addr v4;
246 struct in6_addr v6;
247 char *p, *s, *e;
248 int i, m = -1;
249
250 if (*val == '!')
251 {
252 addr.invert = true;
253 while (isspace(*++val));
254 }
255
256 s = strdup(val);
257
258 if (!s)
259 return false;
260
261 if ((p = strchr(s, '/')) != NULL)
262 {
263 *p++ = 0;
264 m = strtoul(p, &e, 10);
265
266 if ((e == p) || (*e != 0))
267 {
268 if (strchr(s, ':') || !inet_pton(AF_INET, p, &v4))
269 {
270 free(s);
271 return false;
272 }
273
274 for (i = 0, m = 32; !(v4.s_addr & 1) && (i < 32); i++)
275 {
276 m--;
277 v4.s_addr >>= 1;
278 }
279 }
280 }
281 else if ((p = strchr(s, '-')) != NULL)
282 {
283 *p++ = 0;
284
285 if (inet_pton(AF_INET6, p, &v6))
286 {
287 addr.family = FW3_FAMILY_V6;
288 addr.address2.v6 = v6;
289 addr.range = true;
290 }
291 else if (inet_pton(AF_INET, p, &v4))
292 {
293 addr.family = FW3_FAMILY_V4;
294 addr.address2.v4 = v4;
295 addr.range = true;
296 }
297 else
298 {
299 free(s);
300 return false;
301 }
302 }
303
304 if (inet_pton(AF_INET6, s, &v6))
305 {
306 addr.family = FW3_FAMILY_V6;
307 addr.address.v6 = v6;
308 addr.mask = (m >= 0) ? m : 128;
309 }
310 else if (inet_pton(AF_INET, s, &v4))
311 {
312 addr.family = FW3_FAMILY_V4;
313 addr.address.v4 = v4;
314 addr.mask = (m >= 0) ? m : 32;
315 }
316 else
317 {
318 free(s);
319 return false;
320 }
321
322 free(s);
323 addr.set = true;
324 put_value(ptr, &addr, sizeof(addr), is_list);
325 return true;
326 }
327
328 bool
329 fw3_parse_network(void *ptr, const char *val, bool is_list)
330 {
331 struct fw3_device dev = { };
332 struct fw3_address *addr;
333 struct list_head *addr_list;
334
335 if (!fw3_parse_address(ptr, val, is_list))
336 {
337 if (!fw3_parse_device(&dev, val, false))
338 return false;
339
340 addr_list = fw3_ubus_address(dev.name);
341
342 if (addr_list)
343 {
344 list_for_each_entry(addr, addr_list, list)
345 {
346 addr->invert = dev.invert;
347 addr->resolved = true;
348
349 if (!put_value(ptr, addr, sizeof(*addr), is_list))
350 break;
351 }
352
353 fw3_free_list(addr_list);
354 }
355 }
356
357 return true;
358 }
359
360 bool
361 fw3_parse_mac(void *ptr, const char *val, bool is_list)
362 {
363 struct fw3_mac addr = { };
364 struct ether_addr *mac;
365
366 if (*val == '!')
367 {
368 addr.invert = true;
369 while (isspace(*++val));
370 }
371
372 if ((mac = ether_aton(val)) != NULL)
373 {
374 addr.mac = *mac;
375 addr.set = true;
376
377 put_value(ptr, &addr, sizeof(addr), is_list);
378 return true;
379 }
380
381 return false;
382 }
383
384 bool
385 fw3_parse_port(void *ptr, const char *val, bool is_list)
386 {
387 struct fw3_port range = { };
388 uint16_t n;
389 uint16_t m;
390 char *p;
391
392 if (*val == '!')
393 {
394 range.invert = true;
395 while (isspace(*++val));
396 }
397
398 n = strtoul(val, &p, 10);
399
400 if (errno == ERANGE || errno == EINVAL)
401 return false;
402
403 if (*p && *p != '-' && *p != ':')
404 return false;
405
406 if (*p)
407 {
408 m = strtoul(++p, NULL, 10);
409
410 if (errno == ERANGE || errno == EINVAL || m < n)
411 return false;
412
413 range.port_min = n;
414 range.port_max = m;
415 }
416 else
417 {
418 range.port_min = n;
419 range.port_max = n;
420 }
421
422 range.set = true;
423 put_value(ptr, &range, sizeof(range), is_list);
424 return true;
425 }
426
427 bool
428 fw3_parse_family(void *ptr, const char *val, bool is_list)
429 {
430 if (!strcmp(val, "any"))
431 *((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
432 else if (!strcmp(val, "inet") || strrchr(val, '4'))
433 *((enum fw3_family *)ptr) = FW3_FAMILY_V4;
434 else if (!strcmp(val, "inet6") || strrchr(val, '6'))
435 *((enum fw3_family *)ptr) = FW3_FAMILY_V6;
436 else
437 return false;
438
439 return true;
440 }
441
442 bool
443 fw3_parse_icmptype(void *ptr, const char *val, bool is_list)
444 {
445 struct fw3_icmptype icmp = { };
446 bool v4 = false;
447 bool v6 = false;
448 char *p;
449 int i;
450
451 for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v4); i++)
452 {
453 if (!strcmp(val, fw3_icmptype_list_v4[i].name))
454 {
455 icmp.type = fw3_icmptype_list_v4[i].type;
456 icmp.code_min = fw3_icmptype_list_v4[i].code_min;
457 icmp.code_max = fw3_icmptype_list_v4[i].code_max;
458
459 v4 = true;
460 break;
461 }
462 }
463
464 for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v6); i++)
465 {
466 if (!strcmp(val, fw3_icmptype_list_v6[i].name))
467 {
468 icmp.type6 = fw3_icmptype_list_v6[i].type;
469 icmp.code6_min = fw3_icmptype_list_v6[i].code_min;
470 icmp.code6_max = fw3_icmptype_list_v6[i].code_max;
471
472 v6 = true;
473 break;
474 }
475 }
476
477 if (!v4 && !v6)
478 {
479 i = strtoul(val, &p, 10);
480
481 if ((p == val) || (*p != '/' && *p != 0) || (i > 0xFF))
482 return false;
483
484 icmp.type = i;
485
486 if (*p == '/')
487 {
488 val = ++p;
489 i = strtoul(val, &p, 10);
490
491 if ((p == val) || (*p != 0) || (i > 0xFF))
492 return false;
493
494 icmp.code_min = i;
495 icmp.code_max = i;
496 }
497 else
498 {
499 icmp.code_min = 0;
500 icmp.code_max = 0xFF;
501 }
502
503 icmp.type6 = icmp.type;
504 icmp.code6_min = icmp.code_max;
505 icmp.code6_max = icmp.code_max;
506
507 v4 = true;
508 v6 = true;
509 }
510
511 icmp.family = (v4 && v6) ? FW3_FAMILY_ANY
512 : (v6 ? FW3_FAMILY_V6 : FW3_FAMILY_V4);
513
514 put_value(ptr, &icmp, sizeof(icmp), is_list);
515 return true;
516 }
517
518 bool
519 fw3_parse_protocol(void *ptr, const char *val, bool is_list)
520 {
521 struct fw3_protocol proto = { };
522 struct protoent *ent;
523 char *e;
524
525 if (*val == '!')
526 {
527 proto.invert = true;
528 while (isspace(*++val));
529 }
530
531 if (!strcmp(val, "all"))
532 {
533 proto.any = true;
534 put_value(ptr, &proto, sizeof(proto), is_list);
535 return true;
536 }
537 else if (!strcmp(val, "icmpv6"))
538 {
539 val = "ipv6-icmp";
540 }
541 else if (!strcmp(val, "tcpudp"))
542 {
543 proto.protocol = 6;
544 if (put_value(ptr, &proto, sizeof(proto), is_list))
545 {
546 proto.protocol = 17;
547 put_value(ptr, &proto, sizeof(proto), is_list);
548 }
549
550 return true;
551 }
552
553 ent = getprotobyname(val);
554
555 if (ent)
556 {
557 proto.protocol = ent->p_proto;
558 put_value(ptr, &proto, sizeof(proto), is_list);
559 return true;
560 }
561
562 proto.protocol = strtoul(val, &e, 10);
563
564 if ((e == val) || (*e != 0))
565 return false;
566
567 put_value(ptr, &proto, sizeof(proto), is_list);
568 return true;
569 }
570
571 bool
572 fw3_parse_ipset_method(void *ptr, const char *val, bool is_list)
573 {
574 return parse_enum(ptr, val, &fw3_ipset_method_names[FW3_IPSET_METHOD_BITMAP],
575 FW3_IPSET_METHOD_BITMAP, FW3_IPSET_METHOD_LIST);
576 }
577
578 bool
579 fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list)
580 {
581 struct fw3_ipset_datatype type = { };
582
583 type.dir = "src";
584
585 if (!strncmp(val, "dest_", 5))
586 {
587 val += 5;
588 type.dir = "dst";
589 }
590 else if (!strncmp(val, "dst_", 4))
591 {
592 val += 4;
593 type.dir = "dst";
594 }
595 else if (!strncmp(val, "src_", 4))
596 {
597 val += 4;
598 type.dir = "src";
599 }
600
601 if (parse_enum(&type.type, val, &fw3_ipset_type_names[FW3_IPSET_TYPE_IP],
602 FW3_IPSET_TYPE_IP, FW3_IPSET_TYPE_SET))
603 {
604 put_value(ptr, &type, sizeof(type), is_list);
605 return true;
606 }
607
608 return false;
609 }
610
611 bool
612 fw3_parse_date(void *ptr, const char *val, bool is_list)
613 {
614 unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0;
615 struct tm tm = { 0 };
616 char *p;
617
618 year = strtoul(val, &p, 10);
619 if ((*p != '-' && *p) || year < 1970 || year > 2038)
620 goto fail;
621 else if (!*p)
622 goto ret;
623
624 mon = strtoul(++p, &p, 10);
625 if ((*p != '-' && *p) || mon > 12)
626 goto fail;
627 else if (!*p)
628 goto ret;
629
630 day = strtoul(++p, &p, 10);
631 if ((*p != 'T' && *p) || day > 31)
632 goto fail;
633 else if (!*p)
634 goto ret;
635
636 hour = strtoul(++p, &p, 10);
637 if ((*p != ':' && *p) || hour > 23)
638 goto fail;
639 else if (!*p)
640 goto ret;
641
642 min = strtoul(++p, &p, 10);
643 if ((*p != ':' && *p) || min > 59)
644 goto fail;
645 else if (!*p)
646 goto ret;
647
648 sec = strtoul(++p, &p, 10);
649 if (*p || sec > 59)
650 goto fail;
651
652 ret:
653 tm.tm_year = year - 1900;
654 tm.tm_mon = mon - 1;
655 tm.tm_mday = day;
656 tm.tm_hour = hour;
657 tm.tm_min = min;
658 tm.tm_sec = sec;
659
660 if (mktime(&tm) >= 0)
661 {
662 *((struct tm *)ptr) = tm;
663 return true;
664 }
665
666 fail:
667 return false;
668 }
669
670 bool
671 fw3_parse_time(void *ptr, const char *val, bool is_list)
672 {
673 unsigned int hour = 0, min = 0, sec = 0;
674 char *p;
675
676 hour = strtoul(val, &p, 10);
677 if (*p != ':' || hour > 23)
678 goto fail;
679
680 min = strtoul(++p, &p, 10);
681 if ((*p != ':' && *p) || min > 59)
682 goto fail;
683 else if (!*p)
684 goto ret;
685
686 sec = strtoul(++p, &p, 10);
687 if (*p || sec > 59)
688 goto fail;
689
690 ret:
691 *((int *)ptr) = 60 * 60 * hour + 60 * min + sec;
692 return true;
693
694 fail:
695 return false;
696 }
697
698 bool
699 fw3_parse_weekdays(void *ptr, const char *val, bool is_list)
700 {
701 unsigned int w = 0;
702 char *p, *s;
703
704 if (*val == '!')
705 {
706 setbit(*(uint8_t *)ptr, 0);
707 while (isspace(*++val));
708 }
709
710 if (!(s = strdup(val)))
711 return false;
712
713 for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
714 {
715 if (!parse_enum(&w, p, weekdays, 1, 7))
716 {
717 w = strtoul(p, &p, 10);
718
719 if (*p || w < 1 || w > 7)
720 {
721 free(s);
722 return false;
723 }
724 }
725
726 setbit(*(uint8_t *)ptr, w);
727 }
728
729 free(s);
730 return true;
731 }
732
733 bool
734 fw3_parse_monthdays(void *ptr, const char *val, bool is_list)
735 {
736 unsigned int d;
737 char *p, *s;
738
739 if (*val == '!')
740 {
741 setbit(*(uint32_t *)ptr, 0);
742 while (isspace(*++val));
743 }
744
745 if (!(s = strdup(val)))
746 return false;
747
748 for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
749 {
750 d = strtoul(p, &p, 10);
751
752 if (*p || d < 1 || d > 31)
753 {
754 free(s);
755 return false;
756 }
757
758 setbit(*(uint32_t *)ptr, d);
759 }
760
761 free(s);
762 return true;
763 }
764
765 bool
766 fw3_parse_include_type(void *ptr, const char *val, bool is_list)
767 {
768 return parse_enum(ptr, val, include_types,
769 FW3_INC_TYPE_SCRIPT, FW3_INC_TYPE_RESTORE);
770 }
771
772 bool
773 fw3_parse_reflection_source(void *ptr, const char *val, bool is_list)
774 {
775 return parse_enum(ptr, val, reflection_sources,
776 FW3_REFLECTION_INTERNAL, FW3_REFLECTION_EXTERNAL);
777 }
778
779 bool
780 fw3_parse_mark(void *ptr, const char *val, bool is_list)
781 {
782 uint32_t n;
783 char *s, *e;
784 struct fw3_mark *m = ptr;
785
786 if (*val == '!')
787 {
788 m->invert = true;
789 while (isspace(*++val));
790 }
791
792 if ((s = strchr(val, '/')) != NULL)
793 *s++ = 0;
794
795 n = strtoul(val, &e, 0);
796
797 if (e == val || *e)
798 return false;
799
800 m->mark = n;
801 m->mask = 0xFFFFFFFF;
802
803 if (s)
804 {
805 n = strtoul(s, &e, 0);
806
807 if (e == s || *e)
808 return false;
809
810 m->mask = n;
811 }
812
813 m->set = true;
814 return true;
815 }
816
817 bool
818 fw3_parse_setmatch(void *ptr, const char *val, bool is_list)
819 {
820 struct fw3_setmatch *m = ptr;
821 char *p, *s;
822 int i;
823
824 if (*val == '!')
825 {
826 m->invert = true;
827 while (isspace(*++val));
828 }
829
830 if (!(s = strdup(val)))
831 return false;
832
833 if (!(p = strtok(s, " \t")))
834 {
835 free(s);
836 return false;
837 }
838
839 strncpy(m->name, p, sizeof(m->name));
840
841 for (i = 0, p = strtok(NULL, " \t,");
842 i < 3 && p != NULL;
843 i++, p = strtok(NULL, " \t,"))
844 {
845 if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3))
846 m->dir[i] = "dst";
847 else if (!strncmp(p, "src", 3))
848 m->dir[i] = "src";
849 }
850
851 free(s);
852
853 m->set = true;
854 return true;
855 }
856
857 bool
858 fw3_parse_direction(void *ptr, const char *val, bool is_list)
859 {
860 bool *is_out = ptr;
861 bool valid = true;
862
863 if (!strcmp(val, "in") || !strcmp(val, "ingress"))
864 *is_out = false;
865 else if (!strcmp(val, "out") || !strcmp(val, "egress"))
866 *is_out = true;
867 else
868 valid = false;
869
870 return valid;
871 }
872
873
874 bool
875 fw3_parse_options(void *s, const struct fw3_option *opts,
876 struct uci_section *section)
877 {
878 char *p, *v;
879 bool known;
880 struct uci_element *e, *l;
881 struct uci_option *o;
882 const struct fw3_option *opt;
883 struct list_head *dest;
884 bool valid = true;
885
886 uci_foreach_element(&section->options, e)
887 {
888 o = uci_to_option(e);
889 known = false;
890
891 for (opt = opts; opt->name; opt++)
892 {
893 if (!opt->parse)
894 continue;
895
896 if (strcmp(opt->name, e->name))
897 continue;
898
899 if (o->type == UCI_TYPE_LIST)
900 {
901 if (!opt->elem_size)
902 {
903 warn_elem(e, "must not be a list");
904 valid = false;
905 }
906 else
907 {
908 dest = (struct list_head *)((char *)s + opt->offset);
909
910 uci_foreach_element(&o->v.list, l)
911 {
912 if (!l->name)
913 continue;
914
915 if (!opt->parse(dest, l->name, true))
916 {
917 warn_elem(e, "has invalid value '%s'", l->name);
918 valid = false;
919 continue;
920 }
921 }
922 }
923 }
924 else
925 {
926 v = o->v.string;
927
928 if (!v)
929 continue;
930
931 if (!opt->elem_size)
932 {
933 if (!opt->parse((char *)s + opt->offset, o->v.string, false))
934 {
935 warn_elem(e, "has invalid value '%s'", o->v.string);
936 valid = false;
937 }
938 }
939 else
940 {
941 dest = (struct list_head *)((char *)s + opt->offset);
942
943 for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
944 {
945 if (!opt->parse(dest, p, true))
946 {
947 warn_elem(e, "has invalid value '%s'", p);
948 valid = false;
949 continue;
950 }
951 }
952 }
953 }
954
955 known = true;
956 break;
957 }
958
959 if (!known)
960 warn_elem(e, "is unknown");
961 }
962
963 return valid;
964 }
965
966
967 bool
968 fw3_parse_blob_options(void *s, const struct fw3_option *opts,
969 struct blob_attr *a)
970 {
971 char *p, *v, buf[16];
972 bool known;
973 unsigned rem, erem;
974 struct blob_attr *o, *e;
975 const struct fw3_option *opt;
976 struct list_head *dest;
977 bool valid = true;
978
979 blobmsg_for_each_attr(o, a, rem)
980 {
981 known = false;
982
983 for (opt = opts; opt->name; opt++)
984 {
985 if (!opt->parse)
986 continue;
987
988 if (strcmp(opt->name, blobmsg_name(o)))
989 continue;
990
991 if (blobmsg_type(o) == BLOBMSG_TYPE_ARRAY)
992 {
993 if (!opt->elem_size)
994 {
995 fprintf(stderr, "%s must not be a list\n", opt->name);
996 valid = false;
997 }
998 else
999 {
1000 dest = (struct list_head *)((char *)s + opt->offset);
1001
1002 blobmsg_for_each_attr(e, o, erem)
1003 {
1004 if (blobmsg_type(e) == BLOBMSG_TYPE_INT32) {
1005 snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(e));
1006 v = buf;
1007 } else {
1008 v = blobmsg_get_string(e);
1009 }
1010
1011 if (!opt->parse(dest, v, true))
1012 {
1013 fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
1014 valid = false;
1015 continue;
1016 }
1017 }
1018 }
1019 }
1020 else
1021 {
1022 if (blobmsg_type(o) == BLOBMSG_TYPE_INT32) {
1023 snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(o));
1024 v = buf;
1025 } else {
1026 v = blobmsg_get_string(o);
1027 }
1028
1029 if (!v)
1030 continue;
1031
1032 if (!opt->elem_size)
1033 {
1034 if (!opt->parse((char *)s + opt->offset, v, false))
1035 {
1036 fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
1037 valid = false;
1038 }
1039 }
1040 else
1041 {
1042 dest = (struct list_head *)((char *)s + opt->offset);
1043
1044 for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
1045 {
1046 if (!opt->parse(dest, p, true))
1047 {
1048 fprintf(stderr, "%s has invalid value '%s'\n", opt->name, p);
1049 valid = false;
1050 continue;
1051 }
1052 }
1053 }
1054 }
1055
1056 known = true;
1057 break;
1058 }
1059
1060 if (!known)
1061 fprintf(stderr, "%s is unknown\n", blobmsg_name(o));
1062 }
1063
1064 return valid;
1065 }
1066
1067
1068 const char *
1069 fw3_address_to_string(struct fw3_address *address, bool allow_invert)
1070 {
1071 char *p, ip[INET6_ADDRSTRLEN];
1072 static char buf[INET6_ADDRSTRLEN * 2 + 2];
1073
1074 p = buf;
1075
1076 if (address->invert && allow_invert)
1077 p += sprintf(p, "!");
1078
1079 inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
1080 &address->address.v4, ip, sizeof(ip));
1081
1082 p += sprintf(p, "%s", ip);
1083
1084 if (address->range)
1085 {
1086 inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
1087 &address->address2.v4, ip, sizeof(ip));
1088
1089 p += sprintf(p, "-%s", ip);
1090 }
1091 else
1092 {
1093 p += sprintf(p, "/%u", address->mask);
1094 }
1095
1096 return buf;
1097 }