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 "defaults.h" 20 21 22 #define C(f, tbl, def, fmt) \ 23 { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_FLAG_##def, fmt } 24 25 static const struct fw3_chain_spec default_chains[] = { 26 C(ANY, FILTER, UNSPEC, "reject"), 27 C(ANY, FILTER, CUSTOM_CHAINS, "input_rule"), 28 C(ANY, FILTER, CUSTOM_CHAINS, "output_rule"), 29 C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_rule"), 30 C(ANY, FILTER, SYN_FLOOD, "syn_flood"), 31 32 C(V4, NAT, CUSTOM_CHAINS, "prerouting_rule"), 33 C(V4, NAT, CUSTOM_CHAINS, "postrouting_rule"), 34 35 { } 36 }; 37 38 const struct fw3_option fw3_flag_opts[] = { 39 FW3_OPT("input", target, defaults, policy_input), 40 FW3_OPT("forward", target, defaults, policy_forward), 41 FW3_OPT("output", target, defaults, policy_output), 42 43 FW3_OPT("drop_invalid", bool, defaults, drop_invalid), 44 FW3_OPT("tcp_reject_code", reject_code, defaults, tcp_reject_code), 45 FW3_OPT("any_reject_code", reject_code, defaults, any_reject_code), 46 47 FW3_OPT("syn_flood", bool, defaults, syn_flood), 48 FW3_OPT("synflood_protect", bool, defaults, syn_flood), 49 FW3_OPT("synflood_rate", limit, defaults, syn_flood_rate), 50 FW3_OPT("synflood_burst", int, defaults, syn_flood_rate.burst), 51 52 FW3_OPT("tcp_syncookies", bool, defaults, tcp_syncookies), 53 FW3_OPT("tcp_ecn", int, defaults, tcp_ecn), 54 FW3_OPT("tcp_window_scaling", bool, defaults, tcp_window_scaling), 55 56 FW3_OPT("accept_redirects", bool, defaults, accept_redirects), 57 FW3_OPT("accept_source_route", bool, defaults, accept_source_route), 58 59 FW3_OPT("auto_helper", bool, defaults, auto_helper), 60 FW3_OPT("custom_chains", bool, defaults, custom_chains), 61 FW3_OPT("disable_ipv6", bool, defaults, disable_ipv6), 62 FW3_OPT("flow_offloading", bool, defaults, flow_offloading), 63 FW3_OPT("flow_offloading_hw", bool, defaults, flow_offloading_hw), 64 65 FW3_OPT("__flags_v4", int, defaults, flags[0]), 66 FW3_OPT("__flags_v6", int, defaults, flags[1]), 67 68 { } 69 }; 70 71 72 static void 73 check_policy(struct uci_element *e, enum fw3_flag *pol, const char *name) 74 { 75 if (*pol == FW3_FLAG_UNSPEC) 76 { 77 warn_elem(e, "has no %s policy specified, defaulting to DROP", name); 78 *pol = FW3_FLAG_DROP; 79 } 80 else if (*pol > FW3_FLAG_DROP) 81 { 82 warn_elem(e, "has invalid %s policy, defaulting to DROP", name); 83 *pol = FW3_FLAG_DROP; 84 } 85 } 86 87 static void 88 check_target(struct uci_element *e, bool *available, const char *target, const bool ipv6) 89 { 90 const bool b = fw3_has_target(ipv6, target); 91 if (!b) 92 { 93 warn_elem(e, "requires unavailable target extension %s, disabling", target); 94 *available = false; 95 } 96 } 97 98 static void 99 check_any_reject_code(struct uci_element *e, enum fw3_reject_code *any_reject_code) 100 { 101 if (*any_reject_code == FW3_REJECT_CODE_TCP_RESET) { 102 warn_elem(e, "tcp-reset not valid for any_reject_code, defaulting to port-unreach"); 103 *any_reject_code = FW3_REJECT_CODE_PORT_UNREACH; 104 } 105 } 106 107 static const char* 108 get_reject_code(enum fw3_family family, enum fw3_reject_code reject_code) 109 { 110 switch (reject_code) { 111 case FW3_REJECT_CODE_TCP_RESET: 112 return "tcp-reset"; 113 case FW3_REJECT_CODE_PORT_UNREACH: 114 return "port-unreach"; 115 case FW3_REJECT_CODE_ADM_PROHIBITED: 116 return family == FW3_FAMILY_V6 ? "adm-prohibited": "admin-prohib"; 117 default: 118 return "unknown"; 119 } 120 } 121 122 void 123 fw3_load_defaults(struct fw3_state *state, struct uci_package *p) 124 { 125 struct uci_section *s; 126 struct uci_element *e; 127 struct fw3_defaults *defs = &state->defaults; 128 129 bool seen = false; 130 131 defs->tcp_reject_code = FW3_REJECT_CODE_TCP_RESET; 132 defs->any_reject_code = FW3_REJECT_CODE_PORT_UNREACH; 133 defs->syn_flood_rate.rate = 25; 134 defs->syn_flood_rate.burst = 50; 135 defs->tcp_syncookies = true; 136 defs->tcp_window_scaling = true; 137 defs->custom_chains = true; 138 defs->auto_helper = true; 139 140 uci_foreach_element(&p->sections, e) 141 { 142 s = uci_to_section(e); 143 144 if (strcmp(s->type, "defaults")) 145 continue; 146 147 if (seen) 148 { 149 warn_elem(e, "ignoring duplicate section"); 150 continue; 151 } 152 153 seen = true; 154 155 if(!fw3_parse_options(&state->defaults, fw3_flag_opts, s)) 156 warn_elem(e, "has invalid options"); 157 158 check_policy(e, &defs->policy_input, "input"); 159 check_policy(e, &defs->policy_output, "output"); 160 check_policy(e, &defs->policy_forward, "forward"); 161 162 check_any_reject_code(e, &defs->any_reject_code); 163 164 /* exists in both ipv4 and ipv6, if at all, so only check ipv4 */ 165 check_target(e, &defs->flow_offloading, "FLOWOFFLOAD", false); 166 } 167 } 168 169 void 170 fw3_print_default_chains(struct fw3_ipt_handle *handle, struct fw3_state *state, 171 bool reload) 172 { 173 struct fw3_defaults *defs = &state->defaults; 174 const struct fw3_chain_spec *c; 175 176 #define policy(t) \ 177 ((t == FW3_FLAG_REJECT) ? FW3_FLAG_DROP : t) 178 179 if (handle->family == FW3_FAMILY_V6 && defs->disable_ipv6) 180 return; 181 182 if (handle->table == FW3_TABLE_FILTER) 183 { 184 fw3_ipt_set_policy(handle, "INPUT", policy(defs->policy_input)); 185 fw3_ipt_set_policy(handle, "OUTPUT", policy(defs->policy_output)); 186 fw3_ipt_set_policy(handle, "FORWARD", policy(defs->policy_forward)); 187 } 188 189 if (defs->custom_chains) 190 set(defs->flags, handle->family, FW3_FLAG_CUSTOM_CHAINS); 191 192 if (defs->syn_flood) 193 set(defs->flags, handle->family, FW3_FLAG_SYN_FLOOD); 194 195 for (c = default_chains; c->format; c++) 196 { 197 if (!fw3_is_family(c, handle->family)) 198 continue; 199 200 if (c->table != handle->table) 201 continue; 202 203 if (c->flag && 204 !fw3_hasbit(defs->flags[handle->family == FW3_FAMILY_V6], c->flag)) 205 continue; 206 207 fw3_ipt_create_chain(handle, reload, c->format); 208 } 209 210 set(defs->flags, handle->family, handle->table); 211 } 212 213 void 214 fw3_print_default_head_rules(struct fw3_ipt_handle *handle, 215 struct fw3_state *state, bool reload) 216 { 217 int i; 218 struct fw3_defaults *defs = &state->defaults; 219 struct fw3_device lodev = { .set = true, .name = "lo" }; 220 struct fw3_protocol tcp = { .protocol = 6 }; 221 struct fw3_ipt_rule *r; 222 223 const char *chains[] = { 224 "INPUT", "input", 225 "OUTPUT", "output", 226 "FORWARD", "forwarding", 227 }; 228 229 switch (handle->table) 230 { 231 case FW3_TABLE_FILTER: 232 233 r = fw3_ipt_rule_create(handle, NULL, &lodev, NULL, NULL, NULL); 234 fw3_ipt_rule_target(r, "ACCEPT"); 235 fw3_ipt_rule_append(r, "INPUT"); 236 237 r = fw3_ipt_rule_create(handle, NULL, NULL, &lodev, NULL, NULL); 238 fw3_ipt_rule_target(r, "ACCEPT"); 239 fw3_ipt_rule_append(r, "OUTPUT"); 240 241 if (defs->custom_chains) 242 { 243 for (i = 0; i < ARRAY_SIZE(chains); i += 2) 244 { 245 r = fw3_ipt_rule_new(handle); 246 fw3_ipt_rule_comment(r, "Custom %s rule chain", chains[i+1]); 247 fw3_ipt_rule_target(r, "%s_rule", chains[i+1]); 248 fw3_ipt_rule_append(r, chains[i]); 249 } 250 } 251 252 if (defs->flow_offloading) 253 { 254 r = fw3_ipt_rule_new(handle); 255 fw3_ipt_rule_comment(r, "Traffic offloading"); 256 fw3_ipt_rule_extra(r, "-m conntrack --ctstate RELATED,ESTABLISHED"); 257 fw3_ipt_rule_target(r, "FLOWOFFLOAD"); 258 if (defs->flow_offloading_hw) 259 fw3_ipt_rule_addarg(r, false, "--hw", NULL); 260 fw3_ipt_rule_append(r, "FORWARD"); 261 } 262 263 for (i = 0; i < ARRAY_SIZE(chains); i += 2) 264 { 265 r = fw3_ipt_rule_new(handle); 266 fw3_ipt_rule_extra(r, "-m conntrack --ctstate RELATED,ESTABLISHED"); 267 fw3_ipt_rule_target(r, "ACCEPT"); 268 fw3_ipt_rule_append(r, chains[i]); 269 270 if (defs->drop_invalid) 271 { 272 r = fw3_ipt_rule_new(handle); 273 fw3_ipt_rule_extra(r, "-m conntrack --ctstate INVALID"); 274 fw3_ipt_rule_target(r, "DROP"); 275 fw3_ipt_rule_append(r, chains[i]); 276 } 277 } 278 279 if (defs->syn_flood) 280 { 281 r = fw3_ipt_rule_create(handle, NULL, NULL, NULL, NULL, NULL); 282 fw3_ipt_rule_limit(r, &defs->syn_flood_rate); 283 fw3_ipt_rule_target(r, "RETURN"); 284 fw3_ipt_rule_append(r, "syn_flood"); 285 286 r = fw3_ipt_rule_new(handle); 287 fw3_ipt_rule_target(r, "DROP"); 288 fw3_ipt_rule_append(r, "syn_flood"); 289 290 r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL); 291 fw3_ipt_rule_extra(r, "--syn"); 292 fw3_ipt_rule_target(r, "syn_flood"); 293 fw3_ipt_rule_append(r, "INPUT"); 294 } 295 296 r = fw3_ipt_rule_create(handle, &tcp, NULL, NULL, NULL, NULL); 297 fw3_ipt_rule_target(r, "REJECT"); 298 fw3_ipt_rule_addarg(r, false, "--reject-with", get_reject_code(handle->family, defs->tcp_reject_code)); 299 fw3_ipt_rule_append(r, "reject"); 300 301 r = fw3_ipt_rule_new(handle); 302 fw3_ipt_rule_target(r, "REJECT"); 303 fw3_ipt_rule_addarg(r, false, "--reject-with", get_reject_code(handle->family, defs->any_reject_code)); 304 fw3_ipt_rule_append(r, "reject"); 305 306 break; 307 308 case FW3_TABLE_NAT: 309 if (defs->custom_chains) 310 { 311 r = fw3_ipt_rule_new(handle); 312 fw3_ipt_rule_comment(r, "Custom prerouting rule chain"); 313 fw3_ipt_rule_target(r, "prerouting_rule"); 314 fw3_ipt_rule_append(r, "PREROUTING"); 315 316 r = fw3_ipt_rule_new(handle); 317 fw3_ipt_rule_comment(r, "Custom postrouting rule chain"); 318 fw3_ipt_rule_target(r, "postrouting_rule"); 319 fw3_ipt_rule_append(r, "POSTROUTING"); 320 } 321 break; 322 323 default: 324 break; 325 } 326 } 327 328 void 329 fw3_print_default_tail_rules(struct fw3_ipt_handle *handle, 330 struct fw3_state *state, bool reload) 331 { 332 struct fw3_defaults *defs = &state->defaults; 333 struct fw3_ipt_rule *r; 334 335 if (handle->table != FW3_TABLE_FILTER) 336 return; 337 338 if (defs->policy_input == FW3_FLAG_REJECT) 339 { 340 r = fw3_ipt_rule_new(handle); 341 342 if (!r) 343 return; 344 345 fw3_ipt_rule_target(r, "reject"); 346 fw3_ipt_rule_append(r, "INPUT"); 347 } 348 349 if (defs->policy_output == FW3_FLAG_REJECT) 350 { 351 r = fw3_ipt_rule_new(handle); 352 353 if (!r) 354 return; 355 356 fw3_ipt_rule_target(r, "reject"); 357 fw3_ipt_rule_append(r, "OUTPUT"); 358 } 359 360 if (defs->policy_forward == FW3_FLAG_REJECT) 361 { 362 r = fw3_ipt_rule_new(handle); 363 364 if (!r) 365 return; 366 367 fw3_ipt_rule_target(r, "reject"); 368 fw3_ipt_rule_append(r, "FORWARD"); 369 } 370 } 371 372 static void 373 set_default(const char *name, int set) 374 { 375 FILE *f; 376 char path[sizeof("/proc/sys/net/ipv4/tcp_window_scaling")]; 377 378 snprintf(path, sizeof(path), "/proc/sys/net/ipv4/tcp_%s", name); 379 380 info(" * Set tcp_%s to %s", name, set ? "on" : "off"); 381 382 if (!(f = fopen(path, "w"))) 383 { 384 info(" ! Unable to write value: %s", strerror(errno)); 385 return; 386 } 387 388 fprintf(f, "%u\n", set); 389 fclose(f); 390 } 391 392 void 393 fw3_set_defaults(struct fw3_state *state) 394 { 395 set_default("ecn", state->defaults.tcp_ecn); 396 set_default("syncookies", state->defaults.tcp_syncookies); 397 set_default("window_scaling", state->defaults.tcp_window_scaling); 398 } 399 400 void 401 fw3_flush_rules(struct fw3_ipt_handle *handle, struct fw3_state *state, 402 bool reload) 403 { 404 enum fw3_flag policy = reload ? FW3_FLAG_DROP : FW3_FLAG_ACCEPT; 405 struct fw3_defaults *defs = &state->defaults; 406 const struct fw3_chain_spec *c; 407 408 if (!has(defs->flags, handle->family, handle->table)) 409 return; 410 411 if (handle->table == FW3_TABLE_FILTER) 412 { 413 fw3_ipt_set_policy(handle, "INPUT", policy); 414 fw3_ipt_set_policy(handle, "OUTPUT", policy); 415 fw3_ipt_set_policy(handle, "FORWARD", policy); 416 } 417 418 fw3_ipt_delete_id_rules(handle, "INPUT"); 419 fw3_ipt_delete_id_rules(handle, "OUTPUT"); 420 fw3_ipt_delete_id_rules(handle, "FORWARD"); 421 fw3_ipt_delete_id_rules(handle, "PREROUTING"); 422 fw3_ipt_delete_id_rules(handle, "POSTROUTING"); 423 424 /* first flush all the rules ... */ 425 for (c = default_chains; c->format; c++) 426 { 427 /* don't touch user chains on selective stop */ 428 if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS) 429 continue; 430 431 if (!fw3_is_family(c, handle->family)) 432 continue; 433 434 if (c->table != handle->table) 435 continue; 436 437 if (c->flag && !has(defs->flags, handle->family, c->flag)) 438 continue; 439 440 fw3_ipt_flush_chain(handle, c->format); 441 } 442 443 /* ... then remove the chains */ 444 for (c = default_chains; c->format; c++) 445 { 446 if (!fw3_is_family(c, handle->family)) 447 continue; 448 449 if (c->table != handle->table) 450 continue; 451 452 if (c->flag && !has(defs->flags, handle->family, c->flag)) 453 continue; 454 455 fw3_ipt_delete_chain(handle, reload, c->format); 456 } 457 458 del(defs->flags, handle->family, handle->table); 459 } 460 461 void 462 fw3_flush_all(struct fw3_ipt_handle *handle) 463 { 464 if (handle->table == FW3_TABLE_FILTER) 465 { 466 fw3_ipt_set_policy(handle, "INPUT", FW3_FLAG_ACCEPT); 467 fw3_ipt_set_policy(handle, "OUTPUT", FW3_FLAG_ACCEPT); 468 fw3_ipt_set_policy(handle, "FORWARD", FW3_FLAG_ACCEPT); 469 } 470 471 fw3_ipt_flush(handle); 472 } 473
This page was automatically generated by LXR 0.3.1. • OpenWrt