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_LIST("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_proto(const struct fw3_cthelper
*helper
)
52 struct fw3_protocol
*proto
;
54 if (list_empty(&helper
->proto
))
57 list_for_each_entry(proto
, &helper
->proto
, list
)
59 if (!proto
->protocol
|| proto
->any
|| proto
->invert
)
67 check_cthelper(struct fw3_state
*state
, struct fw3_cthelper
*helper
, struct uci_element
*e
)
69 if (!helper
->name
|| !*helper
->name
)
71 warn_section("helper", helper
, e
, "must have a name assigned");
73 else if (!helper
->module
|| !*helper
->module
)
75 warn_section("helper", helper
, e
, "must have a module assigned");
77 else if (!check_cthelper_proto(helper
))
79 warn_section("helper", helper
, e
, "must specify a protocol");
81 else if (helper
->port
.set
&& helper
->port
.invert
)
83 warn_section("helper", helper
, e
, "must not specify negated ports");
93 static struct fw3_cthelper
*
94 fw3_alloc_cthelper(struct fw3_state
*state
)
96 struct fw3_cthelper
*helper
;
98 helper
= calloc(1, sizeof(*helper
));
102 helper
->enabled
= true;
103 helper
->family
= FW3_FAMILY_ANY
;
104 INIT_LIST_HEAD(&helper
->proto
);
106 list_add_tail(&helper
->list
, &state
->cthelpers
);
112 load_cthelpers(struct fw3_state
*state
, struct uci_package
*p
)
114 struct fw3_cthelper
*helper
;
115 struct uci_section
*s
;
116 struct uci_element
*e
;
118 uci_foreach_element(&p
->sections
, e
)
120 s
= uci_to_section(e
);
122 if (strcmp(s
->type
, "helper"))
125 helper
= fw3_alloc_cthelper(state
);
130 if (!fw3_parse_options(helper
, fw3_cthelper_opts
, s
))
131 warn_elem(e
, "has invalid options");
133 if (!check_cthelper(state
, helper
, e
))
134 fw3_free_cthelper(helper
);
139 fw3_load_cthelpers(struct fw3_state
*state
, struct uci_package
*p
)
141 struct uci_package
*hp
= NULL
;
144 INIT_LIST_HEAD(&state
->cthelpers
);
146 fp
= fopen(FW3_HELPERCONF
, "r");
149 uci_import(state
->uci
, fp
, "fw3_ct_helpers", &hp
, true);
153 load_cthelpers(state
, hp
);
156 load_cthelpers(state
, p
);
159 struct fw3_cthelper
*
160 fw3_lookup_cthelper(struct fw3_state
*state
, const char *name
)
162 struct fw3_cthelper
*h
;
164 if (list_empty(&state
->cthelpers
))
167 list_for_each_entry(h
, &state
->cthelpers
, list
)
169 if (strcasecmp(h
->name
, name
))
179 fw3_cthelper_check_proto(const struct fw3_cthelper
*h
, const struct fw3_protocol
*proto
)
181 struct fw3_protocol
*p
;
183 list_for_each_entry(p
, &h
->proto
, list
)
185 if (p
->protocol
== proto
->protocol
)
192 struct fw3_cthelper
*
193 fw3_lookup_cthelper_by_proto_port(struct fw3_state
*state
,
194 struct fw3_protocol
*proto
,
195 struct fw3_port
*port
)
197 struct fw3_cthelper
*h
;
199 if (list_empty(&state
->cthelpers
))
202 if (!proto
|| !proto
->protocol
|| proto
->any
|| proto
->invert
)
205 if (port
&& port
->invert
)
208 list_for_each_entry(h
, &state
->cthelpers
, list
)
213 if (!fw3_cthelper_check_proto(h
, proto
))
216 if (h
->port
.set
&& (!port
|| !port
->set
))
219 if (!h
->port
.set
&& (!port
|| !port
->set
))
222 if (h
->port
.set
&& port
&& port
->set
&&
223 h
->port
.port_min
<= port
->port_min
&&
224 h
->port
.port_max
>= port
->port_max
)
232 print_helper_rule(struct fw3_ipt_handle
*handle
, struct fw3_cthelper
*helper
,
233 struct fw3_zone
*zone
, struct fw3_protocol
*proto
)
235 struct fw3_ipt_rule
*r
;
237 r
= fw3_ipt_rule_create(handle
, proto
, NULL
, NULL
, NULL
, NULL
);
239 if (helper
->description
&& *helper
->description
)
240 fw3_ipt_rule_comment(r
, helper
->description
);
242 fw3_ipt_rule_comment(r
, helper
->name
);
244 fw3_ipt_rule_sport_dport(r
, NULL
, &helper
->port
);
245 fw3_ipt_rule_target(r
, "CT");
246 fw3_ipt_rule_addarg(r
, false, "--helper", helper
->name
);
247 fw3_ipt_rule_replace(r
, "zone_%s_helper", zone
->name
);
251 expand_helper_rule(struct fw3_ipt_handle
*handle
, struct fw3_cthelper
*helper
,
252 struct fw3_zone
*zone
)
254 struct fw3_protocol
*proto
;
256 list_for_each_entry(proto
, &helper
->proto
, list
)
257 print_helper_rule(handle
, helper
, zone
, proto
);
261 fw3_print_cthelpers(struct fw3_ipt_handle
*handle
, struct fw3_state
*state
,
262 struct fw3_zone
*zone
)
264 struct fw3_cthelper
*helper
;
265 struct fw3_cthelpermatch
*match
;
267 if (handle
->table
!= FW3_TABLE_RAW
)
270 if (!fw3_is_family(zone
, handle
->family
))
273 if (list_empty(&zone
->cthelpers
))
275 if (zone
->masq
|| !zone
->auto_helper
)
278 if (list_empty(&state
->cthelpers
))
281 info(" - Using automatic conntrack helper attachment");
283 list_for_each_entry(helper
, &state
->cthelpers
, list
)
285 if (!helper
|| !helper
->enabled
)
288 if (!fw3_is_family(helper
, handle
->family
))
291 if (!test_module(helper
))
294 expand_helper_rule(handle
, helper
, zone
);
299 list_for_each_entry(match
, &zone
->cthelpers
, list
)
303 if (!helper
|| !helper
->enabled
)
306 if (!fw3_is_family(helper
, handle
->family
))
309 if (!test_module(helper
))
311 info(" ! Conntrack module '%s' for helper '%s' is not loaded",
312 helper
->module
, helper
->name
);
316 expand_helper_rule(handle
, helper
, zone
);