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.
22 static int lock_fd = -1;
23 static pid_t pipe_pid = -1;
24 static FILE *pipe_fd = NULL;
27 warn_elem_section_name(struct uci_section *s, bool find_name)
31 struct uci_element *tmp;
35 uci_foreach_element(&s->package->sections, tmp)
37 if (strcmp(uci_to_section(tmp)->type, s->type))
46 fprintf(stderr, "@%s[%d]", s->type, i);
50 uci_foreach_element(&s->options, tmp)
52 o = uci_to_option(tmp);
54 if (!strcmp(tmp->name, "name") && (o->type == UCI_TYPE_STRING))
56 fprintf(stderr, " (%s)", o->v.string);
64 fprintf(stderr, "'%s'", s->e.name);
72 warn_elem(struct uci_element *e, const char *format, ...)
74 if (e->type == UCI_TYPE_SECTION)
76 fprintf(stderr, "Warning: Section ");
77 warn_elem_section_name(uci_to_section(e), true);
79 else if (e->type == UCI_TYPE_OPTION)
81 fprintf(stderr, "Warning: Option ");
82 warn_elem_section_name(uci_to_option(e)->section, false);
83 fprintf(stderr, ".%s ", e->name);
87 va_start(argptr, format);
88 vfprintf(stderr, format, argptr);
91 fprintf(stderr, "\n");
95 warn(const char* format, ...)
97 fprintf(stderr, "Warning: ");
99 va_start(argptr, format);
100 vfprintf(stderr, format, argptr);
102 fprintf(stderr, "\n");
106 error(const char* format, ...)
108 fprintf(stderr, "Error: ");
110 va_start(argptr, format);
111 vfprintf(stderr, format, argptr);
113 fprintf(stderr, "\n");
119 info(const char* format, ...)
122 va_start(argptr, format);
123 vfprintf(stderr, format, argptr);
125 fprintf(stderr, "\n");
129 fw3_find_command(const char *cmd)
132 int plen = 0, clen = strlen(cmd) + 1;
134 static char path[PATH_MAX];
136 if (!stat(cmd, &s) && S_ISREG(s.st_mode))
139 search = getenv("PATH");
142 search = "/bin:/usr/bin:/sbin:/usr/sbin";
148 if (*p != ':' && *p != '\0')
153 if ((plen + clen) >= sizeof(path))
156 strncpy(path, search, plen);
157 sprintf(path + plen, "/%s", cmd);
159 if (!stat(path, &s) && S_ISREG(s.st_mode))
170 fw3_stdout_pipe(void)
177 __fw3_command_pipe(bool silent, const char *command, ...)
183 char *arg, **args, **tmp;
185 command = fw3_find_command(command);
194 args = malloc(argn * sizeof(arg));
199 args[0] = (char *)command;
202 va_start(argp, command);
204 while ((arg = va_arg(argp, char *)) != NULL)
206 tmp = realloc(args, ++argn * sizeof(arg));
218 switch ((pid = fork()))
234 execv(command, args);
237 signal(SIGPIPE, SIG_IGN);
242 pipe_fd = fdopen(pfds[1], "w");
247 fw3_pr(const char *fmt, ...)
251 vfprintf(pipe_fd, fmt, args);
256 fw3_command_close(void)
258 if (pipe_fd && pipe_fd != stdout)
262 waitpid(pipe_pid, NULL, 0);
264 signal(SIGPIPE, SIG_DFL);
271 fw3_has_table(bool ipv6, const char *table)
278 const char *path = ipv6
279 ? "/proc/net/ip6_tables_names" : "/proc/net/ip_tables_names";
281 if (!(f = fopen(path, "r")))
284 while (fgets(line, sizeof(line), f))
286 if (!strncmp(line, table, strlen(table)))
302 lock_fd = open(FW3_LOCKFILE, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
306 warn("Cannot create lock file %s: %s", FW3_LOCKFILE, strerror(errno));
310 if (flock(lock_fd, LOCK_EX))
312 warn("Cannot acquire exclusive lock: %s", strerror(errno));
325 if (flock(lock_fd, LOCK_UN))
326 warn("Cannot release exclusive lock: %s", strerror(errno));
329 unlink(FW3_LOCKFILE);
336 fw3_read_statefile(void)
344 struct list_head *state;
345 struct fw3_statefile_entry *entry;
347 sf = fopen(FW3_STATEFILE, "r");
352 state = malloc(sizeof(*state));
357 INIT_LIST_HEAD(state);
359 while (fgets(line, sizeof(line), sf))
361 entry = malloc(sizeof(*entry));
366 memset(entry, 0, sizeof(*entry));
368 p = strtok(line, " \t\n");
373 entry->type = strtoul(p, NULL, 10);
375 p = strtok(NULL, " \t\n");
380 entry->name = strdup(p);
382 for (n = 0, p = strtok(NULL, " \t\n");
383 n < ARRAY_SIZE(entry->flags) && p != NULL;
384 n++, p = strtok(NULL, " \t\n"))
386 entry->flags[n] = strtoul(p, NULL, 10);
389 list_add_tail(&entry->list, state);
398 fw3_write_statefile(void *state)
401 struct fw3_state *s = state;
402 struct fw3_defaults *d = &s->defaults;
406 int mask = (1 << FW3_DEFAULT_IPV4_LOADED) | (1 << FW3_DEFAULT_IPV6_LOADED);
408 if (!(d->flags & mask))
410 if (unlink(FW3_STATEFILE))
411 warn("Unable to remove state %s: %s",
412 FW3_STATEFILE, strerror(errno));
417 sf = fopen(FW3_STATEFILE, "w");
421 warn("Cannot create state %s: %s", FW3_STATEFILE, strerror(errno));
425 fprintf(sf, "%u - %u\n", FW3_TYPE_DEFAULTS, d->flags);
427 list_for_each_entry(z, &s->zones, list)
429 fprintf(sf, "%u %s %u %u\n", FW3_TYPE_ZONE,
430 z->name, z->src_flags, z->dst_flags);
433 list_for_each_entry(i, &s->ipsets, list)
435 if (i->external && *i->external)
438 fprintf(sf, "%u %s\n", FW3_TYPE_IPSET, i->name);
445 fw3_free_statefile(struct list_head *statefile)
447 struct fw3_statefile_entry *e, *tmp;
452 list_for_each_entry_safe(e, tmp, statefile, list)