// retoor <retoor@molodetz.nl>
import Foundation
enum GuardUrl {
static let privateRanges: [(UInt32, UInt32)] = [
(0x0A000000, 0x0AFFFFFF), // 10.0.0.0/8
(0x7F000000, 0x7FFFFFFF), // 127.0.0.0/8
(0xA9FE0000, 0xA9FEFFFF), // 169.254.0.0/16
(0xAC100000, 0xAC1FFFFF), // 172.16.0.0/12
(0xC0A80000, 0xC0A8FFFF), // 192.168.0.0/16
(0x64400000, 0x647FFFFF), // 100.64.0.0/10
(0xCB007100, 0xCB0071FF), // 203.0.113.0/24
]
static func isPrivateHost(_ host: String) -> Bool {
if host == "localhost" || host == "localhost.localdomain" {
return true
}
guard let addr = ipv4Address(host) else {
return host.hasSuffix(".local") || host.hasSuffix(".internal")
}
for (start, end) in privateRanges {
if addr >= start && addr <= end {
return true
}
}
return false
}
static func isPrivateURL(_ urlString: String) -> Bool {
guard let url = URL(string: urlString), let host = url.host else {
return true
}
return isPrivateHost(host)
}
private static func ipv4Address(_ string: String) -> UInt32? {
var sin = sockaddr_in()
guard string.withCString({ cstring in
inet_pton(AF_INET, cstring, &sin.sin_addr) == 1
}) else { return nil }
let addr = sin.sin_addr.s_addr.bigEndian
return addr
}
}