<?php

class ConfigRouterOSFirewallNAT extends NetworkConfigItem
{
  function Run()
  {
    $Path = array('ip', 'firewall', 'nat');

    $Routerboard = new Routerboard($this->System->Config['MainRouter']['HostName']);
    $Routerboard->UserName = $this->System->Config['MainRouter']['UserName'];
    $Routerboard->Timeout = $this->System->Config['MainRouter']['ConnectTimeout'];
    $Routerboard->Debug = true;

    $InetInterface = $this->System->Config['MainRouter']['InetInterface'];
    $LocalInterface = $this->System->Config['MainRouter']['LocalInterface'];
    $IPCentrala = '10.145.64.8';

    $Items = array();

    /*
     // NTP redirect
     $Items[] = array('chain' => 'srcnat', 'src-address' => '10.145.66.1', 'protocol' => 'udp', 'src-port' => 123, 'action' => 'src-nat', 'to-addresses' => '10.145.64.1', 'comment' => 'NTP_redirect_4');
     $Items[] = array('chain' => 'srcnat', 'src-address' => '10.145.66.161', 'protocol' => 'udp', 'src-port' => 123, 'action' => 'src-nat', 'to-addresses' => '10.145.64.1', 'comment' => 'NTP_redirect_5');
     $Items[] = array('chain' => 'srcnat', 'src-address' => '10.145.66.193', 'protocol' => 'udp', 'src-port' => 123, 'action' => 'src-nat', 'to-addresses' => '10.145.64.1', 'comment' => 'NTP_redirect_1');
     $Items[] = array('chain' => 'srcnat', 'src-address' => '10.145.66.225', 'protocol' => 'udp', 'src-port' => 123, 'action' => 'src-nat', 'to-addresses' => '10.145.64.1', 'comment' => 'NTP_redirect_2');
     $Items[] = array('chain' => 'srcnat', 'src-address' => '10.145.66.250', 'protocol' => 'udp', 'src-port' => 123, 'action' => 'src-nat', 'to-addresses' => '10.145.64.1', 'comment' => 'NTP_redirect_3');
     $Items[] = array('chain' => 'srcnat', 'src-address' => '10.145.66.253', 'protocol' => 'udp', 'src-port' => 123, 'action' => 'src-nat', 'to-addresses' => '10.145.64.1', 'comment' => 'NTP_redirect_6');
     */

    // Chain for inet interface
    $Items[] = array('chain' => 'srcnat', 'out-interface' => $InetInterface, 'action' => 'jump', 'jump-target' => 'inet-out', 'comment' => 'inet-out');
    $Items[] = array('chain' => 'dstnat', 'in-interface' => $InetInterface, 'action' => 'jump', 'jump-target' => 'inet-in', 'comment' => 'inet-in');

    // Skip local subnet
    //$Items[] = array('chain' => 'inet-out', 'dst-address' => '172.16.1.1/30', 'action' => 'accept', 'comment' => 'Local_subnet');
    //$Items[] = array('chain' => 'inet-in', 'dst-address' => '172.16.1.1/30', 'action' => 'accept', 'comment' => 'Local_subnet');

    $DbResult = $this->Database->query('SELECT `Member`.*, `Subject`.`Name` FROM `Member` '.
        'LEFT JOIN `Subject` ON `Subject`.`Id` = `Member`.`Subject` '.
        'WHERE `Member`.`Blocked` = 0');
    while($Member = $DbResult->fetch_assoc())
    {
      echo($Member['Name'].': ');
      // Hosts
      $DbResult2 = $this->Database->query('SELECT `NetworkInterface`.*, `NetworkDevice`.`Name` AS `DeviceName`, `NetworkDevice`.`InboundNATPriority` FROM `NetworkInterface`'.
          ' LEFT JOIN `NetworkDevice` ON `NetworkDevice`.`Id` = `NetworkInterface`.`Device` WHERE (`NetworkInterface`.`ExternalIP` <> "")'.
          ' AND (`NetworkInterface`.`LocalIP` <> "")'.
          ' AND (`NetworkDevice`.`Member` = '.$Member['Id'].') AND (`NetworkInterface`.`LocalIP` != `NetworkInterface`.`ExternalIP`) ORDER BY `id` DESC');
      while($Interface = $DbResult2->fetch_assoc())
      {
        $Name = $Interface['DeviceName'];
        if($Interface['Name'] != '') $Name .= '-'.$Interface['Name'];
        $Name = RouterOSIdent($Name);
        echo($Name.'('.$Interface['LocalIP'].'), ');
        if($Member['Blocked'] == 0)
        {
          $Items[] = array('chain' => 'inet-out', 'src-address' => $Interface['LocalIP'], 'action' => 'src-nat',  'to-addresses' => $Interface['ExternalIP'], 'comment' => $Name.'-out');
          if($Interface['InboundNATPriority'] > 0)
            $Items[] = array('chain' => 'inet-in', 'dst-address' => $Interface['ExternalIP'], 'action' => 'dst-nat', 'to-addresses' => $Interface['LocalIP'], 'comment' => $Name.'-in');
        } else
        {
          $Items[] = array('chain' => 'dstnat', 'src-address' => $Interface['LocalIP'], 'protocol' => 'tcp', 'dst-port' => 80, 'action' => 'dst-nat',  'to-addresses' => $IPCentrala, 'to-ports' => 81, 'comment' => $Name.'-out');
        }
      }

      // Subnets
      $DbResult2 = $this->Database->select('NetworkSubnet', '*', '`Member`='.$Member['Id']);
      while($Subnet = $DbResult2->fetch_assoc())
      {
        $Subnet['Name'] = RouterOSIdent('subnet-'.$Subnet['Name']);
        echo($Subnet['Name'].'('.$Subnet['AddressRange'].'/'.$Subnet['Mask'].'), ');
        if($Member['Blocked'] == 0)
        {
          $NewAddress = new NetworkAddressIPv4();
          $NewAddress->AddressFromString($Subnet['ExtAddressRange']);
          $NewAddress->Prefix = $Subnet['ExtMask'];
          $Range = $NewAddress->GetRange();
          if($Subnet['ExtMask'] != 32) $Range = $Range['From']->AddressToString().'-'.$Range['To']->AddressToString();
          else $Range = $Range['From']->AddressToString();
          if($Subnet['Mask'] == 32) $Src = $Subnet['AddressRange'];
          else $Src = $Subnet['AddressRange'].'/'.$Subnet['Mask'];
          $Items[] = array('chain' => 'inet-out', 'src-address' => $Src, 'action' => 'src-nat', 'to-addresses' => $Range, 'comment' => $Subnet['Name'].'-out');

          $NewAddress = new NetworkAddressIPv4();
          $NewAddress->AddressFromString($Subnet['AddressRange']);
          $NewAddress->Prefix = $Subnet['Mask'];
          $Range = $NewAddress->GetRange();
          if($Subnet['Mask'] != 32) $Range = $Range['From']->AddressToString().'-'.$Range['To']->AddressToString();
          else $Range = $Range['From']->AddressToString();
          if($Subnet['ExtMask'] == 32) $Dest = $Subnet['ExtAddressRange'];
          else $Dest = $Subnet['ExtAddressRange'].'/'.$Subnet['ExtMask'];
          $Items[] = array('chain' => 'inet-in', 'dst-address' => $Dest, 'action' => 'dst-nat', 'to-addresses' => $Range, 'comment' => $Subnet['Name'].'-in');
        } else
        {
          if($Subnet['Mask'] == 32) $Src = $Subnet['AddressRange'];
          else $Src = $Subnet['AddressRange'].'/'.$Subnet['Mask'];
          $Items[] = array('chain' => 'dstnat', 'src-address' => $Src, 'protocol' => 'tcp', 'dst-port' => 80, 'action' => 'dst-nat',  'to-addresses' => $IPCentrala, 'to-ports' => 81, 'comment' => $Subnet['Name'].'-out');
        }
      }
      echo("\n");
    }

    // Redirect DNS port
    $Items[] = array('chain' => 'dstnat', 'dst-address' => '212.111.4.174', 'protocol' => 'tcp', 'dst-port' => 53, 'in-interface' => $InetInterface, 'action' => 'dst-nat', 'to-addresses' => '10.145.64.8', 'to-ports' => 53, 'comment' => 'DNS_redirection_TCP');
    $Items[] = array('chain' => 'dstnat', 'dst-address' => '212.111.4.174', 'protocol' => 'udp', 'dst-port' => 53, 'in-interface' => $InetInterface, 'action' => 'dst-nat', 'to-addresses' => '10.145.64.8', 'to-ports' => 53, 'comment' => 'DNS_redirection_UDP');

    // Chain for local interface
    $Items[] = array('chain' => 'srcnat', 'out-interface' => $LocalInterface, 'action' => 'jump', 'jump-target' => 'local-out', 'comment' => 'local-out');
    $Items[] = array('chain' => 'dstnat', 'in-interface' => $LocalInterface, 'action' => 'jump', 'jump-target' => 'local-in', 'comment' => 'local-in');

    // Accept free-access clients
    //$Items[] = array('chain' => 'dstnat', 'dst-address' => '!10.145.0.0/16',
    //    'src-address-list' => 'free-access', 'in-interface' => $LocalInterface,
    //    'action' => 'accept', 'comment' => 'Free_access');
    // Redirect unregistred clients to free access activation page
    //$Items[] = array('chain' => 'dstnat', 'dst-address' => '!10.145.0.0/16',
    //    'src-address-list' => 'unregistred', 'in-interface' => $LocalInterface, 'protocol' => 'tcp',
    //    'action' => 'dst-nat', 'to-addresses' => '10.145.64.70', 'to-ports' => 8080, 'comment' => 'Redirect_unregistred');

    // Masquerade hosts without public ip
    $Items[] = array('chain' => 'inet-out', 'src-address'=> '!212.111.4.174', 'action' => 'src-nat', 'to-addresses' => '77.92.221.188', 'comment' => 'Default_NAT');

    /*
     // Route public addresses localy
     $DbResult = $this->Database->query('SELECT Member.*, Subject.Name FROM Member JOIN Subject ON Member.Subject = Subject.Id');
     while($Member = $DbResult->fetch_assoc())
     {
     echo($Member['Name'].': ');
     // Hosts
     $DbResult2 = $this->Database->query('SELECT NetworkInterface.*, NetworkDevice.Name AS DeviceName FROM NetworkInterface LEFT JOIN NetworkDevice ON NetworkDevice.Id = NetworkInterface.Device WHERE (NetworkInterface.ExternalIP <> "") AND (NetworkDevice.Member = '.$Member['Id'].') AND (NetworkInterface.LocalIP != NetworkInterface.ExternalIP) ORDER BY id DESC');
     while($Interface = $DbResult2->fetch_assoc())
     {
     $Name = $Interface['DeviceName'];
     if($Interface['Name'] != '') $Name .= '-'.$Interface['Name'];
     $Name = RouterOSIdent($Name);
     echo($Name.'('.$Interface['LocalIP'].'), ');
     $Items[] = array('chain' => 'local-in', 'dst-address' => $Interface['ExternalIP'], 'action' => 'dst-nat', 'to-addresses' => $Interface['LocalIP'], 'comment' => $Name.'-in-local');
     }
     echo("\n");
     }

     // Map returned local traffic to virtual subnet
     $Items[] = array('chain' => 'local-out', 'src-address' => '10.145.0.0/16', 'dst-address' => '10.145.0.0/16', 'action' => 'netmap',  'to-addresses' => '10.45.0.0-10.45.255.255', 'comment' => 'map-local');
     */

    //print_r($Items);
    $Routerboard->ListUpdate($Path, array('chain', 'dst-address', 'in-interface', 'src-address', 'out-interface', 'to-ports', 'dst-port', 'protocol', 'action', 'to-addresses', 'comment', 'jump-target', 'src-port'), $Items);
  }
}
