Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

When DHCP is used, the Network Extension will cause the machine to fail to obtain an IP address

When the machine connects to the network cable through the Thunderbolt interface using the docking station, if the Network Extension shown in the following code is running at this time, after unplugging and reinserting the docking station, the machine will not be able to obtain a valid IP address through DHCP until the system is restarted.

@interface MyTransparentProxyProvider : NETransparentProxyProvider
@end

@implementation MyTransparentProxyProvider

- (void)startProxyWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *))completionHandler
{
    NETransparentProxyNetworkSettings *objSettings = [[NETransparentProxyNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"];
    
    // included rules
    NENetworkRule *objIncludedNetworkRule = [[NENetworkRule alloc] initWithRemoteNetwork:nil
                                                                            remotePrefix:0
                                                                            localNetwork:nil
                                                                             localPrefix:0
                                                                                protocol:NENetworkRuleProtocolAny
                                                                               direction:NETrafficDirectionOutbound];
    NSMutableArray<NENetworkRule *> *arrIncludedNetworkRules = [NSMutableArray array];
    [arrIncludedNetworkRules addObject:objIncludedNetworkRule];
    
    objSettings.includedNetworkRules = arrIncludedNetworkRules;
    
    // apply
    [self setTunnelNetworkSettings:objSettings completionHandler:
        ^(NSError * _Nullable error)
        {
            // TODO
        }
    ];
    
    if (completionHandler != nil)
        completionHandler(nil);
}

- (BOOL)handleNewFlow:(NEAppProxyFlow *)flow
{
    return NO;
}

@end

This problem will not occur if the IP of the DNS server or all UDP ports 53 are excluded in the Network Extension.

@interface MyTransparentProxyProvider : NETransparentProxyProvider
@end

@implementation MyTransparentProxyProvider

- (void)startProxyWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *))completionHandler
{
    NETransparentProxyNetworkSettings *objSettings = [[NETransparentProxyNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"];
    
    // included rules
    NENetworkRule *objIncludedNetworkRule = [[NENetworkRule alloc] initWithRemoteNetwork:nil
                                                                            remotePrefix:0
                                                                            localNetwork:nil
                                                                             localPrefix:0
                                                                                protocol:NENetworkRuleProtocolAny
                                                                               direction:NETrafficDirectionOutbound];
    NSMutableArray<NENetworkRule *> *arrIncludedNetworkRules = [NSMutableArray array];
    [arrIncludedNetworkRules addObject:objIncludedNetworkRule];
    
    // excluded rules
    NENetworkRule *objExcludedNetworkRule = [[NENetworkRule alloc] initWithRemoteNetwork:[NWHostEndpoint endpointWithHostname:@"" port:@(53).stringValue]
                                                                            remotePrefix:0
                                                                            localNetwork:nil
                                                                             localPrefix:0
                                                                                protocol:NENetworkRuleProtocolUDP
                                                                               direction:NETrafficDirectionOutbound];
    NSMutableArray<NENetworkRule *> *arrExcludedNetworkRules = [NSMutableArray array];
    [arrExcludedNetworkRules addObject:objExcludedNetworkRule];
    
    objSettings.includedNetworkRules = arrIncludedNetworkRules;
    objSettings.excludedNetworkRules = arrExcludedNetworkRules;
    
    // apply
    [self setTunnelNetworkSettings:objSettings completionHandler:
        ^(NSError * _Nullable error)
        {
            // TODO
        }
    ];
    
    if (completionHandler != nil)
        completionHandler(nil);
}

- (BOOL)handleNewFlow:(NEAppProxyFlow *)flow
{
    return NO;
}

@end

Is MyTransparentProxyProvider in what place do wrong? To handle the connection on port 53, it is necessary to add the implementation of NEDNSProxyProvider? In -[MyTransparentProxyProvider handleNewFlow:] how to reverse DNS? getnameinfo() doesn't work, it returns EAI_NONAME.

Answered by DTS Engineer in 841845022

We’re currently tracking an issue that sounds very similar to the one you’re reporting here, namely that enabling a transparent proxy causes DHCP problems after you disconnect a network interface (r. 150505789). This is not fixed in the latest public release of macOS (15.5) but, as always, I encourage you to re-test on new beta releases as we seed them.

Share and Enjoy

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

We’re currently tracking an issue that sounds very similar to the one you’re reporting here, namely that enabling a transparent proxy causes DHCP problems after you disconnect a network interface (r. 150505789). This is not fixed in the latest public release of macOS (15.5) but, as always, I encourage you to re-test on new beta releases as we seed them.

Share and Enjoy

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

Thanks for your reply. I'll test the beta version later. And I want to further understand how to perform a reverse DNS lookup in handleNewFlow: when getnameinfo() doesn't work.​

I'll test the beta version later.

Well there’s no beta to test right now.

how to perform a reverse DNS lookup in handleNewFlow: when getnameinfo doesn't work.​

Does that fail all the time? Or only after the device has been in this problematic state?

Regardless, if you’re trying to reverse DNS lookup to decide whether to handle a flow or not, that’s likely to be problematic. The handle-new-flow methods are expected to return promptly, and that’s not always the case with DNS calls like getnameinfo.

Share and Enjoy

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

getnameinfo() doesn't always fail. Its failure has nothing to do with being in this problematic state, but it is indeed because of this problem that I consider using getnameinfo() for reverse DNS.

In fact, MyTransparentProxyProvider will obtain some domain names set by the extension user, which indicates that the user wants to block access to these domain names. Initially, MyTransparentProxyProvider, when intercepted UDP Flow, if the target port is 53, would take over the Flow, and deal with the relationship between the Flow data to get the IP addresses to domain names table. However, due to this DHCP issue, I added an exclusion rule, which made me no longer obtain the UDP Flow on port 53. In this case, I consider using getnameinfo() to have a look.

During the process of using getnameinfo(), I will first check whether -[NEAppProxyTCPFlow remoteHostname] is available. If it can be used, there is no need for reverse DNS; otherwise, I will try reverse DNS. For Safari's Flow, the value of -[NEAppProxyTCPFlow remoteHostname] can always be used without the need for active reverse DNS. I guess it might be related to Safari's use of nw_endpoint_create_host(). For Google Chrome's Flow, there is a situation where -[NEAppProxyTCPFlow remoteHostname] are all unavailable. At this point, when reverse DNS is performed, it fails. As described in the https://stackoverflow.com/questions/56118048/getnameinfo-fails-to-perform-a-reverse-dns.

Returning to the issue of DHCP, when the problem occurs, observe the log in Console.app and see that the configd process is handling DHCP. After the message "DHCP en8: INIT waiting at xxx for xxx" appears, there is no more information. Under normal circumstances, there will be processes such as "DHCP en8: INIT", "DHCP en8: SELECT", and "DHCP en8: BOUND". I don't know if this information is helpful for problem checking.

In the log of the Console.app, it was seen that the configd binding to port 68 failed, causing it not to receive the DHCP OFFER.

configd Process interface attach: en8
......
configd DHCP en8: start
configd en8 link INACTIVE
configd RTADV en8: start
configd en8: link inactive timer fired
configd DHCP en8: status = 'media inactive'
configd DHCP en8: INACTIVE
configd RTADV en8: Inactive
configd RTADV en8: Inactive
configd AUTOMATIC-V6 en8: status = 'media inactive'
configd Process interface link status active: en8
configd en8 link ACTIVE
configd DHCP en8: INIT
configd DHCP en8: supplying hostname 'xxx'
configd bootp_session: bind port 68 failed, Address already in use
configd bootp_session_open_socket: S_open_bootp_socket() failed, Address already in use
configd bootp_session_open_socket failed
configd bootp_client_enable_receive(en8): failed
configd DHCP en8: INIT waiting at 0 for 1.627353
configd RTADV en8: link-local address is ready, starting
configd RTADV en8: Solicit
configd RTADV en8: sending Router Solicitation (1 of 3)
configd bootp_session_delayed_close(): socket is already closed
configd DHCP en8: INIT waiting at 1.63551 for 2.155144
configd DHCP en8: INIT waiting at 3.79642 for 4.810702
configd RTADV en8: sending Router Solicitation (2 of 3)
configd DHCP en8: ARP router: No leases to query for
configd DHCP en8: INIT waiting at 8.61294 for 8.428934
configd RTADV en8: sending Router Solicitation (3 of 3)
configd DHCP en8: ARP router: No leases to query for
configd DHCP en8: INIT waiting at 17.0444 for 8.628138
configd LINKLOCAL en8: setting 169.254.93.15 netmask 255.255.0.0 broadcast 169.254.255.255
configd LINKLOCAL en8: publish success { IPv4 }
configd network changed
configd DHCP en8: ARP router: No leases to query for
configd DHCP en8: INIT waiting at 25.6759 for 8.528784

Ok. "This problem will not occur if the IP of the DNS server or all UDP ports 53 are excluded in the Network Extension." is incorrect. In fact, specifying port 53 will cause the Network Extension not to work. Once again, it is verified that port 67 should be excluded.

Reverse DNS isn’t really a viable option for a content filter because most major websites don’t have a useful reverse mapping. Consider:

% host example.com
example.com has address 23.192.228.80
…
% host 23.192.228.80
80.228.192.23.in-addr.arpa domain name pointer a23-192-228-80.deploy.static.akamaitechnologies.com.
For Google Chrome's Flow, there is a situation where -[NEAppProxyTCPFlow remoteHostname] are all unavailable.

Right. That’s usually because the app uses BSD Sockets directly, rather than using one of our connect-by-name APIs. I believe that a BSD Sockets app can tell the system about the DNS name by calling the <networkext/ne_socket.h>, but I’ve found that adoption of that API is pretty sparse.

Share and Enjoy

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

When DHCP is used, the Network Extension will cause the machine to fail to obtain an IP address
 
 
Q