VPN: DNSResolver: A class that does DNS resolution using getaddrinfo
Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
parent
10c4085239
commit
3f4d12c404
|
@ -7,6 +7,7 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
6F5D0C1521832391000F85AD /* DNSResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5D0C1421832391000F85AD /* DNSResolver.swift */; };
|
||||||
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */; };
|
6F628C3D217F09E9003482A3 /* TunnelViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */; };
|
||||||
6F628C3F217F3413003482A3 /* DNSServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3E217F3413003482A3 /* DNSServer.swift */; };
|
6F628C3F217F3413003482A3 /* DNSServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C3E217F3413003482A3 /* DNSServer.swift */; };
|
||||||
6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */; };
|
6F628C41217F47DB003482A3 /* TunnelDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */; };
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
6F5D0C1421832391000F85AD /* DNSResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSResolver.swift; sourceTree = "<group>"; };
|
||||||
6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelViewModel.swift; sourceTree = "<group>"; };
|
6F628C3C217F09E9003482A3 /* TunnelViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelViewModel.swift; sourceTree = "<group>"; };
|
||||||
6F628C3E217F3413003482A3 /* DNSServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSServer.swift; sourceTree = "<group>"; };
|
6F628C3E217F3413003482A3 /* DNSServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DNSServer.swift; sourceTree = "<group>"; };
|
||||||
6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelDetailTableViewController.swift; sourceTree = "<group>"; };
|
6F628C40217F47DB003482A3 /* TunnelDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelDetailTableViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -121,6 +123,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */,
|
6F7774EE21722D97006A79B3 /* TunnelsManager.swift */,
|
||||||
|
6F5D0C1421832391000F85AD /* DNSResolver.swift */,
|
||||||
);
|
);
|
||||||
path = VPN;
|
path = VPN;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -247,6 +250,7 @@
|
||||||
6F6899AC218099F00012E523 /* WgQuickConfigFileParser.swift in Sources */,
|
6F6899AC218099F00012E523 /* WgQuickConfigFileParser.swift in Sources */,
|
||||||
6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */,
|
6F7774E421718281006A79B3 /* TunnelsListTableViewController.swift in Sources */,
|
||||||
6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */,
|
6F7774EF21722D97006A79B3 /* TunnelsManager.swift in Sources */,
|
||||||
|
6F5D0C1521832391000F85AD /* DNSResolver.swift in Sources */,
|
||||||
6F693A562179E556008551C1 /* Endpoint.swift in Sources */,
|
6F693A562179E556008551C1 /* Endpoint.swift in Sources */,
|
||||||
6F6899A62180447E0012E523 /* x25519.c in Sources */,
|
6F6899A62180447E0012E523 /* x25519.c in Sources */,
|
||||||
6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */,
|
6F7774E2217181B1006A79B3 /* AppDelegate.swift in Sources */,
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright © 2018 WireGuard LLC. All rights reserved.
|
||||||
|
|
||||||
|
import Network
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class DNSResolver {
|
||||||
|
let endpoints: [Endpoint]
|
||||||
|
|
||||||
|
init(endpoints: [Endpoint]) {
|
||||||
|
self.endpoints = endpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolve(completionHandler: @escaping ([Endpoint?]) -> Void) {
|
||||||
|
let endpoints = self.endpoints
|
||||||
|
DispatchQueue.global(qos: .userInitiated).async {
|
||||||
|
var resolvedEndpoints = Array<Endpoint?>(repeating: nil, count: endpoints.count)
|
||||||
|
for (i, endpoint) in endpoints.enumerated() {
|
||||||
|
let resolvedEndpoint = DNSResolver.resolveSync(endpoint: endpoint)
|
||||||
|
resolvedEndpoints[i] = resolvedEndpoint
|
||||||
|
}
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
completionHandler(resolvedEndpoints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on DNS resolution code by Jason Donenfeld <jason@zx2c4.com>
|
||||||
|
// in parse_endpoint() in src/tools/config.c in the WireGuard codebase
|
||||||
|
private static func resolveSync(endpoint: Endpoint) -> Endpoint? {
|
||||||
|
var hints = addrinfo(
|
||||||
|
ai_flags: 0,
|
||||||
|
ai_family: AF_UNSPEC,
|
||||||
|
ai_socktype: SOCK_DGRAM, // WireGuard is UDP-only
|
||||||
|
ai_protocol: IPPROTO_UDP, // WireGuard is UDP-only
|
||||||
|
ai_addrlen: 0,
|
||||||
|
ai_canonname: nil,
|
||||||
|
ai_addr: nil,
|
||||||
|
ai_next: nil)
|
||||||
|
var resultPointer = UnsafeMutablePointer<addrinfo>(OpaquePointer(bitPattern: 0))
|
||||||
|
switch (endpoint.host) {
|
||||||
|
case .name(let name, _):
|
||||||
|
// The endpoint is a hostname and needs DNS resolution
|
||||||
|
let returnValue = getaddrinfo(
|
||||||
|
name.cString(using: .utf8), // Hostname
|
||||||
|
"\(endpoint.port)".cString(using: .utf8), // Port
|
||||||
|
&hints,
|
||||||
|
&resultPointer)
|
||||||
|
if (returnValue == 0) {
|
||||||
|
// getaddrinfo succeeded
|
||||||
|
let ipv4Buffer = UnsafeMutablePointer<Int8>.allocate(capacity: Int(INET_ADDRSTRLEN))
|
||||||
|
let ipv6Buffer = UnsafeMutablePointer<Int8>.allocate(capacity: Int(INET6_ADDRSTRLEN))
|
||||||
|
var ipv4AddressString: String? = nil
|
||||||
|
var ipv6AddressString: String? = nil
|
||||||
|
while (resultPointer != nil) {
|
||||||
|
let result = resultPointer!.pointee
|
||||||
|
resultPointer = result.ai_next
|
||||||
|
if (result.ai_family == AF_INET && result.ai_addrlen == INET_ADDRSTRLEN) {
|
||||||
|
if (inet_ntop(result.ai_family, result.ai_addr, ipv4Buffer, result.ai_addrlen) != nil) {
|
||||||
|
ipv4AddressString = String(cString: ipv4Buffer)
|
||||||
|
// If we found an IPv4 address, we can stop
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if (result.ai_family == AF_INET6 && result.ai_addrlen == INET6_ADDRSTRLEN) {
|
||||||
|
if (ipv6AddressString != nil) {
|
||||||
|
// If we already have an IPv6 address, we can skip this one
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (inet_ntop(result.ai_family, result.ai_addr, ipv6Buffer, result.ai_addrlen) != nil) {
|
||||||
|
ipv6AddressString = String(cString: ipv6Buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipv4Buffer.deallocate()
|
||||||
|
ipv6Buffer.deallocate()
|
||||||
|
// We prefer an IPv4 address over an IPv6 address
|
||||||
|
if let ipv4AddressString = ipv4AddressString, let ipv4Address = IPv4Address(ipv4AddressString) {
|
||||||
|
return Endpoint(host: NWEndpoint.Host.ipv4(ipv4Address), port: endpoint.port)
|
||||||
|
} else if let ipv6AddressString = ipv6AddressString, let ipv6Address = IPv6Address(ipv6AddressString) {
|
||||||
|
return Endpoint(host: NWEndpoint.Host.ipv6(ipv6Address), port: endpoint.port)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// getaddrinfo failed
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// The endpoint is already resolved
|
||||||
|
return endpoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue