Search code examples
iosswiftdns

iOS: Resolve DNS SRV records


Im my iOS application, I want to resolve the DNS service records (SRV) of a domain.

I found some libraries that allows to do this, but the response is empty. One of the library that I tried is DNS. The code looks sometihng like this:

import UIKit
import DNS

class ViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    let url = "_registration._tcp.gateway.zeeotp.com"
    print("Starting discovery")
    
    do {
    let request = Message(
        type: .query,
        authoritativeAnswer: false, 
        questions: [Question(name: url, type: .service)]
    )
    let requestData = try request.serialize()
    
    // Decoding a message
    let responseData = requestData
    let response = try Message.init(deserialize: responseData)
    print(response)
    } catch {
        print("Unexpected error: \(error).")
    }
  }

}

And the output I get is:

DNS Request(id: 0, authoritativeAnswer: false, truncation: false, recursionDesired: false, recursionAvailable: false, questions: [DNS.Question(name: "_registration._tcp.gateway.zeeotp.com.", type: SRV, unique: false, internetClass: A)], answers: [], authorities: [], additional: [])

During my research I came accross SRVResolver but it is in Objective-C and I have no clue how to make it work with Swift.

Is there something that I am missing in the ablove code to make it work correctly?


Solution

  • After trying various things, I finally was able to make this work. As mentioned in comments by @Paulw11, the library DNS did not send the actual DNS request and hence I was not getting the desired result.

    Option 1:

    I finally decided to integrate the Objective-C example provided by Apple into my Swift application. To do so,

    1. I added the SRVResolver.h and SRVResolver.m into my project
    2. Created a bridging header file and added:
    //
    //  Use this file to import your target's public headers that you would like to expose to Swift.
    //
    
    #include "SRVResolver.h"
    
    1. Added libresolv.tbd in Link Binary With Libraries section under target's Build Phases

    Now in my ViewController.swift I was able to use it as follows to get the priority, weight and hostname values:

    let url = "_registration._tcp.gateway.zeeotp.com"
    print("Starting discovery")
        
    let resolver = SRVResolver.init(srvName: url)
    assert(resolver != nil)
    resolver?.delegate = self
    resolver?.start()
    while !(resolver!.isFinished) {
        RunLoop.current.run(mode: .default, before: Date.distantFuture)
    }
        
    if(resolver?.error == nil) {
        for result in resolver?.results ?? [] {
            let dataArray = result as! NSDictionary;
                
            for (key, value) in dataArray { // loop through data items
                print("\(key) -> \(value)")
            }
        }
    } else {
        print("Error: \(String(describing: resolver?.error))")
    }
    

    Option: 2

    I also found an external library NioDNS that allows us to do some DNS operations. Using this library also I was able to retrieve the SRV records. In my ViewController.swift I added the following code:

    import NIO
    import DNSClient
    
    let loop: MultiThreadedEventLoopGroup!
    
    do {
        loop = MultiThreadedEventLoopGroup(numberOfThreads: 1)
    
        let client = try DNSClient.connect(on: loop).wait()
        let records = try client.getSRVRecords(from: url).wait()
        for record in records {
            print(record.resource.weight)
            print(record.resource.priority)
            print(record.resource.domainName.string)
        }
    } catch {
        print("Error: \(error)")
    }