mirror of
https://git.hexahost.dev/smueller/HexaHost-Frontend.git
synced 2026-06-02 10:08:44 +00:00
216 lines
5.8 KiB
PHP
216 lines
5.8 KiB
PHP
<?php
|
|
/**
|
|
* HexaDNS - Reverse DNS Lookup API
|
|
*
|
|
* Löst eine IP-Adresse zu einem Hostnamen auf
|
|
*
|
|
* Verwendung: GET /api/reverse-dns.php?ip=8.8.8.8
|
|
*/
|
|
|
|
require_once __DIR__ . '/../includes/api-helpers.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: GET, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
http_response_code(200);
|
|
exit;
|
|
}
|
|
|
|
if (!checkApiRateLimit('reverse-dns')) {
|
|
rejectApiRateLimit();
|
|
}
|
|
|
|
$ip = isset($_GET['ip']) ? trim($_GET['ip']) : '';
|
|
|
|
if (empty($ip)) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'IP-Parameter fehlt']);
|
|
exit;
|
|
}
|
|
|
|
// IPv4 oder IPv6 validieren
|
|
$isIPv4 = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
|
$isIPv6 = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
|
|
|
|
if (!$isIPv4 && !$isIPv6) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Ungültiges IP-Format']);
|
|
exit;
|
|
}
|
|
|
|
$startTime = microtime(true);
|
|
$result = performReverseLookup($ip, $isIPv6 ? 'IPv6' : 'IPv4');
|
|
$queryTime = round((microtime(true) - $startTime) * 1000, 2);
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'ip' => $ip,
|
|
'ip_version' => $isIPv6 ? 'IPv6' : 'IPv4',
|
|
'query_time_ms' => $queryTime,
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
|
'result' => $result
|
|
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
|
|
|
/**
|
|
* Führt Reverse DNS Lookup durch
|
|
*/
|
|
function performReverseLookup(string $ip, string $version): array {
|
|
$result = [
|
|
'hostname' => null,
|
|
'ptr_record' => null,
|
|
'additional_info' => []
|
|
];
|
|
|
|
// PHP gethostbyaddr
|
|
$hostname = @gethostbyaddr($ip);
|
|
|
|
if ($hostname && $hostname !== $ip) {
|
|
$result['hostname'] = $hostname;
|
|
|
|
// Verifizieren durch Forward-Lookup
|
|
$forwardIp = gethostbyname($hostname);
|
|
$result['forward_verified'] = ($forwardIp === $ip);
|
|
|
|
// Zusätzliche Infos über den Host sammeln
|
|
$result['additional_info'] = getHostInfo($hostname);
|
|
} else {
|
|
$result['error'] = 'Kein PTR-Record gefunden';
|
|
}
|
|
|
|
// PTR-Record direkt abfragen
|
|
$ptrRecord = getPtrRecord($ip, $version);
|
|
if ($ptrRecord) {
|
|
$result['ptr_record'] = $ptrRecord;
|
|
}
|
|
|
|
// IP-Info (GeoIP wenn verfügbar, sonst Basic-Infos)
|
|
$result['ip_info'] = getIpInfo($ip);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* PTR-Record direkt abfragen
|
|
*/
|
|
function getPtrRecord(string $ip, string $version): ?string {
|
|
if ($version === 'IPv4') {
|
|
// IPv4: Reverse die Oktette
|
|
$parts = array_reverse(explode('.', $ip));
|
|
$ptrDomain = implode('.', $parts) . '.in-addr.arpa';
|
|
} else {
|
|
// IPv6: Komplexer - jedes Nibble umkehren
|
|
$expanded = expandIPv6($ip);
|
|
$nibbles = str_replace(':', '', $expanded);
|
|
$reversed = implode('.', array_reverse(str_split($nibbles)));
|
|
$ptrDomain = $reversed . '.ip6.arpa';
|
|
}
|
|
|
|
$records = @dns_get_record($ptrDomain, DNS_PTR);
|
|
|
|
if ($records && !empty($records[0]['target'])) {
|
|
return $records[0]['target'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Expandiert eine IPv6-Adresse
|
|
*/
|
|
function expandIPv6(string $ip): string {
|
|
// Ersetze :: mit der richtigen Anzahl von 0000
|
|
if (strpos($ip, '::') !== false) {
|
|
$parts = explode('::', $ip);
|
|
$left = $parts[0] ? explode(':', $parts[0]) : [];
|
|
$right = isset($parts[1]) && $parts[1] ? explode(':', $parts[1]) : [];
|
|
$missing = 8 - count($left) - count($right);
|
|
$middle = array_fill(0, $missing, '0000');
|
|
$all = array_merge($left, $middle, $right);
|
|
} else {
|
|
$all = explode(':', $ip);
|
|
}
|
|
|
|
// Jedes Segment auf 4 Zeichen auffüllen
|
|
$all = array_map(function($segment) {
|
|
return str_pad($segment, 4, '0', STR_PAD_LEFT);
|
|
}, $all);
|
|
|
|
return implode(':', $all);
|
|
}
|
|
|
|
/**
|
|
* Sammelt Infos über einen Hostnamen
|
|
*/
|
|
function getHostInfo(string $hostname): array {
|
|
$info = [];
|
|
|
|
// Domain-Teile analysieren
|
|
$parts = explode('.', $hostname);
|
|
$tld = end($parts);
|
|
|
|
$info['tld'] = $tld;
|
|
|
|
// Bekannte Hosting-Provider erkennen
|
|
$providerPatterns = [
|
|
'amazonaws.com' => 'Amazon AWS',
|
|
'googleusercontent.com' => 'Google Cloud',
|
|
'cloudfront.net' => 'Amazon CloudFront',
|
|
'azure' => 'Microsoft Azure',
|
|
'hetzner' => 'Hetzner',
|
|
'ovh' => 'OVH',
|
|
'digitalocean' => 'DigitalOcean',
|
|
'linode' => 'Linode',
|
|
'vultr' => 'Vultr',
|
|
'contabo' => 'Contabo',
|
|
'netcup' => 'Netcup',
|
|
'strato' => 'Strato',
|
|
'ionos' => 'IONOS',
|
|
'1und1' => '1&1',
|
|
'telekom' => 'Deutsche Telekom',
|
|
'vodafone' => 'Vodafone',
|
|
];
|
|
|
|
foreach ($providerPatterns as $pattern => $provider) {
|
|
if (stripos($hostname, $pattern) !== false) {
|
|
$info['provider'] = $provider;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $info;
|
|
}
|
|
|
|
/**
|
|
* Basis-Infos zur IP
|
|
*/
|
|
function getIpInfo(string $ip): array {
|
|
$info = [
|
|
'type' => 'unknown'
|
|
];
|
|
|
|
// Private IP-Bereiche prüfen
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
|
if (preg_match('/^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)/', $ip)) {
|
|
$info['type'] = 'private';
|
|
} elseif (preg_match('/^(127\.)/', $ip)) {
|
|
$info['type'] = 'loopback';
|
|
} else {
|
|
$info['type'] = 'public';
|
|
}
|
|
} else {
|
|
// IPv6
|
|
if (preg_match('/^(fc|fd)/i', $ip)) {
|
|
$info['type'] = 'private';
|
|
} elseif (preg_match('/^::1$/', $ip) || preg_match('/^fe80:/i', $ip)) {
|
|
$info['type'] = 'loopback/link-local';
|
|
} else {
|
|
$info['type'] = 'public';
|
|
}
|
|
}
|
|
|
|
return $info;
|
|
}
|