Merge branch 'main' into develop
This commit is contained in:
209
backend/api/reverse-dns.php
Normal file
209
backend/api/reverse-dns.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?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
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
Reference in New Issue
Block a user