%PDF- %PDF-
Direktori : /backups/router/usr/local/opnsense/mvc/app/library/OPNsense/Firewall/ |
Current File : //backups/router/usr/local/opnsense/mvc/app/library/OPNsense/Firewall/Plugin.php |
<?php /* * Copyright (C) 2016 Deciso B.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ namespace OPNsense\Firewall; use OPNsense\Core\Config; /** * Class Plugin * @package OPNsense\Firewall */ class Plugin { private $gateways = null; private $anchors = array(); private $filterRules = array(); private $natRules = array(); private $interfaceMapping = array(); private $gatewayMapping = array(); private $systemDefaults = array(); private $tables = array(); private $ifconfigDetails = array(); /** * init firewall plugin component */ public function __construct() { $this->systemDefaults = array("filter" => array(), "forward" => array(), "nat" => array()); if (!empty(Config::getInstance()->object()->system->disablereplyto)) { $this->systemDefaults['filter']['disablereplyto'] = true; } if (!empty(Config::getInstance()->object()->system->skip_rules_gw_down)) { $this->systemDefaults['filter']['skip_rules_gw_down'] = true; } if (empty(Config::getInstance()->object()->system->disablenatreflection)) { $this->systemDefaults['forward']['natreflection'] = "enable"; } if (!empty(Config::getInstance()->object()->system->enablebinatreflection)) { $this->systemDefaults['nat']['natreflection'] = "enable"; } if (!empty(Config::getInstance()->object()->system->enablenatreflectionhelper)) { $this->systemDefaults['forward']['enablenatreflectionhelper'] = true; $this->systemDefaults['nat']['enablenatreflectionhelper'] = true; } } /** * set interface mapping to use * @param array $mapping named array */ public function setInterfaceMapping(&$mapping) { $this->interfaceMapping = $mapping; // generate virtual IPv6 interfaces foreach ($this->interfaceMapping as $key => &$intf) { if (!empty($intf['ipaddrv6']) && ($intf['ipaddrv6'] == '6rd' || $intf['ipaddrv6'] == '6to4')) { $realif = "{$key}_stf"; // create new interface $this->interfaceMapping[$realif] = array(); $this->interfaceMapping[$realif]['ifconfig']['ipv6'] = $intf['ifconfig']['ipv6']; $this->interfaceMapping[$realif]['gatewayv6'] = $intf['gatewayv6']; $this->interfaceMapping[$realif]['is_IPv6_override'] = true; $this->interfaceMapping[$realif]['descr'] = $intf['descr']; $this->interfaceMapping[$realif]['if'] = $realif; // link original interface $intf['IPv6_override'] = $realif; } } } /** * set defined gateways (route-to) * @param \OPNsense\Routing\Gateways $gateways object */ public function setGateways(\OPNsense\Routing\Gateways $gateways) { $this->gateways = $gateways; foreach ($gateways->gatewaysIndexedByName(false, true) as $key => $gw) { if (!empty($gw['gateway_interface']) || Util::isIpAddress($gw['gateway'] ?? null)) { $this->gatewayMapping[$key] = [ "interface" => $gw['if'], "proto" => $gw['ipprotocol'], "type" => "gateway" ]; if (!empty($gw['gateway']) && Util::isIpAddress($gw['gateway'])) { $this->gatewayMapping[$key]['logic'] = "route-to ( {$gw['if']} {$gw['gateway']} )"; $this->gatewayMapping[$key]['gateway'] = $gw['gateway']; } else { $this->gatewayMapping[$key]['logic'] = "route-to {$gw['if']}"; } } } } /** * @return \OPNsense\Routing\Gateways gateway object */ public function getGateways(): ?\OPNsense\Routing\Gateways { return $this->gateways; } /** * set defined gateway groups (route-to) * @param array $groups named array */ public function setGatewayGroups($groups) { if (is_array($groups)) { foreach ($groups as $key => $gwgr) { $routeto = array(); $proto = 'inet'; foreach ($gwgr as $gw) { if (Util::isIpAddress($gw['gwip']) && !empty($gw['int'])) { $gwweight = empty($gw['weight']) ? 1 : $gw['weight']; $routeto[] = str_repeat("( {$gw['int']} {$gw['gwip']} )", $gwweight); if (strstr($gw['gwip'], ':')) { $proto = 'inet6'; } } } if (count($routeto) > 0) { $routetologic = "route-to {" . implode(' ', $routeto) . "}"; if (!empty($gwgr[0]['poolopts'])) { // Since Gateways->getGroups() returns detail items, we have no other choice than // to copy top level attributes into the details if they matter (poolopts) $routetologic .= " {$gwgr[0]['poolopts']} "; } elseif (count($routeto) > 1) { $routetologic .= " round-robin "; if (!empty(Config::getInstance()->object()->system->lb_use_sticky)) { $routetologic .= " sticky-address "; } } $this->gatewayMapping[$key] = array("logic" => $routetologic, "proto" => $proto, "type" => "group"); } } } } /** * Fetch gateway * @param string $gw gateway name */ public function getGateway($gw) { return $this->gatewayMapping[$gw]; } /** * @return array */ public function getInterfaceMapping() { foreach ($this->interfaceMapping as $intfkey => $intf) { // suppress virtual ipv6 interfaces if (empty($intf['is_IPv6_override'])) { yield $intfkey => $intf; } } } /** * link parsed ifconfig output * @param array $ifconfig from legacy_interfaces_details() */ public function setIfconfigDetails($ifconfig) { $this->ifconfigDetails = $ifconfig; } /** * @return array */ public function getIfconfigDetails() { return $this->ifconfigDetails; } /** * register anchor * @param string $name anchor name * @param string $type anchor type (fw for filter, other options are nat,rdr,binat) * @param string $priority sort order from low to high * @param string $placement placement head,tail * @param bool $quick * @return null */ public function registerAnchor($name, $type = "fw", $priority = 0, $placement = "tail", $quick = false) { $anchorKey = sprintf("%s.%s.%08d.%08d", $type, $placement, $priority, count($this->anchors)); $this->anchors[$anchorKey] = array('name' => $name, 'quick' => $quick); ksort($this->anchors); } /** * fetch anchors as text (pf ruleset part) * @param string $types anchor types (fw for filter, other options are nat,rdr,binat. comma-separated) * @param string $placement placement head,tail * @return string */ public function anchorToText($types = "fw", $placement = "tail") { $result = ""; foreach (explode(',', $types) as $type) { foreach ($this->anchors as $anchorKey => $anchor) { if (strpos($anchorKey, "{$type}.{$placement}") === 0) { $result .= $type == "fw" ? "" : "{$type}-"; $result .= "anchor \"{$anchor['name']}\""; if ($anchor['quick']) { $result .= " quick"; } $result .= "\n"; } } } return $result; } /** * register a filter rule * @param int $prio priority * @param array $conf configuration * @param array $defaults merge these defaults when provided */ public function registerFilterRule($prio, $conf, $defaults = null) { if (!empty($this->systemDefaults['filter'])) { $conf = array_merge($this->systemDefaults['filter'], $conf); } if ($defaults != null) { $conf = array_merge($defaults, $conf); } if (empty($conf['label'])) { // generated rule, has no label $rule_hash = Util::calcRuleHash($conf); $conf['label'] = $rule_hash; } $conf['#priority'] = $prio; $rule = new FilterRule($this->interfaceMapping, $this->gatewayMapping, $conf); if (empty($this->filterRules[$prio])) { $this->filterRules[$prio] = array(); } $this->filterRules[$prio][] = $rule; } /** * register a Forward (rdr) rule * @param int $prio priority * @param array $conf configuration */ public function registerForwardRule($prio, $conf) { if (!empty($this->systemDefaults['forward'])) { $conf = array_merge($this->systemDefaults['forward'], $conf); } $rule = new ForwardRule($this->interfaceMapping, $conf); if (empty($this->natRules[$prio])) { $this->natRules[$prio] = array(); } $this->natRules[$prio][] = $rule; } /** * register a destination Nat rule * @param int $prio priority * @param array $conf configuration */ public function registerDNatRule($prio, $conf) { if (!empty($this->systemDefaults['nat'])) { $conf = array_merge($this->systemDefaults['nat'], $conf); } $rule = new DNatRule($this->interfaceMapping, $conf); if (empty($this->natRules[$prio])) { $this->natRules[$prio] = array(); } $this->natRules[$prio][] = $rule; } /** * register a destination Nat rule * @param int $prio priority * @param array $conf configuration */ public function registerSNatRule($prio, $conf) { $rule = new SNatRule($this->interfaceMapping, $conf); if (empty($this->natRules[$prio])) { $this->natRules[$prio] = array(); } $this->natRules[$prio][] = $rule; } /** * register an Npt rule * @param int $prio priority * @param array $conf configuration */ public function registerNptRule($prio, $conf) { $rule = new NptRule($this->interfaceMapping, $conf); if (empty($this->natRules[$prio])) { $this->natRules[$prio] = array(); } $this->natRules[$prio][] = $rule; } /** * filter rules to text * @return string */ public function outputFilterRules() { $output = ""; ksort($this->filterRules); foreach ($this->filterRules as $prio => $ruleset) { $output .= "# [prio: {$prio}]\n"; foreach ($ruleset as $rule) { $output .= (string)$rule; } } return $output; } /** * iterate through registered rules * @return Iterator */ public function iterateFilterRules() { ksort($this->filterRules); /* sort rules by priority */ foreach ($this->filterRules as $prio => $ruleset) { foreach ($ruleset as $rule) { yield $rule; } } } /** * filter rules to text * @return string */ public function outputNatRules() { $output = ""; ksort($this->natRules); foreach ($this->natRules as $prio => $ruleset) { $output .= "# [prio: {$prio}]\n"; foreach ($ruleset as $rule) { $output .= (string)$rule; } } return $output; } /** * register a pf table * @param string $name table name * @param boolean $persist persistent * @param string $file get table from file */ public function registerTable($name, $persist = false, $file = null) { $this->tables[] = array('name' => $name, 'persist' => $persist, 'file' => $file); } /** * fetch tables as text (pf tables part) * @return string */ public function tablesToText() { $result = ""; foreach ($this->tables as $table) { $result .= "table <{$table['name']}>"; if ($table['persist']) { $result .= " persist"; } if (!empty($table['file'])) { $result .= " file \"{$table['file']}\""; } $result .= "\n"; } return $result; } }