123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- /*
- * firewall3 - 3rd OpenWrt UCI firewall implementation
- *
- * Copyright (C) 2018 Jo-Philipp Wich <jo@mein.io>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "helpers.h"
- const struct fw3_option fw3_cthelper_opts[] = {
- FW3_OPT("enabled", bool, cthelper, enabled),
- FW3_OPT("name", string, cthelper, name),
- FW3_OPT("module", string, cthelper, module),
- FW3_OPT("description", string, cthelper, description),
- FW3_OPT("family", family, cthelper, family),
- FW3_LIST("proto", protocol, cthelper, proto),
- FW3_OPT("port", port, cthelper, port),
- { }
- };
- static bool
- test_module(struct fw3_cthelper *helper)
- {
- struct stat s;
- char path[sizeof("/sys/module/nf_conntrack_xxxxxxxxxxxxxxxx")];
- snprintf(path, sizeof(path), "/sys/module/%s", helper->module);
- if (stat(path, &s) || !S_ISDIR(s.st_mode))
- return false;
- return true;
- }
- static bool
- check_cthelper_proto(const struct fw3_cthelper *helper)
- {
- struct fw3_protocol *proto;
- if (list_empty(&helper->proto))
- return false;
- list_for_each_entry(proto, &helper->proto, list)
- {
- if (!proto->protocol || proto->any || proto->invert)
- return false;
- }
- return true;
- }
- static bool
- check_cthelper(struct fw3_state *state, struct fw3_cthelper *helper, struct uci_element *e)
- {
- if (!helper->name || !*helper->name)
- {
- warn_section("helper", helper, e, "must have a name assigned");
- }
- else if (!helper->module || !*helper->module)
- {
- warn_section("helper", helper, e, "must have a module assigned");
- }
- else if (!check_cthelper_proto(helper))
- {
- warn_section("helper", helper, e, "must specify a protocol");
- }
- else if (helper->port.set && helper->port.invert)
- {
- warn_section("helper", helper, e, "must not specify negated ports");
- }
- else
- {
- return true;
- }
- return false;
- }
- static struct fw3_cthelper *
- fw3_alloc_cthelper(struct fw3_state *state)
- {
- struct fw3_cthelper *helper;
- helper = calloc(1, sizeof(*helper));
- if (!helper)
- return NULL;
- helper->enabled = true;
- helper->family = FW3_FAMILY_ANY;
- INIT_LIST_HEAD(&helper->proto);
- list_add_tail(&helper->list, &state->cthelpers);
- return helper;
- }
- static void
- load_cthelpers(struct fw3_state *state, struct uci_package *p)
- {
- struct fw3_cthelper *helper;
- struct uci_section *s;
- struct uci_element *e;
- uci_foreach_element(&p->sections, e)
- {
- s = uci_to_section(e);
- if (strcmp(s->type, "helper"))
- continue;
- helper = fw3_alloc_cthelper(state);
- if (!helper)
- continue;
- if (!fw3_parse_options(helper, fw3_cthelper_opts, s))
- warn_elem(e, "has invalid options");
- if (!check_cthelper(state, helper, e))
- fw3_free_cthelper(helper);
- }
- }
- void
- fw3_load_cthelpers(struct fw3_state *state, struct uci_package *p)
- {
- struct uci_package *hp = NULL;
- FILE *fp;
- INIT_LIST_HEAD(&state->cthelpers);
- fp = fopen(FW3_HELPERCONF, "r");
- if (fp) {
- uci_import(state->uci, fp, "fw3_ct_helpers", &hp, true);
- fclose(fp);
- if (hp)
- load_cthelpers(state, hp);
- }
- load_cthelpers(state, p);
- }
- struct fw3_cthelper *
- fw3_lookup_cthelper(struct fw3_state *state, const char *name)
- {
- struct fw3_cthelper *h;
- if (list_empty(&state->cthelpers))
- return NULL;
- list_for_each_entry(h, &state->cthelpers, list)
- {
- if (strcasecmp(h->name, name))
- continue;
- return h;
- }
- return NULL;
- }
- bool
- fw3_cthelper_check_proto(const struct fw3_cthelper *h, const struct fw3_protocol *proto)
- {
- struct fw3_protocol *p;
- list_for_each_entry(p, &h->proto, list)
- {
- if (p->protocol == proto->protocol)
- return true;
- }
- return false;
- }
- struct fw3_cthelper *
- fw3_lookup_cthelper_by_proto_port(struct fw3_state *state,
- struct fw3_protocol *proto,
- struct fw3_port *port)
- {
- struct fw3_cthelper *h;
- if (list_empty(&state->cthelpers))
- return NULL;
- if (!proto || !proto->protocol || proto->any || proto->invert)
- return NULL;
- if (port && port->invert)
- return NULL;
- list_for_each_entry(h, &state->cthelpers, list)
- {
- if (!h->enabled)
- continue;
- if (!fw3_cthelper_check_proto(h, proto))
- continue;
- if (h->port.set && (!port || !port->set))
- continue;
- if (!h->port.set && (!port || !port->set))
- return h;
- if (h->port.set && port && port->set &&
- h->port.port_min <= port->port_min &&
- h->port.port_max >= port->port_max)
- return h;
- }
- return NULL;
- }
- static void
- print_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
- struct fw3_zone *zone, struct fw3_protocol *proto)
- {
- struct fw3_ipt_rule *r;
- r = fw3_ipt_rule_create(handle, proto, NULL, NULL, NULL, NULL);
- if (helper->description && *helper->description)
- fw3_ipt_rule_comment(r, helper->description);
- else
- fw3_ipt_rule_comment(r, helper->name);
- fw3_ipt_rule_sport_dport(r, NULL, &helper->port);
- fw3_ipt_rule_target(r, "CT");
- fw3_ipt_rule_addarg(r, false, "--helper", helper->name);
- fw3_ipt_rule_replace(r, "zone_%s_helper", zone->name);
- }
- static void
- expand_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
- struct fw3_zone *zone)
- {
- struct fw3_protocol *proto;
- list_for_each_entry(proto, &helper->proto, list)
- print_helper_rule(handle, helper, zone, proto);
- }
- void
- fw3_print_cthelpers(struct fw3_ipt_handle *handle, struct fw3_state *state,
- struct fw3_zone *zone)
- {
- struct fw3_cthelper *helper;
- struct fw3_cthelpermatch *match;
- if (handle->table != FW3_TABLE_RAW)
- return;
- if (!fw3_is_family(zone, handle->family))
- return;
- if (list_empty(&zone->cthelpers))
- {
- if (zone->masq || !zone->auto_helper)
- return;
- if (list_empty(&state->cthelpers))
- return;
- info(" - Using automatic conntrack helper attachment");
- list_for_each_entry(helper, &state->cthelpers, list)
- {
- if (!helper || !helper->enabled)
- continue;
- if (!fw3_is_family(helper, handle->family))
- continue;
- if (!test_module(helper))
- continue;
- expand_helper_rule(handle, helper, zone);
- }
- }
- else
- {
- list_for_each_entry(match, &zone->cthelpers, list)
- {
- helper = match->ptr;
- if (!helper || !helper->enabled)
- continue;
- if (!fw3_is_family(helper, handle->family))
- continue;
- if (!test_module(helper))
- {
- info(" ! Conntrack module '%s' for helper '%s' is not loaded",
- helper->module, helper->name);
- continue;
- }
- expand_helper_rule(handle, helper, zone);
- }
- }
- }
|