<?php

// phpcs:disable WordPress.DB.RestrictedClasses.mysql__mysqli -- auto_prepend_file script runs outside WordPress; direct DB connection is intentional.
/**
 * Hovedscriptet for firewall som installeres i .htaccess
 *
 */

namespace WtbFirewall;

class WtbFirewall {

    //Settes i rangeCheck funksjonen. Holder firewall regel ID dersom blokkering skal logføres.
    private $ruleID = null;

    /**
     * Hvor vi lagrer loggen.     
     */
    private $logFile = null;

    /**
     * Disse to settes for å indikere om tilkoblingen er IPv4 eller IPv6.
     */
    private $isIPv4 = false;
    private $isIPv6 = false;

    /**
     * Her lagrer vi IP addressen som en string. Brukt i logfilen.
     */
    private $ipString = '';

    /**
     * Her lagrer vi manuelt lagt inn IPv6 regler lest fra fil.
     */
    private $ipv6AllowPrefix, $ipv6AllowListe, $ipv6BlockPrefix, $ipv6BlockListe;

    /**
     * Her lagrer vi IPv6 regler for land lest fra fil.
     */
    private $ipv6CountryAllowPrefix, $ipv6CountryAllowListe, $ipv6CountryBlockPrefix, $ipv6CountryBlockListe;

    /**
     * Her lagrer vi automatisk genererte IPv6 regler.  
     */
    private $ipv6AutoBlock, $ipv6AutoBlockPrefix;

    /**
     * Her lagrer vi manuelt lagt inn IPv4 regler lest fra fil.     
     */
    private $ipv4AllowListe, $ipv4BlockListe, $ipv4AllowRange, $ipv4BlockRange;

    /**
     * Her lagrer vi IPv4 regler for land.
     */
    private $ipv4CountryBlockListe, $ipv4CountryAllowListe;

    /**
     * Her lagrer vi automatisk genererte IPv4 regler.
     */
    private $ipv4AutoBlock;

    public function __construct() {
        $this->Start();
    }

    /**
     * Setter i $_GLOBALS['wtb_firewall_messages'] at et problem har oppstått.
     * $msg er feilmelding som skal sendes videre.
     * NB! Denne anonyme funksjonen må være her og kan ikke plasseres i wtb_firewall_functions.php
     */
    private function sendErrorMsg($msg) {
        $GLOBALS['wtb_firewall_messages']['type'] = 1;
        $GLOBALS['wtb_firewall_messages']['msg'] = $msg;
    }

    /**
     * Setter i $_GLOBALS['wtb_firewall_messages'] at status er OK! Ingen problemer.
     */
    private function sendOKstatus() {
        $GLOBALS['wtb_firewall_messages']['type'] = 2;
    }

    /**
     * Denne funksjonen sjekker om $ip er innenfor $ipRange.
     * $ipRange er array der hvert element er et array med tre elementer [0]=Start IP range, [1]=Slutt IP range, [2]=Firewall rule ID,
     * [3]=Tid når regel går ut på dato, eller null dersom regel er permanent.
     *
     * Funksjonen benytter binærsøk, $ipRange er forventet å være sortert på Start IP.
     *
     * Returnerer TRUE dersom $ip er innenfor $ipRange, FALSE hvis ikke.
     */
    private function rangeCheckBinary($ipRange, $ip): bool {
        $low = 0;
        $high = count($ipRange) - 1;

        while ($low <= $high) {
            $mid = intdiv($low + $high, 2);
            $range = $ipRange[$mid];

            if ($ip < $range[0]) {
                // IP is before this range → search left half
                $high = $mid - 1;
            } elseif ($ip > $range[1]) {
                // IP is after this range → search right half
                $low = $mid + 1;
            } else {
                //Har funnet en match. Sjekk at regel ikke er utgått på dato.
                if (!isset($range[3]) || $range[3] == null) {
                    //Regel er ikke midlertidig.
                    $this->ruleID = $range[2];
                    return true;
                } else {
                    //Regel er midlertidig. Sjekk om den utgått på dato.
                    $expiry = new \DateTime($range[3], new \DateTimeZone('UTC'));
                    $now = new \DateTime('now', new \DateTimeZone('UTC'));

                    if ($now < $expiry) {
                        //Regel er fremdeles gyldig.
                        $this->ruleID = $range[2];
                        return true;
                    }

                    //Regel utgått på dato.
                    return false;
                }
            }
        }

        return false;
    }

    /**
     * Sjekker om IP skal blokkeres ifølge automatisk genererte regler.
     * Setter også $this->ruleID dersom IP skal blokkeres.
     *
     * @param array $ipListe Liste over automatisk genererte regler.
     * @param type $ip IPv4 addressen dette gjelder.
     * @return bool TRUE dersom IP skal blokkeres, FALSE hvis ikke.
     */
    private function autoRuleCheck(array $ipListe, $ip): bool {

        if (isset($ipListe[$ip])) {
            //Sjekk at regel ikke er utgått på dato.
            $expiry = new \DateTime($ipListe[$ip][1], new \DateTimeZone('UTC'));
            $now = new \DateTime('now', new \DateTimeZone('UTC'));

            if ($now < $expiry) {
                //Regel er fremdeles gyldig.
                $this->ruleID = $ipListe[$ip][0];
                return true;
            }
        }

        return false;
    }

    /**
     * Sjekker om IPv4 skal blokkeres/tillates ifølge manuelle regler.
     * Sjekker kun enkelt IP og ikke IP range eller CIDR.
     * Setter også $this->ruleID dersom IP skal blokkeres.
     *
     * @param array $ipListe Liste over manuelle regler.
     * @param type $ip IPv4 addressen dette gjelder.
     * @return bool TRUE dersom IP skal blokkeres, FALSE hvis ikke.
     */
    private function singleIpCheck(array $ipListe, $ip): bool {

        if (isset($ipListe[$ip])) {
            //Sjekk om regel er midlertidig og ikke utgått på dato.
            if ($ipListe[$ip][1] == null) {
                //Regel er ikke midlertidig.
                $this->ruleID = $ipListe[$ip][0];
                return true;
            } else {
                //Regel er midlertidig. Sjekk om den utgått på dato.
                $expiry = new \DateTime($ipListe[$ip][1], new \DateTimeZone('UTC'));
                $now = new \DateTime('now', new \DateTimeZone('UTC'));

                if ($now < $expiry) {
                    //Regel er fremdeles gyldig.
                    $this->ruleID = $ipListe[$ip][0];
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * For IPv4. Sjekker om oppgitt IP skal blokkeres eller ikke.
     * Det er antatt at firewall er i ALLOW ALL mode.
     *
     * @param $ip IPv4 som skal sjekkes.    
     *
     * @return TRUE dersom IP skal blokkeres, FALSE hvis IP ikke skal blokkeres.
     *          $this-ruleID inneholder regel ID dersom IP skal blokkeres.
     */
    private function ipV4checkBlocked(int $ip): bool {

        if ($this->singleIpCheck($this->ipv4BlockListe, $ip) || $this->rangeCheckBinary($this->ipv4BlockRange, $ip) || $this->rangeCheckBinary($this->ipv4CountryBlockListe, $ip) || $this->autoRuleCheck($this->ipv4AutoBlock, $ip)) {
            //Blokkert. Sjekk om IP er i ALLOW listen.
            if ($this->singleIpCheck($this->ipv4AllowListe, $ip) || $this->rangeCheckBinary($this->ipv4AllowRange, $ip) || $this->rangeCheckBinary($this->ipv4CountryAllowListe, $ip)) {
                //Skal gjøre unntak for IP.
                return false;
            } else {
                //Blokkert.
                return true;
            }
        }

        return false;
    }

    /**
     * For IPv4. Sjekker om oppgitt IP skal tillates eller ikke.
     * Det er antatt at firewall er i BLOCK ALL mode.
     *
     * @param $ip IPv4 som skal sjekkes.
     *
     * @return TRUE dersom IP skal tillates, FALSE hvis IP ikke skal tillates.
     *          $this-ruleID inneholder regel ID dersom IP ikke skal tillates og logføres. Ellers satt til null.
     */
    private function ipV4checkAllowed(int $ip): bool {

        if ($this->singleIpCheck($this->ipv4AllowListe, $ip) || $this->rangeCheckBinary($this->ipv4AllowRange, $ip) || $this->rangeCheckBinary($this->ipv4CountryAllowListe, $ip)) {
            // Tillatt. Sjekk om IP er i BLOCK listen.            
            if ($this->singleIpCheck($this->ipv4BlockListe, $ip) || $this->rangeCheckBinary($this->ipv4BlockRange, $ip) || $this->rangeCheckBinary($this->ipv4CountryBlockListe, $ip) || $this->autoRuleCheck($this->ipv4AutoBlock, $ip)) {
                //Blokkert.
                return false;
            } else {
                return true;
            }
        }

        //Ikke funnet i allow listene. Sett ruleID til null for sikkerhetskyld.
        $this->ruleID = null;
        return false;
    }

    /**
     * Henter IP addresse mottatt fra proxy server.
     *
     * @param string $header Proxy header vi skal bruke, eller auto for å automatisk velge header.
     * @return string IP addresse fra proxy header, eller $_SERVER['REMOTE_ADDR'] dersom header ikke funnet.
     *                Eventuelt tom string hvis ingen gyldig verdi i $_SERVER['REMOTE_ADDR']
     */
    private function proxyGetIp(string $header = 'auto'): string {

        $supportedHeaders = [
            'x_forwarded_for' => 'HTTP_X_FORWARDED_FOR',
            'x_real_ip' => 'HTTP_X_REAL_IP',
            'forwarded' => 'HTTP_FORWARDED',
            'cf_connecting_ip' => 'HTTP_CF_CONNECTING_IP',
            'true_client_ip' => 'HTTP_TRUE_CLIENT_IP',
            'x_client_ip' => 'HTTP_X_CLIENT_IP',
        ];

        $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '';

        if (!is_string($remoteAddr)) {
            return '';
        }

        if (!filter_var($remoteAddr, FILTER_VALIDATE_IP)) {
            return '';
        }

        // Auto-detect header (first match wins)
        if ($header === 'auto') {
            foreach ($supportedHeaders as $key => $serverKey) {
                if (!isset($_SERVER[$serverKey])) {
                    continue;
                }

                $value = trim((string) $_SERVER[$serverKey]);
                if ($value !== '') {
                    $header = $key;
                    break;
                }
            }
        }

        //Ingen proxy header.
        if (!isset($supportedHeaders[$header])) {
            return $remoteAddr;
        }

        $value = $_SERVER[$supportedHeaders[$header]] ?? '';

        if (!is_string($value) || $value === '') {
            return $remoteAddr;
        }

        $ip = '';

        switch ($header) {

            case 'x_forwarded_for':
                $parts = explode(',', $value);

                foreach ($parts as $part) {
                    $candidate = trim($part);
                    if (filter_var($candidate, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
                        $ip = $candidate;
                        break;
                    }
                }
                break;

            case 'forwarded':
                // Take the first Forwarded "element" if multiple are present (comma-separated).
                $first = trim(strtok($value, ','));

                // Find the `for=` parameter value (quoted or unquoted) up to next ; or end.
                if (preg_match('/(?:^|;\s*)for=(?:"([^"]+)"|([^;]+))/i', $first, $m)) {
                    $forVal = trim($m[1] !== '' ? $m[1] : $m[2]);

                    // Remove optional "unknown" and obfuscated identifiers; only accept real IPs.
                    // Normalize: strip surrounding quotes already handled, now remove brackets for IPv6.
                    $forVal = trim($forVal);
                    $forVal = trim($forVal, " \t\n\r\0\x0B"); // whitespace
                    $forVal = trim($forVal, '"');            // just in case
                    // If bracketed IPv6 like [2001:db8::1] or [2001:db8::1]:1234
                    if (strlen($forVal) > 0 && $forVal[0] === '[') {
                        $end = strpos($forVal, ']');
                        if ($end !== false) {
                            $candidate = substr($forVal, 1, $end - 1);
                        } else {
                            $candidate = ltrim($forVal, '['); // malformed but try
                        }
                    } else {
                        $candidate = $forVal;

                        // Strip port for IPv4 (1.2.3.4:1234)
                        if (preg_match('/^\d{1,3}(?:\.\d{1,3}){3}:\d+$/', $candidate)) {
                            $candidate = preg_replace('/:\d+$/', '', $candidate);
                        }
                        // NOTE: Unbracketed IPv6 with port is ambiguous; Forwarded should bracket it.
                        // If it's unbracketed IPv6, we keep it as-is (no port stripping).
                    }

                    // Final validation (IPv4 or IPv6)
                    if (filter_var($candidate, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
                        $ip = $candidate;
                    }
                }
                break;

            default:
                $ip = trim($value);
                if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
                    return $remoteAddr;
                }
        }

        //I tilfelle vi ikke klarer å få IP fra header.
        if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
            return $remoteAddr;
        }
        return $ip;
    }

    /**
     * Returnerer IP addresse for tilkoblingen.
     *
     * @param array proxyServer Konfigurasjonen for eventuell proxyserver.
     * @return IPv4 som int, IPv6 som binary string eller null dersom feil.
     */
    private function getIP(array $proxyServer) {
        $ip = $_SERVER['REMOTE_ADDR'];

        if (!is_string($ip) || !filter_var($ip, FILTER_VALIDATE_IP)) {
            return null;
        }

        /**
         * Sjekker om vi har en godkjent proxyserver for IPv4.
         */
        $ipv4HasProxyServer = function () use ($ip, $proxyServer): bool {
            $ipBin = ip2long($ip);
            foreach ($proxyServer['proxyListIpv4'] as $proxy) {
                switch ($proxy['type']) {
                    case 'single':
                        if ($ipBin == $proxy['start'])
                            return true;
                        break;

                    case 'cidr':
                        $networkStart = $proxy['start'];
                        $networkEnd = $networkStart | ((1 << (32 - $proxy['prefix'])) - 1);
                        if ($ipBin >= $networkStart && $ipBin <= $networkEnd)
                            return true;
                        break;

                    case 'range':
                        if ($ipBin >= $proxy['start'] && $ipBin <= $proxy['end'])
                            return true;
                        break;
                }
            }
            return false;
        };

        /**
         * Sjekker om en IPv6 addresse tilhører et gitt IPv6 nettverk.
         *
         * @param string $remoteBin IPv6 addresse, binary string.
         * @param string $networkBin IPv6 nettverket, binary string.
         * @param int $prefix Prefix for IPv6 nettverket.
         *
         * @return bool TRUE dersom $remoteIP tilhører $networkBin
         */
        $ipv6InNetwork = function (string $remoteBin, string $networkBin, int $prefix): bool {
            //Prefix 0 matcher alle IP addresser.
            if ($prefix === 0) {
                return true;
            }

            $fullBytes = intdiv($prefix, 8);
            $remBits = $prefix % 8;

            //Sammenlign hele byte i IP addressene.
            if ($fullBytes > 0) {
                if (substr($remoteBin, 0, $fullBytes) !== substr($networkBin, 0, $fullBytes)) {
                    return false;
                }
            }

            //Sammenlign eventuelle gjenværende bits.
            if ($remBits > 0) {
                $mask = 0xFF << (8 - $remBits);
                $r = ord($remoteBin[$fullBytes]) & $mask;
                $n = ord($networkBin[$fullBytes]) & $mask;
                if ($r !== $n) {
                    return false;
                }
            }

            return true;
        };

        /**
         * Sjekker om vi har en godkjent proxyserver for IPv6.
         */
        $ipv6HasProxyServer = function () use ($ip, $proxyServer, $ipv6InNetwork): bool {
            $ipBin = @inet_pton($ip);
            if ($ipBin === false)
                return false;
            foreach ($proxyServer['proxyListIpv6'] as $proxy) {
                if ($ipv6InNetwork($ipBin, $proxy['ipv6'], $proxy['prefix'])) {
                    return true;
                }
            }

            return false;
        };

        if ($proxyServer['enabled']) {
            if (((bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && $ipv4HasProxyServer()) ||
                    ((bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && $ipv6HasProxyServer())) {
                //Tilkobling er fra en godkjent proxyserver.               
                $ip = $this->proxyGetIp($proxyServer['header']);
            }
        }

        //$ip skal nå inneholde rett IPv4 aller IPv6 addresse.
        if ((bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            $this->isIPv4 = true;
            $this->ipString = $ip;
            return ip2long($ip);
        } else if ((bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            $this->isIPv6 = true;
            $this->ipString = $ip;
            return inet_pton($ip);
        } else {
            return null;
        }
    }

    /**
     * Sjekker om oppgitt IPv6 addresse matcher med en av IPv6 reglene vi har mottatt.
     * Dersom regel matcher lagres regel ID i $this->ruleID
     * 
     * @param string $visitorIpv6 IPv6 address som binary string.
     * @param array $rules Listen over IPv6 regler vi skal sammenlikne mot.
     * @param array $prefixes Listen over IPv6 nettverk prefixes brukt i regellisten.
     * @return bool TRUE dersom IPv6 addressen matcher med en regel, FALSE hvis ikke.
     */
    private function ipV6rulesCheck(string $visitorIpv6, array $rules, array $prefixes): bool {

        /**
         * Tar imot en IPv6 addresse, binary string, og returnerer kun nettverket.
         * $prefix er IPv6 nettverk prefix 0-128.
         */
        $ipv6PrefixMask = function (string $packedIpv6, int $prefix): string {
            if ($prefix <= 0) {
                return str_repeat("\x00", 16);
            }
            if ($prefix >= 128) {
                return $packedIpv6;
            }

            $fullBytes = intdiv($prefix, 8);   // number of full bytes to keep
            $remainBits = $prefix % 8;          // bits to keep in next byte (0..7)

            $out = $packedIpv6;

            // If we have a partial byte, mask it; otherwise we start zeroing at $fullBytes
            $zeroFrom = $fullBytes;

            if ($remainBits !== 0) {
                // Mask the next byte (at index $fullBytes) to keep only top $remainBits
                $mask = (0xFF << (8 - $remainBits)) & 0xFF;
                $out[$fullBytes] = chr(ord($out[$fullBytes]) & $mask);
                $zeroFrom = $fullBytes + 1;
            }

            // Zero all bytes after the last kept (full + partial) byte
            for ($i = $zeroFrom; $i < 16; $i++) {
                $out[$i] = "\x00";
            }

            return $out;
        };

        $now = time();

        foreach ($prefixes as $p) {
            $p = (int) $p;

            if ($p <= 0 || $p > 128) {
                continue;
            }

            if (empty($rules[$p])) {
                continue;
            }

            $netHex = bin2hex($ipv6PrefixMask($visitorIpv6, $p));

            if (!isset($rules[$p][$netHex])) {
                continue;
            }

            //Fant en regel som matcher. Sjekk at den ikke er utgått på tid.
            $entry = $rules[$p][$netHex];

            if ($entry[1] === null || $entry[1] === '') {
                //Permanent regel.
                $this->ruleID = $entry[0];
                return true;
            }

            //Midlertidig regel. Sjekk at den ikke er utgått på dato.
            $expTs = strtotime($entry[1] . ' UTC');
            if ($expTs === false) {
                //Feil i formatet? Burde ikke skje men tolker det som utgått på dato.
                continue;
            }

            if ($expTs > $now) {
                $this->ruleID = $entry[0];
                return true;
            }
        }

        //Ingen match.
        return false;
    }

    /**
     * Sjekker om oppgitt IPv6 addresse skal blokkeres eller ikke.
     * Det er antatt at firewall er i ALLOW ALL MODE.
     * 
     * @param string $ip IPv6 som skal sjekkes, binary string.
     * @return bool TRUE dersom oppgitt IP skal blokkeres, FALSE hvis ikke.
     */
    private function ipV6checkBlock(string $ip): bool {
        //Sjekk om IP er blokkert.
        if ($this->ipV6rulesCheck($ip, $this->ipv6BlockListe, $this->ipv6BlockPrefix) ||
                $this->ipV6rulesCheck($ip, $this->ipv6CountryBlockListe, $this->ipv6CountryBlockPrefix) ||
                $this->ipV6rulesCheck($ip, $this->ipv6AutoBlock, $this->ipv6AutoBlockPrefix)) {
            //IP er blokkert. Sjekk om vi skal gjøre unntak.
            if ($this->ipV6rulesCheck($ip, $this->ipv6AllowListe, $this->ipv6AllowPrefix) ||
                    $this->ipV6rulesCheck($ip, $this->ipv6CountryAllowListe, $this->ipv6CountryAllowPrefix)) {
                //I allow listen. IP skal ikke blokkeres.
                return false;
            } else {
                //Ikke i allow listen. IP skal blokkeres.
                return true;
            }
        }

        return false;
    }

    /**
     * Sjekker om oppgitt IPv6 addresse skal tillates eller ikke.
     * Dette er antatt at firewall er i DENY ALL MODE.
     * 
     * @param string $ip IPv6 som skal sjekkes, binary string.
     * @return bool TRUE dersom oppgitt IP skal tillates, FALSE hvis ikke.
     */
    private function ipV6checkAllow(string $ip): bool {
        //Sjekk om IP skal tillates.
        if ($this->ipV6rulesCheck($ip, $this->ipv6AllowListe, $this->ipv6AllowPrefix) ||
                $this->ipV6rulesCheck($ip, $this->ipv6CountryAllowListe, $this->ipv6CountryAllowPrefix)) {
            //IP skal tillates. Sjekk om vi skal gjøre unntak.
            if ($this->ipV6rulesCheck($ip, $this->ipv6BlockListe, $this->ipv6BlockPrefix) ||
                    $this->ipV6rulesCheck($ip, $this->ipv6CountryBlockListe, $this->ipv6CountryBlockPrefix) ||
                    $this->ipV6rulesCheck($ip, $this->ipv6AutoBlock, $this->ipv6AutoBlockPrefix)) {
                //I block listen. IP skal ikke tillates.
                return false;
            } else {
                return true;
            }
        }

        return false;
    }

    /**
     * Kalles når en tilkobling skal blokkeres, håndterer alt som må gjøres.
     *      
     */
    private function connectionBlocked() {
        
        //Pause i 200ms. For å redusere problemer med bots som forsøker igjen umiddelbart.
        usleep(200000); 
        
        http_response_code(403);
        header('Content-Type: text/plain');
        echo 'Access denied.';

        //Logfør blokkering.        
        $data['type'] = 'blocked';
        $data['rule_id'] = $this->ruleID;
        $data['time'] = gmdate('Y-m-d H:i:s');
        $data['ip'] = $this->ipString;

        $line = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE) . "\n";

        file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);

        exit;
    }

    public function Start() {

        //Inkluder PHP script med konfigurasjonen.
        if (is_file(__DIR__ . '/wtb_firewall_config.php')) {
            include __DIR__ . '/wtb_firewall_config.php';
            $this->logFile = $logFile;
        } else {
            $this->sendErrorMsg('Firewall configuration file missing. Reinstalling the firewall should fix this issue.');
            return;
        }

        $visitorIP = $this->getIP($proxyServer);
        if ($visitorIP === null) {
            $this->sendErrorMsg('Firewall received an invalid IP.');
            return;
        }

        //Inkluder PHP script med manuelle regler.
        if ($this->isIPv4) {
            if (is_file(__DIR__ . '/wtb_firewall_rules.php')) {
                include __DIR__ . '/wtb_firewall_rules.php';
                $this->ipv4AllowListe = $ipAllowListe;
                $this->ipv4BlockListe = $ipBlockListe;
                $this->ipv4AllowRange = $ipAllowRange;
                $this->ipv4BlockRange = $ipBlockRange;
            } else {
                $this->sendErrorMsg('Firewall rule file missing. Reinstalling the firewall should fix this issue.');
                return;
            }

            //Inkluder PHP script med regler for land.
            if (is_file(__DIR__ . '/wtb_firewall_country_rules.php')) {
                include __DIR__ . '/wtb_firewall_country_rules.php';
                $this->ipv4CountryAllowListe = $countryAllowListe;
                $this->ipv4CountryBlockListe = $countryBlockListe;
            } else {
                $this->sendErrorMsg('Firewall rule file for countries is missing. Reinstalling the firewall should fix this issue.');
                return;
            }

            //Inkluder PHP script med automatisk lagde regler.
            //Dersom filen ikke eksisterer lager vi et tomt array.
            if (is_file(__DIR__ . '/wtb_firewall_auto_rules.php')) {
                include __DIR__ . '/wtb_firewall_auto_rules.php';
                $this->ipv4AutoBlock = $ipAutoBlock;
            } else {
                $this->ipv4AutoBlock = array();
            }
        } else if ($this->isIPv6) {
            if (is_file(__DIR__ . '/wtb_firewall_rules_ipv6.php')) {
                include __DIR__ . '/wtb_firewall_rules_ipv6.php';
                $this->ipv6AllowPrefix = $ipv6AllowPrefix;
                $this->ipv6AllowListe = $ipv6AllowListe;
                $this->ipv6BlockPrefix = $ipv6BlockPrefix;
                $this->ipv6BlockListe = $ipv6BlockListe;
            } else {
                $this->sendErrorMsg('Firewall rule file missing. Reinstalling the firewall should fix this issue.');
                return;
            }

            //Inkluder PHP script med regler for land.
            if (is_file(__DIR__ . '/wtb_firewall_country_rules_ipv6.php')) {
                include __DIR__ . '/wtb_firewall_country_rules_ipv6.php';
                $this->ipv6CountryAllowPrefix = $ipv6CountryAllowPrefix;
                $this->ipv6CountryAllowListe = $ipv6CountryAllowListe;
                $this->ipv6CountryBlockPrefix = $ipv6CountryBlockPrefix;
                $this->ipv6CountryBlockListe = $ipv6CountryBlockListe;
            } else {
                $this->sendErrorMsg('Firewall rule file for countries is missing. Reinstalling the firewall should fix this issue.');
                return;
            }

            //Inkluder PHP script med automatisk lagde regler.
            //Dersom filen ikke eksisterer lager vi et tomt array.
            if (is_file(__DIR__ . '/wtb_firewall_auto_rules_ipv6.php')) {
                include __DIR__ . '/wtb_firewall_auto_rules_ipv6.php';
                $this->ipv6AutoBlock = $ipv6AutoBlockListe;
                $this->ipv6AutoBlockPrefix = $ipv6AutoBlockPrefix;
            } else {
                $this->ipv6AutoBlock = array();
                $this->ipv6AutoBlockPrefix = array();
            }
        }


        if ($blockMode == 1 && $this->isIPv6) {
            //IPv6 ALLOW ALL MODE, Sjekk om $visitorIP skal blokkeres.
            if ($this->ipV6checkBlock($visitorIP)) {
                //Blokkert
                $this->connectionBlocked();
            }
        } else if ($blockMode == 2 && $this->isIPv6) {
            //IPv6 DENY ALL MODE. Sjekk om $visitorIP skal tillates.
            if (!$this->ipV6checkAllow($visitorIP)) {
                //Blokkert
                $this->connectionBlocked();
            }
        } else if ($blockMode == 1 && $this->isIPv4) {
            //ALLOW ALL MODE, Sjekk om $visitorIP skal blokkeres.
            if ($this->ipV4checkBlocked($visitorIP)) {
                //Blokkert.
                $this->connectionBlocked();
            }
        } else if ($blockMode == 2 && $this->isIPv4) {
            //DENY ALL MODE, Sjekk om $visitorIP skal tillates.
            if (!$this->ipV4checkAllowed($visitorIP)) {
                //Blokkert.
                $this->connectionBlocked();
            }
        } else {
            $this->sendErrorMsg('Invalid firewall mode. Check configuration.');
            return;
        }

        $this->sendOKstatus();
    }
}

new \WtbFirewall\WtbFirewall();
