1/* 2 * Firewall services 3 * 4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. 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 ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: firewall.c 374496 2012-12-13 08:59:12Z $ 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <signal.h> 25#include <sys/socket.h> 26#include <netinet/in.h> 27#include <arpa/inet.h> 28#include <sys/types.h> 29#include <dirent.h> 30#include <errno.h> 31#include <linux/sockios.h> 32#include <sys/ioctl.h> 33#include <unistd.h> 34 35#include <bcmnvram.h> 36#include <shutils.h> 37#include <rc.h> 38#include <netconf.h> 39#include <nvparse.h> 40 41/* Add filter to specified table */ 42static void 43add_filter(netconf_filter_t *filter, int dir) 44{ 45 filter->dir = dir; 46 netconf_add_filter(filter); 47} 48 49 50/* Add port forward and a matching ACCEPT rule to the FORWARD table */ 51static void 52add_forward(netconf_nat_t *nat, int dir, int target) 53{ 54 netconf_filter_t filter; 55 56 /* Set up LAN side match */ 57 memset(&filter, 0, sizeof(filter)); 58 filter.match.ipproto = nat->match.ipproto; 59 filter.match.src.ports[1] = nat->match.src.ports[1]; 60 filter.match.dst.ipaddr.s_addr = nat->ipaddr.s_addr; 61 filter.match.dst.netmask.s_addr = htonl(0xffffffff); 62 filter.match.dst.ports[0] = nat->ports[0]; 63 filter.match.dst.ports[1] = nat->ports[1]; 64 strncpy(filter.match.in.name, nat->match.in.name, IFNAMSIZ); 65 66 /* Accept connection */ 67 filter.target = target; 68 filter.dir = dir; 69 70 /* Do it */ 71 netconf_add_nat(nat); 72 netconf_add_filter(&filter); 73} 74 75 76#if defined(LINUX_2_6_36) && defined(__CONFIG_SAMBA__) 77static void 78add_conntrack(void) 79{ 80 char ifname[IFNAMSIZ]; 81 82 strncpy(ifname, nvram_safe_get("lan_ifname"), IFNAMSIZ); 83 84 /* Add rules to disable conntrack on SMB ports to reduce CPU loading 85 * for SAMBA storage application 86 */ 87 eval("iptables", "-t", "raw", "-F"); 88 eval("iptables", "-t", "raw", "-A", "PREROUTING", "-i", ifname, "-p", "tcp", 89 "--dport", "137:139", "-j", "NOTRACK"); 90 eval("iptables", "-t", "raw", "-A", "PREROUTING", "-i", ifname, "-p", "tcp", 91 "--dport", "445", "-j", "NOTRACK"); 92 eval("iptables", "-t", "raw", "-A", "PREROUTING", "-i", ifname, "-p", "udp", 93 "--dport", "137:139", "-j", "NOTRACK"); 94 eval("iptables", "-t", "raw", "-A", "PREROUTING", "-i", ifname, "-p", "udp", 95 "--dport", "445", "-j", "NOTRACK"); 96 eval("iptables", "-t", "raw", "-A", "OUTPUT", "-o", ifname, "-p", "tcp", 97 "--sport", "137:139", "-j", "NOTRACK"); 98 eval("iptables", "-t", "raw", "-A", "OUTPUT", "-o", ifname, "-p", "tcp", 99 "--sport", "445", "-j", "NOTRACK"); 100 eval("iptables", "-t", "raw", "-A", "OUTPUT", "-o", ifname, "-p", "udp", 101 "--sport", "137:139", "-j", "NOTRACK"); 102 eval("iptables", "-t", "raw", "-A", "OUTPUT", "-o", ifname, "-p", "udp", 103 "--sport", "445", "-j", "NOTRACK"); 104 105 eval("iptables", "-t", "filter", "-I", "INPUT", "-i", ifname, "-p", "udp", 106 "--dport", "137:139", "-j", "ACCEPT"); 107 eval("iptables", "-t", "filter", "-I", "INPUT", "-i", ifname, "-p", "udp", 108 "--dport", "445", "-j", "ACCEPT"); 109 eval("iptables", "-t", "filter", "-I", "INPUT", "-i", ifname, "-p", "tcp", 110 "--dport", "137:139", "-j", "ACCEPT"); 111 eval("iptables", "-t", "filter", "-I", "INPUT", "-i", ifname, "-p", "tcp", 112 "--dport", "445", "-j", "ACCEPT"); 113} 114#endif /* LINUX_2_6_36 && __CONFIG_SAMBA__ */ 115 116int 117start_firewall(void) 118{ 119#if 0 120 DIR *dir; 121 struct dirent *file; 122 FILE *fp; 123 char name[NAME_MAX]; 124 netconf_filter_t filter; 125 netconf_app_t app; 126 int i, index; 127 char var[256], *next; 128 int log_level, log_drop, log_accept; 129 struct ipaddress_pairs { 130 struct in_addr address; 131 struct in_addr mask; 132 } *ip_addrs = NULL; 133 char lan_proto[20]; 134 char lan_ifname[20]; 135 char lan_ipaddr[20]; 136 char lan_netmask[20]; 137 char *address, *mask; 138 struct ipaddress_pairs *cur_ipaddr; 139 140 /* Reset firewall */ 141 netconf_reset_fw(); 142 143 /* Block obviously spoofed IP addresses */ 144 if (!(dir = opendir("/proc/sys/net/ipv4/conf"))) 145 perror("/proc/sys/net/ipv4/conf"); 146 while (dir && (file = readdir(dir))) { 147 if (strncmp(file->d_name, ".", NAME_MAX) != 0 && 148 strncmp(file->d_name, "..", NAME_MAX) != 0) { 149 snprintf(name, sizeof(name), 150 "/proc/sys/net/ipv4/conf/%s/rp_filter", file->d_name); 151 if (!(fp = fopen(name, "r+"))) { 152 perror(name); 153 break; 154 } 155 fputc('1', fp); 156 fclose(fp); 157 } 158 } 159 if (dir) 160 closedir(dir); 161 162 /* Optionally log connections */ 163 log_level = atoi(nvram_safe_get("log_level")); 164 log_drop = (log_level & 1) ? NETCONF_LOG_DROP : NETCONF_DROP; 165 log_accept = (log_level & 2) ? NETCONF_LOG_ACCEPT : NETCONF_ACCEPT; 166 167 /* 168 * Inbound drops 169 */ 170 171 /* Drop invalid packets */ 172 memset(&filter, 0, sizeof(filter)); 173 filter.match.state = NETCONF_INVALID; 174 filter.target = NETCONF_DROP; 175 add_filter(&filter, NETCONF_IN); 176 add_filter(&filter, NETCONF_FORWARD); 177 178 /* 179 * Forward drops 180 */ 181 182 /* Client filters */ 183 for (i = 0; i < MAX_NVPARSE; i++) { 184 netconf_filter_t start, end; 185 186 if (get_filter_client(i, &start, &end) && !(start.match.flags & NETCONF_DISABLED)) { 187 while (ntohl(start.match.src.ipaddr.s_addr) <= 188 ntohl(end.match.src.ipaddr.s_addr)) { 189 /* Override target */ 190 start.target = log_drop; 191 add_filter(&start, NETCONF_FORWARD); 192 start.match.src.ipaddr.s_addr = 193 htonl(ntohl(start.match.src.ipaddr.s_addr) + 1); 194 } 195 } 196 } 197 198 /* Filter by MAC address */ 199 if (!nvram_match("filter_macmode", "disabled")) { 200 memset(&filter, 0, sizeof(filter)); 201 strncpy(filter.match.in.name, nvram_safe_get("lan_ifname"), IFNAMSIZ); 202 if (nvram_match("filter_macmode", "allow")) { 203 /* Allow new connections from 204 * the LAN side only from the specified addresses 205 */ 206 filter.target = log_accept; 207 filter.match.state = NETCONF_NEW; 208 } else { 209 /* Drop connections from the specified addresses */ 210 filter.target = log_drop; 211 } 212 foreach(var, nvram_safe_get("filter_maclist"), next) { 213 if (ether_atoe(var, filter.match.mac.octet)) 214 add_filter(&filter, NETCONF_FORWARD); 215 } 216 } 217 218 /* 219 * Inbound accepts 220 */ 221 /* Allow new connections from the loopback interface */ 222 memset(&filter, 0, sizeof(filter)); 223 filter.match.state = NETCONF_NEW; 224 filter.match.src.ipaddr.s_addr = htonl(INADDR_LOOPBACK); 225 filter.match.src.netmask.s_addr = htonl(INADDR_BROADCAST); 226 strncpy(filter.match.in.name, "lo", IFNAMSIZ); 227 filter.target = log_accept; 228 add_filter(&filter, NETCONF_IN); 229 add_filter(&filter, NETCONF_FORWARD); 230 231 /* allocate memory for ip_addrs */ 232 ip_addrs = malloc(sizeof(struct ipaddress_pairs) * MAX_NO_BRIDGE); 233 if (!ip_addrs) { 234 dprintf("start_firewall()Error allocating memory\n"); 235 goto start_firewall_cleanup0; 236 } 237 memset(ip_addrs, 0, sizeof(struct ipaddress_pairs) * MAX_NO_BRIDGE); 238 cur_ipaddr = ip_addrs; 239 240 for (i = 0; i < MAX_NO_BRIDGE; i++) { 241 if (!i) { 242 snprintf(lan_ifname, sizeof(lan_ifname), "lan_ifname"); 243 snprintf(lan_proto, sizeof(lan_proto), "lan_proto"); 244 snprintf(lan_ipaddr, sizeof(lan_ipaddr), "lan_ipaddr"); 245 snprintf(lan_netmask, sizeof(lan_netmask), "lan_netmask"); 246 } 247 else { 248 snprintf(lan_proto, sizeof(lan_proto), "lan%x_proto", i); 249 snprintf(lan_ifname, sizeof(lan_ifname), "lan%x_ifname", i); 250 snprintf(lan_ipaddr, sizeof(lan_ipaddr), "lan%x_ipaddr", i); 251 snprintf(lan_netmask, sizeof(lan_netmask), "lan%x_netmask", i); 252 } 253 if (!strcmp(nvram_safe_get(lan_ifname), "")) 254 continue; 255 256 /* Allow new connections from the LAN side */ 257 memset(&filter, 0, sizeof(filter)); 258 filter.match.state = NETCONF_NEW; 259 strncpy(filter.match.in.name, nvram_safe_get(lan_ifname), IFNAMSIZ); 260 inet_aton(nvram_safe_get(lan_ipaddr), (struct in_addr *)&filter.match.src.ipaddr); 261 inet_aton(nvram_safe_get(lan_netmask), (struct in_addr *)&filter.match.src.netmask); 262 filter.match.src.ipaddr.s_addr &= filter.match.src.netmask.s_addr; 263 264 filter.target = log_accept; 265 add_filter(&filter, NETCONF_IN); 266 /* filter_macmode applies only to the first bridge (for now). */ 267 /* On other bridges, add this filter */ 268 if (!nvram_match("filter_macmode", "allow") || (i > 0)) { 269 add_filter(&filter, NETCONF_FORWARD); 270 } 271 272 /* Allow DHCP broadcast requests */ 273 if (nvram_match(lan_proto, "dhcp")) { 274 memset(&filter, 0, sizeof(filter)); 275 filter.match.state = NETCONF_NEW; 276 filter.match.ipproto = IPPROTO_UDP; 277 strncpy(filter.match.in.name, nvram_safe_get(lan_ifname), IFNAMSIZ); 278 filter.match.src.netmask.s_addr = htonl(INADDR_BROADCAST); 279 filter.match.src.ipaddr.s_addr = htonl(INADDR_ANY); 280 filter.match.dst.netmask.s_addr = htonl(INADDR_BROADCAST); 281 filter.match.dst.ipaddr.s_addr = htonl(INADDR_BROADCAST); 282 filter.match.dst.ports[0] = htons(67); 283 filter.match.dst.ports[1] = htons(67); 284 filter.match.src.ports[0] = htons(68); 285 filter.match.src.ports[1] = htons(68); 286 filter.target = log_accept; 287 add_filter(&filter, NETCONF_IN); 288 }; 289 290 /* store all lanX_ipaddr lanX_netmask */ 291 address = nvram_get(lan_ipaddr); 292 mask = nvram_get(lan_netmask); 293 294 if (address && mask) { 295 if (!inet_aton(address, &cur_ipaddr->address)) { 296 cprintf("start_firewall():Invalid lan_ipaddr:%s\n", address); 297 goto start_firewall_cleanup1; 298 } 299 if (!inet_aton(mask, &cur_ipaddr->mask)) { 300 cprintf("start_firewall():Invalid lan_netmask:%s\n", mask); 301 goto start_firewall_cleanup1; 302 } 303 cur_ipaddr++; 304 305 } else if (address || mask) { 306 dprintf("start_firewall(): " 307 "Both bridge ipaddress and ipmask must be defined.\n"); 308 goto start_firewall_cleanup1; 309 } 310 311 312 } 313 /* Create restriction filters among bridges */ 314 for (i = 1; i < MAX_NO_BRIDGE; i++) { 315 if (!i) { 316 snprintf(lan_ifname, sizeof(lan_ifname), "lan_ifname"); 317 } 318 else { 319 snprintf(lan_ifname, sizeof(lan_ifname), "lan%x_ifname", i); 320 } 321 if (!strcmp(nvram_safe_get(lan_ifname), "")) 322 continue; 323 324 for (index = 0; index < MAX_NO_BRIDGE; index++) { 325 326 /* Skip making rule if the dest address is ours 327 * Assume that the ranges do not overlap so we do not 328 * check the mask value 329 */ 330 if (index == i) 331 continue; 332 333 memset(&filter, 0, sizeof(filter)); 334 filter.match.state = NETCONF_NEW; 335 filter.match.src.ipaddr.s_addr = ip_addrs[i].address.s_addr; 336 filter.match.src.ipaddr.s_addr &= ip_addrs[i].mask.s_addr; 337 filter.match.src.netmask.s_addr = ip_addrs[i].mask.s_addr; 338 filter.match.dst.ipaddr.s_addr = ip_addrs[index].address.s_addr; 339 filter.match.dst.ipaddr.s_addr &= ip_addrs[index].mask.s_addr; 340 filter.match.dst.netmask.s_addr = ip_addrs[index].mask.s_addr; 341 strncpy(filter.match.in.name, nvram_safe_get(lan_ifname), IFNAMSIZ); 342 filter.target = log_drop; 343 add_filter(&filter, NETCONF_IN); 344 add_filter(&filter, NETCONF_FORWARD); 345 } 346 } 347 348 /* Allow established and related outbound connections back in */ 349 memset(&filter, 0, sizeof(filter)); 350 filter.match.state = NETCONF_ESTABLISHED | NETCONF_RELATED; 351 filter.target = log_accept; 352 add_filter(&filter, NETCONF_IN); 353 add_filter(&filter, NETCONF_FORWARD); 354 355 /* 356 * NAT 357 */ 358 359 /* Enable IP masquerading */ 360 if ((fp = fopen("/proc/sys/net/ipv4/ip_forward", "r+"))) { 361 fputc('1', fp); 362 fclose(fp); 363 } else 364 perror("/proc/sys/net/ipv4/ip_forward"); 365 366#if !defined(AUTOFW_PORT_DEPRECATED) 367 /* Application specific port forwards */ 368 for (i = 0; i < MAX_NVPARSE; i++) { 369 memset(&app, 0, sizeof(app)); 370 if (get_autofw_port(i, &app) && !(app.match.flags & NETCONF_DISABLED)) 371 netconf_add_fw((netconf_fw_t *) &app); 372 } 373#endif /* !AUTOFW_PORT_DEPRECATED */ 374 375 /* 376 * Inbound defaults 377 */ 378 379 /* Log refused connections */ 380 memset(&filter, 0, sizeof(filter)); 381 filter.target = log_drop; 382 add_filter(&filter, NETCONF_IN); 383 add_filter(&filter, NETCONF_FORWARD); 384 385#if defined(LINUX_2_6_36) && defined(__CONFIG_SAMBA__) 386 add_conntrack(); 387#endif /* LINUX_2_6_36 && __CONFIG_SAMBA__ */ 388 389 dprintf("done\n"); 390 return 0; 391 392start_firewall_cleanup1: 393 if (ip_addrs) { 394 free(ip_addrs); 395 ip_addrs = NULL; 396 } 397 398start_firewall_cleanup0: 399 400 return 1; 401#endif 402 return 0; 403} 404 405 406int 407start_firewall2(char *wan_ifname) 408{ 409#if 0 410 netconf_nat_t nat; 411 netconf_filter_t filter; 412 int log_level, log_accept; 413 char tmp[100], prefix[] = "wanXXXXXXXXXX_"; 414 int i; 415 char lan_ipaddr[20]; 416 char lan_netmask[20]; 417 418 /* Optionally log connections */ 419 log_level = atoi(nvram_safe_get("log_level")); 420 log_accept = (log_level & 2) ? NETCONF_LOG_ACCEPT : NETCONF_ACCEPT; 421 422 /* Allow new connections from the WAN side */ 423 if (nvram_match("fw_disable", "1")) { 424 memset(&filter, 0, sizeof(filter)); 425 filter.match.state = NETCONF_NEW; 426 strncpy(filter.match.in.name, wan_ifname, IFNAMSIZ); 427 filter.target = log_accept; 428 add_filter(&filter, NETCONF_IN); 429 add_filter(&filter, NETCONF_FORWARD); 430 } 431 432 /* Enable IP masquerading for bridge */ 433 for (i = 0; i < MAX_NO_BRIDGE; i++) { 434 if (!i) { 435 snprintf(lan_ipaddr, sizeof(lan_ipaddr), "lan_ipaddr"); 436 snprintf(lan_netmask, sizeof(lan_netmask), "lan_netmask"); 437 } 438 else { 439 snprintf(lan_ipaddr, sizeof(lan_ipaddr), "lan%x_ipaddr", i); 440 snprintf(lan_netmask, sizeof(lan_netmask), "lan%x_netmask", i); 441 } 442 443 444 memset(&nat, 0, sizeof(nat)); 445 inet_aton(nvram_safe_get(lan_ipaddr), &nat.match.src.ipaddr); 446 inet_aton(nvram_safe_get(lan_netmask), &nat.match.src.netmask); 447 nat.match.src.ipaddr.s_addr &= nat.match.src.netmask.s_addr; 448 strncpy(nat.match.out.name, wan_ifname, IFNAMSIZ); 449 nat.target = NETCONF_MASQ; 450 if (nvram_match("nat_type", "cone")) 451 nat.type = NETCONF_CONE_NAT; 452 netconf_add_nat(&nat); 453 } 454 455 /* Enable remote management */ 456 if (nvram_invmatch("http_wanport", "")) { 457 /* Set up WAN side match */ 458 memset(&nat, 0, sizeof(nat)); 459 nat.match.ipproto = IPPROTO_TCP; 460 nat.match.src.ports[1] = htons(0xffff); 461 nat.match.dst.ports[0] = htons(atoi(nvram_safe_get("http_wanport"))); 462 nat.match.dst.ports[1] = htons(atoi(nvram_safe_get("http_wanport"))); 463 strncpy(nat.match.in.name, wan_ifname, IFNAMSIZ); 464 465 /* Set up DNAT to LAN */ 466 nat.target = NETCONF_DNAT; 467 (void) inet_aton(nvram_safe_get("lan_ipaddr"), &nat.ipaddr); 468 nat.ports[0] = htons(atoi(nvram_safe_get("http_lanport"))); 469 nat.ports[1] = htons(atoi(nvram_safe_get("http_lanport"))); 470 471 add_forward(&nat, NETCONF_IN, log_accept); 472 } 473 474 /* Persistent (static) port forwards */ 475 for (i = 0; i < MAX_NVPARSE; i++) { 476 memset(&nat, 0, sizeof(nat)); 477 if (get_forward_port(i, &nat) && !(nat.match.flags & NETCONF_DISABLED)) { 478 /* Set interface name (match packets entering WAN interface) */ 479 strncpy(nat.match.in.name, wan_ifname, IFNAMSIZ); 480 add_forward(&nat, NETCONF_FORWARD, log_accept); 481 } 482 } 483 484 /* Forward all WAN ports to DMZ IP address */ 485 if (nvram_invmatch("dmz_ipaddr", "")) { 486 /* Set up WAN side match */ 487 memset(&nat, 0, sizeof(nat)); 488 nat.match.src.ports[1] = htons(0xffff); 489 nat.match.dst.ports[1] = htons(0xffff); 490 strncpy(nat.match.in.name, wan_ifname, IFNAMSIZ); 491 492 /* Set up DNAT to LAN */ 493 nat.target = NETCONF_DNAT; 494 (void) inet_aton(nvram_safe_get("dmz_ipaddr"), &nat.ipaddr); 495 nat.ports[1] = htons(0xffff); 496 497 nat.match.ipproto = IPPROTO_TCP; 498 add_forward(&nat, NETCONF_FORWARD, log_accept); 499 nat.match.ipproto = IPPROTO_UDP; 500 add_forward(&nat, NETCONF_FORWARD, log_accept); 501 } 502 503 /* Clamp TCP MSS to PMTU of WAN interface */ 504 snprintf(prefix, sizeof(prefix), "wan%d_", wan_ifunit(wan_ifname)); 505 if (nvram_match(strcat_r(prefix, "proto", tmp), "pppoe")) 506 netconf_clamp_mss_to_pmtu(); 507 508 dprintf("done\n"); 509#endif 510 return 0; 511} 512 513 514/* 515*/ 516