defaults: add support for xt_FLOWOFFLOAD rule
[project/firewall3.git] / main.c
1 /*
2  * firewall3 - 3rd OpenWrt UCI firewall implementation
3  *
4  *   Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
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 <stdio.h>
20 #include <unistd.h>
21
22 #include "options.h"
23 #include "defaults.h"
24 #include "zones.h"
25 #include "rules.h"
26 #include "redirects.h"
27 #include "snats.h"
28 #include "forwards.h"
29 #include "ipsets.h"
30 #include "includes.h"
31 #include "ubus.h"
32 #include "iptables.h"
33 #include "helpers.h"
34
35
36 static enum fw3_family print_family = FW3_FAMILY_ANY;
37
38 static struct fw3_state *run_state = NULL;
39 static struct fw3_state *cfg_state = NULL;
40
41
42 static bool
43 build_state(bool runtime)
44 {
45         struct fw3_state *state = NULL;
46         struct uci_package *p = NULL;
47         FILE *sf;
48
49         state = calloc(1, sizeof(*state));
50         if (!state)
51                 error("Out of memory");
52
53         state->uci = uci_alloc_context();
54
55         if (!state->uci)
56                 error("Out of memory");
57
58         if (runtime)
59         {
60                 sf = fopen(FW3_STATEFILE, "r");
61
62                 if (sf)
63                 {
64                         uci_import(state->uci, sf, "fw3_state", &p, true);
65                         fclose(sf);
66                 }
67
68                 if (!p)
69                 {
70                         uci_free_context(state->uci);
71                         free(state);
72
73                         return false;
74                 }
75
76                 state->statefile = true;
77
78                 run_state = state;
79         }
80         else
81         {
82                 if (!fw3_ubus_connect())
83                         warn("Failed to connect to ubus");
84
85                 if (uci_load(state->uci, "firewall", &p))
86                 {
87                         uci_perror(state->uci, NULL);
88                         error("Failed to load /etc/config/firewall");
89                 }
90
91                 if (!fw3_find_command("ipset"))
92                 {
93                         warn("Unable to locate ipset utility, disabling ipset support");
94                         state->disable_ipsets = true;
95                 }
96
97                 cfg_state = state;
98         }
99
100
101         struct blob_buf b = {NULL, NULL, 0, NULL};
102         fw3_ubus_rules(&b);
103
104         fw3_load_defaults(state, p);
105         fw3_load_cthelpers(state, p);
106         fw3_load_ipsets(state, p, b.head);
107         fw3_load_zones(state, p);
108         fw3_load_rules(state, p, b.head);
109         fw3_load_redirects(state, p, b.head);
110         fw3_load_snats(state, p, b.head);
111         fw3_load_forwards(state, p, b.head);
112         fw3_load_includes(state, p, b.head);
113
114         return true;
115 }
116
117 static void
118 free_state(struct fw3_state *state)
119 {
120         struct list_head *cur, *tmp;
121
122         list_for_each_safe(cur, tmp, &state->zones)
123                 fw3_free_zone((struct fw3_zone *)cur);
124
125         list_for_each_safe(cur, tmp, &state->rules)
126                 fw3_free_rule((struct fw3_rule *)cur);
127
128         list_for_each_safe(cur, tmp, &state->redirects)
129                 fw3_free_redirect((struct fw3_redirect *)cur);
130
131         list_for_each_safe(cur, tmp, &state->snats)
132                 fw3_free_snat((struct fw3_snat *)cur);
133
134         list_for_each_safe(cur, tmp, &state->forwards)
135                 fw3_free_forward((struct fw3_forward *)cur);
136
137         list_for_each_safe(cur, tmp, &state->ipsets)
138                 fw3_free_ipset((struct fw3_ipset *)cur);
139
140         list_for_each_safe(cur, tmp, &state->includes)
141                 fw3_free_include((struct fw3_include *)cur);
142
143         list_for_each_safe(cur, tmp, &state->cthelpers)
144                 fw3_free_cthelper((struct fw3_cthelper *)cur);
145
146         uci_free_context(state->uci);
147
148         free(state);
149
150         fw3_ubus_disconnect();
151 }
152
153
154 static bool
155 family_running(enum fw3_family family)
156 {
157         return (run_state && has(run_state->defaults.flags, family, family));
158 }
159
160 static void
161 family_set(struct fw3_state *state, enum fw3_family family, bool set)
162 {
163         if (!state)
164                 return;
165
166         if (set)
167                 set(state->defaults.flags, family, family);
168         else
169                 del(state->defaults.flags, family, family);
170 }
171
172 static int
173 stop(bool complete)
174 {
175         int rv = 1;
176         enum fw3_family family;
177         enum fw3_table table;
178         struct fw3_ipt_handle *handle;
179
180         if (!complete && !run_state)
181         {
182                 warn("The firewall appears to be stopped. "
183                          "Use the 'flush' command to forcefully purge all rules.");
184
185                 return rv;
186         }
187
188         if (!print_family && run_state)
189                 fw3_hotplug_zones(run_state, false);
190
191         for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
192         {
193                 if (!complete && !family_running(family))
194                         continue;
195
196                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
197                 {
198                         if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
199                                 continue;
200
201                         if (!(handle = fw3_ipt_open(family, table)))
202                                 continue;
203
204                         info(" * %sing %s %s table", complete ? "Flush" : "Clear",
205                              fw3_flag_names[family], fw3_flag_names[table]);
206
207                         if (complete)
208                         {
209                                 fw3_flush_all(handle);
210                         }
211                         else if (run_state)
212                         {
213                                 fw3_flush_rules(handle, run_state, false);
214                                 fw3_flush_zones(handle, run_state, false);
215                         }
216
217                         fw3_ipt_commit(handle);
218                         fw3_ipt_close(handle);
219                 }
220
221                 family_set(run_state, family, false);
222                 family_set(cfg_state, family, false);
223
224                 rv = 0;
225         }
226
227         if (run_state)
228                 fw3_destroy_ipsets(run_state);
229
230         if (complete)
231                 fw3_flush_conntrack(NULL);
232
233         if (!rv && run_state)
234                 fw3_write_statefile(run_state);
235
236         return rv;
237 }
238
239 static int
240 start(void)
241 {
242         int rv = 1;
243         enum fw3_family family;
244         enum fw3_table table;
245         struct fw3_ipt_handle *handle;
246
247         if (!print_family)
248                 fw3_create_ipsets(cfg_state);
249
250         for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
251         {
252                 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
253                         continue;
254
255                 if (print_family && family != print_family)
256                         continue;
257
258                 if (!print_family && family_running(family))
259                 {
260                         warn("The %s firewall appears to be started already. "
261                              "If it is indeed empty, remove the %s file and retry.",
262                              fw3_flag_names[family], FW3_STATEFILE);
263
264                         continue;
265                 }
266
267                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
268                 {
269                         if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
270                                 continue;
271
272                         if (!(handle = fw3_ipt_open(family, table)))
273                                 continue;
274
275                         info(" * Populating %s %s table",
276                              fw3_flag_names[family], fw3_flag_names[table]);
277
278                         fw3_print_default_chains(handle, cfg_state, false);
279                         fw3_print_zone_chains(handle, cfg_state, false);
280                         fw3_print_default_head_rules(handle, cfg_state, false);
281                         fw3_print_rules(handle, cfg_state);
282                         fw3_print_redirects(handle, cfg_state);
283                         fw3_print_snats(handle, cfg_state);
284                         fw3_print_forwards(handle, cfg_state);
285                         fw3_print_zone_rules(handle, cfg_state, false);
286                         fw3_print_default_tail_rules(handle, cfg_state, false);
287
288                         if (!print_family)
289                                 fw3_ipt_commit(handle);
290
291                         fw3_ipt_close(handle);
292                 }
293
294                 if (!print_family)
295                         fw3_print_includes(cfg_state, family, false);
296
297                 family_set(run_state, family, true);
298                 family_set(cfg_state, family, true);
299
300                 rv = 0;
301         }
302
303         if (!rv)
304         {
305                 fw3_flush_conntrack(run_state);
306                 fw3_set_defaults(cfg_state);
307
308                 if (!print_family)
309                 {
310                         fw3_run_includes(cfg_state, false);
311                         fw3_hotplug_zones(cfg_state, true);
312                         fw3_write_statefile(cfg_state);
313                 }
314         }
315
316         return rv;
317 }
318
319
320 static int
321 reload(void)
322 {
323         int rv = 1;
324         enum fw3_family family;
325         enum fw3_table table;
326         struct fw3_ipt_handle *handle;
327
328         if (!run_state)
329                 return start();
330
331         fw3_hotplug_zones(run_state, false);
332
333         for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
334         {
335                 if (!family_running(family))
336                         goto start;
337
338                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
339                 {
340                         if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
341                                 continue;
342
343                         if (!(handle = fw3_ipt_open(family, table)))
344                                 continue;
345
346                         info(" * Clearing %s %s table",
347                              fw3_flag_names[family], fw3_flag_names[table]);
348
349                         fw3_flush_rules(handle, run_state, true);
350                         fw3_flush_zones(handle, run_state, true);
351                         fw3_ipt_commit(handle);
352                         fw3_ipt_close(handle);
353                 }
354
355                 family_set(run_state, family, false);
356                 family_set(cfg_state, family, false);
357
358 start:
359                 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
360                         continue;
361
362                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
363                 {
364                         if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
365                                 continue;
366
367                         if (!(handle = fw3_ipt_open(family, table)))
368                                 continue;
369
370                         info(" * Populating %s %s table",
371                              fw3_flag_names[family], fw3_flag_names[table]);
372
373                         fw3_print_default_chains(handle, cfg_state, true);
374                         fw3_print_zone_chains(handle, cfg_state, true);
375                         fw3_print_default_head_rules(handle, cfg_state, true);
376                         fw3_print_rules(handle, cfg_state);
377                         fw3_print_redirects(handle, cfg_state);
378                         fw3_print_snats(handle, cfg_state);
379                         fw3_print_forwards(handle, cfg_state);
380                         fw3_print_zone_rules(handle, cfg_state, true);
381                         fw3_print_default_tail_rules(handle, cfg_state, true);
382
383                         fw3_ipt_commit(handle);
384                         fw3_ipt_close(handle);
385                 }
386
387                 fw3_print_includes(cfg_state, family, true);
388
389                 family_set(run_state, family, true);
390                 family_set(cfg_state, family, true);
391
392                 rv = 0;
393         }
394
395         if (!rv)
396         {
397                 fw3_flush_conntrack(run_state);
398
399                 fw3_set_defaults(cfg_state);
400                 fw3_run_includes(cfg_state, true);
401                 fw3_hotplug_zones(cfg_state, true);
402                 fw3_write_statefile(cfg_state);
403         }
404
405         return rv;
406 }
407
408 static int
409 gc(void)
410 {
411         enum fw3_family family;
412         enum fw3_table table;
413         struct fw3_ipt_handle *handle;
414
415         for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
416         {
417                 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
418                         continue;
419
420                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
421                 {
422                         if (!fw3_has_table(family == FW3_FAMILY_V6, fw3_flag_names[table]))
423                                 continue;
424
425                         if (!(handle = fw3_ipt_open(family, table)))
426                                 continue;
427
428                         fw3_ipt_gc(handle);
429                         fw3_ipt_commit(handle);
430                         fw3_ipt_close(handle);
431                 }
432         }
433
434         return 0;
435 }
436
437 static int
438 lookup_network(const char *net)
439 {
440         struct fw3_zone *z;
441         struct fw3_device *d;
442
443         list_for_each_entry(z, &cfg_state->zones, list)
444         {
445                 list_for_each_entry(d, &z->networks, list)
446                 {
447                         if (!strcmp(d->name, net))
448                         {
449                                 printf("%s\n", z->name);
450                                 return 0;
451                         }
452                 }
453         }
454
455         return 1;
456 }
457
458 static int
459 lookup_device(const char *dev)
460 {
461         struct fw3_zone *z;
462         struct fw3_device *d;
463
464         list_for_each_entry(z, &cfg_state->zones, list)
465         {
466                 list_for_each_entry(d, &z->devices, list)
467                 {
468                         if (!strcmp(d->name, dev))
469                         {
470                                 printf("%s\n", z->name);
471                                 return 0;
472                         }
473                 }
474         }
475
476         return 1;
477 }
478
479 static int
480 lookup_zone(const char *zone, const char *device)
481 {
482         struct fw3_zone *z;
483         struct fw3_device *d;
484
485         list_for_each_entry(z, &cfg_state->zones, list)
486         {
487                 if (strcmp(z->name, zone))
488                         continue;
489
490                 list_for_each_entry(d, &z->devices, list)
491                 {
492                         if (device && strcmp(device, d->name))
493                                 continue;
494
495                         printf("%s\n", d->name);
496
497                         if (device)
498                                 return 0;
499                 }
500
501                 if (!device)
502                         return 0;
503         }
504
505         return 1;
506 }
507
508 static int
509 usage(void)
510 {
511         fprintf(stderr, "fw3 [-4] [-6] [-q] print\n");
512         fprintf(stderr, "fw3 [-q] {start|stop|flush|reload|restart}\n");
513         fprintf(stderr, "fw3 [-q] network {net}\n");
514         fprintf(stderr, "fw3 [-q] device {dev}\n");
515         fprintf(stderr, "fw3 [-q] zone {zone} [dev]\n");
516
517         return 1;
518 }
519
520
521 int main(int argc, char **argv)
522 {
523         int ch, rv = 1;
524         enum fw3_family family = FW3_FAMILY_ANY;
525         struct fw3_defaults *defs = NULL;
526
527         while ((ch = getopt(argc, argv, "46dqh")) != -1)
528         {
529                 switch (ch)
530                 {
531                 case '4':
532                         family = FW3_FAMILY_V4;
533                         break;
534
535                 case '6':
536                         family = FW3_FAMILY_V6;
537                         break;
538
539                 case 'd':
540                         fw3_pr_debug = true;
541                         break;
542
543                 case 'q':
544                         if (freopen("/dev/null", "w", stderr)) {}
545                         break;
546
547                 case 'h':
548                         rv = usage();
549                         goto out;
550                 }
551         }
552
553         build_state(false);
554         defs = &cfg_state->defaults;
555
556         if (optind >= argc)
557         {
558                 rv = usage();
559                 goto out;
560         }
561
562         if (!strcmp(argv[optind], "print"))
563         {
564                 if (family == FW3_FAMILY_ANY)
565                 {
566                         family = FW3_FAMILY_V4;
567                 }
568                 else if (family == FW3_FAMILY_V6)
569                 {
570                         if (defs->disable_ipv6)
571                                 warn("IPv6 rules globally disabled in configuration");
572 #ifdef DISABLE_IPV6
573                         else
574                                 warn("IPv6 support is not compiled in");
575 #endif
576                 }
577
578                 if (freopen("/dev/null", "w", stderr)) {};
579
580                 cfg_state->disable_ipsets = true;
581                 print_family = family;
582                 fw3_pr_debug = true;
583
584                 if (fw3_lock())
585                 {
586                         build_state(true);
587                         rv = start();
588                         fw3_unlock();
589                 }
590         }
591         else if (!strcmp(argv[optind], "start"))
592         {
593                 if (fw3_lock())
594                 {
595                         build_state(true);
596                         rv = start();
597                         fw3_unlock();
598                 }
599         }
600         else if (!strcmp(argv[optind], "stop"))
601         {
602                 if (fw3_lock())
603                 {
604                         build_state(true);
605                         rv = stop(false);
606                         fw3_unlock();
607                 }
608         }
609         else if (!strcmp(argv[optind], "flush"))
610         {
611                 if (fw3_lock())
612                 {
613                         build_state(true);
614                         rv = stop(true);
615                         fw3_unlock();
616                 }
617         }
618         else if (!strcmp(argv[optind], "restart"))
619         {
620                 if (fw3_lock())
621                 {
622                         build_state(true);
623                         stop(true);
624                         rv = start();
625                         fw3_unlock();
626                 }
627         }
628         else if (!strcmp(argv[optind], "reload"))
629         {
630                 if (fw3_lock())
631                 {
632                         build_state(true);
633                         rv = reload();
634                         fw3_unlock();
635                 }
636         }
637         else if (!strcmp(argv[optind], "gc"))
638         {
639                 if (fw3_lock())
640                 {
641                         rv = gc();
642                         fw3_unlock();
643                 }
644         }
645         else if (!strcmp(argv[optind], "network") && (optind + 1) < argc)
646         {
647                 rv = lookup_network(argv[optind + 1]);
648         }
649         else if (!strcmp(argv[optind], "device") && (optind + 1) < argc)
650         {
651                 rv = lookup_device(argv[optind + 1]);
652         }
653         else if (!strcmp(argv[optind], "zone") && (optind + 1) < argc)
654         {
655                 rv = lookup_zone(argv[optind + 1], argv[optind + 2]);
656         }
657         else
658         {
659                 rv = usage();
660         }
661
662 out:
663         if (cfg_state)
664                 free_state(cfg_state);
665
666         if (run_state)
667                 free_state(run_state);
668
669         return rv;
670 }