| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/clients/client2/web21/web/api/lib/ |
Upload File : |
<?php
/**
* DNSBL-/RBL-Prüfung (Spam-Blacklists) per DNS. Serverseitig, mit Cache & Timeouts.
*
* @package SafeMyIdent\Api
*/
declare(strict_types=1);
require_once __DIR__ . '/net.php';
/**
* Standard-Liste öffentlicher DNSBLs (Zone, Anzeigename, Delisting-Info).
*
* @return array<int,array{zone:string,name:string,site:string}>
*/
function smi_dnsbl_default_list(): array
{
return [
['zone' => 'zen.spamhaus.org', 'name' => 'Spamhaus ZEN', 'site' => 'https://check.spamhaus.org/'],
['zone' => 'b.barracudacentral.org', 'name' => 'Barracuda', 'site' => 'https://www.barracudacentral.org/rbl/removal-request'],
['zone' => 'bl.spamcop.net', 'name' => 'SpamCop', 'site' => 'https://www.spamcop.net/bl.shtml'],
['zone' => 'dnsbl.sorbs.net', 'name' => 'SORBS', 'site' => 'https://www.sorbs.net/'],
['zone' => 'spam.dnsbl.sorbs.net', 'name' => 'SORBS Spam', 'site' => 'https://www.sorbs.net/'],
['zone' => 'dnsbl-1.uceprotect.net', 'name' => 'UCEPROTECT L1', 'site' => 'https://www.uceprotect.net/en/rblcheck.php'],
['zone' => 'psbl.surriel.com', 'name' => 'PSBL', 'site' => 'https://psbl.org/remove'],
['zone' => 'dnsbl.dronebl.org', 'name' => 'DroneBL', 'site' => 'https://dronebl.org/lookup'],
['zone' => 'cbl.abuseat.org', 'name' => 'CBL (abuseat)', 'site' => 'https://www.abuseat.org/lookup.cgi'],
['zone' => 'bl.mailspike.net', 'name' => 'Mailspike', 'site' => 'https://www.mailspike.org/'],
['zone' => 'db.wpbl.info', 'name' => 'WPBL', 'site' => 'https://wpbl.info/'],
['zone' => 'ubl.unsubscore.com', 'name' => 'Lashback UBL', 'site' => 'https://blacklist.lashback.com/'],
['zone' => 'dnsbl.spfbl.net', 'name' => 'SPFBL', 'site' => 'https://spfbl.net/en/dnsbl/'],
['zone' => 'noptr.spamrats.com', 'name' => 'SpamRats NoPtr', 'site' => 'https://spamrats.com/lookup.php'],
];
}
/**
* Effektive DNSBL-Liste (Default + evtl. Plugin-Ergänzungen).
*
* @return array<int,array{zone:string,name:string,site:string}>
*/
function smi_dnsbl_list(): array
{
$cfg = smi_config();
$custom = $cfg['dnsbl_custom'] ?? [];
$list = smi_dnsbl_default_list();
if (is_array($custom)) {
foreach ($custom as $c) {
if (!empty($c['zone'])) {
$list[] = ['zone' => (string) $c['zone'], 'name' => (string) ($c['name'] ?? $c['zone']), 'site' => (string) ($c['site'] ?? '')];
}
}
}
return $list;
}
/**
* Reverse-Notation einer IPv4 (a.b.c.d → d.c.b.a).
*
* @param string $ip IPv4.
* @return string
*/
function smi_ip_reverse_v4(string $ip): string
{
return implode('.', array_reverse(explode('.', $ip)));
}
/**
* IP gegen alle DNSBLs prüfen. Nur IPv4 (fast alle Listen sind v4).
*
* @param string $ip IPv4 (öffentlich).
* @return array<string,mixed>
*/
function smi_dnsbl_check(string $ip): array
{
if (smi_ip_version($ip) !== 4 || !smi_ip_is_public($ip)) {
return ['supported' => false, 'ip' => $ip, 'results' => [], 'listed' => 0, 'checked' => 0, 'failed' => 0];
}
$cacheKey = 'dnsbl|' . $ip;
$hit = smi_cache_get($cacheKey);
if ($hit !== null) {
$hit['cached'] = true;
return $hit;
}
$rev = smi_ip_reverse_v4($ip);
$list = smi_dnsbl_list();
$results = [];
$listed = 0; $failed = 0;
// Wenn DNS über das Gateway läuft: alle A-Abfragen in EINEM Batch-Round-Trip.
$cfg = smi_config();
$useGateway = !empty($cfg['route_dns_via_gateway']) && function_exists('smi_gateway_dns_batch') && function_exists('smi_intel_enabled') && smi_intel_enabled();
$aResults = null;
if ($useGateway) {
$queries = [];
foreach ($list as $bl) {
$queries[] = ['name' => $rev . '.' . $bl['zone'], 'type' => 'A'];
}
$batch = smi_gateway_dns_batch($queries);
if (is_array($batch)) {
$aResults = [];
foreach ($batch as $recs) {
$aResults[] = smi_dns_map_gateway(is_array($recs) ? $recs : [], 'A');
}
}
}
foreach ($list as $i => $bl) {
$host = $rev . '.' . $bl['zone'];
$status = 'clean';
$reason = '';
// A-Record → gelistet. Kein Record → sauber. false = Fehler (nur Direktmodus).
$a = $aResults !== null ? ($aResults[$i] ?? []) : @dns_get_record($host, DNS_A);
if ($a === false) {
$status = 'error';
$failed++;
} elseif (is_array($a) && count($a) > 0) {
$codes = [];
foreach ($a as $r) {
if (!empty($r['ip'])) {
$codes[] = $r['ip'];
}
}
// 127.255.255.x = Rückgabe-/Fehlercode der Liste (252=Tippfehler, 254=öffentlicher
// Resolver, 255=zu viele Anfragen). KEINE echte Listung → als Fehler werten.
$isReturnCode = count($codes) > 0;
foreach ($codes as $code) {
if (strncmp($code, '127.255.255.', 12) !== 0) {
$isReturnCode = false;
break;
}
}
if ($isReturnCode) {
$status = 'error';
$failed++;
$reason = 'Prüfung über den genutzten Resolver nicht möglich (Liste blockt öffentliche/DoH-Resolver).';
} else {
$status = 'listed';
$listed++;
$reason = implode(', ', $codes);
// TXT-Grund (best effort) nur für echte Listungen; „open resolver"-Hinweise ignorieren.
$txt = $useGateway ? smi_dns_map_gateway((array) (smi_gateway_dns($host, 'TXT') ?? []), 'TXT') : @dns_get_record($host, DNS_TXT);
if (is_array($txt) && isset($txt[0]['txt'])) {
$r0 = trim((string) $txt[0]['txt']);
if (stripos($r0, 'open resolver') === false && stripos($r0, 'error:') !== 0) {
$reason = $r0;
}
}
}
}
$results[] = [
'zone' => $bl['zone'],
'name' => $bl['name'],
'site' => $bl['site'],
'status' => $status, // listed | clean | error
'reason' => $reason,
];
}
$out = [
'supported' => true,
'ip' => $ip,
'results' => $results,
'checked' => count($list),
'listed' => $listed,
'failed' => $failed,
'cached' => false,
];
smi_cache_set($cacheKey, $out, (int) (smi_config()['cache_ttl'] ?? 900));
return $out;
}