remove ip range list hack since fw3_address can now represent true ranges
[project/firewall3.git] / rules.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 "rules.h"
20
21
22 const struct fw3_option fw3_rule_opts[] = {
23         FW3_OPT("name",                string,   rule,     name),
24         FW3_OPT("family",              family,   rule,     family),
25
26         FW3_OPT("src",                 device,   rule,     src),
27         FW3_OPT("dest",                device,   rule,     dest),
28
29         FW3_OPT("ipset",               device,   rule,     ipset),
30
31         FW3_LIST("proto",              protocol, rule,     proto),
32
33         FW3_LIST("src_ip",             address,  rule,     ip_src),
34         FW3_LIST("src_mac",            mac,      rule,     mac_src),
35         FW3_LIST("src_port",           port,     rule,     port_src),
36
37         FW3_LIST("dest_ip",            address,  rule,     ip_dest),
38         FW3_LIST("dest_port",          port,     rule,     port_dest),
39
40         FW3_LIST("icmp_type",          icmptype, rule,     icmp_type),
41         FW3_OPT("extra",               string,   rule,     extra),
42
43         FW3_OPT("limit",               limit,    rule,     limit),
44         FW3_OPT("limit_burst",         int,      rule,     limit.burst),
45
46         FW3_OPT("target",              target,   rule,     target),
47
48         { }
49 };
50
51
52 void
53 fw3_load_rules(struct fw3_state *state, struct uci_package *p)
54 {
55         struct uci_section *s;
56         struct uci_element *e;
57         struct fw3_rule *rule;
58
59         INIT_LIST_HEAD(&state->rules);
60
61         uci_foreach_element(&p->sections, e)
62         {
63                 s = uci_to_section(e);
64
65                 if (strcmp(s->type, "rule"))
66                         continue;
67
68                 rule = malloc(sizeof(*rule));
69
70                 if (!rule)
71                         continue;
72
73                 memset(rule, 0, sizeof(*rule));
74
75                 INIT_LIST_HEAD(&rule->proto);
76
77                 INIT_LIST_HEAD(&rule->ip_src);
78                 INIT_LIST_HEAD(&rule->mac_src);
79                 INIT_LIST_HEAD(&rule->port_src);
80
81                 INIT_LIST_HEAD(&rule->ip_dest);
82                 INIT_LIST_HEAD(&rule->port_dest);
83
84                 INIT_LIST_HEAD(&rule->icmp_type);
85
86                 fw3_parse_options(rule, fw3_rule_opts, s);
87
88                 if (rule->src.invert || rule->dest.invert)
89                 {
90                         warn_elem(e, "must not have inverted 'src' or 'dest' options");
91                         fw3_free_rule(rule);
92                         continue;
93                 }
94                 else if (rule->src.set && !rule->src.any &&
95                          !(rule->_src = fw3_lookup_zone(state, rule->src.name, false)))
96                 {
97                         warn_elem(e, "refers to not existing zone '%s'", rule->src.name);
98                         fw3_free_rule(rule);
99                         continue;
100                 }
101                 else if (rule->dest.set && !rule->dest.any &&
102                          !(rule->_dest = fw3_lookup_zone(state, rule->dest.name, false)))
103                 {
104                         warn_elem(e, "refers to not existing zone '%s'", rule->dest.name);
105                         fw3_free_rule(rule);
106                         continue;
107                 }
108                 else if (rule->ipset.set && state->disable_ipsets)
109                 {
110                         warn_elem(e, "skipped due to disabled ipset support");
111                         fw3_free_rule(rule);
112                         continue;
113                 }
114                 else if (rule->ipset.set && !rule->ipset.any &&
115                          !(rule->_ipset = fw3_lookup_ipset(state, rule->ipset.name, false)))
116                 {
117                         warn_elem(e, "refers to unknown ipset '%s'", rule->ipset.name);
118                         fw3_free_rule(rule);
119                         continue;
120                 }
121
122                 if (!rule->_src && rule->target == FW3_TARGET_NOTRACK)
123                 {
124                         warn_elem(e, "is set to target NOTRACK but has no source assigned");
125                         fw3_free_rule(rule);
126                         continue;
127                 }
128
129                 if (!rule->_src && !rule->_dest && !rule->src.any && !rule->dest.any)
130                 {
131                         warn_elem(e, "has neither a source nor a destination zone assigned "
132                                      "- assuming an output rule");
133                 }
134
135                 if (rule->target == FW3_TARGET_UNSPEC)
136                 {
137                         warn_elem(e, "has no target specified, defaulting to REJECT");
138                         rule->target = FW3_TARGET_REJECT;
139                 }
140                 else if (rule->target > FW3_TARGET_NOTRACK)
141                 {
142                         warn_elem(e, "has invalid target specified, defaulting to REJECT");
143                         rule->target = FW3_TARGET_REJECT;
144                 }
145
146                 if (rule->_dest)
147                         setbit(rule->_dest->dst_flags, rule->target);
148
149                 list_add_tail(&rule->list, &state->rules);
150                 continue;
151         }
152 }
153
154
155 static void
156 print_chain(struct fw3_rule *rule)
157 {
158         char chain[256];
159
160         sprintf(chain, "delegate_output");
161
162         if (rule->target == FW3_TARGET_NOTRACK)
163         {
164                 sprintf(chain, "zone_%s_notrack", rule->src.name);
165         }
166         else
167         {
168                 if (rule->src.set)
169                 {
170                         if (!rule->src.any)
171                         {
172                                 if (rule->dest.set)
173                                         sprintf(chain, "zone_%s_forward", rule->src.name);
174                                 else
175                                         sprintf(chain, "zone_%s_input", rule->src.name);
176                         }
177                         else
178                         {
179                                 if (rule->dest.set)
180                                         sprintf(chain, "delegate_forward");
181                                 else
182                                         sprintf(chain, "delegate_input");
183                         }
184                 }
185
186                 if (rule->dest.set && !rule->src.set)
187                         sprintf(chain, "zone_%s_output", rule->dest.name);
188         }
189
190         fw3_pr("-A %s", chain);
191 }
192
193 static void print_target(struct fw3_rule *rule)
194 {
195         const char *target;
196
197         switch(rule->target)
198         {
199         case FW3_TARGET_ACCEPT:
200         case FW3_TARGET_DROP:
201         case FW3_TARGET_NOTRACK:
202                 target = fw3_flag_names[rule->target];
203                 break;
204
205         default:
206                 target = fw3_flag_names[FW3_TARGET_REJECT];
207                 break;
208         }
209
210         if (rule->dest.set && !rule->dest.any)
211                 fw3_pr(" -j zone_%s_dest_%s\n", rule->dest.name, target);
212         else if (rule->target == FW3_TARGET_REJECT)
213                 fw3_pr(" -j reject\n");
214         else
215                 fw3_pr(" -j %s\n", target);
216 }
217
218 static void
219 print_rule(enum fw3_table table, enum fw3_family family,
220            struct fw3_rule *rule, struct fw3_protocol *proto,
221            struct fw3_address *sip, struct fw3_address *dip,
222            struct fw3_port *sport, struct fw3_port *dport,
223            struct fw3_mac *mac, struct fw3_icmptype *icmptype)
224 {
225         if (!fw3_is_family(sip, family) || !fw3_is_family(dip, family))
226         {
227                 info("     ! Skipping due to different family of ip address");
228                 return;
229         }
230
231         if (proto->protocol == 58 && family == FW3_FAMILY_V4)
232         {
233                 info("     ! Skipping due to different family of protocol");
234                 return;
235         }
236
237         print_chain(rule);
238         fw3_format_ipset(rule->_ipset, rule->ipset.invert);
239         fw3_format_protocol(proto, family);
240         fw3_format_src_dest(sip, dip);
241         fw3_format_sport_dport(sport, dport);
242         fw3_format_icmptype(icmptype, family);
243         fw3_format_mac(mac);
244         fw3_format_limit(&rule->limit);
245         fw3_format_extra(rule->extra);
246         fw3_format_comment(rule->name);
247         print_target(rule);
248 }
249
250 static void
251 expand_rule(enum fw3_table table, enum fw3_family family,
252             struct fw3_rule *rule, int num)
253 {
254         struct fw3_protocol *proto;
255         struct fw3_address *sip;
256         struct fw3_address *dip;
257         struct fw3_port *sport;
258         struct fw3_port *dport;
259         struct fw3_mac *mac;
260         struct fw3_icmptype *icmptype;
261
262         struct list_head *sports = NULL;
263         struct list_head *dports = NULL;
264         struct list_head *icmptypes = NULL;
265
266         struct list_head empty;
267         INIT_LIST_HEAD(&empty);
268
269         if (!fw3_is_family(rule, family))
270                 return;
271
272         if ((table == FW3_TABLE_RAW && rule->target != FW3_TARGET_NOTRACK) ||
273             (table != FW3_TABLE_FILTER))
274                 return;
275
276         if (rule->name)
277                 info("   * Rule '%s'", rule->name);
278         else
279                 info("   * Rule #%u", num);
280
281         if (!fw3_is_family(rule->_src, family) ||
282             !fw3_is_family(rule->_dest, family))
283         {
284                 info("     ! Skipping due to different family of zone");
285                 return;
286         }
287
288         if (rule->_ipset)
289         {
290                 if (!fw3_is_family(rule->_ipset, family))
291                 {
292                         info("     ! Skipping due to different family in ipset");
293                         return;
294                 }
295
296                 setbit(rule->_ipset->flags, family);
297         }
298
299         list_for_each_entry(proto, &rule->proto, list)
300         {
301                 /* icmp / ipv6-icmp */
302                 if (proto->protocol == 1 || proto->protocol == 58)
303                 {
304                         sports = &empty;
305                         dports = &empty;
306                         icmptypes = &rule->icmp_type;
307                 }
308                 else
309                 {
310                         sports = &rule->port_src;
311                         dports = &rule->port_dest;
312                         icmptypes = &empty;
313                 }
314
315                 fw3_foreach(sip, &rule->ip_src)
316                 fw3_foreach(dip, &rule->ip_dest)
317                 fw3_foreach(sport, sports)
318                 fw3_foreach(dport, dports)
319                 fw3_foreach(mac, &rule->mac_src)
320                 fw3_foreach(icmptype, icmptypes)
321                         print_rule(table, family, rule, proto, sip, dip, sport, dport,
322                                    mac, icmptype);
323         }
324 }
325
326 void
327 fw3_print_rules(enum fw3_table table, enum fw3_family family,
328                 struct fw3_state *state)
329 {
330         int num = 0;
331         struct fw3_rule *rule;
332
333         list_for_each_entry(rule, &state->rules, list)
334                 expand_rule(table, family, rule, num++);
335 }