• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firewall3/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 (!(handle = fw3_ipt_open(family, table)))
199                                 continue;
200 
201                         info(" * %sing %s %s table", complete ? "Flush" : "Clear",
202                              fw3_flag_names[family], fw3_flag_names[table]);
203 
204                         if (complete)
205                         {
206                                 fw3_flush_all(handle);
207                         }
208                         else if (run_state)
209                         {
210                                 fw3_flush_rules(handle, run_state, false);
211                                 fw3_flush_zones(handle, run_state, false);
212                         }
213 
214                         fw3_ipt_commit(handle);
215                         fw3_ipt_close(handle);
216                 }
217 
218                 family_set(run_state, family, false);
219                 family_set(cfg_state, family, false);
220 
221                 rv = 0;
222         }
223 
224         if (run_state) {
225                 for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
226                         fw3_destroy_ipsets(run_state, family, false);
227         }
228 
229         if (complete)
230                 fw3_flush_conntrack(NULL);
231 
232         if (!rv && run_state)
233                 fw3_write_statefile(run_state);
234 
235         return rv;
236 }
237 
238 static int
239 start(void)
240 {
241         int rv = 1;
242         enum fw3_family family;
243         enum fw3_table table;
244         struct fw3_ipt_handle *handle;
245 
246         for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
247         {
248                 if (!print_family)
249                         fw3_create_ipsets(cfg_state, family, false);
250 
251                 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
252                         continue;
253 
254                 if (print_family && family != print_family)
255                         continue;
256 
257                 if (!print_family && family_running(family))
258                 {
259                         warn("The %s firewall appears to be started already. "
260                              "If it is indeed empty, remove the %s file and retry.",
261                              fw3_flag_names[family], FW3_STATEFILE);
262 
263                         continue;
264                 }
265 
266                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
267                 {
268                         if (!(handle = fw3_ipt_open(family, table)))
269                                 continue;
270 
271                         info(" * Populating %s %s table",
272                              fw3_flag_names[family], fw3_flag_names[table]);
273 
274                         fw3_print_default_chains(handle, cfg_state, false);
275                         fw3_print_zone_chains(handle, cfg_state, false);
276                         fw3_print_default_head_rules(handle, cfg_state, false);
277                         fw3_print_rules(handle, cfg_state);
278                         fw3_print_redirects(handle, cfg_state);
279                         fw3_print_snats(handle, cfg_state);
280                         fw3_print_forwards(handle, cfg_state);
281                         fw3_print_zone_rules(handle, cfg_state, false);
282                         fw3_print_default_tail_rules(handle, cfg_state, false);
283 
284                         if (!print_family)
285                                 fw3_ipt_commit(handle);
286 
287                         fw3_ipt_close(handle);
288                 }
289 
290                 if (!print_family)
291                         fw3_print_includes(cfg_state, family, false);
292 
293                 family_set(run_state, family, true);
294                 family_set(cfg_state, family, true);
295 
296                 rv = 0;
297         }
298 
299         if (!rv)
300         {
301                 fw3_flush_conntrack(run_state);
302                 fw3_set_defaults(cfg_state);
303 
304                 if (!print_family)
305                 {
306                         fw3_run_includes(cfg_state, false);
307                         fw3_hotplug_zones(cfg_state, true);
308                         fw3_write_statefile(cfg_state);
309                 }
310         }
311 
312         return rv;
313 }
314 
315 
316 static int
317 reload(void)
318 {
319         int rv = 1;
320         enum fw3_family family;
321         enum fw3_table table;
322         struct fw3_ipt_handle *handle;
323 
324         if (!run_state)
325                 return start();
326 
327         fw3_hotplug_zones(run_state, false);
328 
329         for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
330         {
331                 if (!family_running(family))
332                         goto start;
333 
334                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
335                 {
336                         if (!(handle = fw3_ipt_open(family, table)))
337                                 continue;
338 
339                         info(" * Clearing %s %s table",
340                              fw3_flag_names[family], fw3_flag_names[table]);
341 
342                         fw3_flush_rules(handle, run_state, true);
343                         fw3_flush_zones(handle, run_state, true);
344                         fw3_ipt_commit(handle);
345                         fw3_ipt_close(handle);
346                 }
347 
348                 fw3_ipsets_update_run_state(family, run_state, cfg_state);
349                 fw3_destroy_ipsets(run_state, family, true);
350 
351                 family_set(run_state, family, false);
352                 family_set(cfg_state, family, false);
353 
354 start:
355                 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
356                         continue;
357 
358                 fw3_create_ipsets(cfg_state, family, true);
359 
360                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
361                 {
362                         if (!(handle = fw3_ipt_open(family, table)))
363                                 continue;
364 
365                         info(" * Populating %s %s table",
366                              fw3_flag_names[family], fw3_flag_names[table]);
367 
368                         fw3_print_default_chains(handle, cfg_state, true);
369                         fw3_print_zone_chains(handle, cfg_state, true);
370                         fw3_print_default_head_rules(handle, cfg_state, true);
371                         fw3_print_rules(handle, cfg_state);
372                         fw3_print_redirects(handle, cfg_state);
373                         fw3_print_snats(handle, cfg_state);
374                         fw3_print_forwards(handle, cfg_state);
375                         fw3_print_zone_rules(handle, cfg_state, true);
376                         fw3_print_default_tail_rules(handle, cfg_state, true);
377 
378                         fw3_ipt_commit(handle);
379                         fw3_ipt_close(handle);
380                 }
381 
382                 fw3_print_includes(cfg_state, family, true);
383 
384                 family_set(run_state, family, true);
385                 family_set(cfg_state, family, true);
386 
387                 rv = 0;
388         }
389 
390         if (!rv)
391         {
392                 fw3_flush_conntrack(run_state);
393 
394                 fw3_set_defaults(cfg_state);
395                 fw3_run_includes(cfg_state, true);
396                 fw3_hotplug_zones(cfg_state, true);
397                 fw3_write_statefile(cfg_state);
398         }
399 
400         return rv;
401 }
402 
403 static int
404 gc(void)
405 {
406         enum fw3_family family;
407         enum fw3_table table;
408         struct fw3_ipt_handle *handle;
409 
410         for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
411         {
412                 if (family == FW3_FAMILY_V6 && cfg_state->defaults.disable_ipv6)
413                         continue;
414 
415                 for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
416                 {
417                         if (!(handle = fw3_ipt_open(family, table)))
418                                 continue;
419 
420                         fw3_ipt_gc(handle);
421                         fw3_ipt_commit(handle);
422                         fw3_ipt_close(handle);
423                 }
424         }
425 
426         return 0;
427 }
428 
429 static int
430 lookup_network(const char *net)
431 {
432         struct fw3_zone *z;
433         struct fw3_device *d;
434 
435         list_for_each_entry(z, &cfg_state->zones, list)
436         {
437                 list_for_each_entry(d, &z->networks, list)
438                 {
439                         if (!strcmp(d->name, net))
440                         {
441                                 printf("%s\n", z->name);
442                                 return 0;
443                         }
444                 }
445         }
446 
447         return 1;
448 }
449 
450 static int
451 lookup_device(const char *dev)
452 {
453         struct fw3_zone *z;
454         struct fw3_device *d;
455 
456         list_for_each_entry(z, &cfg_state->zones, list)
457         {
458                 list_for_each_entry(d, &z->devices, list)
459                 {
460                         if (!strcmp(d->name, dev))
461                         {
462                                 printf("%s\n", z->name);
463                                 return 0;
464                         }
465                 }
466         }
467 
468         return 1;
469 }
470 
471 static int
472 lookup_zone(const char *zone, const char *device)
473 {
474         struct fw3_zone *z;
475         struct fw3_device *d;
476 
477         list_for_each_entry(z, &cfg_state->zones, list)
478         {
479                 if (strcmp(z->name, zone))
480                         continue;
481 
482                 list_for_each_entry(d, &z->devices, list)
483                 {
484                         if (device && strcmp(device, d->name))
485                                 continue;
486 
487                         printf("%s\n", d->name);
488 
489                         if (device)
490                                 return 0;
491                 }
492 
493                 if (!device)
494                         return 0;
495         }
496 
497         return 1;
498 }
499 
500 static int
501 usage(void)
502 {
503         fprintf(stderr, "fw3 [-4] [-6] [-q] print\n");
504         fprintf(stderr, "fw3 [-q] {start|stop|flush|reload|restart}\n");
505         fprintf(stderr, "fw3 [-q] network {net}\n");
506         fprintf(stderr, "fw3 [-q] device {dev}\n");
507         fprintf(stderr, "fw3 [-q] zone {zone} [dev]\n");
508 
509         return 1;
510 }
511 
512 
513 int main(int argc, char **argv)
514 {
515         int ch, rv = 1;
516         enum fw3_family family = FW3_FAMILY_ANY;
517         struct fw3_defaults *defs = NULL;
518 
519         while ((ch = getopt(argc, argv, "46dqh")) != -1)
520         {
521                 switch (ch)
522                 {
523                 case '4':
524                         family = FW3_FAMILY_V4;
525                         break;
526 
527                 case '6':
528                         family = FW3_FAMILY_V6;
529                         break;
530 
531                 case 'd':
532                         fw3_pr_debug = true;
533                         break;
534 
535                 case 'q':
536                         if (freopen("/dev/null", "w", stderr)) {}
537                         break;
538 
539                 case 'h':
540                         rv = usage();
541                         goto out;
542                 }
543         }
544 
545         build_state(false);
546         defs = &cfg_state->defaults;
547 
548         if (optind >= argc)
549         {
550                 rv = usage();
551                 goto out;
552         }
553 
554         if (!strcmp(argv[optind], "print"))
555         {
556                 if (family == FW3_FAMILY_ANY)
557                 {
558                         family = FW3_FAMILY_V4;
559                 }
560                 else if (family == FW3_FAMILY_V6)
561                 {
562                         if (defs->disable_ipv6)
563                                 warn("IPv6 rules globally disabled in configuration");
564 #ifdef DISABLE_IPV6
565                         else
566                                 warn("IPv6 support is not compiled in");
567 #endif
568                 }
569 
570                 if (freopen("/dev/null", "w", stderr)) {};
571 
572                 cfg_state->disable_ipsets = true;
573                 print_family = family;
574                 fw3_pr_debug = true;
575 
576                 if (fw3_lock())
577                 {
578                         build_state(true);
579                         rv = start();
580                         fw3_unlock();
581                 }
582         }
583         else if (!strcmp(argv[optind], "start"))
584         {
585                 if (fw3_lock())
586                 {
587                         build_state(true);
588                         rv = start();
589                         fw3_unlock();
590                 }
591         }
592         else if (!strcmp(argv[optind], "stop"))
593         {
594                 if (fw3_lock())
595                 {
596                         build_state(true);
597                         rv = stop(false);
598                         fw3_unlock();
599                 }
600         }
601         else if (!strcmp(argv[optind], "flush"))
602         {
603                 if (fw3_lock())
604                 {
605                         build_state(true);
606                         rv = stop(true);
607                         fw3_unlock();
608                 }
609         }
610         else if (!strcmp(argv[optind], "restart"))
611         {
612                 if (fw3_lock())
613                 {
614                         build_state(true);
615                         stop(true);
616                         rv = start();
617                         fw3_unlock();
618                 }
619         }
620         else if (!strcmp(argv[optind], "reload"))
621         {
622                 if (fw3_lock())
623                 {
624                         build_state(true);
625                         rv = reload();
626                         fw3_unlock();
627                 }
628         }
629         else if (!strcmp(argv[optind], "gc"))
630         {
631                 if (fw3_lock())
632                 {
633                         rv = gc();
634                         fw3_unlock();
635                 }
636         }
637         else if (!strcmp(argv[optind], "network") && (optind + 1) < argc)
638         {
639                 rv = lookup_network(argv[optind + 1]);
640         }
641         else if (!strcmp(argv[optind], "device") && (optind + 1) < argc)
642         {
643                 rv = lookup_device(argv[optind + 1]);
644         }
645         else if (!strcmp(argv[optind], "zone") && (optind + 1) < argc)
646         {
647                 rv = lookup_zone(argv[optind + 1], argv[optind + 2]);
648         }
649         else
650         {
651                 rv = usage();
652         }
653 
654 out:
655         if (cfg_state)
656                 free_state(cfg_state);
657 
658         if (run_state)
659                 free_state(run_state);
660 
661         return rv;
662 }
663 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt