Restore iptables-save include functionality
[project/firewall3.git] / includes.c
1 /*
2  * firewall3 - 3rd OpenWrt UCI firewall implementation
3  *
4  *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
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 "includes.h"
20
21
22 const struct fw3_option fw3_include_opts[] = {
23         FW3_OPT("enabled",             bool,           include,     enabled),
24
25         FW3_OPT("path",                string,         include,     path),
26         FW3_OPT("type",                include_type,   include,     type),
27         FW3_OPT("family",              family,         include,     family),
28         FW3_OPT("reload",              bool,           include,     reload),
29
30         { }
31 };
32
33
34 void
35 fw3_load_includes(struct fw3_state *state, struct uci_package *p)
36 {
37         struct uci_section *s;
38         struct uci_element *e;
39         struct fw3_include *include;
40
41         INIT_LIST_HEAD(&state->includes);
42
43         uci_foreach_element(&p->sections, e)
44         {
45                 s = uci_to_section(e);
46
47                 if (strcmp(s->type, "include"))
48                         continue;
49
50                 include = malloc(sizeof(*include));
51
52                 if (!include)
53                         continue;
54
55                 memset(include, 0, sizeof(*include));
56
57                 include->name = e->name;
58                 include->enabled = true;
59
60                 fw3_parse_options(include, fw3_include_opts, s);
61
62                 if (!include->enabled)
63                 {
64                         fw3_free_include(include);
65                         continue;
66                 }
67
68                 if (!include->path)
69                 {
70                         warn_elem(e, "must specify a path");
71                         fw3_free_include(include);
72                         continue;
73                 }
74
75                 if (include->type == FW3_INC_TYPE_RESTORE && !include->family)
76                         warn_elem(e, "does not specify a family, include will get loaded "
77                                      "with both iptables-restore and ip6tables-restore!");
78
79                 list_add_tail(&include->list, &state->includes);
80                 continue;
81         }
82 }
83
84
85 static void
86 print_include(struct fw3_include *include)
87 {
88         FILE *f;
89         char line[1024];
90
91         info(" * Loading include '%s'", include->path);
92
93         if (!(f = fopen(include->path, "r")))
94         {
95                 info("   ! Skipping due to open error: %s", strerror(errno));
96                 return;
97         }
98
99         while (fgets(line, sizeof(line), f))
100                 fw3_pr(line);
101
102         fclose(f);
103 }
104
105 void
106 fw3_print_includes(struct fw3_state *state, enum fw3_family family, bool reload)
107 {
108         struct fw3_include *include;
109
110         bool exec = false;
111         const char *restore = "iptables-restore";
112
113         if (family == FW3_FAMILY_V6)
114                 restore = "ip6tables-restore";
115
116         list_for_each_entry(include, &state->includes, list)
117         {
118                 if (reload && !include->reload)
119                         continue;
120
121                 if (include->type != FW3_INC_TYPE_RESTORE)
122                         continue;
123
124                 if (!fw3_is_family(include, family))
125                         continue;
126
127                 if (!exec)
128                 {
129                         exec = fw3_command_pipe(false, restore, "--noflush");
130
131                         if (!exec)
132                                 return;
133                 }
134
135                 print_include(include);
136         }
137
138         fw3_command_close();
139 }
140
141
142 static void
143 run_include(struct fw3_include *include)
144 {
145         int rv;
146         struct stat s;
147         const char *tmpl =
148                 "config() { "
149                         "echo \"You cannot use UCI in firewall includes!\" >&2; "
150                         "exit 1; "
151                 "}; . %s";
152
153         char buf[PATH_MAX + sizeof(tmpl)];
154
155         info(" * Running script '%s'", include->path);
156
157         if (stat(include->path, &s))
158         {
159                 info("   ! Skipping due to path error: %s", strerror(errno));
160                 return;
161         }
162
163         snprintf(buf, sizeof(buf), tmpl, include->path);
164         rv = system(buf);
165
166         if (rv)
167                 info("   ! Failed with exit code %u", WEXITSTATUS(rv));
168 }
169
170 void
171 fw3_run_includes(struct fw3_state *state, bool reload)
172 {
173         struct fw3_include *include;
174
175         list_for_each_entry(include, &state->includes, list)
176         {
177                 if (reload && !include->reload)
178                         continue;
179
180                 if (include->type == FW3_INC_TYPE_SCRIPT)
181                         run_include(include);
182         }
183 }