2 * firewall3 - 3rd OpenWrt UCI firewall implementation
4 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
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.
26 static int lock_fd = -1;
27 static pid_t pipe_pid = -1;
28 static FILE *pipe_fd = NULL;
31 warn_elem_section_name(struct uci_section *s, bool find_name)
35 struct uci_element *tmp;
39 uci_foreach_element(&s->package->sections, tmp)
41 if (strcmp(uci_to_section(tmp)->type, s->type))
50 fprintf(stderr, "@%s[%d]", s->type, i);
54 uci_foreach_element(&s->options, tmp)
56 o = uci_to_option(tmp);
58 if (!strcmp(tmp->name, "name") && (o->type == UCI_TYPE_STRING))
60 fprintf(stderr, " (%s)", o->v.string);
68 fprintf(stderr, "'%s'", s->e.name);
76 warn_elem(struct uci_element *e, const char *format, ...)
78 if (e->type == UCI_TYPE_SECTION)
80 fprintf(stderr, "Warning: Section ");
81 warn_elem_section_name(uci_to_section(e), true);
83 else if (e->type == UCI_TYPE_OPTION)
85 fprintf(stderr, "Warning: Option ");
86 warn_elem_section_name(uci_to_option(e)->section, false);
87 fprintf(stderr, ".%s ", e->name);
91 va_start(argptr, format);
92 vfprintf(stderr, format, argptr);
95 fprintf(stderr, "\n");
99 warn(const char* format, ...)
101 fprintf(stderr, "Warning: ");
103 va_start(argptr, format);
104 vfprintf(stderr, format, argptr);
106 fprintf(stderr, "\n");
110 error(const char* format, ...)
112 fprintf(stderr, "Error: ");
114 va_start(argptr, format);
115 vfprintf(stderr, format, argptr);
117 fprintf(stderr, "\n");
123 info(const char* format, ...)
126 va_start(argptr, format);
127 vfprintf(stderr, format, argptr);
129 fprintf(stderr, "\n");
133 fw3_find_command(const char *cmd)
136 int plen = 0, clen = strlen(cmd) + 1;
138 static char path[PATH_MAX];
140 if (!stat(cmd, &s) && S_ISREG(s.st_mode))
143 search = getenv("PATH");
146 search = "/bin:/usr/bin:/sbin:/usr/sbin";
152 if (*p != ':' && *p != '\0')
157 if ((plen + clen) >= sizeof(path))
160 strncpy(path, search, plen);
161 sprintf(path + plen, "/%s", cmd);
163 if (!stat(path, &s) && S_ISREG(s.st_mode))
174 fw3_stdout_pipe(void)
181 __fw3_command_pipe(bool silent, const char *command, ...)
187 char *arg, **args, **tmp;
189 command = fw3_find_command(command);
198 args = malloc(argn * sizeof(arg));
203 args[0] = (char *)command;
206 va_start(argp, command);
208 while ((arg = va_arg(argp, char *)) != NULL)
210 tmp = realloc(args, ++argn * sizeof(arg));
222 switch ((pid = fork()))
238 execv(command, args);
241 signal(SIGPIPE, SIG_IGN);
246 pipe_fd = fdopen(pfds[1], "w");
251 fw3_pr(const char *fmt, ...)
255 vfprintf(pipe_fd, fmt, args);
260 fw3_command_close(void)
262 if (pipe_fd && pipe_fd != stdout)
266 waitpid(pipe_pid, NULL, 0);
268 signal(SIGPIPE, SIG_DFL);
275 fw3_has_table(bool ipv6, const char *table)
282 const char *path = ipv6
283 ? "/proc/net/ip6_tables_names" : "/proc/net/ip_tables_names";
285 if (!(f = fopen(path, "r")))
288 while (fgets(line, sizeof(line), f))
290 if (!strncmp(line, table, strlen(table)))
306 lock_fd = open(FW3_LOCKFILE, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
310 warn("Cannot create lock file %s: %s", FW3_LOCKFILE, strerror(errno));
314 if (flock(lock_fd, LOCK_EX))
316 warn("Cannot acquire exclusive lock: %s", strerror(errno));
329 if (flock(lock_fd, LOCK_UN))
330 warn("Cannot release exclusive lock: %s", strerror(errno));
333 unlink(FW3_LOCKFILE);
340 fw3_read_statefile(void *state)
346 const char *p, *name;
350 struct fw3_state *s = state;
351 struct fw3_zone *zone;
352 struct fw3_ipset *ipset;
354 sf = fopen(FW3_STATEFILE, "r");
359 while (fgets(line, sizeof(line), sf))
361 p = strtok(line, " \t\n");
366 type = strtoul(p, NULL, 10);
367 name = strtok(NULL, " \t\n");
372 for (n = 0, p = strtok(NULL, " \t\n");
373 n < ARRAY_SIZE(flags) && p != NULL;
374 n++, p = strtok(NULL, " \t\n"))
376 flags[n] = strtoul(p, NULL, 10);
381 case FW3_TYPE_DEFAULTS:
382 s->running_defaults.flags = flags[0];
386 if (!(zone = fw3_lookup_zone(state, name, false)))
388 zone = fw3_alloc_zone();
393 zone->name = strdup(name);
394 list_add_tail(&zone->list, &s->zones);
397 zone->src_flags = flags[0];
398 zone->dst_flags = flags[1];
399 list_add_tail(&zone->running_list, &s->running_zones);
403 if (!(ipset = fw3_lookup_ipset(state, name, false)))
405 ipset = fw3_alloc_ipset();
410 ipset->name = strdup(name);
411 list_add_tail(&ipset->list, &s->ipsets);
414 ipset->flags = flags[0];
415 list_add_tail(&ipset->running_list, &s->running_ipsets);
426 fw3_write_statefile(void *state)
429 struct fw3_state *s = state;
430 struct fw3_defaults *d = &s->defaults;
434 int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6);
436 if (!(d->flags & mask))
438 if (unlink(FW3_STATEFILE))
439 warn("Unable to remove state %s: %s",
440 FW3_STATEFILE, strerror(errno));
445 sf = fopen(FW3_STATEFILE, "w");
449 warn("Cannot create state %s: %s", FW3_STATEFILE, strerror(errno));
453 fprintf(sf, "%u - %u\n", FW3_TYPE_DEFAULTS, d->flags);
455 list_for_each_entry(z, &s->running_zones, running_list)
457 fprintf(sf, "%u %s %u %u\n", FW3_TYPE_ZONE,
458 z->name, z->src_flags, z->dst_flags);
461 list_for_each_entry(i, &s->running_ipsets, running_list)
463 fprintf(sf, "%u %s %u\n", FW3_TYPE_IPSET, i->name, i->flags);
470 struct object_list_heads
472 struct list_head list;
473 struct list_head running_list;
477 fw3_set_running(void *object, struct list_head *dest)
479 struct object_list_heads *o = object;
481 if (dest && !o->running_list.next)
482 list_add_tail(&o->running_list, dest);
483 else if (!dest && o->running_list.next)
484 list_del(&o->running_list);
488 fw3_free_object(void *obj, const void *opts)
490 const struct fw3_option *ol;
492 for (ol = opts; ol->name; ol++)
494 fw3_free_list((struct list_head *)((char *)obj + ol->offset));