CPAProxy
CPAProxy copied to clipboard
Works in an emulator but not on a device
I tried to send a GET request to https://facebookcorewww.onion. In an emulator everything works perfectly, I receive a web page but on a real device I have an error and the data buffer is nil. I'm not sure where to move next.
iOS version 10.2.1 Xcode version 8.2.1
Some extracts from the log file
...
02:59:57 test(libsystem_network.dylib)[362] <Debug>: -[NWConcrete_nw_endpoint_resolver startWithHandler:] [2.1 127.0.0.1:60223 waiting resolver (unsatisfied)]
02:59:57 mDNSResponder[93] <Info>: 16: connect_callback: Adding FD for uid 501
02:59:57 test(libsystem_network.dylib)[362] <Debug>: nw_endpoint_proxy_receive_report [2 facebookcorewwwi.onion:443 in_progress proxy (unsatisfied)] received child report:[2.1 127.0.0.1:60223 in_progress resolver (unsatisfied)]
02:59:57 mDNSResponder[93] <Info>: 16: DNSServiceCreateConnection START PID[362](test)
02:59:57 test(libsystem_network.dylib)[362] <Info>: nw_connection_endpoint_report [2.1 127.0.0.1:60223 in_progress resolver (unsatisfied)] reported event resolver:start_dns
02:59:57 mDNSResponder[93] <Info>: 16: DNSServiceCreateConnection STOP PID[362](test)
02:59:57 mDNSResponder[93] <Info>: 16: Removing FD
02:59:57 test(libsystem_dnssd.dylib)[362] <Notice>: dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef
02:59:57 test(libsystem_network.dylib)[362] <Error>: nw_resolver_create_dns_service_on_queue DNSServiceSetDispatchQueue failed: BadParam(-65540)
...
02:59:57 test(libsystem_network.dylib)[362] <Debug>: __tcp_connection_start_block_invoke 2 sending event TCP_CONNECTION_EVENT_DISCONNECTED in response to state failed and error Error Domain=kNWErrorDomainPOSIX Code=50 "Network is down" UserInfo={NSDescription=Network is down}
...
03:01:44 test[362] <Notice>: error = Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={NSErrorFailingURLStringKey=https://facebookcorewwwi.onion/, _kCFStreamErrorCodeKey=50, NSErrorFailingURLKey=https://facebookcorewwwi.onion/, NSLocalizedDescription=The Internet connection appears to be offline., _kCFStreamErrorDomainKey=1, NSUnderlyingError=0x168bd560 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50}}}
The source code. Basically it's just a copy of the example
#include <CPAProxy/CPAProxy.h>
@interface ViewController ()
@property (nonatomic, strong, readwrite) CPAProxyManager *cpaProxyManager;
@end
@implementation ViewController
- (void)handleCPAProxySetupWithSOCKSHost:(NSString *)SOCKSHost SOCKSPort:(NSUInteger)SOCKSPort
{
// Create a NSURLSessionConfiguration that uses the newly setup SOCKS proxy
NSDictionary *proxyDict = @{
(NSString *)kCFStreamPropertySOCKSProxyHost : SOCKSHost,
(NSString *)kCFStreamPropertySOCKSProxyPort : @(SOCKSPort)
};
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
configuration.connectionProxyDictionary = proxyDict;
NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *URL = [NSURL URLWithString:@"https://facebookcorewwwi.onion/"];
NSURLSessionDataTask *dataTask = [urlSession dataTaskWithURL:URL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
NSString* data_str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", data_str);
} else {
NSLog(@"error = %@", error);
}
}];
[dataTask resume];
}
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *cpaProxyBundleURL = [[NSBundle bundleForClass:[CPAProxyManager class]] URLForResource:@"CPAProxy" withExtension:@"bundle"];
NSBundle *cpaProxyBundle = [NSBundle bundleWithURL:cpaProxyBundleURL];
NSString *torrcPath = [cpaProxyBundle pathForResource:@"torrc" ofType:nil];
NSString *geoipPath = [cpaProxyBundle pathForResource:@"geoip" ofType:nil];
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *torDataDir = [documentsDirectory stringByAppendingPathComponent:@"tor"];
CPAConfiguration *configuration = [CPAConfiguration configurationWithTorrcPath:torrcPath geoipPath:geoipPath torDataDirectoryPath:torDataDir];
_cpaProxyManager = [CPAProxyManager proxyWithConfiguration:configuration];
[_cpaProxyManager setupWithCompletion:^(NSString *socksHost, NSUInteger socksPort, NSError *error) {
if (error == nil) {
NSLog(@"Connected: host=%@, port=%lu", socksHost, (long)socksPort);
[self handleCPAProxySetupWithSOCKSHost:socksHost SOCKSPort:socksPort];
}
} progress:^(NSInteger progress, NSString *summaryString) {
NSLog(@"%li %@", (long)progress, summaryString);
}];
}
@end
It does seem to work partly on device, you can still connect to non-onion hosts (like https://check.torproject.org) that way on device. For onion hosts NSURLProtocol seems to complain that it's an unsupported URL, subclassing NSURLProtocol might work but I can't be certain (I couldn't get it to work).
I can still connect to onion addresses (not http servers) on my device, so there is probably an arduous workaround for you. OnionBrowser may offer clues on how to get there.
I am having the exact same issue in iCepa Tor.framework... Very very frustrating. What is the point of using Tor if you can not connect to hidden services? I would be very keen to know if you solved this? I am sure Onion Browser has a work around but I only know Swift. I am making an open source Bitcoin app that allows you to connect to and control your own full node. I am able to connect to the nodes V3 hidden service in simulator but not on device and it is driving me crazy to be so close to such a great break through for iOS. If anyone can nudge me in the right direction I would really appreciate it.