Files
NachoSoto 2a73f2f735 DNSChecker: simplified NetworkError initialization (#2166)
`DNSChecker.errorWithBlockedHostFromError` already checks
`isBlockedAPIError` when constructing this error, so we can simplify
this to avoid calling `DNSChecker.resolvedHost` twice.
2022-12-21 08:25:23 -08:00

87 lines
2.5 KiB
Swift

//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// DNSChecker.swift
//
// Created by Joshua Liebowitz on 12/20/21.
import Foundation
protocol DNSCheckerType {
static func isBlockedAPIError(_ error: Error?) -> Bool
static func errorWithBlockedHostFromError(_ error: Error?) -> NetworkError?
static func isBlockedURL(_ url: URL) -> Bool
static func resolvedHost(fromURL url: URL) -> String?
}
enum DNSChecker: DNSCheckerType {
static let invalidHosts = Set(["0.0.0.0", "127.0.0.1"])
static func isBlockedAPIError(_ error: Error?) -> Bool {
guard let error = error else {
return false
}
let nsError = error as NSError
guard nsError.domain == NSURLErrorDomain,
nsError.code == NSURLErrorCannotConnectToHost else {
return false
}
guard let failedURL = nsError.userInfo[NSURLErrorFailingURLErrorKey] as? URL else {
return false
}
return isBlockedURL(failedURL)
}
static func errorWithBlockedHostFromError(_ error: Error?) -> NetworkError? {
guard self.isBlockedAPIError(error),
let nsError = error as NSError?,
let failedURL = nsError.userInfo[NSURLErrorFailingURLErrorKey] as? URL else {
return nil
}
let host = self.resolvedHost(fromURL: failedURL)
return .dnsError(failedURL: failedURL, resolvedHost: host)
}
static func isBlockedURL(_ url: URL) -> Bool {
guard let resolvedHostName = self.resolvedHost(fromURL: url) else {
return false
}
Logger.debug(Strings.network.failing_url_resolved_to_host(url: url,
resolvedHost: resolvedHostName))
return self.invalidHosts.contains(resolvedHostName)
}
static func resolvedHost(fromURL url: URL) -> String? {
guard let name = url.host,
let host = name.withCString({gethostbyname($0)}),
host.pointee.h_length > 0 else {
return nil
}
var addr = in_addr()
memcpy(&addr.s_addr, host.pointee.h_addr_list[0], Int(host.pointee.h_length))
guard let remoteIPAsC = inet_ntoa(addr) else {
return nil
}
let hostIP = String(cString: remoteIPAsC)
return hostIP
}
}