#!/usr/bin/php
<?php

declare(strict_types=1);

$blockdir = "/var/lib/ipblocklist";
$source = "https://www.spamhaus.org/drop/drop.txt";
$list = "SPAMHAUS_DROPv4";
$dest = $list.".ipset";
$stamp = time();
$stale = 86400;
$timeout = 10000;

if (@file_exists($blockdir."/".$dest)) {
    $stat = stat($blockdir."/".$dest);
    if (is_array($stat)) {
        if ($stat['mtime'] > $stamp-$stale) {
            printf("%s is up to date\n", $dest);
            exit(0);
        }
    }
}

$ch = curl_init();
if ($ch === false) {
    fprintf(STDERR, "Failed to initialize curl\n");
    exit(1);
}
$cv = curl_version();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_USERAGENT, 'curl/'.$cv['version']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $source);
$data = curl_exec($ch);
if ($data === false || !is_string($data) || strlen($data) == 0) {
    fprintf(STDERR, "Failed to download\n%s\n", curl_error($ch));
    curl_close($ch);
    exit(1);
}
curl_close($ch);

$blocklist = array();
$lines = explode("\n", $data);
foreach ($lines as $line) {
    $line = trim($line);
    if (strlen($line) == 0 || str_starts_with($line, "#") || str_starts_with($line, ";")) {
        continue;
    }
    $pos = strpos($line, ";");
    if ($pos === false) {
        $pos = strpos($line, "#");
    }
    if ($pos !== false) {
        $line = trim(substr($line, 0, $pos));
    }
    $pos = strpos($line, "/");
    if ($pos === false) {
        $line = $line."/32";
    }
    if (!in_array($line, $blocklist)) {
        $blocklist[] = $line;
    }
}
$numelem = count($blocklist);
if ($numelem == 0) {
    fprintf(STDERR, "Blocklist contains 0 entries\n");
    exit(1);
}
$maxelem = count($blocklist)*2;
$hashsize = 1;
while ($hashsize < $maxelem) {
    $hashsize *= 2;
}
$data = "# Autogenerated file. Any custom changes will be overwritten!\n\n";
$data .= sprintf("create %s hash:net family inet hashsize %d maxelem %d -exist\n", $list, $hashsize, $maxelem);
$data .= sprintf("flush %s\n", $list);
foreach ($blocklist as $entry) {
    $data .= sprintf("add %s %s\n", $list, $entry);
}
if (@file_put_contents($blockdir."/".$dest, $data) === false) {
    fprintf(STDERR, "Failed to write %s/%s\n", $blockdir, $dest);
    exit(1);
}
printf("Wrote %s/%s\nBlocklist contains %d %s\n", $blockdir, $dest, $numelem, ($numelem == 1 ? "entry": "entries"));
if (!@touch($blockdir."/".$dest, $stamp)) {
    fprintf(STDERR, "Failed to touch blocklist file\n");
    exit(1);
}
$command = "systemctl is-active firewalld.service";
@exec($command, $output, $retval);
if ($retval == 0 && isset($output[0]) && is_string($output[0]) && $output[0] === "active") {
    $command = "systemctl reload firewalld.service";
    @exec($command, $output, $retval);
    printf("Reload command returned %d\n", $retval);
} else {
    printf("Firewall is not active\n");
}
exit(0);
