57 lines
2.4 KiB
Swift
57 lines
2.4 KiB
Swift
|
|
import Foundation
|
||
|
|
|
||
|
|
/// A curated CIDR → owner table, used as a fallback when a host has no PTR
|
||
|
|
/// record. Many large operators (Apple's 17.0.0.0/8 famously, Telegram, the
|
||
|
|
/// cloud edges) publish no reverse DNS, so this recovers the obvious ones.
|
||
|
|
/// IPv4 only — the no-PTR giants we care about are reachable on v4.
|
||
|
|
public enum IPRanges {
|
||
|
|
|
||
|
|
private struct Block { let net: UInt32; let mask: UInt32; let key: String; let name: String }
|
||
|
|
|
||
|
|
private static let blocks: [Block] = [
|
||
|
|
("17.0.0.0/8", "apple", "Apple"),
|
||
|
|
("149.154.160.0/20", "telegram", "Telegram"),
|
||
|
|
("91.108.0.0/16", "telegram", "Telegram"),
|
||
|
|
("13.64.0.0/11", "microsoft", "Microsoft"),
|
||
|
|
("157.240.0.0/16", "meta", "Meta"),
|
||
|
|
("31.13.24.0/21", "meta", "Meta"),
|
||
|
|
("129.134.0.0/16", "meta", "Meta"),
|
||
|
|
("1.1.1.0/24", "cloudflare", "Cloudflare"),
|
||
|
|
("104.16.0.0/13", "cloudflare", "Cloudflare"),
|
||
|
|
// Private / link-local space collapses into one neighbourhood.
|
||
|
|
("10.0.0.0/8", "lan", "Local Network"),
|
||
|
|
("172.16.0.0/12", "lan", "Local Network"),
|
||
|
|
("192.168.0.0/16", "lan", "Local Network"),
|
||
|
|
("169.254.0.0/16", "lan", "Local Network"),
|
||
|
|
].compactMap { parse($0.0, key: $0.1, name: $0.2) }
|
||
|
|
|
||
|
|
public static func match(_ ip: String) -> (key: String, name: String)? {
|
||
|
|
guard let value = ipv4ToUInt32(ip) else { return nil }
|
||
|
|
for b in blocks where (value & b.mask) == b.net {
|
||
|
|
return (b.key, b.name)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Parsing
|
||
|
|
|
||
|
|
private static func parse(_ cidr: String, key: String, name: String) -> Block? {
|
||
|
|
let parts = cidr.split(separator: "/")
|
||
|
|
guard parts.count == 2, let bits = UInt32(parts[1]), bits <= 32,
|
||
|
|
let net = ipv4ToUInt32(String(parts[0])) else { return nil }
|
||
|
|
let mask: UInt32 = bits == 0 ? 0 : ~UInt32(0) << (32 - bits)
|
||
|
|
return Block(net: net & mask, mask: mask, key: key, name: name)
|
||
|
|
}
|
||
|
|
|
||
|
|
static func ipv4ToUInt32(_ ip: String) -> UInt32? {
|
||
|
|
let octets = ip.split(separator: ".")
|
||
|
|
guard octets.count == 4 else { return nil }
|
||
|
|
var result: UInt32 = 0
|
||
|
|
for octet in octets {
|
||
|
|
guard let n = UInt32(octet), n <= 255 else { return nil }
|
||
|
|
result = (result << 8) | n
|
||
|
|
}
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
}
|