summaryrefslogtreecommitdiff
path: root/DomainDig/ReverseDNSService.swift
blob: caab0f74517e995bb54bbee42ab7e22798bb825b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import Foundation

struct ReverseDNSService {
    /// Look up the PTR record for an IPv4 address via Cloudflare DoH.
    static func lookup(ip: String) async -> String? {
        let octets = ip.split(separator: ".")
        guard octets.count == 4 else { return nil }

        let reversed = octets.reversed().joined(separator: ".")
        let ptrDomain = "\(reversed).in-addr.arpa"

        // PTR record type = 12
        do {
            let records = try await lookupPTR(domain: ptrDomain)
            return records.first
        } catch {
            return nil
        }
    }

    private static func lookupPTR(domain: String) async throws -> [String] {
        var components = URLComponents(string: "https://cloudflare-dns.com/dns-query")!
        components.queryItems = [
            URLQueryItem(name: "name", value: domain),
            URLQueryItem(name: "type", value: "12") // PTR
        ]

        var request = URLRequest(url: components.url!)
        request.setValue("application/dns-json", forHTTPHeaderField: "Accept")

        let (data, response) = try await URLSession.shared.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw URLError(.badServerResponse)
        }

        let dnsResponse = try JSONDecoder().decode(CloudflareDNSResponse.self, from: data)

        guard let answers = dnsResponse.Answer else {
            return []
        }

        return answers
            .filter { $0.type == 12 }
            .map { $0.data.trimmingCharacters(in: CharacterSet(charactersIn: "\"")) }
    }
}