Can handleNewUDPFlow of NEDNSProxyProvider act like NETransparentProxyProvider?

If handleNewUDPFlow of NEDNSProxyProvider returns false, the flow (DNS request) is terminated. Is there a way to make the system take care of it like in the case of NETransparentProxyProvider that returns false? Right now, our extension has to process all DNS flows while we need only a limited set. If it could act like NETransparentProxyProvider, it would significantly reduce the overhead and even could make DoH/DoT settings work for bypassed requests.

Another question,

Is there a way to know the hostname from the DNS request at the moment when handleNewUDPFlow callbacks gets called?

Thanks!

If handleNewUDPFlow of NEDNSProxyProvider returns false, the flow (DNS request) is terminated. Is there a way to make the system take care of it like in the case of NETransparentProxyProvider that returns false? Right now, our extension has to process all DNS flows while we need only a limited set. If it could act like NETransparentProxyProvider, it would significantly reduce the overhead and even could make DoH/DoT settings work for bypassed requests.

NEDNSProxyProvider and NEAppProxyProvider do not allow for selectively handling flows. For selectively handling flows you will need to use NETransparentProxyProvider.

Regarding:

Is there a way to know the hostname from the DNS request at the moment when handleNewUDPFlow callbacks gets called?

When handleNewUDPFlow is called you will get a localEndpoint in NEAppProxyUDPFlow and remoteEndpoint from the method call. Typically, you will get an IP as a localEndpoint because you will need to open the flow side of the connection first, and then you will get a IP based remoteEndpoint again from the data read from the local flow side of the connection. If you can derive a NWEndpoint as a hostPort property then you may be able to extract the hostname, but typically this is not the case.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

For selectively handling flows you will need to use NETransparentProxyProvider.

Unfortunately, NETransparentProxyProvider cannot process UDP port 53. This is explicitly stated in the documentation. It would be really nice to have an option to handle DNS flows selectively.

.

When handleNewUDPFlow is called you will get a localEndpoint in NEAppProxyUDPFlow and remoteEndpoint from the method call..

Sorry, my question wasn't clear enough. Suppose that we have a new DNS request to DNS server 1.1.1.1. The request is to resolve apple.com. Its flow gets to handleNewUDPFlow with remoteEndpoint=1.1.1.1. Is there a way to understand the hostname being resolved (apple.com) on this stage?

Unfortunately, NETransparentProxyProvider cannot process UDP port 53.

Have you tried using a hostname with port 53? For example:

NENetworkRule(remoteNetwork: NWHostEndpoint(hostname: "example.com", port: "53"),
                          remotePrefix: 0,
                          localNetwork: nil,
                          localPrefix: 0,
                          protocol: .UDP,
                          direction: .outbound)

Regarding:

Is there a way to understand the hostname being resolved (apple.com) on this stage?

No. You may see that when you are performing the flow copying process, but by then it may be too late.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

Sorry for the delayed reply.

Have you tried using a hostname with port 53? For example:

NENetworkRule(remoteNetwork: NWHostEndpoint(hostname: "example.com", port: "53"),

Is there a way to apply this rule for all hostnames?

NETransparentProxyProvider can't process port 53 specifically for some reason (I don't see a technical reason it shouldn't), but it seems to work (i.e. catch UDP 53 traffic) when you don't specify a port:

NENetworkRule(remoteNetwork: nil, remotePrefix: 0, localNetwork: nil, localPrefix: 0, protocol: .UDP, direction: .outbound)

You can then ignore everything you are not interested in filtering:

override func handleNewUDPFlow(_ flow: NEAppProxyUDPFlow, initialRemoteEndpoint: NWEndpoint) -> Bool {
    if let endpoint = initialRemoteEndpoint as? NWHostEndpoint {
        if endpoint.port == "53" {
            // Do the filtering
        } else {
            return false    // Let OS handle it
        }
    }
}   

Beware of this bug though. I'm not sure if it has been resolved yet.

Is there a way to apply this rule for all hostnames?

You can try using a top level domain here also to capture groups of hostnames for com or net on port 53. I just ran a quick test for com and this seems to be grabbing all of my Safari DNS traffic at least:

NENetworkRule(remoteNetwork: NWHostEndpoint(hostname: "com", port: "53"),
              remotePrefix: 0,
              localNetwork: nil,
              localPrefix: 0,
              protocol: .UDP,
              direction: .outbound)

Regarding:

Beware of this bug though. I'm not sure if it has been resolved yet.

It looks like based on this bug report the originator mentioned that (r. 71369277) has been fixed in macOS 11.3.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Can handleNewUDPFlow of NEDNSProxyProvider act like NETransparentProxyProvider?
 
 
Q