2 * firewall3 - 3rd OpenWrt UCI firewall implementation
4 * Copyright (C) 2018 Jo-Philipp Wich <jo@mein.io>
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 const struct fw3_option fw3_cthelper_opts[] = {
23 FW3_OPT("enabled", bool, cthelper, enabled),
24 FW3_OPT("name", string, cthelper, name),
25 FW3_OPT("module", string, cthelper, module),
26 FW3_OPT("description", string, cthelper, description),
27 FW3_OPT("family", family, cthelper, family),
28 FW3_OPT("proto", protocol, cthelper, proto),
29 FW3_OPT("port", port, cthelper, port),
36 test_module(struct fw3_cthelper *helper)
39 char path[sizeof("/sys/module/nf_conntrack_xxxxxxxxxxxxxxxx")];
41 snprintf(path, sizeof(path), "/sys/module/%s", helper->module);
43 if (stat(path, &s) || !S_ISDIR(s.st_mode))
50 check_cthelper(struct fw3_state *state, struct fw3_cthelper *helper, struct uci_element *e)
52 if (!helper->name || !*helper->name)
54 warn_section("helper", helper, e, "must have a name assigned");
56 else if (!helper->module || !*helper->module)
58 warn_section("helper", helper, e, "must have a module assigned");
60 else if (!helper->proto.protocol || helper->proto.any || helper->proto.invert)
62 warn_section("helper", helper, e, "must specify a protocol");
64 else if (helper->port.set && helper->port.invert)
66 warn_section("helper", helper, e, "must not specify negated ports");
76 static struct fw3_cthelper *
77 fw3_alloc_cthelper(struct fw3_state *state)
79 struct fw3_cthelper *helper;
81 helper = calloc(1, sizeof(*helper));
85 helper->enabled = true;
86 helper->family = FW3_FAMILY_ANY;
88 list_add_tail(&helper->list, &state->cthelpers);
94 load_cthelpers(struct fw3_state *state, struct uci_package *p)
96 struct fw3_cthelper *helper;
97 struct uci_section *s;
98 struct uci_element *e;
100 uci_foreach_element(&p->sections, e)
102 s = uci_to_section(e);
104 if (strcmp(s->type, "helper"))
107 helper = fw3_alloc_cthelper(state);
112 if (!fw3_parse_options(helper, fw3_cthelper_opts, s))
113 warn_elem(e, "has invalid options");
115 if (!check_cthelper(state, helper, e))
116 fw3_free_cthelper(helper);
121 fw3_load_cthelpers(struct fw3_state *state, struct uci_package *p)
123 struct uci_package *hp = NULL;
126 INIT_LIST_HEAD(&state->cthelpers);
128 fp = fopen(FW3_HELPERCONF, "r");
131 uci_import(state->uci, fp, "fw3_ct_helpers", &hp, true);
135 load_cthelpers(state, hp);
138 load_cthelpers(state, p);
141 struct fw3_cthelper *
142 fw3_lookup_cthelper(struct fw3_state *state, const char *name)
144 struct fw3_cthelper *h;
146 if (list_empty(&state->cthelpers))
149 list_for_each_entry(h, &state->cthelpers, list)
151 if (strcasecmp(h->name, name))
160 struct fw3_cthelper *
161 fw3_lookup_cthelper_by_proto_port(struct fw3_state *state,
162 struct fw3_protocol *proto,
163 struct fw3_port *port)
165 struct fw3_cthelper *h;
167 if (list_empty(&state->cthelpers))
170 if (!proto || !proto->protocol || proto->any || proto->invert)
173 if (port && port->invert)
176 list_for_each_entry(h, &state->cthelpers, list)
181 if (h->proto.protocol != proto->protocol)
184 if (h->port.set && (!port || !port->set))
187 if (!h->port.set && (!port || !port->set))
190 if (h->port.set && port && port->set &&
191 h->port.port_min <= port->port_min &&
192 h->port.port_max >= port->port_max)
200 print_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
201 struct fw3_zone *zone)
203 struct fw3_ipt_rule *r;
205 r = fw3_ipt_rule_create(handle, &helper->proto, NULL, NULL, NULL, NULL);
207 if (helper->description && *helper->description)
208 fw3_ipt_rule_comment(r, helper->description);
210 fw3_ipt_rule_comment(r, helper->name);
212 fw3_ipt_rule_sport_dport(r, NULL, &helper->port);
213 fw3_ipt_rule_target(r, "CT");
214 fw3_ipt_rule_addarg(r, false, "--helper", helper->name);
215 fw3_ipt_rule_replace(r, "zone_%s_helper", zone->name);
219 fw3_print_cthelpers(struct fw3_ipt_handle *handle, struct fw3_state *state,
220 struct fw3_zone *zone)
222 struct fw3_cthelper *helper;
223 struct fw3_cthelpermatch *match;
225 if (handle->table != FW3_TABLE_RAW)
228 if (!fw3_is_family(zone, handle->family))
231 if (list_empty(&zone->cthelpers))
233 if (zone->masq || !zone->auto_helper)
236 if (list_empty(&state->cthelpers))
239 info(" - Using automatic conntrack helper attachment");
241 list_for_each_entry(helper, &state->cthelpers, list)
243 if (!helper || !helper->enabled)
246 if (!fw3_is_family(helper, handle->family))
249 if (!test_module(helper))
252 print_helper_rule(handle, helper, zone);
257 list_for_each_entry(match, &zone->cthelpers, list)
261 if (!helper || !helper->enabled)
264 if (!fw3_is_family(helper, handle->family))
267 if (!test_module(helper))
269 info(" ! Conntrack module '%s' for helper '%s' is not loaded",
270 helper->module, helper->name);
274 print_helper_rule(handle, helper, zone);