2 * firewall3 - 3rd OpenWrt UCI firewall implementation
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
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.
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.
21 const char *fw3_flag_names[FW3_DEFAULT_DROP_INVALID + 1] = {
39 fw3_parse_bool(void *ptr, const char *val)
41 if (!strcmp(val, "true") || !strcmp(val, "yes") || !strcmp(val, "1"))
42 *((bool *)ptr) = true;
44 *((bool *)ptr) = false;
50 fw3_parse_int(void *ptr, const char *val)
52 int n = strtol(val, NULL, 10);
54 if (errno == ERANGE || errno == EINVAL)
63 fw3_parse_string(void *ptr, const char *val)
65 *((char **)ptr) = (char *)val;
70 fw3_parse_target(void *ptr, const char *val)
72 if (!strcmp(val, "ACCEPT"))
74 *((enum fw3_target *)ptr) = FW3_TARGET_ACCEPT;
77 else if (!strcmp(val, "REJECT"))
79 *((enum fw3_target *)ptr) = FW3_TARGET_REJECT;
82 else if (!strcmp(val, "DROP"))
84 *((enum fw3_target *)ptr) = FW3_TARGET_DROP;
87 else if (!strcmp(val, "NOTRACK"))
89 *((enum fw3_target *)ptr) = FW3_TARGET_NOTRACK;
92 else if (!strcmp(val, "DNAT"))
94 *((enum fw3_target *)ptr) = FW3_TARGET_DNAT;
97 else if (!strcmp(val, "SNAT"))
99 *((enum fw3_target *)ptr) = FW3_TARGET_SNAT;
107 fw3_parse_limit(void *ptr, const char *val)
109 struct fw3_limit *limit = ptr;
110 enum fw3_limit_unit u = FW3_LIMIT_UNIT_SECOND;
116 limit->invert = true;
117 while (isspace(*++val));
120 n = strtol(val, &e, 10);
122 if (errno == ERANGE || errno == EINVAL)
125 if (*e && *e++ != '/')
131 if (!strncmp(e, "second", strlen(e)))
132 u = FW3_LIMIT_UNIT_SECOND;
133 else if (!strncmp(e, "minute", strlen(e)))
134 u = FW3_LIMIT_UNIT_MINUTE;
135 else if (!strncmp(e, "hour", strlen(e)))
136 u = FW3_LIMIT_UNIT_HOUR;
137 else if (!strncmp(e, "day", strlen(e)))
138 u = FW3_LIMIT_UNIT_DAY;
149 fw3_parse_device(void *ptr, const char *val)
151 struct fw3_device *dev = ptr;
163 while (isspace(*++val));
167 snprintf(dev->name, sizeof(dev->name), "%s", val);
176 fw3_parse_address(void *ptr, const char *val)
178 struct fw3_address *addr = ptr;
187 while (isspace(*++val));
195 if ((p = strchr(s, '/')) != NULL)
198 m = strtoul(p, &e, 10);
200 if ((e == p) || (*e != 0))
202 if (strchr(s, ':') || !inet_pton(AF_INET, p, &v4))
208 for (i = 0, m = 32; !(v4.s_addr & 1) && (i < 32); i++)
215 else if ((p = strchr(s, '-')) != NULL)
219 if (inet_pton(AF_INET6, p, &v6))
221 addr->family = FW3_FAMILY_V6;
222 addr->address2.v6 = v6;
225 else if (inet_pton(AF_INET, p, &v4))
227 addr->family = FW3_FAMILY_V4;
228 addr->address2.v4 = v4;
238 if (inet_pton(AF_INET6, s, &v6))
240 addr->family = FW3_FAMILY_V6;
241 addr->address.v6 = v6;
242 addr->mask = (m >= 0) ? m : 128;
244 else if (inet_pton(AF_INET, s, &v4))
246 addr->family = FW3_FAMILY_V4;
247 addr->address.v4 = v4;
248 addr->mask = (m >= 0) ? m : 32;
262 fw3_parse_mac(void *ptr, const char *val)
264 struct fw3_mac *addr = ptr;
265 struct ether_addr *mac;
270 while (isspace(*++val));
273 if ((mac = ether_aton(val)) != NULL)
284 fw3_parse_port(void *ptr, const char *val)
286 struct fw3_port *range = ptr;
293 range->invert = true;
294 while (isspace(*++val));
297 n = strtoul(val, &p, 10);
299 if (errno == ERANGE || errno == EINVAL)
302 if (*p && *p != '-' && *p != ':')
307 m = strtoul(++p, NULL, 10);
309 if (errno == ERANGE || errno == EINVAL || m < n)
326 fw3_parse_family(void *ptr, const char *val)
328 if (!strcmp(val, "any"))
329 *((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
330 else if (!strcmp(val, "inet") || strrchr(val, '4'))
331 *((enum fw3_family *)ptr) = FW3_FAMILY_V4;
332 else if (!strcmp(val, "inet6") || strrchr(val, '6'))
333 *((enum fw3_family *)ptr) = FW3_FAMILY_V6;
341 fw3_parse_icmptype(void *ptr, const char *val)
343 struct fw3_icmptype *icmp = ptr;
349 for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v4); i++)
351 if (!strcmp(val, fw3_icmptype_list_v4[i].name))
353 icmp->type = fw3_icmptype_list_v4[i].type;
354 icmp->code_min = fw3_icmptype_list_v4[i].code_min;
355 icmp->code_max = fw3_icmptype_list_v4[i].code_max;
362 for (i = 0; i < ARRAY_SIZE(fw3_icmptype_list_v6); i++)
364 if (!strcmp(val, fw3_icmptype_list_v6[i].name))
366 icmp->type6 = fw3_icmptype_list_v6[i].type;
367 icmp->code6_min = fw3_icmptype_list_v6[i].code_min;
368 icmp->code6_max = fw3_icmptype_list_v6[i].code_max;
377 i = strtoul(val, &p, 10);
379 if ((p == val) || (*p != '/' && *p != 0) || (i > 0xFF))
387 i = strtoul(val, &p, 10);
389 if ((p == val) || (*p != 0) || (i > 0xFF))
398 icmp->code_max = 0xFF;
401 icmp->type6 = icmp->type;
402 icmp->code6_min = icmp->code_max;
403 icmp->code6_max = icmp->code_max;
409 icmp->family = (v4 && v6) ? FW3_FAMILY_ANY
410 : (v6 ? FW3_FAMILY_V6 : FW3_FAMILY_V4);
416 fw3_parse_protocol(void *ptr, const char *val)
418 struct fw3_protocol *proto = ptr;
419 struct protoent *ent;
423 proto->invert = true;
424 while (isspace(*++val));
427 if (!strcmp(val, "all"))
432 else if (!strcmp(val, "icmpv6"))
437 ent = getprotobyname(val);
441 proto->protocol = ent->p_proto;
445 proto->protocol = strtoul(val, NULL, 10);
446 return (errno != ERANGE && errno != EINVAL);
450 fw3_parse_ipset_method(void *ptr, const char *val)
452 if (!strncmp(val, "bitmap", strlen(val)))
454 *((enum fw3_ipset_method *)ptr) = FW3_IPSET_METHOD_BITMAP;
457 else if (!strncmp(val, "hash", strlen(val)))
459 *((enum fw3_ipset_method *)ptr) = FW3_IPSET_METHOD_HASH;
462 else if (!strncmp(val, "list", strlen(val)))
464 *((enum fw3_ipset_method *)ptr) = FW3_IPSET_METHOD_LIST;
472 fw3_parse_ipset_datatype(void *ptr, const char *val)
474 struct fw3_ipset_datatype *type = ptr;
476 if (!strncmp(val, "dest_", 5))
481 else if (!strncmp(val, "dst_", 4))
486 else if (!strncmp(val, "src_", 4))
492 if (!strncmp(val, "ip", strlen(val)))
494 type->type = FW3_IPSET_TYPE_IP;
497 else if (!strncmp(val, "port", strlen(val)))
499 type->type = FW3_IPSET_TYPE_PORT;
502 else if (!strncmp(val, "mac", strlen(val)))
504 type->type = FW3_IPSET_TYPE_MAC;
507 else if (!strncmp(val, "net", strlen(val)))
509 type->type = FW3_IPSET_TYPE_NET;
512 else if (!strncmp(val, "set", strlen(val)))
514 type->type = FW3_IPSET_TYPE_SET;
522 fw3_parse_date(void *ptr, const char *val)
524 unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0;
525 struct tm tm = { 0 };
528 year = strtoul(val, &p, 10);
529 if ((*p != '-' && *p) || year < 1970 || year > 2038)
534 mon = strtoul(++p, &p, 10);
535 if ((*p != '-' && *p) || mon > 12)
540 day = strtoul(++p, &p, 10);
541 if ((*p != 'T' && *p) || day > 31)
546 hour = strtoul(++p, &p, 10);
547 if ((*p != ':' && *p) || hour > 23)
552 min = strtoul(++p, &p, 10);
553 if ((*p != ':' && *p) || min > 59)
558 sec = strtoul(++p, &p, 10);
563 tm.tm_year = year - 1900;
570 if (mktime(&tm) >= 0)
572 *((struct tm *)ptr) = tm;
581 fw3_parse_time(void *ptr, const char *val)
583 unsigned int hour = 0, min = 0, sec = 0;
586 hour = strtoul(val, &p, 10);
587 if (*p != ':' || hour > 23)
590 min = strtoul(++p, &p, 10);
591 if ((*p != ':' && *p) || min > 59)
596 sec = strtoul(++p, &p, 10);
601 *((int *)ptr) = 60 * 60 * hour + 60 * min + sec;
609 fw3_parse_weekdays(void *ptr, const char *val)
616 setbit(*(uint8_t *)ptr, 0);
617 while (isspace(*++val));
620 for (p = strtok((char *)val, " \t"); p; p = strtok(NULL, " \t"))
622 if (!strncasecmp(p, "monday", strlen(p)))
624 else if (!strncasecmp(p, "tuesday", strlen(p)))
626 else if (!strncasecmp(p, "wednesday", strlen(p)))
628 else if (!strncasecmp(p, "thursday", strlen(p)))
630 else if (!strncasecmp(p, "friday", strlen(p)))
632 else if (!strncasecmp(p, "saturday", strlen(p)))
634 else if (!strncasecmp(p, "sunday", strlen(p)))
638 w = strtoul(p, &p, 10);
640 if (*p || w < 1 || w > 7)
644 setbit(*(uint8_t *)ptr, w);
651 fw3_parse_monthdays(void *ptr, const char *val)
658 setbit(*(uint32_t *)ptr, 0);
659 while (isspace(*++val));
662 for (p = strtok((char *)val, " \t"); p; p = strtok(NULL, " \t"))
664 d = strtoul(p, &p, 10);
666 if (*p || d < 1 || d > 31)
669 setbit(*(uint32_t *)ptr, d);
676 fw3_parse_include_type(void *ptr, const char *val)
678 if (!strcmp(val, "script"))
679 *((enum fw3_include_type *)ptr) = FW3_INC_TYPE_SCRIPT;
680 else if (!strcmp(val, "restore"))
681 *((enum fw3_include_type *)ptr) = FW3_INC_TYPE_RESTORE;
690 fw3_parse_options(void *s, const struct fw3_option *opts,
691 struct uci_section *section)
695 struct uci_element *e, *l;
696 struct uci_option *o;
697 const struct fw3_option *opt;
698 struct list_head *item;
699 struct list_head *dest;
701 uci_foreach_element(§ion->options, e)
703 o = uci_to_option(e);
706 for (opt = opts; opt->name; opt++)
711 if (strcmp(opt->name, e->name))
714 if (o->type == UCI_TYPE_LIST)
718 warn_elem(e, "must not be a list");
722 uci_foreach_element(&o->v.list, l)
727 item = malloc(opt->elem_size);
732 memset(item, 0, opt->elem_size);
734 if (!opt->parse(item, l->name))
736 warn_elem(e, "has invalid value '%s'", l->name);
741 dest = (struct list_head *)((char *)s + opt->offset);
742 list_add_tail(item, dest);
753 if (!opt->parse((char *)s + opt->offset, o->v.string))
754 warn_elem(e, "has invalid value '%s'", o->v.string);
758 for (p = strtok(o->v.string, " \t");
760 p = strtok(NULL, " \t"))
762 item = malloc(opt->elem_size);
767 memset(item, 0, opt->elem_size);
769 if (!opt->parse(item, p))
771 warn_elem(e, "has invalid value '%s'", p);
776 dest = (struct list_head *)((char *)s + opt->offset);
777 list_add_tail(item, dest);
787 warn_elem(e, "is unknown");
793 fw3_format_in_out(struct fw3_device *in, struct fw3_device *out)
796 fw3_pr(" %s-i %s", in->invert ? "! " : "", in->name);
798 if (out && !out->any)
799 fw3_pr(" %s-o %s", out->invert ? "! " : "", out->name);
803 fw3_format_src_dest(struct fw3_address *src, struct fw3_address *dest)
805 char s[INET6_ADDRSTRLEN];
807 if ((src && src->range) || (dest && dest->range))
808 fw3_pr(" -m iprange");
814 inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
815 &src->address.v4, s, sizeof(s));
817 fw3_pr(" %s--src-range %s", src->invert ? "! " : "", s);
819 inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
820 &src->address2.v4, s, sizeof(s));
826 inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
827 &src->address.v4, s, sizeof(s));
829 fw3_pr(" %s-s %s/%u", src->invert ? "! " : "", s, src->mask);
833 if (dest && dest->set)
837 inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
838 &dest->address.v4, s, sizeof(s));
840 fw3_pr(" %s--dst-range %s", dest->invert ? "! " : "", s);
842 inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
843 &dest->address2.v4, s, sizeof(s));
849 inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
850 &dest->address.v4, s, sizeof(s));
852 fw3_pr(" %s-d %s/%u", dest->invert ? "! " : "", s, dest->mask);
858 fw3_format_sport_dport(struct fw3_port *sp, struct fw3_port *dp)
862 if (sp->port_min == sp->port_max)
863 fw3_pr(" %s--sport %u", sp->invert ? "! " : "", sp->port_min);
865 fw3_pr(" %s--sport %u:%u",
866 sp->invert ? "! " : "", sp->port_min, sp->port_max);
871 if (dp->port_min == dp->port_max)
872 fw3_pr(" %s--dport %u", dp->invert ? "! " : "", dp->port_min);
874 fw3_pr(" %s--dport %u:%u",
875 dp->invert ? "! " : "", dp->port_min, dp->port_max);
880 fw3_format_mac(struct fw3_mac *mac)
885 fw3_pr(" -m mac %s--mac-source %s",
886 mac->invert ? "! " : "", ether_ntoa(&mac->mac));
890 fw3_format_protocol(struct fw3_protocol *proto, enum fw3_family family)
897 pr = proto->protocol;
899 if (pr == 1 && family == FW3_FAMILY_V6)
905 fw3_pr(" %s-p %u", proto->invert ? "! " : "", pr);
909 fw3_format_icmptype(struct fw3_icmptype *icmp, enum fw3_family family)
914 if (family != FW3_FAMILY_V6)
916 if (icmp->code_min == 0 && icmp->code_max == 0xFF)
917 fw3_pr(" %s--icmp-type %u", icmp->invert ? "! " : "", icmp->type);
919 fw3_pr(" %s--icmp-type %u/%u",
920 icmp->invert ? "! " : "", icmp->type, icmp->code_min);
924 if (icmp->code6_min == 0 && icmp->code6_max == 0xFF)
925 fw3_pr(" %s--icmpv6-type %u", icmp->invert ? "! " : "", icmp->type6);
927 fw3_pr(" %s--icmpv6-type %u/%u",
928 icmp->invert ? "! " : "", icmp->type6, icmp->code6_min);
933 fw3_format_limit(struct fw3_limit *limit)
938 const char *units[] = {
939 [FW3_LIMIT_UNIT_SECOND] = "second",
940 [FW3_LIMIT_UNIT_MINUTE] = "minute",
941 [FW3_LIMIT_UNIT_HOUR] = "hour",
942 [FW3_LIMIT_UNIT_DAY] = "day",
947 fw3_pr(" -m limit %s--limit %u/%s",
948 limit->invert ? "! " : "", limit->rate, units[limit->unit]);
950 if (limit->burst > 0)
951 fw3_pr(" --limit-burst %u", limit->burst);
956 fw3_format_ipset(struct fw3_ipset *ipset, bool invert)
959 const char *name = NULL;
960 struct fw3_ipset_datatype *type;
965 if (ipset->external && *ipset->external)
966 name = ipset->external;
970 fw3_pr(" -m set %s--match-set %s", invert ? "! " : "", name);
972 list_for_each_entry(type, &ipset->datatypes, list)
974 fw3_pr("%c%s", first ? ' ' : ',', type->dest ? "dst" : "src");
980 fw3_format_time(struct fw3_time *time)
983 struct tm empty = { 0 };
984 char buf[sizeof("9999-99-99T23:59:59\0")];
985 bool d1 = memcmp(&time->datestart, &empty, sizeof(empty));
986 bool d2 = memcmp(&time->datestop, &empty, sizeof(empty));
989 if (!d1 && !d2 && !time->timestart && !time->timestop &&
990 !(time->monthdays & 0xFFFFFFFE) && !(time->weekdays & 0xFE))
1002 strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestart);
1003 fw3_pr(" --datestart %s", buf);
1008 strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestop);
1009 fw3_pr(" --datestop %s", buf);
1012 if (time->timestart)
1014 fw3_pr(" --timestart %02d:%02d:%02d",
1015 time->timestart / 3600,
1016 time->timestart % 3600 / 60,
1017 time->timestart % 60);
1022 fw3_pr(" --timestop %02d:%02d:%02d",
1023 time->timestop / 3600,
1024 time->timestop % 3600 / 60,
1025 time->timestop % 60);
1028 if (time->monthdays & 0xFFFFFFFE)
1030 fw3_pr(" %s--monthdays", hasbit(time->monthdays, 0) ? "! " : "");
1032 for (i = 1, first = true; i < 32; i++)
1034 if (hasbit(time->monthdays, i))
1036 fw3_pr("%c%u", first ? ' ' : ',', i);
1042 if (time->weekdays & 0xFE)
1044 fw3_pr(" %s--weekdays", hasbit(time->weekdays, 0) ? "! " : "");
1046 for (i = 1, first = true; i < 8; i++)
1048 if (hasbit(time->weekdays, i))
1050 fw3_pr("%c%u", first ? ' ' : ',', i);
1058 __fw3_format_comment(const char *comment, ...)
1064 if (!comment || !*comment)
1067 fw3_pr(" -m comment --comment \"");
1071 va_start(ap, comment);
1097 c = va_arg(ap, const char *);
1107 fw3_format_extra(const char *extra)
1109 if (!extra || !*extra)
1112 fw3_pr(" %s", extra);