1 /* 2 * firewall3 - 3rd OpenWrt UCI firewall implementation 3 * 4 * Copyright (C) 2014 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 "snats.h" 20 21 22 const struct fw3_option fw3_snat_opts[] = { 23 FW3_OPT("enabled", bool, snat, enabled), 24 25 FW3_OPT("name", string, snat, name), 26 FW3_OPT("family", family, snat, family), 27 28 FW3_OPT("src", device, snat, src), 29 FW3_OPT("device", string, snat, device), 30 31 FW3_OPT("ipset", setmatch, snat, ipset), 32 33 FW3_LIST("proto", protocol, snat, proto), 34 35 FW3_OPT("src_ip", network, snat, ip_src), 36 FW3_OPT("src_port", port, snat, port_src), 37 38 FW3_OPT("snat_ip", network, snat, ip_snat), 39 FW3_OPT("snat_port", port, snat, port_snat), 40 41 FW3_OPT("dest_ip", network, snat, ip_dest), 42 FW3_OPT("dest_port", port, snat, port_dest), 43 44 FW3_OPT("extra", string, snat, extra), 45 46 FW3_OPT("limit", limit, snat, limit), 47 FW3_OPT("limit_burst", int, snat, limit.burst), 48 49 FW3_OPT("connlimit_ports", bool, snat, connlimit_ports), 50 51 FW3_OPT("utc_time", bool, snat, time.utc), 52 FW3_OPT("start_date", date, snat, time.datestart), 53 FW3_OPT("stop_date", date, snat, time.datestop), 54 FW3_OPT("start_time", time, snat, time.timestart), 55 FW3_OPT("stop_time", time, snat, time.timestop), 56 FW3_OPT("weekdays", weekdays, snat, time.weekdays), 57 FW3_OPT("monthdays", monthdays, snat, time.monthdays), 58 59 FW3_OPT("mark", mark, snat, mark), 60 61 FW3_OPT("target", target, snat, target), 62 63 { } 64 }; 65 66 67 static bool 68 check_families(struct uci_element *e, struct fw3_snat *r) 69 { 70 if (r->family == FW3_FAMILY_ANY) 71 return true; 72 73 if (r->_src && r->_src->family && r->_src->family != r->family) 74 { 75 warn_section("nat", r, e, "refers to source zone with different family"); 76 return false; 77 } 78 79 if (r->ipset.ptr && r->ipset.ptr->family && 80 r->ipset.ptr->family != r->family) 81 { 82 warn_section("nat", r, e, "refers to ipset with different family"); 83 return false; 84 } 85 86 if (r->ip_src.family && r->ip_src.family != r->family) 87 { 88 warn_section("nat", r, e, "uses source ip with different family"); 89 return false; 90 } 91 92 if (r->ip_dest.family && r->ip_dest.family != r->family) 93 { 94 warn_section("nat", r, e, "uses destination ip with different family"); 95 return false; 96 } 97 98 if (r->ip_snat.family && r->ip_snat.family != r->family) 99 { 100 warn_section("nat", r, e, "uses snat ip with different family"); 101 return false; 102 } 103 104 return true; 105 } 106 107 108 static struct fw3_snat* 109 alloc_snat(struct fw3_state *state) 110 { 111 struct fw3_snat *snat = calloc(1, sizeof(*snat)); 112 113 if (snat) { 114 INIT_LIST_HEAD(&snat->proto); 115 list_add_tail(&snat->list, &state->snats); 116 snat->enabled = true; 117 } 118 119 return snat; 120 } 121 122 static bool 123 check_snat(struct fw3_state *state, struct fw3_snat *snat, struct uci_element *e) 124 { 125 if (!snat->enabled) 126 return false; 127 128 if (snat->src.invert) 129 { 130 warn_section("nat", snat, e, "must not have an inverted source"); 131 return false; 132 } 133 else if (snat->src.set && !snat->src.any && 134 !(snat->_src = fw3_lookup_zone(state, snat->src.name))) 135 { 136 warn_section("nat", snat, e, "refers to not existing zone '%s'", snat->src.name); 137 return false; 138 } 139 else if (snat->ipset.set && state->disable_ipsets) 140 { 141 warn_section("nat", snat, e, "skipped due to disabled ipset support"); 142 return false; 143 } 144 else if (snat->ipset.set && 145 !(snat->ipset.ptr = fw3_lookup_ipset(state, snat->ipset.name))) 146 { 147 warn_section("nat", snat, e, "refers to unknown ipset '%s'", snat->ipset.name); 148 return false; 149 } 150 151 if (!check_families(e, snat)) 152 return false; 153 154 if (snat->target == FW3_FLAG_UNSPEC) 155 { 156 warn_section("nat", snat, e, "has no target specified, defaulting to MASQUERADE"); 157 snat->target = FW3_FLAG_MASQUERADE; 158 } 159 else if (snat->target != FW3_FLAG_ACCEPT && snat->target != FW3_FLAG_SNAT && 160 snat->target != FW3_FLAG_MASQUERADE) 161 { 162 warn_section("nat", snat, e, "has invalid target specified, defaulting to MASQUERADE"); 163 snat->target = FW3_FLAG_MASQUERADE; 164 } 165 166 if (snat->target == FW3_FLAG_SNAT && 167 !snat->ip_snat.set && !snat->port_snat.set) 168 { 169 warn_section("nat", snat, e, "needs either 'snat_ip' or 'snat_port' for SNAT"); 170 return false; 171 } 172 else if (snat->target != FW3_FLAG_SNAT && snat->ip_snat.set) 173 { 174 warn_section("nat", snat, e, "must not use 'snat_ip' for non-SNAT"); 175 return false; 176 } 177 else if (snat->target != FW3_FLAG_SNAT && snat->port_snat.set) 178 { 179 warn_section("nat", snat, e, "must not use 'snat_port' for non-SNAT"); 180 return false; 181 } 182 183 if (list_empty(&snat->proto)) 184 { 185 warn_section("nat", snat, e, "does not specify a protocol, assuming all"); 186 fw3_parse_protocol(&snat->proto, "all", true); 187 } 188 189 if (snat->_src) 190 set(snat->_src->flags, FW3_FAMILY_V4, FW3_FLAG_SNAT); 191 192 return true; 193 } 194 195 196 void 197 fw3_load_snats(struct fw3_state *state, struct uci_package *p, struct blob_attr *a) 198 { 199 struct uci_section *s; 200 struct uci_element *e; 201 struct fw3_snat *snat; 202 struct blob_attr *entry; 203 unsigned rem; 204 205 INIT_LIST_HEAD(&state->snats); 206 207 blob_for_each_attr(entry, a, rem) { 208 const char *type = NULL; 209 const char *name = "ubus rule"; 210 211 if (!fw3_attr_parse_name_type(entry, &name, &type)) 212 continue; 213 214 if (strcmp(type, "nat")) 215 continue; 216 217 snat = alloc_snat(state); 218 if (!snat) 219 continue; 220 221 if (!fw3_parse_blob_options(snat, fw3_snat_opts, entry, name)) 222 { 223 warn_section("nat", snat, NULL, "skipped due to invalid options"); 224 fw3_free_snat(snat); 225 continue; 226 } 227 228 if (!check_snat(state, snat, NULL)) 229 fw3_free_snat(snat); 230 } 231 232 uci_foreach_element(&p->sections, e) 233 { 234 s = uci_to_section(e); 235 236 if (strcmp(s->type, "nat")) 237 continue; 238 239 snat = alloc_snat(state); 240 if (!snat) 241 continue; 242 243 if (!fw3_parse_options(snat, fw3_snat_opts, s)) 244 { 245 warn_elem(e, "skipped due to invalid options"); 246 fw3_free_snat(snat); 247 continue; 248 } 249 250 if (!check_snat(state, snat, e)) 251 fw3_free_snat(snat); 252 } 253 } 254 255 static void 256 append_chain(struct fw3_ipt_rule *r, struct fw3_snat *snat) 257 { 258 if (snat->_src) 259 fw3_ipt_rule_append(r, "zone_%s_postrouting", snat->src.name); 260 else 261 fw3_ipt_rule_append(r, "POSTROUTING"); 262 } 263 264 static void 265 set_target(struct fw3_ipt_rule *r, struct fw3_snat *snat, 266 struct fw3_protocol *proto) 267 { 268 char buf[sizeof("255.255.255.255:65535-65535")] = {}; 269 char ip[INET_ADDRSTRLEN], portcntbuf[6], *p = buf; 270 size_t rem = sizeof(buf); 271 int len; 272 273 if (snat->target == FW3_FLAG_SNAT) 274 { 275 if (snat->ip_snat.set) 276 { 277 inet_ntop(AF_INET, &snat->ip_snat.address.v4, ip, sizeof(ip)); 278 279 len = snprintf(p, rem, "%s", ip); 280 281 if (len < 0 || len >= rem) 282 return; 283 284 rem -= len; 285 p += len; 286 } 287 288 if (snat->port_snat.set && proto && !proto->any && 289 (proto->protocol == 6 || proto->protocol == 17 || proto->protocol == 1)) 290 { 291 if (snat->port_snat.port_min == snat->port_snat.port_max) 292 snprintf(p, rem, ":%u", snat->port_snat.port_min); 293 else 294 snprintf(p, rem, ":%u-%u", 295 snat->port_snat.port_min, snat->port_snat.port_max); 296 297 if (snat->connlimit_ports) { 298 snprintf(portcntbuf, sizeof(portcntbuf), "%u", 299 1 + snat->port_snat.port_max - snat->port_snat.port_min); 300 301 fw3_ipt_rule_addarg(r, false, "-m", "connlimit"); 302 fw3_ipt_rule_addarg(r, false, "--connlimit-daddr", NULL); 303 fw3_ipt_rule_addarg(r, false, "--connlimit-upto", portcntbuf); 304 } 305 } 306 307 fw3_ipt_rule_target(r, "SNAT"); 308 fw3_ipt_rule_addarg(r, false, "--to-source", buf); 309 } 310 else if (snat->target == FW3_FLAG_ACCEPT) 311 { 312 fw3_ipt_rule_target(r, "ACCEPT"); 313 } 314 else 315 { 316 fw3_ipt_rule_target(r, "MASQUERADE"); 317 } 318 } 319 320 static void 321 set_comment(struct fw3_ipt_rule *r, const char *name, int num) 322 { 323 if (name) 324 fw3_ipt_rule_comment(r, name); 325 else 326 fw3_ipt_rule_comment(r, "@nat[%u]", num); 327 } 328 329 static void 330 print_snat(struct fw3_ipt_handle *h, struct fw3_state *state, 331 struct fw3_snat *snat, int num, struct fw3_protocol *proto) 332 { 333 struct fw3_ipt_rule *r; 334 struct fw3_address *src, *dst; 335 struct fw3_port *spt, *dpt; 336 337 switch (h->table) 338 { 339 case FW3_TABLE_NAT: 340 src = &snat->ip_src; 341 dst = &snat->ip_dest; 342 spt = &snat->port_src; 343 dpt = &snat->port_dest; 344 345 r = fw3_ipt_rule_create(h, proto, NULL, NULL, src, dst); 346 fw3_ipt_rule_sport_dport(r, spt, dpt); 347 fw3_ipt_rule_device(r, snat->device, true); 348 fw3_ipt_rule_ipset(r, &snat->ipset); 349 fw3_ipt_rule_limit(r, &snat->limit); 350 fw3_ipt_rule_time(r, &snat->time); 351 fw3_ipt_rule_mark(r, &snat->mark); 352 set_target(r, snat, proto); 353 fw3_ipt_rule_extra(r, snat->extra); 354 set_comment(r, snat->name, num); 355 append_chain(r, snat); 356 break; 357 358 default: 359 break; 360 } 361 } 362 363 static void 364 expand_snat(struct fw3_ipt_handle *handle, struct fw3_state *state, 365 struct fw3_snat *snat, int num) 366 { 367 struct fw3_protocol *proto; 368 369 if (snat->name) 370 info(" * NAT '%s'", snat->name); 371 else 372 info(" * NAT #%u", num); 373 374 if (!fw3_is_family(snat->_src, handle->family)) 375 { 376 info(" ! Skipping due to different family of zone"); 377 return; 378 } 379 380 if (!fw3_is_family(&snat->ip_src, handle->family) || 381 !fw3_is_family(&snat->ip_dest, handle->family) || 382 !fw3_is_family(&snat->ip_snat, handle->family)) 383 { 384 if (!snat->ip_src.resolved || 385 !snat->ip_dest.resolved || 386 !snat->ip_snat.resolved) 387 info(" ! Skipping due to different family of ip address"); 388 389 return; 390 } 391 392 if (snat->ipset.ptr) 393 { 394 if (!fw3_is_family(snat->ipset.ptr, handle->family)) 395 { 396 info(" ! Skipping due to different family in ipset"); 397 return; 398 } 399 400 if (!fw3_check_ipset(snat->ipset.ptr)) 401 { 402 info(" ! Skipping due to missing ipset '%s'", 403 snat->ipset.ptr->external ? 404 snat->ipset.ptr->external : snat->ipset.ptr->name); 405 return; 406 } 407 408 set(snat->ipset.ptr->flags, handle->family, handle->family); 409 } 410 411 fw3_foreach(proto, &snat->proto) 412 print_snat(handle, state, snat, num, proto); 413 } 414 415 void 416 fw3_print_snats(struct fw3_ipt_handle *handle, struct fw3_state *state) 417 { 418 int num = 0; 419 struct fw3_snat *snat; 420 421 if (handle->family == FW3_FAMILY_V6) 422 return; 423 424 if (handle->table != FW3_TABLE_NAT) 425 return; 426 427 list_for_each_entry(snat, &state->snats, list) 428 expand_snat(handle, state, snat, num++); 429 } 430
This page was automatically generated by LXR 0.3.1. • OpenWrt