2 * firewall3 - 3rd OpenWrt UCI firewall implementation
4 * Copyright (C) 2013 Jo-Philipp Wich <jo@mein.io>
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.
19 #define _GNU_SOURCE /* RTLD_NEXT */
21 /* include userspace headers */
26 #include <netinet/in.h>
27 #include <sys/utsname.h>
28 #include <sys/socket.h>
30 /* prevent indirect inclusion of kernel headers */
35 /* prevent libiptc from including kernel headers */
36 #define _FWCHAINS_KERNEL_HEADERS_H
38 /* finally include libiptc and xtables */
39 #include <libiptc/libiptc.h>
40 #include <libiptc/libip6tc.h>
47 /* xtables interface */
48 #if (XTABLES_VERSION_CODE >= 10)
49 # include "xtables-10.h"
50 #elif (XTABLES_VERSION_CODE == 5)
51 # include "xtables-5.h"
53 # error "Unsupported xtables version"
60 struct fw3_ipt_handle
*h
;
67 struct xtables_rule_match
*matches
;
68 struct xtables_target
*target
;
77 static struct option base_opts
[] = {
78 { .name
= "match", .has_arg
= 1, .val
= 'm' },
79 { .name
= "jump", .has_arg
= 1, .val
= 'j' },
84 static jmp_buf fw3_ipt_error_jmp
;
86 static __attribute__((noreturn
))
87 void fw3_ipt_error_handler(enum xtables_exittype status
,
92 fprintf(stderr
, " ! Exception: ");
95 vfprintf(stderr
, fmt
, args
);
98 longjmp(fw3_ipt_error_jmp
, status
);
101 static struct xtables_globals xtg
= {
103 .program_version
= "4",
104 .orig_opts
= base_opts
,
105 .exit_err
= fw3_ipt_error_handler
,
106 #if XTABLES_VERSION_CODE > 10
107 .compat_rev
= xtables_compatible_revision
,
111 static struct xtables_globals xtg6
= {
113 .program_version
= "6",
114 .orig_opts
= base_opts
,
115 .exit_err
= fw3_ipt_error_handler
,
116 #if XTABLES_VERSION_CODE > 10
117 .compat_rev
= xtables_compatible_revision
,
124 struct xtables_match
**matches
;
125 struct xtables_target
**targets
;
126 void (*register_match
)(struct xtables_match
*);
127 void (*register_target
)(struct xtables_target
*);
131 /* Required by certain extensions like SNAT and DNAT */
132 int kernel_version
= 0;
135 get_kernel_version(void)
137 static struct utsname uts
;
138 int x
= 0, y
= 0, z
= 0;
140 if (uname(&uts
) == -1)
141 sprintf(uts
.release
, "3.0.0");
143 sscanf(uts
.release
, "%d.%d.%d", &x
, &y
, &z
);
144 kernel_version
= 0x10000 * x
+ 0x100 * y
+ z
;
147 static void fw3_init_extensions(void)
157 struct fw3_ipt_handle
*
158 fw3_ipt_open(enum fw3_family family
, enum fw3_table table
)
161 struct fw3_ipt_handle
*h
;
163 h
= fw3_alloc(sizeof(*h
));
167 if (family
== FW3_FAMILY_V6
)
170 h
->family
= FW3_FAMILY_V6
;
172 h
->handle
= ip6tc_init(fw3_flag_names
[table
]);
174 xtables_set_params(&xtg6
);
175 xtables_set_nfproto(NFPROTO_IPV6
);
180 h
->family
= FW3_FAMILY_V4
;
182 h
->handle
= iptc_init(fw3_flag_names
[table
]);
184 xtables_set_params(&xtg
);
185 xtables_set_nfproto(NFPROTO_IPV4
);
195 fw3_init_extensions();
197 if (xext
.register_match
)
198 for (i
= 0; i
< xext
.mcount
; i
++)
199 xext
.register_match(xext
.matches
[i
]);
201 if (xext
.register_target
)
202 for (i
= 0; i
< xext
.tcount
; i
++)
203 xext
.register_target(xext
.targets
[i
]);
209 debug(struct fw3_ipt_handle
*h
, const char *fmt
, ...)
213 printf("%s -t %s ", (h
->family
== FW3_FAMILY_V6
) ? "ip6tables" : "iptables",
214 fw3_flag_names
[h
->table
]);
222 fw3_ipt_set_policy(struct fw3_ipt_handle
*h
, const char *chain
,
223 enum fw3_flag policy
)
226 debug(h
, "-P %s %s\n", chain
, fw3_flag_names
[policy
]);
229 if (h
->family
== FW3_FAMILY_V6
)
230 ip6tc_set_policy(chain
, fw3_flag_names
[policy
], NULL
, h
->handle
);
233 iptc_set_policy(chain
, fw3_flag_names
[policy
], NULL
, h
->handle
);
237 fw3_ipt_flush_chain(struct fw3_ipt_handle
*h
, const char *chain
)
240 debug(h
, "-F %s\n", chain
);
243 if (h
->family
== FW3_FAMILY_V6
)
244 ip6tc_flush_entries(chain
, h
->handle
);
247 iptc_flush_entries(chain
, h
->handle
);
251 delete_rules(struct fw3_ipt_handle
*h
, const char *target
)
254 const struct ipt_entry
*e
;
260 if (h
->family
== FW3_FAMILY_V6
)
262 for (chain
= ip6tc_first_chain(h
->handle
);
264 chain
= ip6tc_next_chain(h
->handle
))
269 const struct ip6t_entry
*e6
;
270 for (num
= 0, e6
= ip6tc_first_rule(chain
, h
->handle
);
272 num
++, e6
= ip6tc_next_rule(e6
, h
->handle
))
274 t
= ip6tc_get_target(e6
, h
->handle
);
276 if (*t
&& !strcmp(t
, target
))
279 debug(h
, "-D %s %u\n", chain
, num
+ 1);
281 ip6tc_delete_num_entry(chain
, num
, h
->handle
);
292 for (chain
= iptc_first_chain(h
->handle
);
294 chain
= iptc_next_chain(h
->handle
))
299 for (num
= 0, e
= iptc_first_rule(chain
, h
->handle
);
301 num
++, e
= iptc_next_rule(e
, h
->handle
))
303 t
= iptc_get_target(e
, h
->handle
);
305 if (*t
&& !strcmp(t
, target
))
308 debug(h
, "-D %s %u\n", chain
, num
+ 1);
310 iptc_delete_num_entry(chain
, num
, h
->handle
);
321 fw3_ipt_delete_chain(struct fw3_ipt_handle
*h
, const char *chain
)
323 delete_rules(h
, chain
);
326 debug(h
, "-X %s\n", chain
);
329 if (h
->family
== FW3_FAMILY_V6
)
330 ip6tc_delete_chain(chain
, h
->handle
);
333 iptc_delete_chain(chain
, h
->handle
);
337 has_rule_tag(const void *base
, unsigned int start
, unsigned int end
)
340 const struct xt_entry_match
*em
;
342 for (i
= start
; i
< end
; i
+= em
->u
.match_size
)
346 if (strcmp(em
->u
.user
.name
, "comment"))
349 if (!memcmp(em
->data
, "!fw3", 4))
357 fw3_ipt_delete_id_rules(struct fw3_ipt_handle
*h
, const char *chain
)
360 const struct ipt_entry
*e
;
364 if (h
->family
== FW3_FAMILY_V6
)
366 if (!ip6tc_is_chain(chain
, h
->handle
))
372 const struct ip6t_entry
*e6
;
373 for (num
= 0, e6
= ip6tc_first_rule(chain
, h
->handle
);
375 num
++, e6
= ip6tc_next_rule(e6
, h
->handle
))
377 if (has_rule_tag(e6
, sizeof(*e6
), e6
->target_offset
))
380 debug(h
, "-D %s %u\n", chain
, num
+ 1);
382 ip6tc_delete_num_entry(chain
, num
, h
->handle
);
392 if (!iptc_is_chain(chain
, h
->handle
))
398 for (num
= 0, e
= iptc_first_rule(chain
, h
->handle
);
400 num
++, e
= iptc_next_rule(e
, h
->handle
))
402 if (has_rule_tag(e
, sizeof(*e
), e
->target_offset
))
405 debug(h
, "-D %s %u\n", chain
, num
+ 1);
407 iptc_delete_num_entry(chain
, num
, h
->handle
);
417 fw3_ipt_create_chain(struct fw3_ipt_handle
*h
, const char *fmt
, ...)
423 vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
427 debug(h
, "-N %s\n", buf
);
429 iptc_create_chain(buf
, h
->handle
);
433 fw3_ipt_flush(struct fw3_ipt_handle
*h
)
438 if (h
->family
== FW3_FAMILY_V6
)
440 for (chain
= ip6tc_first_chain(h
->handle
);
442 chain
= ip6tc_next_chain(h
->handle
))
444 ip6tc_flush_entries(chain
, h
->handle
);
447 for (chain
= ip6tc_first_chain(h
->handle
);
449 chain
= ip6tc_next_chain(h
->handle
))
451 ip6tc_delete_chain(chain
, h
->handle
);
457 for (chain
= iptc_first_chain(h
->handle
);
459 chain
= iptc_next_chain(h
->handle
))
461 iptc_flush_entries(chain
, h
->handle
);
464 for (chain
= iptc_first_chain(h
->handle
);
466 chain
= iptc_next_chain(h
->handle
))
468 iptc_delete_chain(chain
, h
->handle
);
474 chain_is_empty(struct fw3_ipt_handle
*h
, const char *chain
)
477 if (h
->family
== FW3_FAMILY_V6
)
478 return (!ip6tc_builtin(chain
, h
->handle
) &&
479 !ip6tc_first_rule(chain
, h
->handle
));
482 return (!iptc_builtin(chain
, h
->handle
) &&
483 !iptc_first_rule(chain
, h
->handle
));
487 fw3_ipt_gc(struct fw3_ipt_handle
*h
)
493 if (h
->family
== FW3_FAMILY_V6
)
498 for (chain
= ip6tc_first_chain(h
->handle
);
500 chain
= ip6tc_next_chain(h
->handle
))
502 if (!chain_is_empty(h
, chain
))
505 fw3_ipt_delete_chain(h
, chain
);
517 for (chain
= iptc_first_chain(h
->handle
);
519 chain
= iptc_next_chain(h
->handle
))
521 warn("C=%s\n", chain
);
523 if (!chain_is_empty(h
, chain
))
526 warn("D=%s\n", chain
);
528 fw3_ipt_delete_chain(h
, chain
);
537 fw3_ipt_commit(struct fw3_ipt_handle
*h
)
542 if (h
->family
== FW3_FAMILY_V6
)
544 rv
= ip6tc_commit(h
->handle
);
546 warn("ip6tc_commit(): %s", ip6tc_strerror(errno
));
551 rv
= iptc_commit(h
->handle
);
553 warn("iptc_commit(): %s", iptc_strerror(errno
));
558 fw3_ipt_close(struct fw3_ipt_handle
*h
)
563 struct fw3_ipt_rule
*
564 fw3_ipt_rule_new(struct fw3_ipt_handle
*h
)
566 struct fw3_ipt_rule
*r
;
568 r
= fw3_alloc(sizeof(*r
));
571 r
->argv
= fw3_alloc(sizeof(char *));
572 r
->argv
[r
->argc
++] = "fw3";
579 is_chain(struct fw3_ipt_handle
*h
, const char *name
)
582 if (h
->family
== FW3_FAMILY_V6
)
583 return ip6tc_is_chain(name
, h
->handle
);
586 return iptc_is_chain(name
, h
->handle
);
590 get_protoname(struct fw3_ipt_rule
*r
)
592 const struct xtables_pprot
*pp
;
595 for (pp
= xtables_chain_protos
; pp
->name
; pp
++)
596 if (pp
->num
== r
->protocol
)
597 return (char *)pp
->name
;
602 static struct xtables_match
*
603 find_match(struct fw3_ipt_rule
*r
, const char *name
)
605 struct xtables_match
*m
;
608 m
= xtables_find_match(name
, XTF_TRY_LOAD
, &r
->matches
);
615 init_match(struct fw3_ipt_rule
*r
, struct xtables_match
*m
, bool no_clone
)
618 struct xtables_globals
*g
;
623 s
= XT_ALIGN(sizeof(struct xt_entry_match
)) + m
->size
;
627 fw3_xt_set_match_name(m
);
629 m
->m
->u
.user
.revision
= m
->revision
;
630 m
->m
->u
.match_size
= s
;
632 /* free previous userspace data */
633 fw3_xt_free_match_udata(m
);
638 /* don't merge options if no_clone is set and this match is a clone */
639 if (no_clone
&& (m
== m
->next
))
642 /* merge option table */
643 g
= (r
->h
->family
== FW3_FAMILY_V6
) ? &xtg6
: &xtg
;
644 fw3_xt_merge_match_options(g
, m
);
648 need_protomatch(struct fw3_ipt_rule
*r
, const char *pname
)
653 if (!xtables_find_match(pname
, XTF_DONT_LOAD
, NULL
))
656 return !r
->protocol_loaded
;
659 static struct xtables_match
*
660 load_protomatch(struct fw3_ipt_rule
*r
)
662 const char *pname
= get_protoname(r
);
664 if (!need_protomatch(r
, pname
))
667 return find_match(r
, pname
);
670 static struct xtables_target
*
671 find_target(struct fw3_ipt_rule
*r
, const char *name
)
673 struct xtables_target
*t
;
677 if (is_chain(r
->h
, name
))
678 t
= xtables_find_target(XT_STANDARD_TARGET
, XTF_TRY_LOAD
);
680 t
= xtables_find_target(name
, XTF_TRY_LOAD
);
687 static struct xtables_target
*
688 get_target(struct fw3_ipt_rule
*r
, const char *name
)
691 struct xtables_target
*t
;
692 struct xtables_globals
*g
;
694 t
= find_target(r
, name
);
699 s
= XT_ALIGN(sizeof(struct xt_entry_target
)) + t
->size
;
702 fw3_xt_set_target_name(t
, name
);
704 t
->t
->u
.user
.revision
= t
->revision
;
705 t
->t
->u
.target_size
= s
;
707 /* free previous userspace data */
708 fw3_xt_free_target_udata(t
);
713 /* merge option table */
714 g
= (r
->h
->family
== FW3_FAMILY_V6
) ? &xtg6
: &xtg
;
715 fw3_xt_merge_target_options(g
, t
);
723 fw3_ipt_rule_proto(struct fw3_ipt_rule
*r
, struct fw3_protocol
*proto
)
727 if (!proto
|| proto
->any
)
730 pr
= proto
->protocol
;
733 if (r
->h
->family
== FW3_FAMILY_V6
)
738 r
->e6
.ipv6
.proto
= pr
;
739 r
->e6
.ipv6
.flags
|= IP6T_F_PROTO
;
742 r
->e6
.ipv6
.invflags
|= XT_INV_PROTO
;
750 r
->e
.ip
.invflags
|= XT_INV_PROTO
;
757 fw3_ipt_rule_in_out(struct fw3_ipt_rule
*r
,
758 struct fw3_device
*in
, struct fw3_device
*out
)
761 if (r
->h
->family
== FW3_FAMILY_V6
)
765 xtables_parse_interface(in
->name
, r
->e6
.ipv6
.iniface
,
766 r
->e6
.ipv6
.iniface_mask
);
769 r
->e6
.ipv6
.invflags
|= IP6T_INV_VIA_IN
;
772 if (out
&& !out
->any
)
774 xtables_parse_interface(out
->name
, r
->e6
.ipv6
.outiface
,
775 r
->e6
.ipv6
.outiface_mask
);
778 r
->e6
.ipv6
.invflags
|= IP6T_INV_VIA_OUT
;
786 xtables_parse_interface(in
->name
, r
->e
.ip
.iniface
,
787 r
->e
.ip
.iniface_mask
);
790 r
->e
.ip
.invflags
|= IPT_INV_VIA_IN
;
793 if (out
&& !out
->any
)
795 xtables_parse_interface(out
->name
, r
->e
.ip
.outiface
,
796 r
->e
.ip
.outiface_mask
);
799 r
->e
.ip
.invflags
|= IPT_INV_VIA_OUT
;
806 fw3_ipt_rule_src_dest(struct fw3_ipt_rule
*r
,
807 struct fw3_address
*src
, struct fw3_address
*dest
)
809 if ((src
&& src
->range
) || (dest
&& dest
->range
))
811 fw3_ipt_rule_addarg(r
, false, "-m", "iprange");
818 fw3_ipt_rule_addarg(r
, src
->invert
, "--src-range",
819 fw3_address_to_string(src
, false, false));
822 else if (r
->h
->family
== FW3_FAMILY_V6
)
824 r
->e6
.ipv6
.src
= src
->address
.v6
;
825 r
->e6
.ipv6
.smsk
= src
->mask
.v6
;
828 for (i
= 0; i
< 4; i
++)
829 r
->e6
.ipv6
.src
.s6_addr32
[i
] &= r
->e6
.ipv6
.smsk
.s6_addr32
[i
];
832 r
->e6
.ipv6
.invflags
|= IP6T_INV_SRCIP
;
837 r
->e
.ip
.src
= src
->address
.v4
;
838 r
->e
.ip
.smsk
= src
->mask
.v4
;
840 r
->e
.ip
.src
.s_addr
&= r
->e
.ip
.smsk
.s_addr
;
843 r
->e
.ip
.invflags
|= IPT_INV_SRCIP
;
847 if (dest
&& dest
->set
)
851 fw3_ipt_rule_addarg(r
, dest
->invert
, "--dst-range",
852 fw3_address_to_string(dest
, false, false));
855 else if (r
->h
->family
== FW3_FAMILY_V6
)
857 r
->e6
.ipv6
.dst
= dest
->address
.v6
;
858 r
->e6
.ipv6
.dmsk
= dest
->mask
.v6
;
861 for (i
= 0; i
< 4; i
++)
862 r
->e6
.ipv6
.dst
.s6_addr32
[i
] &= r
->e6
.ipv6
.dmsk
.s6_addr32
[i
];
865 r
->e6
.ipv6
.invflags
|= IP6T_INV_DSTIP
;
870 r
->e
.ip
.dst
= dest
->address
.v4
;
871 r
->e
.ip
.dmsk
= dest
->mask
.v4
;
873 r
->e
.ip
.dst
.s_addr
&= r
->e
.ip
.dmsk
.s_addr
;
876 r
->e
.ip
.invflags
|= IPT_INV_DSTIP
;
882 fw3_ipt_rule_sport_dport(struct fw3_ipt_rule
*r
,
883 struct fw3_port
*sp
, struct fw3_port
*dp
)
885 char buf
[sizeof("65535:65535\0")];
887 if ((!sp
|| !sp
->set
) && (!dp
|| !dp
->set
))
890 if (!get_protoname(r
))
895 if (sp
->port_min
== sp
->port_max
)
896 sprintf(buf
, "%u", sp
->port_min
);
898 sprintf(buf
, "%u:%u", sp
->port_min
, sp
->port_max
);
900 fw3_ipt_rule_addarg(r
, sp
->invert
, "--sport", buf
);
905 if (dp
->port_min
== dp
->port_max
)
906 sprintf(buf
, "%u", dp
->port_min
);
908 sprintf(buf
, "%u:%u", dp
->port_min
, dp
->port_max
);
910 fw3_ipt_rule_addarg(r
, dp
->invert
, "--dport", buf
);
915 fw3_ipt_rule_device(struct fw3_ipt_rule
*r
, const char *device
, bool out
)
918 struct fw3_device dev
= { .any
= false };
919 strncpy(dev
.name
, device
, sizeof(dev
.name
) - 1);
920 fw3_ipt_rule_in_out(r
, (out
) ? NULL
: &dev
, (out
) ? &dev
: NULL
);
925 fw3_ipt_rule_mac(struct fw3_ipt_rule
*r
, struct fw3_mac
*mac
)
927 char buf
[sizeof("ff:ff:ff:ff:ff:ff\0")];
928 uint8_t *addr
= mac
->mac
.ether_addr_octet
;
933 sprintf(buf
, "%02x:%02x:%02x:%02x:%02x:%02x",
934 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
936 fw3_ipt_rule_addarg(r
, false, "-m", "mac");
937 fw3_ipt_rule_addarg(r
, mac
->invert
, "--mac-source", buf
);
941 fw3_ipt_rule_icmptype(struct fw3_ipt_rule
*r
, struct fw3_icmptype
*icmp
)
943 char buf
[sizeof("255/255\0")];
949 if (r
->h
->family
== FW3_FAMILY_V6
)
951 if (icmp
->code6_min
== 0 && icmp
->code6_max
== 0xFF)
952 sprintf(buf
, "%u", icmp
->type6
);
954 sprintf(buf
, "%u/%u", icmp
->type6
, icmp
->code6_min
);
956 fw3_ipt_rule_addarg(r
, icmp
->invert
, "--icmpv6-type", buf
);
961 if (icmp
->code_min
== 0 && icmp
->code_max
== 0xFF)
962 sprintf(buf
, "%u", icmp
->type
);
964 sprintf(buf
, "%u/%u", icmp
->type
, icmp
->code_min
);
966 fw3_ipt_rule_addarg(r
, icmp
->invert
, "--icmp-type", buf
);
971 fw3_ipt_rule_limit(struct fw3_ipt_rule
*r
, struct fw3_limit
*limit
)
973 char buf
[sizeof("-4294967296/second\0")];
975 if (!limit
|| limit
->rate
<= 0)
978 fw3_ipt_rule_addarg(r
, false, "-m", "limit");
980 sprintf(buf
, "%u/%s", limit
->rate
, fw3_limit_units
[limit
->unit
]);
981 fw3_ipt_rule_addarg(r
, limit
->invert
, "--limit", buf
);
983 if (limit
->burst
> 0)
985 sprintf(buf
, "%u", limit
->burst
);
986 fw3_ipt_rule_addarg(r
, limit
->invert
, "--limit-burst", buf
);
991 fw3_ipt_rule_ipset(struct fw3_ipt_rule
*r
, struct fw3_setmatch
*match
)
993 char buf
[sizeof("dst,dst,dst\0")];
997 struct fw3_ipset
*set
;
998 struct fw3_ipset_datatype
*type
;
1000 if (!match
|| !match
->set
|| !match
->ptr
)
1004 list_for_each_entry(type
, &set
->datatypes
, list
)
1012 p
+= sprintf(p
, "%s", match
->dir
[i
] ? match
->dir
[i
] : type
->dir
);
1016 fw3_ipt_rule_addarg(r
, false, "-m", "set");
1018 fw3_ipt_rule_addarg(r
, match
->invert
, "--match-set",
1019 set
->external
? set
->external
: set
->name
);
1021 fw3_ipt_rule_addarg(r
, false, buf
, NULL
);
1025 fw3_ipt_rule_time(struct fw3_ipt_rule
*r
, struct fw3_time
*time
)
1028 struct tm empty
= { 0 };
1030 char buf
[84]; /* sizeof("1,2,3,...,30,31\0") */
1033 bool d1
= memcmp(&time
->datestart
, &empty
, sizeof(empty
));
1034 bool d2
= memcmp(&time
->datestop
, &empty
, sizeof(empty
));
1036 if (!d1
&& !d2
&& !time
->timestart
&& !time
->timestop
&&
1037 !(time
->monthdays
& 0xFFFFFFFE) && !(time
->weekdays
& 0xFE))
1042 fw3_ipt_rule_addarg(r
, false, "-m", "time");
1045 fw3_ipt_rule_addarg(r
, false, "--kerneltz", NULL
);
1049 strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S", &time
->datestart
);
1050 fw3_ipt_rule_addarg(r
, false, "--datestart", buf
);
1055 strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S", &time
->datestop
);
1056 fw3_ipt_rule_addarg(r
, false, "--datestop", buf
);
1059 if (time
->timestart
)
1061 sprintf(buf
, "%02d:%02d:%02d",
1062 time
->timestart
/ 3600,
1063 time
->timestart
% 3600 / 60,
1064 time
->timestart
% 60);
1066 fw3_ipt_rule_addarg(r
, false, "--timestart", buf
);
1071 sprintf(buf
, "%02d:%02d:%02d",
1072 time
->timestop
/ 3600,
1073 time
->timestop
% 3600 / 60,
1074 time
->timestop
% 60);
1076 fw3_ipt_rule_addarg(r
, false, "--timestop", buf
);
1079 if (time
->monthdays
& 0xFFFFFFFE)
1081 for (i
= 1, p
= buf
; i
< 32; i
++)
1083 if (fw3_hasbit(time
->monthdays
, i
))
1088 p
+= sprintf(p
, "%u", i
);
1092 fw3_ipt_rule_addarg(r
, fw3_hasbit(time
->monthdays
, 0), "--monthdays", buf
);
1095 if (time
->weekdays
& 0xFE)
1097 for (i
= 1, p
= buf
; i
< 8; i
++)
1099 if (fw3_hasbit(time
->weekdays
, i
))
1104 p
+= sprintf(p
, "%u", i
);
1108 fw3_ipt_rule_addarg(r
, fw3_hasbit(time
->weekdays
, 0), "--weekdays", buf
);
1113 fw3_ipt_rule_mark(struct fw3_ipt_rule
*r
, struct fw3_mark
*mark
)
1115 char buf
[sizeof("0xFFFFFFFF/0xFFFFFFFF\0")];
1117 if (!mark
|| !mark
->set
)
1120 if (mark
->mask
< 0xFFFFFFFF)
1121 sprintf(buf
, "0x%x/0x%x", mark
->mark
, mark
->mask
);
1123 sprintf(buf
, "0x%x", mark
->mark
);
1125 fw3_ipt_rule_addarg(r
, false, "-m", "mark");
1126 fw3_ipt_rule_addarg(r
, mark
->invert
, "--mark", buf
);
1130 fw3_ipt_rule_comment(struct fw3_ipt_rule
*r
, const char *fmt
, ...)
1139 vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
1142 fw3_ipt_rule_addarg(r
, false, "-m", "comment");
1143 fw3_ipt_rule_addarg(r
, false, "--comment", buf
);
1147 fw3_ipt_rule_extra(struct fw3_ipt_rule
*r
, const char *extra
)
1151 if (!extra
|| !*extra
)
1154 s
= fw3_strdup(extra
);
1156 for (p
= strtok(s
, " \t"); p
; p
= strtok(NULL
, " \t"))
1158 tmp
= realloc(r
->argv
, (r
->argc
+ 1) * sizeof(*r
->argv
));
1164 r
->argv
[r
->argc
++] = fw3_strdup(p
);
1170 #ifndef DISABLE_IPV6
1172 rule_print6(struct ip6t_entry
*e
)
1174 char buf1
[INET6_ADDRSTRLEN
], buf2
[INET6_ADDRSTRLEN
];
1177 if (e
->ipv6
.flags
& IP6T_F_PROTO
)
1179 if (e
->ipv6
.invflags
& XT_INV_PROTO
)
1182 pname
= get_protoname(container_of(e
, struct fw3_ipt_rule
, e6
));
1185 printf(" -p %s", pname
);
1187 printf(" -p %u", e
->ipv6
.proto
);
1190 if (e
->ipv6
.iniface
[0])
1192 if (e
->ipv6
.invflags
& IP6T_INV_VIA_IN
)
1195 printf(" -i %s", e
->ipv6
.iniface
);
1198 if (e
->ipv6
.outiface
[0])
1200 if (e
->ipv6
.invflags
& IP6T_INV_VIA_OUT
)
1203 printf(" -o %s", e
->ipv6
.outiface
);
1206 if (memcmp(&e
->ipv6
.src
, &in6addr_any
, sizeof(struct in6_addr
)))
1208 if (e
->ipv6
.invflags
& IP6T_INV_SRCIP
)
1212 inet_ntop(AF_INET6
, &e
->ipv6
.src
, buf1
, sizeof(buf1
)),
1213 inet_ntop(AF_INET6
, &e
->ipv6
.smsk
, buf2
, sizeof(buf2
)));
1216 if (memcmp(&e
->ipv6
.dst
, &in6addr_any
, sizeof(struct in6_addr
)))
1218 if (e
->ipv6
.invflags
& IP6T_INV_DSTIP
)
1222 inet_ntop(AF_INET6
, &e
->ipv6
.dst
, buf1
, sizeof(buf1
)),
1223 inet_ntop(AF_INET6
, &e
->ipv6
.dmsk
, buf2
, sizeof(buf2
)));
1229 rule_print4(struct ipt_entry
*e
)
1231 struct in_addr in_zero
= { 0 };
1232 char buf1
[sizeof("255.255.255.255\0")], buf2
[sizeof("255.255.255.255\0")];
1237 if (e
->ip
.invflags
& XT_INV_PROTO
)
1240 pname
= get_protoname(container_of(e
, struct fw3_ipt_rule
, e
));
1243 printf(" -p %s", pname
);
1245 printf(" -p %u", e
->ip
.proto
);
1248 if (e
->ip
.iniface
[0])
1250 if (e
->ip
.invflags
& IPT_INV_VIA_IN
)
1253 printf(" -i %s", e
->ip
.iniface
);
1256 if (e
->ip
.outiface
[0])
1258 if (e
->ip
.invflags
& IPT_INV_VIA_OUT
)
1261 printf(" -o %s", e
->ip
.outiface
);
1264 if (memcmp(&e
->ip
.src
, &in_zero
, sizeof(struct in_addr
)))
1266 if (e
->ip
.invflags
& IPT_INV_SRCIP
)
1270 inet_ntop(AF_INET
, &e
->ip
.src
, buf1
, sizeof(buf1
)),
1271 inet_ntop(AF_INET
, &e
->ip
.smsk
, buf2
, sizeof(buf2
)));
1274 if (memcmp(&e
->ip
.dst
, &in_zero
, sizeof(struct in_addr
)))
1276 if (e
->ip
.invflags
& IPT_INV_DSTIP
)
1280 inet_ntop(AF_INET
, &e
->ip
.dst
, buf1
, sizeof(buf1
)),
1281 inet_ntop(AF_INET
, &e
->ip
.dmsk
, buf2
, sizeof(buf2
)));
1286 rule_print(struct fw3_ipt_rule
*r
, const char *prefix
, const char *chain
)
1288 debug(r
->h
, "%s %s", prefix
, chain
);
1290 #ifndef DISABLE_IPV6
1291 if (r
->h
->family
== FW3_FAMILY_V6
)
1292 rule_print6(&r
->e6
);
1297 fw3_xt_print_matches(&r
->e
.ip
, r
->matches
);
1298 fw3_xt_print_target(&r
->e
.ip
, r
->target
);
1304 parse_option(struct fw3_ipt_rule
*r
, int optc
, bool inv
)
1306 struct xtables_rule_match
*m
;
1307 struct xtables_match
*em
;
1309 /* is a target option */
1310 if (r
->target
&& fw3_xt_has_target_parse(r
->target
) &&
1311 optc
>= r
->target
->option_offset
&&
1312 optc
< (r
->target
->option_offset
+ 256))
1314 xtables_option_tpcall(optc
, r
->argv
, inv
, r
->target
, &r
->e
);
1318 /* try to dispatch argument to one of the match parsers */
1319 for (m
= r
->matches
; m
; m
= m
->next
)
1323 if (m
->completed
|| !fw3_xt_has_match_parse(em
))
1326 if (optc
< em
->option_offset
||
1327 optc
>= (em
->option_offset
+ 256))
1330 xtables_option_mpcall(optc
, r
->argv
, inv
, em
, &r
->e
);
1334 /* unhandled option, might belong to a protocol match */
1335 if ((em
= load_protomatch(r
)) != NULL
)
1337 init_match(r
, em
, false);
1339 r
->protocol_loaded
= true;
1346 warn("parse_option(): option '%s' needs argument", r
->argv
[optind
-1]);
1349 warn("parse_option(): unknown option '%s'", r
->argv
[optind
-1]);
1355 fw3_ipt_rule_addarg(struct fw3_ipt_rule
*r
, bool inv
,
1356 const char *k
, const char *v
)
1364 n
= inv
+ !!k
+ !!v
;
1365 tmp
= realloc(r
->argv
, (r
->argc
+ n
) * sizeof(*tmp
));
1373 r
->argv
[r
->argc
++] = fw3_strdup("!");
1375 r
->argv
[r
->argc
++] = fw3_strdup(k
);
1378 r
->argv
[r
->argc
++] = fw3_strdup(v
);
1381 static unsigned char *
1382 rule_mask(struct fw3_ipt_rule
*r
)
1385 unsigned char *p
, *mask
= NULL
;
1386 struct xtables_rule_match
*m
;
1388 #define SZ(x) XT_ALIGN(sizeof(struct x))
1390 #ifndef DISABLE_IPV6
1391 if (r
->h
->family
== FW3_FAMILY_V6
)
1395 for (m
= r
->matches
; m
; m
= m
->next
)
1396 s
+= SZ(ip6t_entry_match
) + m
->match
->size
;
1398 s
+= SZ(ip6t_entry_target
);
1400 s
+= r
->target
->size
;
1402 mask
= fw3_alloc(s
);
1403 memset(mask
, 0xFF, SZ(ip6t_entry
));
1404 p
= mask
+ SZ(ip6t_entry
);
1406 for (m
= r
->matches
; m
; m
= m
->next
)
1408 memset(p
, 0xFF, SZ(ip6t_entry_match
) + m
->match
->userspacesize
);
1409 p
+= SZ(ip6t_entry_match
) + m
->match
->size
;
1412 memset(p
, 0xFF, SZ(ip6t_entry_target
) + (r
->target
) ? r
->target
->userspacesize
: 0);
1419 for (m
= r
->matches
; m
; m
= m
->next
)
1420 s
+= SZ(ipt_entry_match
) + m
->match
->size
;
1422 s
+= SZ(ipt_entry_target
);
1424 s
+= r
->target
->size
;
1426 mask
= fw3_alloc(s
);
1427 memset(mask
, 0xFF, SZ(ipt_entry
));
1428 p
= mask
+ SZ(ipt_entry
);
1430 for (m
= r
->matches
; m
; m
= m
->next
)
1432 memset(p
, 0xFF, SZ(ipt_entry_match
) + m
->match
->userspacesize
);
1433 p
+= SZ(ipt_entry_match
) + m
->match
->size
;
1436 memset(p
, 0xFF, SZ(ipt_entry_target
) + (r
->target
) ? r
->target
->userspacesize
: 0);
1443 rule_build(struct fw3_ipt_rule
*r
)
1445 size_t s
, target_size
= (r
->target
) ? r
->target
->t
->u
.target_size
: 0;
1446 struct xtables_rule_match
*m
;
1448 #ifndef DISABLE_IPV6
1449 if (r
->h
->family
== FW3_FAMILY_V6
)
1451 struct ip6t_entry
*e6
;
1453 s
= XT_ALIGN(sizeof(struct ip6t_entry
));
1455 for (m
= r
->matches
; m
; m
= m
->next
)
1456 s
+= m
->match
->m
->u
.match_size
;
1458 e6
= fw3_alloc(s
+ target_size
);
1460 memcpy(e6
, &r
->e6
, sizeof(struct ip6t_entry
));
1462 e6
->target_offset
= s
;
1463 e6
->next_offset
= s
+ target_size
;
1467 for (m
= r
->matches
; m
; m
= m
->next
)
1469 memcpy(e6
->elems
+ s
, m
->match
->m
, m
->match
->m
->u
.match_size
);
1470 s
+= m
->match
->m
->u
.match_size
;
1474 memcpy(e6
->elems
+ s
, r
->target
->t
, target_size
);
1481 struct ipt_entry
*e
;
1483 s
= XT_ALIGN(sizeof(struct ipt_entry
));
1485 for (m
= r
->matches
; m
; m
= m
->next
)
1486 s
+= m
->match
->m
->u
.match_size
;
1488 e
= fw3_alloc(s
+ target_size
);
1490 memcpy(e
, &r
->e
, sizeof(struct ipt_entry
));
1492 e
->target_offset
= s
;
1493 e
->next_offset
= s
+ target_size
;
1497 for (m
= r
->matches
; m
; m
= m
->next
)
1499 memcpy(e
->elems
+ s
, m
->match
->m
, m
->match
->m
->u
.match_size
);
1500 s
+= m
->match
->m
->u
.match_size
;
1504 memcpy(e
->elems
+ s
, r
->target
->t
, target_size
);
1511 set_rule_tag(struct fw3_ipt_rule
*r
)
1515 const char *tag
= "!fw3";
1517 for (i
= 0; i
< r
->argc
; i
++)
1518 if (!strcmp(r
->argv
[i
], "--comment") && (i
+ 1) < r
->argc
)
1519 if (asprintf(&p
, "%s: %s", tag
, r
->argv
[i
+ 1]) > 0)
1521 free(r
->argv
[i
+ 1]);
1526 tmp
= realloc(r
->argv
, (r
->argc
+ 4) * sizeof(*r
->argv
));
1531 r
->argv
[r
->argc
++] = fw3_strdup("-m");
1532 r
->argv
[r
->argc
++] = fw3_strdup("comment");
1533 r
->argv
[r
->argc
++] = fw3_strdup("--comment");
1534 r
->argv
[r
->argc
++] = fw3_strdup(tag
);
1539 __fw3_ipt_rule_append(struct fw3_ipt_rule
*r
, bool repl
, const char *fmt
, ...)
1542 unsigned char *mask
;
1544 struct xtables_rule_match
*m
;
1545 struct xtables_match
*em
;
1546 struct xtables_target
*et
;
1547 struct xtables_globals
*g
;
1549 enum xtables_exittype status
;
1557 vsnprintf(buf
, sizeof(buf
) - 1, fmt
, ap
);
1560 g
= (r
->h
->family
== FW3_FAMILY_V6
) ? &xtg6
: &xtg
;
1561 g
->opts
= g
->orig_opts
;
1566 status
= setjmp(fw3_ipt_error_jmp
);
1570 info(" ! Skipping due to previous exception (code %u)", status
);
1576 while ((optc
= getopt_long(r
->argc
, r
->argv
, "-:m:j:", g
->opts
,
1582 em
= find_match(r
, optarg
);
1586 warn("fw3_ipt_rule_append(): Can't find match '%s'", optarg
);
1590 init_match(r
, em
, true);
1594 et
= get_target(r
, optarg
);
1598 warn("fw3_ipt_rule_append(): Can't find target '%s'", optarg
);
1605 if ((optarg
[0] == '!') && (optarg
[1] == '\0'))
1612 warn("fw3_ipt_rule_append(): Bad argument '%s'", optarg
);
1616 if (parse_option(r
, optc
, inv
))
1624 for (m
= r
->matches
; m
; m
= m
->next
)
1625 xtables_option_mfcall(m
->match
);
1628 xtables_option_tfcall(r
->target
);
1630 rule
= rule_build(r
);
1632 #ifndef DISABLE_IPV6
1633 if (r
->h
->family
== FW3_FAMILY_V6
)
1637 mask
= rule_mask(r
);
1639 while (ip6tc_delete_entry(buf
, rule
, mask
, r
->h
->handle
))
1641 rule_print(r
, "-D", buf
);
1647 rule_print(r
, "-A", buf
);
1649 if (!ip6tc_append_entry(buf
, rule
, r
->h
->handle
))
1650 warn("ip6tc_append_entry(): %s", ip6tc_strerror(errno
));
1657 mask
= rule_mask(r
);
1659 while (iptc_delete_entry(buf
, rule
, mask
, r
->h
->handle
))
1661 rule_print(r
, "-D", buf
);
1667 rule_print(r
, "-A", buf
);
1669 if (!iptc_append_entry(buf
, rule
, r
->h
->handle
))
1670 warn("iptc_append_entry(): %s\n", iptc_strerror(errno
));
1676 for (i
= 1; i
< r
->argc
; i
++)
1681 xtables_rule_matches_free(&r
->matches
);
1688 /* reset all targets and matches */
1689 for (em
= xtables_matches
; em
; em
= em
->next
)
1692 for (et
= xtables_targets
; et
; et
= et
->next
)
1698 xtables_free_opts(1);
1701 struct fw3_ipt_rule
*
1702 fw3_ipt_rule_create(struct fw3_ipt_handle
*handle
, struct fw3_protocol
*proto
,
1703 struct fw3_device
*in
, struct fw3_device
*out
,
1704 struct fw3_address
*src
, struct fw3_address
*dest
)
1706 struct fw3_ipt_rule
*r
;
1708 r
= fw3_ipt_rule_new(handle
);
1710 fw3_ipt_rule_proto(r
, proto
);
1711 fw3_ipt_rule_in_out(r
, in
, out
);
1712 fw3_ipt_rule_src_dest(r
, src
, dest
);
1718 xtables_register_match(struct xtables_match
*me
)
1721 static struct xtables_match
**tmp
;
1723 if (!xext
.register_match
)
1724 xext
.register_match
= dlsym(RTLD_NEXT
, "xtables_register_match");
1726 if (!xext
.register_match
)
1729 xext
.register_match(me
);
1733 for (i
= 0; i
< xext
.mcount
; i
++)
1734 if (xext
.matches
[i
] == me
)
1737 tmp
= realloc(xext
.matches
, sizeof(me
) * (xext
.mcount
+ 1));
1743 xext
.matches
[xext
.mcount
++] = me
;
1748 xtables_register_target(struct xtables_target
*me
)
1751 static struct xtables_target
**tmp
;
1753 if (!xext
.register_target
)
1754 xext
.register_target
= dlsym(RTLD_NEXT
, "xtables_register_target");
1756 if (!xext
.register_target
)
1759 xext
.register_target(me
);
1763 for (i
= 0; i
< xext
.tcount
; i
++)
1764 if (xext
.targets
[i
] == me
)
1767 tmp
= realloc(xext
.targets
, sizeof(me
) * (xext
.tcount
+ 1));
1773 xext
.targets
[xext
.tcount
++] = me
;