7e62ca694f0eb141cc7c43cc5c1e9fa1fa7db38d
[project/firewall3.git] / options.c
1 /*
2  * firewall3 - 3rd OpenWrt UCI firewall implementation
3  *
4  *   Copyright (C) 2013 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
82         "ACCEPT",
83         "REJECT",
84         "DROP",
85 };
86
87 const char *fw3_limit_units[__FW3_LIMIT_UNIT_MAX] = {
88         "second",
89         "minute",
90         "hour",
91         "day",
92 };
93
94 const char *fw3_ipset_method_names[__FW3_IPSET_METHOD_MAX] = {
95         "(bug)",
96         "bitmap",
97         "hash",
98         "list",
99 };
100
101 const char *fw3_ipset_type_names[__FW3_IPSET_TYPE_MAX] = {
102         "(bug)",
103         "ip",
104         "port",
105         "mac",
106         "net",
107         "set",
108 };
109
110 static const char *weekdays[] = {
111         "monday",
112         "tuesday",
113         "wednesday",
114         "thursday",
115         "friday",
116         "saturday",
117         "sunday",
118 };
119
120 static const char *include_types[] = {
121         "script",
122         "restore",
123 };
124
125 static const char *reflection_sources[] = {
126         "internal",
127         "external",
128 };
129
130
131 bool
132 fw3_parse_bool(void *ptr, const char *val, bool is_list)
133 {
134         if (!strcmp(val, "true") || !strcmp(val, "yes") || !strcmp(val, "1"))
135                 *((bool *)ptr) = true;
136         else
137                 *((bool *)ptr) = false;
138
139         return true;
140 }
141
142 bool
143 fw3_parse_int(void *ptr, const char *val, bool is_list)
144 {
145         char *e;
146         int n = strtol(val, &e, 0);
147
148         if (e == val || *e)
149                 return false;
150
151         *((int *)ptr) = n;
152
153         return true;
154 }
155
156 bool
157 fw3_parse_string(void *ptr, const char *val, bool is_list)
158 {
159         *((char **)ptr) = (char *)val;
160         return true;
161 }
162
163 bool
164 fw3_parse_target(void *ptr, const char *val, bool is_list)
165 {
166         return parse_enum(ptr, val, &fw3_flag_names[FW3_FLAG_ACCEPT],
167                           FW3_FLAG_ACCEPT, FW3_FLAG_SNAT);
168 }
169
170 bool
171 fw3_parse_limit(void *ptr, const char *val, bool is_list)
172 {
173         struct fw3_limit *limit = ptr;
174         enum fw3_limit_unit u = FW3_LIMIT_UNIT_SECOND;
175         char *e;
176         int n;
177
178         if (*val == '!')
179         {
180                 limit->invert = true;
181                 while (isspace(*++val));
182         }
183
184         n = strtol(val, &e, 10);
185
186         if (errno == ERANGE || errno == EINVAL)
187                 return false;
188
189         if (*e && *e++ != '/')
190                 return false;
191
192         if (!strlen(e))
193                 return false;
194
195         if (!parse_enum(&u, e, fw3_limit_units, 0, FW3_LIMIT_UNIT_DAY))
196                 return false;
197
198         limit->rate = n;
199         limit->unit = u;
200
201         return true;
202 }
203
204 bool
205 fw3_parse_device(void *ptr, const char *val, bool is_list)
206 {
207         char *p;
208         struct fw3_device dev = { };
209
210         if (*val == '*')
211         {
212                 dev.set = true;
213                 dev.any = true;
214                 put_value(ptr, &dev, sizeof(dev), is_list);
215                 return true;
216         }
217
218         if (*val == '!')
219         {
220                 dev.invert = true;
221                 while (isspace(*++val));
222         }
223
224         if ((p = strchr(val, '@')) != NULL)
225         {
226                 *p++ = 0;
227                 snprintf(dev.network, sizeof(dev.network), "%s", p);
228         }
229
230         if (*val)
231                 snprintf(dev.name, sizeof(dev.name), "%s", val);
232         else
233                 return false;
234
235         dev.set = true;
236         put_value(ptr, &dev, sizeof(dev), is_list);
237         return true;
238 }
239
240 bool
241 fw3_parse_address(void *ptr, const char *val, bool is_list)
242 {
243         struct fw3_address addr = { };
244         struct in_addr v4;
245         struct in6_addr v6;
246         char *p, *s, *e;
247         int i, m = -1;
248
249         if (*val == '!')
250         {
251                 addr.invert = true;
252                 while (isspace(*++val));
253         }
254
255         s = strdup(val);
256
257         if (!s)
258                 return false;
259
260         if ((p = strchr(s, '/')) != NULL)
261         {
262                 *p++ = 0;
263                 m = strtoul(p, &e, 10);
264
265                 if ((e == p) || (*e != 0))
266                 {
267                         if (strchr(s, ':') || !inet_pton(AF_INET, p, &v4))
268                         {
269                                 free(s);
270                                 return false;
271                         }
272
273                         for (i = 0, m = 32; !(v4.s_addr & 1) && (i < 32); i++)
274                         {
275                                 m--;
276                                 v4.s_addr >>= 1;
277                         }
278                 }
279         }
280         else if ((p = strchr(s, '-')) != NULL)
281         {
282                 *p++ = 0;
283
284                 if (inet_pton(AF_INET6, p, &v6))
285                 {
286                         addr.family = FW3_FAMILY_V6;
287                         addr.address2.v6 = v6;
288                         addr.range = true;
289                 }
290                 else if (inet_pton(AF_INET, p, &v4))
291                 {
292                         addr.family = FW3_FAMILY_V4;
293                         addr.address2.v4 = v4;
294                         addr.range = true;
295                 }
296                 else
297                 {
298                         free(s);
299                         return false;
300                 }
301         }
302
303         if (inet_pton(AF_INET6, s, &v6))
304         {
305                 addr.family = FW3_FAMILY_V6;
306                 addr.address.v6 = v6;
307                 addr.mask = (m >= 0) ? m : 128;
308         }
309         else if (inet_pton(AF_INET, s, &v4))
310         {
311                 addr.family = FW3_FAMILY_V4;
312                 addr.address.v4 = v4;
313                 addr.mask = (m >= 0) ? m : 32;
314         }
315         else
316         {
317                 free(s);
318                 return false;
319         }
320
321         free(s);
322         addr.set = true;
323         put_value(ptr, &addr, sizeof(addr), is_list);
324         return true;
325 }
326
327 bool
328 fw3_parse_network(void *ptr, const char *val, bool is_list)
329 {
330         struct fw3_device dev = { };
331         struct fw3_address *addr;
332         struct list_head *addr_list;
333
334         if (!fw3_parse_address(ptr, val, is_list))
335         {
336                 if (!fw3_parse_device(&dev, val, false))
337                         return false;
338
339                 addr_list = fw3_ubus_address(dev.name);
340
341                 if (addr_list)
342                 {
343                         list_for_each_entry(addr, addr_list, list)
344                         {
345                                 addr->invert = dev.invert;
346                                 addr->resolved = true;
347
348                                 if (!put_value(ptr, addr, sizeof(*addr), is_list))
349                                         break;
350                         }
351
352                         fw3_free_list(addr_list);
353                 }
354         }
355
356         return true;
357 }
358
359 bool
360 fw3_parse_mac(void *ptr, const char *val, bool is_list)
361 {
362         struct fw3_mac addr = { };
363         struct ether_addr *mac;
364
365         if (*val == '!')
366         {
367                 addr.invert = true;
368                 while (isspace(*++val));
369         }
370
371         if ((mac = ether_aton(val)) != NULL)
372         {
373                 addr.mac = *mac;
374                 addr.set = true;
375
376                 put_value(ptr, &addr, sizeof(addr), is_list);
377                 return true;
378         }
379
380         return false;
381 }
382
383 bool
384 fw3_parse_port(void *ptr, const char *val, bool is_list)
385 {
386         struct fw3_port range = { };
387         uint16_t n;
388         uint16_t m;
389         char *p;
390
391         if (*val == '!')
392         {
393                 range.invert = true;
394                 while (isspace(*++val));
395         }
396
397         n = strtoul(val, &p, 10);
398
399         if (errno == ERANGE || errno == EINVAL)
400                 return false;
401
402         if (*p && *p != '-' && *p != ':')
403                 return false;
404
405         if (*p)
406         {
407                 m = strtoul(++p, NULL, 10);
408
409                 if (errno == ERANGE || errno == EINVAL || m < n)
410                         return false;
411
412                 range.port_min = n;
413                 range.port_max = m;
414         }
415         else
416         {
417                 range.port_min = n;
418                 range.port_max = n;
419         }
420
421         range.set = true;
422         put_value(ptr, &range, sizeof(range), is_list);
423         return true;
424 }
425
426 bool
427 fw3_parse_family(void *ptr, const char *val, bool is_list)
428 {
429         if (!strcmp(val, "any"))
430                 *((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
431         else if (!strcmp(val, "inet") || strrchr(val, '4'))
432                 *((enum fw3_family *)ptr) = FW3_FAMILY_V4;
433         else if (!strcmp(val, "inet6") || strrchr(val, '6'))
434                 *((enum fw3_family *)ptr) = FW3_FAMILY_V6;
435         else
436                 return false;
437
438         return true;
439 }
440
441 bool
442 fw3_parse_icmptype(void *ptr, const char *val, bool is_list)
443 {
444         struct fw3_icmptype icmp = { };
445         bool v4 = false;
446         bool v6 = false;
447         char *p;
448         int i;
449
450         for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v4); i++)
451         {
452                 if (!strcmp(val, fw3_icmptype_list_v4[i].name))
453                 {
454                         icmp.type     = fw3_icmptype_list_v4[i].type;
455                         icmp.code_min = fw3_icmptype_list_v4[i].code_min;
456                         icmp.code_max = fw3_icmptype_list_v4[i].code_max;
457
458                         v4 = true;
459                         break;
460                 }
461         }
462
463         for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v6); i++)
464         {
465                 if (!strcmp(val, fw3_icmptype_list_v6[i].name))
466                 {
467                         icmp.type6     = fw3_icmptype_list_v6[i].type;
468                         icmp.code6_min = fw3_icmptype_list_v6[i].code_min;
469                         icmp.code6_max = fw3_icmptype_list_v6[i].code_max;
470
471                         v6 = true;
472                         break;
473                 }
474         }
475
476         if (!v4 && !v6)
477         {
478                 i = strtoul(val, &p, 10);
479
480                 if ((p == val) || (*p != '/' && *p != 0) || (i > 0xFF))
481                         return false;
482
483                 icmp.type = i;
484
485                 if (*p == '/')
486                 {
487                         val = ++p;
488                         i = strtoul(val, &p, 10);
489
490                         if ((p == val) || (*p != 0) || (i > 0xFF))
491                                 return false;
492
493                         icmp.code_min = i;
494                         icmp.code_max = i;
495                 }
496                 else
497                 {
498                         icmp.code_min = 0;
499                         icmp.code_max = 0xFF;
500                 }
501
502                 icmp.type6     = icmp.type;
503                 icmp.code6_min = icmp.code_max;
504                 icmp.code6_max = icmp.code_max;
505
506                 v4 = true;
507                 v6 = true;
508         }
509
510         icmp.family = (v4 && v6) ? FW3_FAMILY_ANY
511                                  : (v6 ? FW3_FAMILY_V6 : FW3_FAMILY_V4);
512
513         put_value(ptr, &icmp, sizeof(icmp), is_list);
514         return true;
515 }
516
517 bool
518 fw3_parse_protocol(void *ptr, const char *val, bool is_list)
519 {
520         struct fw3_protocol proto = { };
521         struct protoent *ent;
522         char *e;
523
524         if (*val == '!')
525         {
526                 proto.invert = true;
527                 while (isspace(*++val));
528         }
529
530         if (!strcmp(val, "all"))
531         {
532                 proto.any = true;
533                 put_value(ptr, &proto, sizeof(proto), is_list);
534                 return true;
535         }
536         else if (!strcmp(val, "icmpv6"))
537         {
538                 val = "ipv6-icmp";
539         }
540         else if (!strcmp(val, "tcpudp"))
541         {
542                 proto.protocol = 6;
543                 if (put_value(ptr, &proto, sizeof(proto), is_list))
544                 {
545                         proto.protocol = 17;
546                         put_value(ptr, &proto, sizeof(proto), is_list);
547                 }
548
549                 return true;
550         }
551
552         ent = getprotobyname(val);
553
554         if (ent)
555         {
556                 proto.protocol = ent->p_proto;
557                 put_value(ptr, &proto, sizeof(proto), is_list);
558                 return true;
559         }
560
561         proto.protocol = strtoul(val, &e, 10);
562
563         if ((e == val) || (*e != 0))
564                 return false;
565
566         put_value(ptr, &proto, sizeof(proto), is_list);
567         return true;
568 }
569
570 bool
571 fw3_parse_ipset_method(void *ptr, const char *val, bool is_list)
572 {
573         return parse_enum(ptr, val, &fw3_ipset_method_names[FW3_IPSET_METHOD_BITMAP],
574                           FW3_IPSET_METHOD_BITMAP, FW3_IPSET_METHOD_LIST);
575 }
576
577 bool
578 fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list)
579 {
580         struct fw3_ipset_datatype type = { };
581
582         type.dir = "src";
583
584         if (!strncmp(val, "dest_", 5))
585         {
586                 val += 5;
587                 type.dir = "dst";
588         }
589         else if (!strncmp(val, "dst_", 4))
590         {
591                 val += 4;
592                 type.dir = "dst";
593         }
594         else if (!strncmp(val, "src_", 4))
595         {
596                 val += 4;
597                 type.dir = "src";
598         }
599
600         if (parse_enum(&type.type, val, &fw3_ipset_type_names[FW3_IPSET_TYPE_IP],
601                        FW3_IPSET_TYPE_IP, FW3_IPSET_TYPE_SET))
602         {
603                 put_value(ptr, &type, sizeof(type), is_list);
604                 return true;
605         }
606
607         return false;
608 }
609
610 bool
611 fw3_parse_date(void *ptr, const char *val, bool is_list)
612 {
613         unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0;
614         struct tm tm = { 0 };
615         char *p;
616
617         year = strtoul(val, &p, 10);
618         if ((*p != '-' && *p) || year < 1970 || year > 2038)
619                 goto fail;
620         else if (!*p)
621                 goto ret;
622
623         mon = strtoul(++p, &p, 10);
624         if ((*p != '-' && *p) || mon > 12)
625                 goto fail;
626         else if (!*p)
627                 goto ret;
628
629         day = strtoul(++p, &p, 10);
630         if ((*p != 'T' && *p) || day > 31)
631                 goto fail;
632         else if (!*p)
633                 goto ret;
634
635         hour = strtoul(++p, &p, 10);
636         if ((*p != ':' && *p) || hour > 23)
637                 goto fail;
638         else if (!*p)
639                 goto ret;
640
641         min = strtoul(++p, &p, 10);
642         if ((*p != ':' && *p) || min > 59)
643                 goto fail;
644         else if (!*p)
645                 goto ret;
646
647         sec = strtoul(++p, &p, 10);
648         if (*p || sec > 59)
649                 goto fail;
650
651 ret:
652         tm.tm_year = year - 1900;
653         tm.tm_mon  = mon - 1;
654         tm.tm_mday = day;
655         tm.tm_hour = hour;
656         tm.tm_min  = min;
657         tm.tm_sec  = sec;
658
659         if (mktime(&tm) >= 0)
660         {
661                 *((struct tm *)ptr) = tm;
662                 return true;
663         }
664
665 fail:
666         return false;
667 }
668
669 bool
670 fw3_parse_time(void *ptr, const char *val, bool is_list)
671 {
672         unsigned int hour = 0, min = 0, sec = 0;
673         char *p;
674
675         hour = strtoul(val, &p, 10);
676         if (*p != ':' || hour > 23)
677                 goto fail;
678
679         min = strtoul(++p, &p, 10);
680         if ((*p != ':' && *p) || min > 59)
681                 goto fail;
682         else if (!*p)
683                 goto ret;
684
685         sec = strtoul(++p, &p, 10);
686         if (*p || sec > 59)
687                 goto fail;
688
689 ret:
690         *((int *)ptr) = 60 * 60 * hour + 60 * min + sec;
691         return true;
692
693 fail:
694         return false;
695 }
696
697 bool
698 fw3_parse_weekdays(void *ptr, const char *val, bool is_list)
699 {
700         unsigned int w = 0;
701         char *p, *s;
702
703         if (*val == '!')
704         {
705                 setbit(*(uint8_t *)ptr, 0);
706                 while (isspace(*++val));
707         }
708
709         if (!(s = strdup(val)))
710                 return false;
711
712         for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
713         {
714                 if (!parse_enum(&w, p, weekdays, 1, 7))
715                 {
716                         w = strtoul(p, &p, 10);
717
718                         if (*p || w < 1 || w > 7)
719                         {
720                                 free(s);
721                                 return false;
722                         }
723                 }
724
725                 setbit(*(uint8_t *)ptr, w);
726         }
727
728         free(s);
729         return true;
730 }
731
732 bool
733 fw3_parse_monthdays(void *ptr, const char *val, bool is_list)
734 {
735         unsigned int d;
736         char *p, *s;
737
738         if (*val == '!')
739         {
740                 setbit(*(uint32_t *)ptr, 0);
741                 while (isspace(*++val));
742         }
743
744         if (!(s = strdup(val)))
745                 return false;
746
747         for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t"))
748         {
749                 d = strtoul(p, &p, 10);
750
751                 if (*p || d < 1 || d > 31)
752                 {
753                         free(s);
754                         return false;
755                 }
756
757                 setbit(*(uint32_t *)ptr, d);
758         }
759
760         free(s);
761         return true;
762 }
763
764 bool
765 fw3_parse_include_type(void *ptr, const char *val, bool is_list)
766 {
767         return parse_enum(ptr, val, include_types,
768                           FW3_INC_TYPE_SCRIPT, FW3_INC_TYPE_RESTORE);
769 }
770
771 bool
772 fw3_parse_reflection_source(void *ptr, const char *val, bool is_list)
773 {
774         return parse_enum(ptr, val, reflection_sources,
775                           FW3_REFLECTION_INTERNAL, FW3_REFLECTION_EXTERNAL);
776 }
777
778 bool
779 fw3_parse_mark(void *ptr, const char *val, bool is_list)
780 {
781         uint32_t n;
782         char *s, *e;
783         struct fw3_mark *m = ptr;
784
785         if (*val == '!')
786         {
787                 m->invert = true;
788                 while (isspace(*++val));
789         }
790
791         if ((s = strchr(val, '/')) != NULL)
792                 *s++ = 0;
793
794         n = strtoul(val, &e, 0);
795
796         if (e == val || *e)
797                 return false;
798
799         m->mark = n;
800         m->mask = 0xFFFFFFFF;
801
802         if (s)
803         {
804                 n = strtoul(s, &e, 0);
805
806                 if (e == s || *e)
807                         return false;
808
809                 m->mask = n;
810         }
811
812         m->set = true;
813         return true;
814 }
815
816 bool
817 fw3_parse_setmatch(void *ptr, const char *val, bool is_list)
818 {
819         struct fw3_setmatch *m = ptr;
820         char *p, *s;
821         int i;
822
823         if (*val == '!')
824         {
825                 m->invert = true;
826                 while (isspace(*++val));
827         }
828
829         if (!(s = strdup(val)))
830                 return false;
831
832         if (!(p = strtok(s, " \t")))
833         {
834                 free(s);
835                 return false;
836         }
837
838         strncpy(m->name, p, sizeof(m->name));
839
840         for (i = 0, p = strtok(NULL, " \t,");
841              i < 3 && p != NULL;
842              i++, p = strtok(NULL, " \t,"))
843         {
844                 if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3))
845                         m->dir[i] = "dst";
846                 else if (!strncmp(p, "src", 3))
847                         m->dir[i] = "src";
848         }
849
850         free(s);
851
852         m->set = true;
853         return true;
854 }
855
856
857 bool
858 fw3_parse_options(void *s, const struct fw3_option *opts,
859                   struct uci_section *section)
860 {
861         char *p, *v;
862         bool known;
863         struct uci_element *e, *l;
864         struct uci_option *o;
865         const struct fw3_option *opt;
866         struct list_head *dest;
867         bool valid = true;
868
869         uci_foreach_element(&section->options, e)
870         {
871                 o = uci_to_option(e);
872                 known = false;
873
874                 for (opt = opts; opt->name; opt++)
875                 {
876                         if (!opt->parse)
877                                 continue;
878
879                         if (strcmp(opt->name, e->name))
880                                 continue;
881
882                         if (o->type == UCI_TYPE_LIST)
883                         {
884                                 if (!opt->elem_size)
885                                 {
886                                         warn_elem(e, "must not be a list");
887                                         valid = false;
888                                 }
889                                 else
890                                 {
891                                         dest = (struct list_head *)((char *)s + opt->offset);
892
893                                         uci_foreach_element(&o->v.list, l)
894                                         {
895                                                 if (!l->name)
896                                                         continue;
897
898                                                 if (!opt->parse(dest, l->name, true))
899                                                 {
900                                                         warn_elem(e, "has invalid value '%s'", l->name);
901                                                         valid = false;
902                                                         continue;
903                                                 }
904                                         }
905                                 }
906                         }
907                         else
908                         {
909                                 v = o->v.string;
910
911                                 if (!v)
912                                         continue;
913
914                                 if (!opt->elem_size)
915                                 {
916                                         if (!opt->parse((char *)s + opt->offset, o->v.string, false))
917                                         {
918                                                 warn_elem(e, "has invalid value '%s'", o->v.string);
919                                                 valid = false;
920                                         }
921                                 }
922                                 else
923                                 {
924                                         dest = (struct list_head *)((char *)s + opt->offset);
925
926                                         for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
927                                         {
928                                                 if (!opt->parse(dest, p, true))
929                                                 {
930                                                         warn_elem(e, "has invalid value '%s'", p);
931                                                         valid = false;
932                                                         continue;
933                                                 }
934                                         }
935                                 }
936                         }
937
938                         known = true;
939                         break;
940                 }
941
942                 if (!known)
943                         warn_elem(e, "is unknown");
944         }
945
946         return valid;
947 }
948
949
950 const char *
951 fw3_address_to_string(struct fw3_address *address, bool allow_invert)
952 {
953         char *p, ip[INET6_ADDRSTRLEN];
954         static char buf[INET6_ADDRSTRLEN * 2 + 2];
955
956         p = buf;
957
958         if (address->invert && allow_invert)
959                 p += sprintf(p, "!");
960
961         inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
962                   &address->address.v4, ip, sizeof(ip));
963
964         p += sprintf(p, "%s", ip);
965
966         if (address->range)
967         {
968                 inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
969                           &address->address2.v4, ip, sizeof(ip));
970
971                 p += sprintf(p, "-%s", ip);
972         }
973         else
974         {
975                 p += sprintf(p, "/%u", address->mask);
976         }
977
978         return buf;
979 }