I implemented a Network Extension in the macOS, use NETransparentProxyProvider. After installing and enabling it, I implemented a UDP client to test its. I found that the UDP client failed to send the data successfully (via sendto, and it returned a success), and when using Wireshark to capture the network data packet, I still couldn't see this UDP data packet.
The code for Network Extension is like this:
@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
{
if (flow == nil)
return NO;
char szProcPath[PROC_PIDPATHINFO_MAXSIZE] = {0};
audit_token_t *lpAuditToken = (audit_token_t*)flow.metaData.sourceAppAuditToken.bytes;
if (lpAuditToken != NULL)
{
proc_pidpath_audittoken(lpAuditToken, szProcPath, sizeof(szProcPath));
}
if ([flow isKindOfClass:[NEAppProxyTCPFlow class]])
{
NWHostEndpoint *objRemoteEndpoint = (NWHostEndpoint *)((NEAppProxyTCPFlow *)flow).remoteEndpoint;
LOG("-MyTransparentProxyProvider handleNewFlow:] TCP flow! Process: (%d)%s, %s Remote: %s:%s, %s",
lpAuditToken != NULL ? audit_token_to_pid(*lpAuditToken) : -1,
flow.metaData.sourceAppSigningIdentifier != nil ? [flow.metaData.sourceAppSigningIdentifier UTF8String] : "",
szProcPath,
objRemoteEndpoint != nil ? (objRemoteEndpoint.hostname != nil ? [objRemoteEndpoint.hostname UTF8String] : "") : "",
objRemoteEndpoint != nil ? (objRemoteEndpoint.port != nil ? [objRemoteEndpoint.port UTF8String] : "") : "",
((NEAppProxyTCPFlow *)flow).remoteHostname != nil ? [((NEAppProxyTCPFlow *)flow).remoteHostname UTF8String] : ""
);
}
else if ([flow isKindOfClass:[NEAppProxyUDPFlow class]])
{
NSString *strLocalEndpoint = [NSString stringWithFormat:@"%@", ((NEAppProxyUDPFlow *)flow).localEndpoint];
LOG("-[MyTransparentProxyProvider handleNewFlow:] UDP flow! Process: (%d)%s, %s LocalEndpoint: %s",
lpAuditToken != NULL ? audit_token_to_pid(*lpAuditToken) : -1,
flow.metaData.sourceAppSigningIdentifier != nil ? [flow.metaData.sourceAppSigningIdentifier UTF8String] : "",
szProcPath,
strLocalEndpoint != nil ? [strLocalEndpoint UTF8String] : ""
);
}
else
{
LOG("-[MyTransparentProxyProvider handleNewFlow:] Unknown flow! Process: (%d)%s, %s",
lpAuditToken != NULL ? audit_token_to_pid(*lpAuditToken) : -1,
flow.metaData.sourceAppSigningIdentifier != nil ? [flow.metaData.sourceAppSigningIdentifier UTF8String] : "",
szProcPath
);
}
return NO;
}
@end
The following methods can all enable UDP data packets to be successfully sent to the UDP server:
1.In -[MyTransparentProxyProvider startProxyWithOptions:completionHandler:], add the exclusion rule "The IP and port of the UDP server, the protocol is UDP";
2.In -[MyTransparentProxyProvider startProxyWithOptions:completionHandler:], add the exclusion rule "All IPs and ports, protocol is UDP";
3.In -[MyTransparentProxyProvider handleNewFlow:] or -[MyTransparentProxyProvider handleNewUDPFlow:initialRemoteEndpoint:], process the UDP Flow and return YES.
Did I do anything wrong?