Async operations with Network Extension

Hi, I was working on some new filtering logic for my Content Filter that I would like to add. It involves making requests to remote DNS resolvers. Is it possible to use it within sync override func handleNewFlow(_ flow: NEFilterFlow) -> NEFilterNewFlowVerdict of the NEFilterDataProvider?

As of right now, I have a concept working in Command Line Tool and playground, however, when I try to add working module to the main project, it's not working (connections are not loading).

Function that makes requests to the servers: In this function I use DispatchGroup and notify for non-main queue

@available(iOS 12, *)
public class NetworkService {

private let nonMainQueue: DispatchQueue = DispatchQueue(label: "non-main-queue")

func isBlocked(hostname: String, completion: @escaping (Bool) -> Void) {
        var isAnyBlocked = false
        let group = DispatchGroup()

        for server in servers {
            group.enter()
            let endpoint = NWEndpoint.Host(server)
            query(host: endpoint, domain: hostname, queue: .global()) { response, error in
                defer {
                    group.leave()
                }

                /* 
                 * some code that determines the filtering logic 
                 * if condition is true =>  isAnyBlocked = true & return
                 */
            }
        }

        group.notify(queue: nonMainQueue) {
            completion(isAnyBlocked)
        }
    }
}

And, for example, in playground Semaphores make it work as expected, but the same approach doesn't work with the NEFilterDataProvider

playground code sample

let hostname = "google.com"

func returnResponse() -> String {
    var result = ""

    let semaphore = DispatchSemaphore(value: 0)
    DispatchQueue.global().async {
        NetworkService.isBlocked(hostname: hostname) { isBlocked in
            result = isBlocked ? "blocked" : "allowed"
            semaphore.signal()
        }
    }
    semaphore.wait()
    return result
}

print(returnResponse())

Output: allowed

Replies

Is it possible to use it within sync … handleNewFlow(…) of the NEFilterDataProvider?

No.

Well, not in any reasonable way. The system is expecting you to return from handleNewFlow(…) promptly. While you might be able to do asynchronous work here — for example, by playing games with semaphores — that’s a really bad idea.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"