ubus: increase ubus network interface dump timeout
[project/firewall3.git] / includes.c
1 /*
2  * firewall3 - 3rd OpenWrt UCI firewall implementation
3  *
4  *   Copyright (C) 2013 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 "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 static bool
34 check_include(struct fw3_state *state, struct fw3_include *include, struct uci_element *e)
35 {
36         if (!include->enabled)
37                 return false;
38
39         if (!include->path)
40         {
41                 warn_section("include", include, e, "must specify a path");
42                 return false;
43         }
44
45         if (include->type == FW3_INC_TYPE_RESTORE && !include->family)
46                 warn_section("include", include, e, "does not specify a family, include will get"
47                                 "loaded with both iptables-restore and ip6tables-restore!");
48
49         return true;
50 }
51
52 static struct fw3_include *
53 fw3_alloc_include(struct fw3_state *state)
54 {
55         struct fw3_include *include;
56
57         include = calloc(1, sizeof(*include));
58         if (!include)
59                 return NULL;
60
61         include->enabled = true;
62
63         list_add_tail(&include->list, &state->includes);
64
65         return include;
66 }
67
68 void
69 fw3_load_includes(struct fw3_state *state, struct uci_package *p,
70                 struct blob_attr *a)
71 {
72         struct uci_section *s;
73         struct uci_element *e;
74         struct fw3_include *include;
75         struct blob_attr *entry;
76         unsigned rem;
77
78         INIT_LIST_HEAD(&state->includes);
79
80         blob_for_each_attr(entry, a, rem)
81         {
82                 const char *type;
83                 const char *name = "ubus include";
84
85                 if (!fw3_attr_parse_name_type(entry, &name, &type))
86                         continue;
87
88                 if (strcmp(type, "script") && strcmp(type, "restore"))
89                         continue;
90
91                 include = fw3_alloc_include(state);
92                 if (!include)
93                         continue;
94
95                 if (!fw3_parse_blob_options(include, fw3_include_opts, entry, name))
96                 {
97                         warn_section("include", include, NULL, "skipped due to invalid options");
98                         fw3_free_include(include);
99                         continue;
100                 }
101
102                 if (!check_include(state, include, NULL))
103                         fw3_free_include(include);
104         }
105
106         uci_foreach_element(&p->sections, e)
107         {
108                 s = uci_to_section(e);
109
110                 if (strcmp(s->type, "include"))
111                         continue;
112
113                 include = fw3_alloc_include(state);
114                 if (!include)
115                         continue;
116
117                 include->name = e->name;
118
119                 if (!fw3_parse_options(include, fw3_include_opts, s))
120                         warn_elem(e, "has invalid options");
121
122                 if (!check_include(state, include, e))
123                         fw3_free_include(include);
124         }
125 }
126
127
128 static void
129 print_include(struct fw3_include *include)
130 {
131         FILE *f;
132         char line[1024];
133
134         info(" * Loading include '%s'", include->path);
135
136         if (!(f = fopen(include->path, "r")))
137         {
138                 info("   ! Skipping due to open error: %s", strerror(errno));
139                 return;
140         }
141
142         while (fgets(line, sizeof(line), f))
143                 fw3_pr(line);
144
145         fclose(f);
146 }
147
148 void
149 fw3_print_includes(struct fw3_state *state, enum fw3_family family, bool reload)
150 {
151         struct fw3_include *include;
152
153         bool exec = false;
154         const char *restore = "iptables-restore";
155
156         if (family == FW3_FAMILY_V6)
157                 restore = "ip6tables-restore";
158
159         list_for_each_entry(include, &state->includes, list)
160         {
161                 if (reload && !include->reload)
162                         continue;
163
164                 if (include->type != FW3_INC_TYPE_RESTORE)
165                         continue;
166
167                 if (!fw3_is_family(include, family))
168                         continue;
169
170                 if (!exec)
171                 {
172                         exec = fw3_command_pipe(false, restore, "--noflush");
173
174                         if (!exec)
175                                 return;
176                 }
177
178                 print_include(include);
179         }
180
181         if (exec)
182                 fw3_command_close();
183 }
184
185
186 static void
187 run_include(struct fw3_include *include)
188 {
189         int rv;
190         struct stat s;
191         const char *tmpl =
192                 "config() { "
193                         "echo \"You cannot use UCI in firewall includes!\" >&2; "
194                         "exit 1; "
195                 "}; . %s";
196
197         char buf[PATH_MAX + sizeof(tmpl)];
198
199         info(" * Running script '%s'", include->path);
200
201         if (stat(include->path, &s))
202         {
203                 info("   ! Skipping due to path error: %s", strerror(errno));
204                 return;
205         }
206
207         snprintf(buf, sizeof(buf), tmpl, include->path);
208         rv = system(buf);
209
210         if (rv)
211                 info("   ! Failed with exit code %u", WEXITSTATUS(rv));
212 }
213
214 void
215 fw3_run_includes(struct fw3_state *state, bool reload)
216 {
217         struct fw3_include *include;
218
219         list_for_each_entry(include, &state->includes, list)
220         {
221                 if (reload && !include->reload)
222                         continue;
223
224                 if (include->type == FW3_INC_TYPE_SCRIPT)
225                         run_include(include);
226         }
227 }