| 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
/**
* Anbindung an das IP-Intel-Gateway (horse.pacim.de): VPN-geroutete
* IP-Reputation über mehrere Provider + gepflegte Blacklist + Verdict/Score.
*
* Der API-Key wird ausschließlich serverseitig aus der (nicht web-abrufbaren)
* Config gelesen und niemals an das Frontend gegeben.
*
* @package SafeMyIdent\Api
*/
declare(strict_types=1);
require_once __DIR__ . '/net.php';
/**
* Ist das Gateway konfiguriert & aktiv?
*
* @return bool
*/
function smi_intel_enabled(): bool
{
$c = smi_config()['intel'] ?? [];
return !empty($c['enabled']) && !empty($c['api_key']) && !empty($c['base_url']);
}
/**
* IP über das Gateway prüfen. Gibt normalisierte Reputationsdaten zurück
* (ohne interne Egress-/Exit-IP-Angaben) oder null, wenn deaktiviert/fehlerhaft.
*
* @param string $ip Öffentliche IP.
* @return array<string,mixed>|null
*/
function smi_intel_check(string $ip): ?array
{
if (!smi_intel_enabled() || !smi_ip_is_public($ip)) {
return null;
}
$cacheKey = 'intel|' . $ip;
$hit = smi_cache_get($cacheKey);
if ($hit !== null) {
return is_array($hit) ? $hit : null;
}
$cfg = smi_config()['intel'];
$url = rtrim((string) $cfg['base_url'], '/') . '/api/v1/ipintel/check';
$data = smi_intel_request('POST', $url, (string) $cfg['api_key'], ['ip' => $ip]);
$out = null;
if (is_array($data) && isset($data['data'])) {
$d = $data['data'];
$providers = [];
foreach ((array) ($d['providers'] ?? []) as $p) {
// Interne Felder (egress, exitIp) NICHT übernehmen.
$providers[] = [
'provider' => (string) ($p['provider'] ?? ''),
'ok' => (bool) ($p['ok'] ?? false),
'score' => isset($p['score']) ? (int) $p['score'] : null,
'is_tor' => isset($p['isTor']) ? (bool) $p['isTor'] : null,
'is_vpn' => isset($p['isVpn']) ? (bool) $p['isVpn'] : null,
'is_proxy' => isset($p['isProxy']) ? (bool) $p['isProxy'] : null,
'is_hosting' => isset($p['isHosting']) ? (bool) $p['isHosting'] : null,
'country' => (string) ($p['countryCode'] ?? ''),
'error' => $p['error'] ?? null,
];
}
$out = [
'ok' => true,
'verdict' => (string) ($d['verdict'] ?? 'unknown'),
'score' => isset($d['score']) ? (int) $d['score'] : null,
'blacklisted' => (bool) ($d['blacklisted'] ?? false),
'blacklist' => $d['blacklist'] ?? null,
'providers' => $providers,
'checked_at' => (string) ($d['checkedAt'] ?? ''),
];
} elseif (is_array($data) && isset($data['error'])) {
$out = ['ok' => false, 'error' => (string) ($data['error']['code'] ?? 'gateway_error')];
}
if ($out !== null) {
smi_cache_set($cacheKey, $out, (int) (smi_config()['cache_ttl'] ?? 900));
}
return $out;
}
/**
* Beliebigen HTTP-GET über den Gateway-Proxy (VPN-Egress) leiten.
* Nutzt /api/v1/gateway/fetch (Scope gateway.fetch). Gibt den Upstream-Body
* als String zurück (leer bei Fehler/deaktiviert).
*
* @param string $targetUrl Ziel-URL (z. B. ip-api.com).
* @return string
*/
function smi_gateway_fetch(string $targetUrl): string
{
if (!smi_intel_enabled()) {
return '';
}
$cfg = smi_config()['intel'];
$url = rtrim((string) $cfg['base_url'], '/') . '/api/v1/gateway/fetch';
$resp = smi_intel_request('POST', $url, (string) $cfg['api_key'], [
'method' => 'GET',
'url' => $targetUrl,
'rotateEvery' => 0,
]);
if (!is_array($resp) || !isset($resp['data'])) {
return '';
}
$d = $resp['data'];
$body = (string) ($d['body'] ?? '');
if (($d['bodyEncoding'] ?? 'text') === 'base64') {
$dec = base64_decode($body, true);
$body = $dec !== false ? $dec : '';
}
return $body;
}
/**
* DNS-Auflösung über den Gateway-DoH-Endpoint (VPN-geroutet). EINZELabfrage.
*
* @param string $name Name.
* @param string $type A|AAAA|MX|TXT|NS|CNAME|SOA|PTR.
* @return array<int,array<string,mixed>>|null Records (auch leer = NXDOMAIN) oder null bei Fehler.
*/
function smi_gateway_dns(string $name, string $type)
{
if (!smi_intel_enabled()) {
return null;
}
$cfg = smi_config()['intel'];
$url = rtrim((string) $cfg['base_url'], '/') . '/api/v1/gateway/dns';
$resp = smi_intel_request('POST', $url, (string) $cfg['api_key'], ['name' => $name, 'type' => $type, 'rotateEvery' => 0]);
if (!is_array($resp) || !isset($resp['data'])) {
return null;
}
return smi_gateway_dns_records($resp['data']);
}
/**
* DNS-Auflösung über den Gateway – BATCH (mehrere Queries, ein Round-Trip).
*
* @param array<int,array{name:string,type:string}> $queries Abfragen.
* @return array<int,array<int,array<string,mixed>>>|null Pro Query die Records oder null bei Fehler.
*/
function smi_gateway_dns_batch(array $queries)
{
if (!smi_intel_enabled() || !$queries) {
return null;
}
$cfg = smi_config()['intel'];
$url = rtrim((string) $cfg['base_url'], '/') . '/api/v1/gateway/dns/batch';
$resp = smi_intel_request('POST', $url, (string) $cfg['api_key'], ['queries' => array_values($queries), 'rotateEvery' => 0], 25);
if (!is_array($resp) || !isset($resp['data']['results']) || !is_array($resp['data']['results'])) {
return null;
}
$out = [];
foreach ($resp['data']['results'] as $r) {
$out[] = smi_gateway_dns_records($r);
}
return $out;
}
/**
* Records aus einer Gateway-DNS-Antwort defensiv extrahieren (tolerant ggü. Feldnamen).
*
* @param array<string,mixed> $data Query-Ergebnis.
* @return array<int,array<string,mixed>>
*/
function smi_gateway_dns_records(array $data): array
{
$records = $data['records'] ?? $data['answers'] ?? $data['answer'] ?? [];
return is_array($records) ? $records : [];
}
/**
* HTTP-Request an das Gateway (JSON), mit Key-Header, Timeout, TLS-Prüfung.
*
* @param string $method HTTP-Methode.
* @param string $url URL.
* @param string $key API-Key.
* @param array<string,mixed> $body JSON-Body.
* @return array<string,mixed>|null
*/
function smi_intel_request(string $method, string $url, string $key, array $body = [], int $timeout = 20): ?array
{
if (!function_exists('curl_init')) {
return null;
}
$ch = curl_init($url);
$opts = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 6,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
'X-Api-Key: ' . $key,
'Content-Type: application/json',
'Accept: application/json',
'User-Agent: SafeMyIdent-IPCheck/1.0',
],
];
if ($method !== 'GET' && $body) {
$opts[CURLOPT_POSTFIELDS] = json_encode($body);
}
curl_setopt_array($ch, $opts);
$resp = curl_exec($ch);
curl_close($ch);
if (!is_string($resp) || $resp === '') {
return null;
}
$dec = json_decode($resp, true);
return is_array($dec) ? $dec : null;
}