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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt