├── .gitignore ├── .gitmodules ├── CBTunService ├── Actions.h ├── CBTunService-Info.plist ├── CBTunService-Launchd.plist ├── PrivilegedAgent.h ├── PrivilegedAgent.m ├── PrivilegedServiceDelegate.h ├── PrivilegedServiceDelegate.m └── main.m ├── LICENSE ├── Podfile ├── Podfile.lock ├── README.md ├── Tether.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── Tether.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── Tether.xccheckout └── Tether ├── Base.lproj └── MainMenu.xib ├── CBAppDelegate.h ├── CBAppDelegate.m ├── CBDeviceConnection.h ├── CBDeviceConnection.m ├── CBDeviceWindowController.h ├── CBDeviceWindowController.m ├── CBDeviceWindowController.xib ├── CBMacAppDelegate.h ├── CBMacAppDelegate.m ├── CBNetworkServiceEditor.h ├── CBNetworkServiceEditor.m ├── CBRootViewController.h ├── CBRootViewController.m ├── Images.xcassets ├── AppIcon.appiconset │ └── Contents.json └── LaunchImage.launchimage │ └── Contents.json ├── Tether-Info.plist ├── Tether-Prefix.pch ├── TetherMac-Info.plist ├── TetherMac-Prefix.pch ├── USBMuxClient.h ├── USBMuxClient.m ├── USBMuxDevice.h ├── USBMuxDevice.m ├── USBMuxDeviceConnection.h ├── USBMuxDeviceConnection.m ├── en.lproj ├── Credits.rtf └── InfoPlist.strings ├── main-mac.m └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | *.mode1v3 4 | *.pbxuser 5 | project.xcworkspace 6 | xcuserdata 7 | .svn 8 | DerivedData 9 | *.orig 10 | 11 | Pods/ 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Submodules/badvpn"] 2 | path = Submodules/badvpn 3 | url = git@github.com:chrisballinger/badvpn.git 4 | [submodule "Submodules/ProxyKit"] 5 | path = Submodules/ProxyKit 6 | url = git@github.com:chrisballinger/ProxyKit.git 7 | -------------------------------------------------------------------------------- /CBTunService/Actions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Actions.h 3 | // SMJobBless 4 | // 5 | // Created by Ludovic Delaveau on 8/5/12. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @protocol TunHandler 12 | 13 | - (void)openTun:(void (^)(NSFileHandle *tun, NSError *error))reply; 14 | - (void)closeTun; 15 | - (void) readData:(void (^)(NSData * data, NSError *error))reply; 16 | - (void) writeData:(NSData*)data; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /CBTunService/CBTunService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.chrisballinger.CBTunService 7 | CFBundleInfoDictionaryVersion 8 | 6.0 9 | CFBundleName 10 | CBTunService 11 | CFBundleVersion 12 | 1.1 13 | SMAuthorizedClients 14 | 15 | identifier com.chrisballinger.TetherMac and certificate leaf[subject.CN] = "3rd Party Mac Developer Application" 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /CBTunService/CBTunService-Launchd.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.chrisballinger.CBTunService 7 | MachServices 8 | 9 | com.chrisballinger.CBTunService 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /CBTunService/PrivilegedAgent.h: -------------------------------------------------------------------------------- 1 | // 2 | // PrivilegedActions.h 3 | // SMJobBless 4 | // 5 | // Created by Ludovic Delaveau on 8/5/12. 6 | // 7 | // 8 | 9 | #import 10 | #import "Actions.h" 11 | 12 | @interface PrivilegedAgent : NSObject 13 | 14 | @property (nonatomic, strong) NSFileHandle *tunHandle; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CBTunService/PrivilegedAgent.m: -------------------------------------------------------------------------------- 1 | // 2 | // PrivilegedActions.m 3 | // SMJobBless 4 | // 5 | // Created by Ludovic Delaveau on 8/5/12. 6 | // 7 | // 8 | 9 | #import 10 | #import 11 | #import "PrivilegedAgent.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include // exit, etc. 26 | 27 | #include 28 | #include 29 | 30 | static inline int 31 | header_modify_read_write_return (int len) 32 | { 33 | if (len > 0) 34 | return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; 35 | else 36 | return len; 37 | } 38 | 39 | int 40 | write_tun (int fd, BOOL ipv6, uint8_t *buf, int len) 41 | { 42 | u_int32_t type; 43 | struct iovec iv[2]; 44 | struct ip *iph; 45 | 46 | iph = (struct ip *) buf; 47 | 48 | if (ipv6 && iph->ip_v == 6) 49 | type = htonl (AF_INET6); 50 | else 51 | type = htonl (AF_INET); 52 | 53 | iv[0].iov_base = &type; 54 | iv[0].iov_len = sizeof (type); 55 | iv[1].iov_base = buf; 56 | iv[1].iov_len = len; 57 | 58 | return header_modify_read_write_return (writev (fd, iv, 2)); 59 | } 60 | 61 | int 62 | read_tun (int fd, uint8_t *buf, int len) 63 | { 64 | u_int32_t type; 65 | struct iovec iv[2]; 66 | 67 | iv[0].iov_base = &type; 68 | iv[0].iov_len = sizeof (type); 69 | iv[1].iov_base = buf; 70 | iv[1].iov_len = len; 71 | 72 | return header_modify_read_write_return (readv (fd, iv, 2)); 73 | } 74 | 75 | 76 | // the below C functions have been adapted from OpenVPN's tun.c 77 | 78 | /* Helper functions that tries to open utun device 79 | return -2 on early initialization failures (utun not supported 80 | at all (old OS X) and -1 on initlization failure of utun 81 | device (utun works but utunX is already used */ 82 | static 83 | int utun_open_helper (struct ctl_info ctlInfo, int utunnum) 84 | { 85 | struct sockaddr_ctl sc; 86 | int fd; 87 | 88 | fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); 89 | 90 | if (fd < 0) 91 | { 92 | NSLog(@"Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", 93 | strerror (errno)); 94 | return -2; 95 | } 96 | 97 | if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) 98 | { 99 | close (fd); 100 | NSLog(@"Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", 101 | strerror (errno)); 102 | return -2; 103 | } 104 | 105 | 106 | sc.sc_id = ctlInfo.ctl_id; 107 | sc.sc_len = sizeof(sc); 108 | sc.sc_family = AF_SYSTEM; 109 | sc.ss_sysaddr = AF_SYS_CONTROL; 110 | 111 | sc.sc_unit = utunnum+1; 112 | 113 | 114 | /* If the connect is successful, a utun%d device will be created, where "%d" 115 | * is (sc.sc_unit - 1) */ 116 | 117 | if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) 118 | { 119 | NSLog(@"Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", 120 | strerror (errno)); 121 | close(fd); 122 | return -1; 123 | } 124 | 125 | fcntl (fd, F_SETFL, O_NONBLOCK); 126 | fcntl (fd, F_SETFD, FD_CLOEXEC); /* don't pass fd to scripts */ 127 | 128 | return fd; 129 | } 130 | 131 | NSData * 132 | read_incoming_tun (int fd) 133 | { 134 | int bufferLength = 1500; 135 | uint8_t *buffer = malloc(sizeof(uint8_t) * bufferLength); 136 | 137 | int readLength = read_tun (fd, buffer, bufferLength); 138 | NSData *incomingData = nil; 139 | 140 | if (readLength >= 0) { 141 | incomingData = [NSData dataWithBytesNoCopy:buffer length:bufferLength freeWhenDone:YES]; 142 | } else { 143 | free(buffer); 144 | } 145 | return incomingData; 146 | } 147 | 148 | void 149 | process_outgoing_tun (int fd, NSData *data) 150 | { 151 | /* 152 | * Write to TUN/TAP device. 153 | */ 154 | int size = write_tun(fd, NO, data.bytes, data.length); 155 | 156 | //if (size > 0) 157 | // c->c2.tun_write_bytes += size; 158 | 159 | /* check written packet size */ 160 | if (size > 0) 161 | { 162 | /* Did we write a different size packet than we intended? */ 163 | if (size != data.length) 164 | NSLog(@"TUN/TAP packet was destructively fragmented on write to tun (tried=%lu,actual=%d)", 165 | (unsigned long)data.length, 166 | size); 167 | } 168 | else 169 | { 170 | /* 171 | * This should never happen, probably indicates some kind 172 | * of MTU mismatch. 173 | */ 174 | NSLog(@"tun packet too large on write (tried=%d,max=%d)", 175 | data.length, 176 | 1500); 177 | } 178 | } 179 | 180 | 181 | @implementation PrivilegedAgent 182 | 183 | - (NSFileHandle*) openUtun { 184 | struct ctl_info ctlInfo; 185 | int fd = -1; 186 | int utunnum =-1; 187 | 188 | memset(&(ctlInfo), 0, sizeof(ctlInfo)); 189 | 190 | if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= 191 | sizeof(ctlInfo.ctl_name)) 192 | { 193 | NSLog(@"Opening utun: UTUN_CONTROL_NAME too long"); 194 | } 195 | 196 | /* try to open first available utun device if no specific utun is requested */ 197 | if (utunnum == -1) 198 | { 199 | for (utunnum=0; utunnum<255; utunnum++) 200 | { 201 | fd = utun_open_helper (ctlInfo, utunnum); 202 | /* Break if the fd is valid, 203 | * or if early initalization failed (-2) */ 204 | if (fd !=-1) 205 | break; 206 | } 207 | } 208 | else 209 | { 210 | fd = utun_open_helper (ctlInfo, utunnum); 211 | } 212 | 213 | /* opening an utun device failed */ 214 | if (fd < 0) { 215 | return nil; 216 | } 217 | 218 | NSFileHandle *fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:YES]; 219 | return fileHandle; 220 | } 221 | 222 | - (NSString*) getHandleInterfaceName:(NSFileHandle*)fileHandle { 223 | int fd = fileHandle.fileDescriptor; 224 | char utunname[20]; 225 | socklen_t utunname_len = sizeof(utunname); 226 | 227 | NSString *interfaceName = nil; 228 | /* Retrieve the assigned interface name. */ 229 | if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len)) { 230 | NSLog(@"Error retrieving utun interface name"); 231 | } else { 232 | interfaceName = [[NSString alloc] initWithBytes:utunname length:utunname_len encoding:NSUTF8StringEncoding]; 233 | } 234 | return interfaceName; 235 | } 236 | 237 | - (void)openTun:(void (^)(NSFileHandle *tun, NSError *error))reply { 238 | [self closeTun]; 239 | self.tunHandle = [self openUtun]; 240 | NSError *error = nil; 241 | if (!self.tunHandle) { 242 | error = [NSError errorWithDomain:@"com.chrisballinger.CBTunService" code:100 userInfo:@{NSLocalizedDescriptionKey: @"Error opening TUN fd"}]; 243 | } 244 | if (reply) { 245 | reply(self.tunHandle, error); 246 | } 247 | } 248 | 249 | - (void) writeData:(NSData*)data { 250 | process_outgoing_tun(self.tunHandle.fileDescriptor, data); 251 | } 252 | 253 | - (void) readData:(void (^)(NSData * data, NSError *error))reply { 254 | NSData *incomingData = read_incoming_tun(self.tunHandle.fileDescriptor); 255 | if (!reply) { 256 | return; 257 | } 258 | if (incomingData) { 259 | reply(incomingData, nil); 260 | } else { 261 | NSError * error = [NSError errorWithDomain:@"com.chrisballinger.CBTunService" code:101 userInfo:@{NSLocalizedDescriptionKey: @"Error reading TUN fd"}]; 262 | reply(nil, error); 263 | } 264 | } 265 | 266 | - (void)closeTun { 267 | self.tunHandle = nil; 268 | } 269 | 270 | @end 271 | -------------------------------------------------------------------------------- /CBTunService/PrivilegedServiceDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // PrivilegedServiceDelegate.h 3 | // SMJobBless 4 | // 5 | // Created by Ludovic Delaveau on 8/5/12. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface PrivilegedServiceDelegate : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CBTunService/PrivilegedServiceDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // PrivilegedServiceDelegate.m 3 | // SMJobBless 4 | // 5 | // Created by Ludovic Delaveau on 8/5/12. 6 | // 7 | // 8 | 9 | #import "PrivilegedServiceDelegate.h" 10 | #import "Actions.h" 11 | #import "PrivilegedAgent.h" 12 | 13 | @implementation PrivilegedServiceDelegate 14 | 15 | - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection { 16 | newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(TunHandler)]; 17 | newConnection.exportedObject = [[PrivilegedAgent alloc] init]; 18 | [newConnection resume]; 19 | 20 | return YES; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CBTunService/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: SMJobBlessHelper.c 4 | Abstract: A helper tool that doesn't do anything event remotely interesting. 5 | See the ssd sample for how to use GCD and launchd to set up an on-demand 6 | server via sockets. 7 | Version: 1.2 8 | 9 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 10 | Inc. ("Apple") in consideration of your agreement to the following 11 | terms, and your use, installation, modification or redistribution of 12 | this Apple software constitutes acceptance of these terms. If you do 13 | not agree with these terms, please do not use, install, modify or 14 | redistribute this Apple software. 15 | 16 | In consideration of your agreement to abide by the following terms, and 17 | subject to these terms, Apple grants you a personal, non-exclusive 18 | license, under Apple's copyrights in this original Apple software (the 19 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 20 | Software, with or without modifications, in source and/or binary forms; 21 | provided that if you redistribute the Apple Software in its entirety and 22 | without modifications, you must retain this notice and the following 23 | text and disclaimers in all such redistributions of the Apple Software. 24 | Neither the name, trademarks, service marks or logos of Apple Inc. may 25 | be used to endorse or promote products derived from the Apple Software 26 | without specific prior written permission from Apple. Except as 27 | expressly stated in this notice, no other rights or licenses, express or 28 | implied, are granted by Apple herein, including but not limited to any 29 | patent rights that may be infringed by your derivative works or by other 30 | works in which the Apple Software may be incorporated. 31 | 32 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 33 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 34 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 35 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 36 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 37 | 38 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 39 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 40 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 41 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 42 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 43 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 44 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 45 | POSSIBILITY OF SUCH DAMAGE. 46 | 47 | Copyright (C) 2011 Apple Inc. All Rights Reserved. 48 | 49 | 50 | */ 51 | 52 | #import 53 | #import 54 | #import 55 | 56 | #import "PrivilegedServiceDelegate.h" 57 | 58 | int main(int argc, const char *argv[]) { 59 | @autoreleasepool { 60 | NSXPCListener *service = [[NSXPCListener alloc] initWithMachServiceName:@"com.chrisballinger.CBTunService"]; 61 | PrivilegedServiceDelegate *serviceDelegate = [[PrivilegedServiceDelegate alloc] init]; 62 | service.delegate = serviceDelegate; 63 | [service resume]; 64 | 65 | dispatch_main(); 66 | 67 | return EXIT_SUCCESS; 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Tether, SOCKS tethering for iPhone over USB 2 | Copyright (C) 2013, Chris Ballinger 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | 17 | If you would like to relicense this code to sell it on the App Store, 18 | please contact me at chris@chatsecure.org. -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | target :TetherMac do 2 | platform :osx, '10.9' 3 | pod 'libplist', '~> 1.11' 4 | pod 'libusbmuxd', '~> 1.0.9' 5 | pod 'ProxyKit', :path => 'Submodules/ProxyKit' 6 | end 7 | 8 | target "com.chrisballinger.CBTunService" do 9 | platform :osx, '10.9' 10 | end 11 | 12 | target :Tether do 13 | platform :ios, '7.0' 14 | pod 'ProxyKit', :path => 'Submodules/ProxyKit' 15 | pod 'AFNetworking', '~> 2.2' 16 | pod 'UIView+AutoLayout', '~> 1.3' 17 | pod 'FormatterKit/UnitOfInformationFormatter', '~> 1.4' 18 | end -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AFNetworking (2.2.3): 3 | - AFNetworking/NSURLConnection 4 | - AFNetworking/NSURLSession 5 | - AFNetworking/Reachability 6 | - AFNetworking/Security 7 | - AFNetworking/Serialization 8 | - AFNetworking/UIKit 9 | - AFNetworking/NSURLConnection (2.2.3): 10 | - AFNetworking/Reachability 11 | - AFNetworking/Security 12 | - AFNetworking/Serialization 13 | - AFNetworking/NSURLSession (2.2.3): 14 | - AFNetworking/NSURLConnection 15 | - AFNetworking/Reachability (2.2.3) 16 | - AFNetworking/Security (2.2.3) 17 | - AFNetworking/Serialization (2.2.3) 18 | - AFNetworking/UIKit (2.2.3): 19 | - AFNetworking/NSURLConnection 20 | - AFNetworking/NSURLSession 21 | - CocoaAsyncSocket (7.3.4) 22 | - CocoaLumberjack (1.8.1): 23 | - CocoaLumberjack/Extensions 24 | - CocoaLumberjack/Core (1.8.1) 25 | - CocoaLumberjack/Extensions (1.8.1): 26 | - CocoaLumberjack/Core 27 | - FormatterKit/UnitOfInformationFormatter (1.4.2) 28 | - libplist (1.11) 29 | - libusbmuxd (1.0.9): 30 | - libplist (~> 1.11) 31 | - ProxyKit (1.0.0): 32 | - CocoaAsyncSocket (~> 7.3) 33 | - CocoaLumberjack (~> 1.8) 34 | - UIView+AutoLayout (1.3.0) 35 | 36 | DEPENDENCIES: 37 | - AFNetworking (~> 2.2) 38 | - FormatterKit/UnitOfInformationFormatter (~> 1.4) 39 | - libplist (~> 1.11) 40 | - libusbmuxd (~> 1.0.9) 41 | - ProxyKit (from `Submodules/ProxyKit`) 42 | - UIView+AutoLayout (~> 1.3) 43 | 44 | EXTERNAL SOURCES: 45 | ProxyKit: 46 | :path: Submodules/ProxyKit 47 | 48 | SPEC CHECKSUMS: 49 | AFNetworking: ae513199cca79e9d7af2708ccabe2ed075550c42 50 | CocoaAsyncSocket: 534d09416f992fd51efb23f534742ce70b3a7999 51 | CocoaLumberjack: 020378ec400d658923bf5887178394f65f052c90 52 | FormatterKit: 2c241963bc3bf3f2b52e82c0a8e29a8f9865bf3d 53 | libplist: 36d0286d0b8adc3f11006f9880a204deac67f017 54 | libusbmuxd: 28b1bfe677f556970487b644ce2d324f09e13121 55 | ProxyKit: 1f503d80895dbcb8a974e654451fbc49d01b56bb 56 | UIView+AutoLayout: 43373a18797954fd8ee3b1423af364f1b80a2af8 57 | 58 | COCOAPODS: 0.32.1 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tether 2 | 3 | Tether your unjailbroken iPhone to your desktop computer via USB for free*! This was inspired by [iProxy](https://github.com/udibr/iProxy), but I always had trouble getting the damn ad-hoc wifi network to work reliably. 4 | 5 | Right now this is mainly proof-of-concept... but it works! It will let you create a SOCKS proxy running on your iPhone and mirror the socket to your local machine over USB via usbmuxd. 6 | 7 | ## Instructions 8 | 9 | ### Getting the Code 10 | 11 | $ git clone git@github.com:chrisballinger/Tether-iOS.git 12 | $ cd Tether-iOS 13 | $ git submodule update --init --recursive 14 | 15 | ### Installing Tether (iOS) 16 | 17 | Open `Tether.xcodeproj` and select the `Tether` target and install it on your iPhone. This will start a SOCKS proxy on port `8123` on the phone, but be warned that you must keep the app in the foreground to accept new sockets. Currently the app is just a blank white screen. You can theoretically use any other SOCKS proxy app instead but I haven't tested this. 18 | 19 | ### Installing TetherMac 20 | 21 | Now build the `TetherMac` target and run it on your local machine. This will create a local listening socket on port `8000` that forwards everything to port `8123` on the phone over USB. 22 | 23 | ### Configuring Firefox 24 | 25 | Open up Firefox and go to Preferences -> Advanced -> Network -> Manual Proxy Configuration. **Important**: make sure to delete the entries and ports for HTTP proxy, SSL proxy and FTP proxy or Firefox will use those instead of the SOCKS proxy settings. Enter `127.0.0.1` for SOCKS Host and `8000` for the port and make sure SOCKS v5 is selected. 26 | 27 | Now go to `about:config` in the address bar and change `network.proxy.socks_remote_dns` to `true`. This will make sure you resolve domain names over the SOCKS proxy instead of on your local machine. 28 | 29 | ### Problems Connecting? Try this. 30 | 31 | 1. Close Tether, TetherMac and Firefox. 32 | 2. Open up the Tether iOS app and keep it in the foreground. 33 | 3. Connect your iPhone to your computer with a USB cable. 34 | 4. Open up TetherMac. 35 | 5. Open up Firefox and double-check your proxy settings. 36 | 37 | ## Caveats / TODO 38 | 39 | * The interface isn't very user friendly, so it would be nice to pretty it up a bit. 40 | * In order to install the iOS app you need a $99/yr iOS Apple Developer account, or a friend with one willing to install it for you. 41 | * It would be nice to also tether your iPhone to your iPad via [MultipeerConnectivity framework](https://developer.apple.com/library/ios/documentation/MultipeerConnectivity/Reference/MultipeerConnectivityFramework/Introduction/Introduction.html) but I heard it's pretty slow in practice. 42 | * You must keep the iOS app in the foreground to accept new connections. Once a connection has been established you can background the app for short times without interrupting your active connections by pretending to be a VoIP app. 43 | * Not all of your internet traffic can go over a SOCKS proxy. Possible solution to investigate is [tun2socks](https://code.google.com/p/badvpn/wiki/tun2socks). I made [some progress porting it to Mac OS X](https://github.com/chrisballinger/badvpn/tree/darwin). 44 | * This shit leaks memory all over the place. 45 | 46 | 47 | ## Dependencies 48 | 49 | * [ProxyKit](https://github.com/chrisballinger/proxykit) - Objective-C SOCKS 5 / RFC 1928 proxy server and socket client libraries built upon GCDAsyncSocket. 50 | * [libusbmuxd](https://github.com/libimobiledevice/libusbmuxd) - A client library to multiplex USB connections from and to iOS devices. 51 | 52 | 53 | ## Author 54 | 55 | [Chris Ballinger](https://github.com/chrisballinger) 56 | 57 | [![bitcoin](https://coinbase.com/assets/buttons/donation_large-6ec72b1a9eec516944e50a22aca7db35.png)](https://coinbase.com/checkouts/1f694173d39984b5c245ae888669ade4) [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YMUV96X4TPRNW) 58 | 59 | ## License 60 | 61 | GPLv3+ -------------------------------------------------------------------------------- /Tether.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 17629344A9444BD29F36FD1A /* libPods-TetherMac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF17F6ED75F54FB5ADE9E7C5 /* libPods-TetherMac.a */; }; 11 | 8E2C05E4790549028265E799 /* libPods-Tether.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78D94A36C5C54DD8B35132D1 /* libPods-Tether.a */; }; 12 | D90E3259182F07DC00A6F642 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D90E3258182F07DC00A6F642 /* Cocoa.framework */; }; 13 | D90E3263182F07DC00A6F642 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D90E3261182F07DC00A6F642 /* InfoPlist.strings */; }; 14 | D90E3269182F07DC00A6F642 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = D90E3267182F07DC00A6F642 /* Credits.rtf */; }; 15 | D90E326C182F07DC00A6F642 /* CBMacAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D90E326B182F07DC00A6F642 /* CBMacAppDelegate.m */; }; 16 | D90E326F182F07DC00A6F642 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D90E326D182F07DC00A6F642 /* MainMenu.xib */; }; 17 | D90E3271182F07DC00A6F642 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D90E3270182F07DC00A6F642 /* Images.xcassets */; }; 18 | D90E3297182F18CC00A6F642 /* CBDeviceWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = D90E3295182F18CC00A6F642 /* CBDeviceWindowController.m */; }; 19 | D90E3298182F18CC00A6F642 /* CBDeviceWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D90E3296182F18CC00A6F642 /* CBDeviceWindowController.xib */; }; 20 | D931A611183012D600593FF9 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D931A610183012D600593FF9 /* Security.framework */; }; 21 | D931A61418304D1200593FF9 /* CBDeviceConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D931A61318304D1200593FF9 /* CBDeviceConnection.m */; }; 22 | D9792EE518FB563F002F2E28 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9792EE418FB563F002F2E28 /* ServiceManagement.framework */; }; 23 | D9792EF718FB593A002F2E28 /* PrivilegedAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = D9792EDE18FB4DCF002F2E28 /* PrivilegedAgent.m */; }; 24 | D9792EF818FB593A002F2E28 /* PrivilegedServiceDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D9792EE018FB4DCF002F2E28 /* PrivilegedServiceDelegate.m */; }; 25 | D9792EF918FB593A002F2E28 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D9792ED618FB4CCE002F2E28 /* main.m */; }; 26 | D9792EFC18FB59CB002F2E28 /* com.chrisballinger.CBTunService in CopyFiles */ = {isa = PBXBuildFile; fileRef = D9792EEE18FB58E2002F2E28 /* com.chrisballinger.CBTunService */; }; 27 | D9B7679B184A8734000566D6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9B7679A184A8734000566D6 /* Foundation.framework */; }; 28 | D9B7679D184A8734000566D6 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9B7679C184A8734000566D6 /* CoreGraphics.framework */; }; 29 | D9B7679F184A8734000566D6 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9B7679E184A8734000566D6 /* UIKit.framework */; }; 30 | D9B767A5184A8734000566D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D9B767A3184A8734000566D6 /* InfoPlist.strings */; }; 31 | D9B767A7184A8734000566D6 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B767A6184A8734000566D6 /* main.m */; }; 32 | D9B767AB184A8734000566D6 /* CBAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B767AA184A8734000566D6 /* CBAppDelegate.m */; }; 33 | D9B767AD184A8734000566D6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D9B767AC184A8734000566D6 /* Images.xcassets */; }; 34 | D9B767C9184A88BA000566D6 /* main-mac.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B767C8184A88BA000566D6 /* main-mac.m */; }; 35 | D9B767CC184A8991000566D6 /* CBRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B767CB184A8991000566D6 /* CBRootViewController.m */; }; 36 | D9B767D2184A8B32000566D6 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9B767D1184A8B32000566D6 /* MobileCoreServices.framework */; }; 37 | D9B767D6184A9432000566D6 /* USBMuxDeviceConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B767D5184A9432000566D6 /* USBMuxDeviceConnection.m */; }; 38 | D9B767D9184A978A000566D6 /* USBMuxDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = D9B767D8184A978A000566D6 /* USBMuxDevice.m */; }; 39 | D9D81107182F83DD003DCCBB /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D90E32CD182F653300A6F642 /* libxml2.dylib */; }; 40 | D9D8110A182F8B80003DCCBB /* USBMuxClient.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D81109182F8B80003DCCBB /* USBMuxClient.m */; }; 41 | D9FA3189190DBA5F003CA4E0 /* tun2socks in CopyFiles */ = {isa = PBXBuildFile; fileRef = D9FA3186190DB9A0003CA4E0 /* tun2socks */; }; 42 | D9FEA98118EA6E6C00EA736D /* CBNetworkServiceEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = D9FEA98018EA6E6C00EA736D /* CBNetworkServiceEditor.m */; }; 43 | /* End PBXBuildFile section */ 44 | 45 | /* Begin PBXContainerItemProxy section */ 46 | D9792EFA18FB59C4002F2E28 /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = D90E324D182F07DC00A6F642 /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = D9792EED18FB58E2002F2E28; 51 | remoteInfo = com.chrisballinger.CBTunService; 52 | }; 53 | D9FA3185190DB9A0003CA4E0 /* PBXContainerItemProxy */ = { 54 | isa = PBXContainerItemProxy; 55 | containerPortal = D9FA3181190DB9A0003CA4E0 /* badvpn.xcodeproj */; 56 | proxyType = 2; 57 | remoteGlobalIDString = D9420A3218FF1AA2003E8F30; 58 | remoteInfo = tun2socks; 59 | }; 60 | D9FA3187190DBA1B003CA4E0 /* PBXContainerItemProxy */ = { 61 | isa = PBXContainerItemProxy; 62 | containerPortal = D9FA3181190DB9A0003CA4E0 /* badvpn.xcodeproj */; 63 | proxyType = 1; 64 | remoteGlobalIDString = D9420A3118FF1AA2003E8F30; 65 | remoteInfo = tun2socks; 66 | }; 67 | /* End PBXContainerItemProxy section */ 68 | 69 | /* Begin PBXCopyFilesBuildPhase section */ 70 | D9792EE818FB5744002F2E28 /* CopyFiles */ = { 71 | isa = PBXCopyFilesBuildPhase; 72 | buildActionMask = 2147483647; 73 | dstPath = Contents/Library/LaunchServices; 74 | dstSubfolderSpec = 1; 75 | files = ( 76 | D9FA3189190DBA5F003CA4E0 /* tun2socks in CopyFiles */, 77 | D9792EFC18FB59CB002F2E28 /* com.chrisballinger.CBTunService in CopyFiles */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | D9792EEC18FB58E2002F2E28 /* CopyFiles */ = { 82 | isa = PBXCopyFilesBuildPhase; 83 | buildActionMask = 2147483647; 84 | dstPath = /usr/share/man/man1/; 85 | dstSubfolderSpec = 0; 86 | files = ( 87 | ); 88 | runOnlyForDeploymentPostprocessing = 1; 89 | }; 90 | /* End PBXCopyFilesBuildPhase section */ 91 | 92 | /* Begin PBXFileReference section */ 93 | 2CDD1E9FE263401C93089B68 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 94 | 3344A729C1604CC882D91F05 /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = ""; }; 95 | 35C98DE2A22046F89D5AE95A /* Pods-TetherMac.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TetherMac.xcconfig"; path = "Pods/Pods-TetherMac.xcconfig"; sourceTree = ""; }; 96 | 3AD9B7FDD45A42F390016C26 /* Pods-Tether.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tether.xcconfig"; path = "Pods/Pods-Tether.xcconfig"; sourceTree = ""; }; 97 | 78D94A36C5C54DD8B35132D1 /* libPods-Tether.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tether.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 98 | D90E3255182F07DC00A6F642 /* TetherMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TetherMac.app; sourceTree = BUILT_PRODUCTS_DIR; }; 99 | D90E3258182F07DC00A6F642 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 100 | D90E325B182F07DC00A6F642 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 101 | D90E325C182F07DC00A6F642 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 102 | D90E325D182F07DC00A6F642 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 103 | D90E3260182F07DC00A6F642 /* TetherMac-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TetherMac-Info.plist"; sourceTree = ""; }; 104 | D90E3262182F07DC00A6F642 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 105 | D90E3264182F07DC00A6F642 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 106 | D90E3266182F07DC00A6F642 /* TetherMac-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TetherMac-Prefix.pch"; sourceTree = ""; }; 107 | D90E3268182F07DC00A6F642 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 108 | D90E326A182F07DC00A6F642 /* CBMacAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBMacAppDelegate.h; sourceTree = ""; }; 109 | D90E326B182F07DC00A6F642 /* CBMacAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CBMacAppDelegate.m; sourceTree = ""; }; 110 | D90E326E182F07DC00A6F642 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 111 | D90E3270182F07DC00A6F642 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 112 | D90E3277182F07DC00A6F642 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 113 | D90E3294182F18CC00A6F642 /* CBDeviceWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBDeviceWindowController.h; sourceTree = ""; }; 114 | D90E3295182F18CC00A6F642 /* CBDeviceWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBDeviceWindowController.m; sourceTree = ""; }; 115 | D90E3296182F18CC00A6F642 /* CBDeviceWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CBDeviceWindowController.xib; sourceTree = ""; }; 116 | D90E32CD182F653300A6F642 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; }; 117 | D931A610183012D600593FF9 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 118 | D931A61218304D1200593FF9 /* CBDeviceConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBDeviceConnection.h; sourceTree = ""; }; 119 | D931A61318304D1200593FF9 /* CBDeviceConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBDeviceConnection.m; sourceTree = ""; }; 120 | D9792ED118FB4CCE002F2E28 /* CBTunService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CBTunService-Info.plist"; sourceTree = ""; }; 121 | D9792ED618FB4CCE002F2E28 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 122 | D9792EDB18FB4DCF002F2E28 /* Actions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Actions.h; sourceTree = ""; }; 123 | D9792EDC18FB4DCF002F2E28 /* CBTunService-Launchd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "CBTunService-Launchd.plist"; sourceTree = ""; }; 124 | D9792EDD18FB4DCF002F2E28 /* PrivilegedAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivilegedAgent.h; sourceTree = ""; }; 125 | D9792EDE18FB4DCF002F2E28 /* PrivilegedAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrivilegedAgent.m; sourceTree = ""; }; 126 | D9792EDF18FB4DCF002F2E28 /* PrivilegedServiceDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivilegedServiceDelegate.h; sourceTree = ""; }; 127 | D9792EE018FB4DCF002F2E28 /* PrivilegedServiceDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrivilegedServiceDelegate.m; sourceTree = ""; }; 128 | D9792EE418FB563F002F2E28 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; 129 | D9792EEE18FB58E2002F2E28 /* com.chrisballinger.CBTunService */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.chrisballinger.CBTunService; sourceTree = BUILT_PRODUCTS_DIR; }; 130 | D9B76799184A8734000566D6 /* Tether.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tether.app; sourceTree = BUILT_PRODUCTS_DIR; }; 131 | D9B7679A184A8734000566D6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 132 | D9B7679C184A8734000566D6 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 133 | D9B7679E184A8734000566D6 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 134 | D9B767A2184A8734000566D6 /* Tether-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tether-Info.plist"; sourceTree = ""; }; 135 | D9B767A4184A8734000566D6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 136 | D9B767A6184A8734000566D6 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 137 | D9B767A8184A8734000566D6 /* Tether-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tether-Prefix.pch"; sourceTree = ""; }; 138 | D9B767A9184A8734000566D6 /* CBAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CBAppDelegate.h; sourceTree = ""; }; 139 | D9B767AA184A8734000566D6 /* CBAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CBAppDelegate.m; sourceTree = ""; }; 140 | D9B767AC184A8734000566D6 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 141 | D9B767C8184A88BA000566D6 /* main-mac.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "main-mac.m"; sourceTree = ""; }; 142 | D9B767CA184A8991000566D6 /* CBRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBRootViewController.h; sourceTree = ""; }; 143 | D9B767CB184A8991000566D6 /* CBRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBRootViewController.m; sourceTree = ""; }; 144 | D9B767D1184A8B32000566D6 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; 145 | D9B767D4184A9432000566D6 /* USBMuxDeviceConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = USBMuxDeviceConnection.h; sourceTree = ""; }; 146 | D9B767D5184A9432000566D6 /* USBMuxDeviceConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = USBMuxDeviceConnection.m; sourceTree = ""; }; 147 | D9B767D7184A978A000566D6 /* USBMuxDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = USBMuxDevice.h; sourceTree = ""; }; 148 | D9B767D8184A978A000566D6 /* USBMuxDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = USBMuxDevice.m; sourceTree = ""; }; 149 | D9C40B4718F67BF2005CD748 /* libPods-libplist.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-libplist.a"; path = "../../Library/Developer/Xcode/DerivedData/Tether-fesemxykvcaanucpsmrkosdeoujg/Build/Products/Debug/libPods-libplist.a"; sourceTree = ""; }; 150 | D9D81108182F8B80003DCCBB /* USBMuxClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = USBMuxClient.h; sourceTree = ""; }; 151 | D9D81109182F8B80003DCCBB /* USBMuxClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = USBMuxClient.m; sourceTree = ""; }; 152 | D9FA3181190DB9A0003CA4E0 /* badvpn.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = badvpn.xcodeproj; path = Submodules/badvpn/badvpn.xcodeproj; sourceTree = ""; }; 153 | D9FEA97F18EA6E6C00EA736D /* CBNetworkServiceEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CBNetworkServiceEditor.h; sourceTree = ""; }; 154 | D9FEA98018EA6E6C00EA736D /* CBNetworkServiceEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CBNetworkServiceEditor.m; sourceTree = ""; }; 155 | DF17F6ED75F54FB5ADE9E7C5 /* libPods-TetherMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-TetherMac.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 156 | /* End PBXFileReference section */ 157 | 158 | /* Begin PBXFrameworksBuildPhase section */ 159 | D90E3252182F07DC00A6F642 /* Frameworks */ = { 160 | isa = PBXFrameworksBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | D9792EE518FB563F002F2E28 /* ServiceManagement.framework in Frameworks */, 164 | D931A611183012D600593FF9 /* Security.framework in Frameworks */, 165 | D9D81107182F83DD003DCCBB /* libxml2.dylib in Frameworks */, 166 | D90E3259182F07DC00A6F642 /* Cocoa.framework in Frameworks */, 167 | 17629344A9444BD29F36FD1A /* libPods-TetherMac.a in Frameworks */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | D9792EEB18FB58E2002F2E28 /* Frameworks */ = { 172 | isa = PBXFrameworksBuildPhase; 173 | buildActionMask = 2147483647; 174 | files = ( 175 | ); 176 | runOnlyForDeploymentPostprocessing = 0; 177 | }; 178 | D9B76796184A8734000566D6 /* Frameworks */ = { 179 | isa = PBXFrameworksBuildPhase; 180 | buildActionMask = 2147483647; 181 | files = ( 182 | D9B767D2184A8B32000566D6 /* MobileCoreServices.framework in Frameworks */, 183 | D9B7679D184A8734000566D6 /* CoreGraphics.framework in Frameworks */, 184 | D9B7679F184A8734000566D6 /* UIKit.framework in Frameworks */, 185 | D9B7679B184A8734000566D6 /* Foundation.framework in Frameworks */, 186 | 8E2C05E4790549028265E799 /* libPods-Tether.a in Frameworks */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXFrameworksBuildPhase section */ 191 | 192 | /* Begin PBXGroup section */ 193 | D90E324C182F07DC00A6F642 = { 194 | isa = PBXGroup; 195 | children = ( 196 | D9B767C7184A877A000566D6 /* USBMuxClient */, 197 | D90E325E182F07DC00A6F642 /* TetherMac */, 198 | D9B767A0184A8734000566D6 /* Tether-iOS */, 199 | D9792ECF18FB4CCE002F2E28 /* CBTunService */, 200 | D90E3257182F07DC00A6F642 /* Frameworks */, 201 | D9FA3181190DB9A0003CA4E0 /* badvpn.xcodeproj */, 202 | D90E3256182F07DC00A6F642 /* Products */, 203 | 3344A729C1604CC882D91F05 /* Pods.xcconfig */, 204 | 3AD9B7FDD45A42F390016C26 /* Pods-Tether.xcconfig */, 205 | 35C98DE2A22046F89D5AE95A /* Pods-TetherMac.xcconfig */, 206 | ); 207 | sourceTree = ""; 208 | }; 209 | D90E3256182F07DC00A6F642 /* Products */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | D90E3255182F07DC00A6F642 /* TetherMac.app */, 213 | D9B76799184A8734000566D6 /* Tether.app */, 214 | D9792EEE18FB58E2002F2E28 /* com.chrisballinger.CBTunService */, 215 | ); 216 | name = Products; 217 | sourceTree = ""; 218 | }; 219 | D90E3257182F07DC00A6F642 /* Frameworks */ = { 220 | isa = PBXGroup; 221 | children = ( 222 | D9792EE418FB563F002F2E28 /* ServiceManagement.framework */, 223 | D9C40B4718F67BF2005CD748 /* libPods-libplist.a */, 224 | D9B767D1184A8B32000566D6 /* MobileCoreServices.framework */, 225 | D931A610183012D600593FF9 /* Security.framework */, 226 | D90E32CD182F653300A6F642 /* libxml2.dylib */, 227 | D90E3258182F07DC00A6F642 /* Cocoa.framework */, 228 | D90E3277182F07DC00A6F642 /* XCTest.framework */, 229 | D9B7679A184A8734000566D6 /* Foundation.framework */, 230 | D9B7679C184A8734000566D6 /* CoreGraphics.framework */, 231 | D9B7679E184A8734000566D6 /* UIKit.framework */, 232 | D90E325A182F07DC00A6F642 /* Other Frameworks */, 233 | 2CDD1E9FE263401C93089B68 /* libPods.a */, 234 | 78D94A36C5C54DD8B35132D1 /* libPods-Tether.a */, 235 | DF17F6ED75F54FB5ADE9E7C5 /* libPods-TetherMac.a */, 236 | ); 237 | name = Frameworks; 238 | sourceTree = ""; 239 | }; 240 | D90E325A182F07DC00A6F642 /* Other Frameworks */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | D90E325B182F07DC00A6F642 /* AppKit.framework */, 244 | D90E325C182F07DC00A6F642 /* CoreData.framework */, 245 | D90E325D182F07DC00A6F642 /* Foundation.framework */, 246 | ); 247 | name = "Other Frameworks"; 248 | sourceTree = ""; 249 | }; 250 | D90E325E182F07DC00A6F642 /* TetherMac */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | D9FEA97F18EA6E6C00EA736D /* CBNetworkServiceEditor.h */, 254 | D9FEA98018EA6E6C00EA736D /* CBNetworkServiceEditor.m */, 255 | D90E326A182F07DC00A6F642 /* CBMacAppDelegate.h */, 256 | D90E326B182F07DC00A6F642 /* CBMacAppDelegate.m */, 257 | D931A61218304D1200593FF9 /* CBDeviceConnection.h */, 258 | D931A61318304D1200593FF9 /* CBDeviceConnection.m */, 259 | D90E3294182F18CC00A6F642 /* CBDeviceWindowController.h */, 260 | D90E3295182F18CC00A6F642 /* CBDeviceWindowController.m */, 261 | D90E3296182F18CC00A6F642 /* CBDeviceWindowController.xib */, 262 | D90E326D182F07DC00A6F642 /* MainMenu.xib */, 263 | D90E3270182F07DC00A6F642 /* Images.xcassets */, 264 | D90E325F182F07DC00A6F642 /* Supporting Files */, 265 | ); 266 | name = TetherMac; 267 | path = Tether; 268 | sourceTree = ""; 269 | }; 270 | D90E325F182F07DC00A6F642 /* Supporting Files */ = { 271 | isa = PBXGroup; 272 | children = ( 273 | D90E3260182F07DC00A6F642 /* TetherMac-Info.plist */, 274 | D90E3261182F07DC00A6F642 /* InfoPlist.strings */, 275 | D9B767C8184A88BA000566D6 /* main-mac.m */, 276 | D90E3264182F07DC00A6F642 /* main.m */, 277 | D90E3266182F07DC00A6F642 /* TetherMac-Prefix.pch */, 278 | D90E3267182F07DC00A6F642 /* Credits.rtf */, 279 | ); 280 | name = "Supporting Files"; 281 | sourceTree = ""; 282 | }; 283 | D9792ECF18FB4CCE002F2E28 /* CBTunService */ = { 284 | isa = PBXGroup; 285 | children = ( 286 | D9792EDB18FB4DCF002F2E28 /* Actions.h */, 287 | D9792EDD18FB4DCF002F2E28 /* PrivilegedAgent.h */, 288 | D9792EDE18FB4DCF002F2E28 /* PrivilegedAgent.m */, 289 | D9792EDF18FB4DCF002F2E28 /* PrivilegedServiceDelegate.h */, 290 | D9792EE018FB4DCF002F2E28 /* PrivilegedServiceDelegate.m */, 291 | D9792ED618FB4CCE002F2E28 /* main.m */, 292 | D9792ED018FB4CCE002F2E28 /* Supporting Files */, 293 | ); 294 | path = CBTunService; 295 | sourceTree = ""; 296 | }; 297 | D9792ED018FB4CCE002F2E28 /* Supporting Files */ = { 298 | isa = PBXGroup; 299 | children = ( 300 | D9792EDC18FB4DCF002F2E28 /* CBTunService-Launchd.plist */, 301 | D9792ED118FB4CCE002F2E28 /* CBTunService-Info.plist */, 302 | ); 303 | name = "Supporting Files"; 304 | sourceTree = ""; 305 | }; 306 | D9B767A0184A8734000566D6 /* Tether-iOS */ = { 307 | isa = PBXGroup; 308 | children = ( 309 | D9B767CA184A8991000566D6 /* CBRootViewController.h */, 310 | D9B767CB184A8991000566D6 /* CBRootViewController.m */, 311 | D9B767A9184A8734000566D6 /* CBAppDelegate.h */, 312 | D9B767AA184A8734000566D6 /* CBAppDelegate.m */, 313 | D9B767AC184A8734000566D6 /* Images.xcassets */, 314 | D9B767A1184A8734000566D6 /* Supporting Files */, 315 | ); 316 | name = "Tether-iOS"; 317 | path = Tether; 318 | sourceTree = ""; 319 | }; 320 | D9B767A1184A8734000566D6 /* Supporting Files */ = { 321 | isa = PBXGroup; 322 | children = ( 323 | D9B767A2184A8734000566D6 /* Tether-Info.plist */, 324 | D9B767A3184A8734000566D6 /* InfoPlist.strings */, 325 | D9B767A6184A8734000566D6 /* main.m */, 326 | D9B767A8184A8734000566D6 /* Tether-Prefix.pch */, 327 | ); 328 | name = "Supporting Files"; 329 | sourceTree = ""; 330 | }; 331 | D9B767C7184A877A000566D6 /* USBMuxClient */ = { 332 | isa = PBXGroup; 333 | children = ( 334 | D9B767D7184A978A000566D6 /* USBMuxDevice.h */, 335 | D9B767D8184A978A000566D6 /* USBMuxDevice.m */, 336 | D9B767D4184A9432000566D6 /* USBMuxDeviceConnection.h */, 337 | D9B767D5184A9432000566D6 /* USBMuxDeviceConnection.m */, 338 | D9D81108182F8B80003DCCBB /* USBMuxClient.h */, 339 | D9D81109182F8B80003DCCBB /* USBMuxClient.m */, 340 | ); 341 | name = USBMuxClient; 342 | path = Tether; 343 | sourceTree = ""; 344 | }; 345 | D9FA3182190DB9A0003CA4E0 /* Products */ = { 346 | isa = PBXGroup; 347 | children = ( 348 | D9FA3186190DB9A0003CA4E0 /* tun2socks */, 349 | ); 350 | name = Products; 351 | sourceTree = ""; 352 | }; 353 | /* End PBXGroup section */ 354 | 355 | /* Begin PBXNativeTarget section */ 356 | D90E3254182F07DC00A6F642 /* TetherMac */ = { 357 | isa = PBXNativeTarget; 358 | buildConfigurationList = D90E3286182F07DC00A6F642 /* Build configuration list for PBXNativeTarget "TetherMac" */; 359 | buildPhases = ( 360 | DEF537F12E604F69A35A5614 /* Check Pods Manifest.lock */, 361 | D90E3251182F07DC00A6F642 /* Sources */, 362 | D90E3252182F07DC00A6F642 /* Frameworks */, 363 | D90E3253182F07DC00A6F642 /* Resources */, 364 | 551353FA86374048AD71A2B9 /* Copy Pods Resources */, 365 | D9792EE818FB5744002F2E28 /* CopyFiles */, 366 | ); 367 | buildRules = ( 368 | ); 369 | dependencies = ( 370 | D9FA3188190DBA1B003CA4E0 /* PBXTargetDependency */, 371 | D9792EFB18FB59C4002F2E28 /* PBXTargetDependency */, 372 | ); 373 | name = TetherMac; 374 | productName = Tether; 375 | productReference = D90E3255182F07DC00A6F642 /* TetherMac.app */; 376 | productType = "com.apple.product-type.application"; 377 | }; 378 | D9792EED18FB58E2002F2E28 /* com.chrisballinger.CBTunService */ = { 379 | isa = PBXNativeTarget; 380 | buildConfigurationList = D9792EF418FB58E2002F2E28 /* Build configuration list for PBXNativeTarget "com.chrisballinger.CBTunService" */; 381 | buildPhases = ( 382 | D9792EEA18FB58E2002F2E28 /* Sources */, 383 | D9792EEB18FB58E2002F2E28 /* Frameworks */, 384 | D9792EEC18FB58E2002F2E28 /* CopyFiles */, 385 | ); 386 | buildRules = ( 387 | ); 388 | dependencies = ( 389 | ); 390 | name = com.chrisballinger.CBTunService; 391 | productName = CBTunService; 392 | productReference = D9792EEE18FB58E2002F2E28 /* com.chrisballinger.CBTunService */; 393 | productType = "com.apple.product-type.tool"; 394 | }; 395 | D9B76798184A8734000566D6 /* Tether */ = { 396 | isa = PBXNativeTarget; 397 | buildConfigurationList = D9B767C0184A8735000566D6 /* Build configuration list for PBXNativeTarget "Tether" */; 398 | buildPhases = ( 399 | 8D5DF3B886B344518F0ABB94 /* Check Pods Manifest.lock */, 400 | D9B76795184A8734000566D6 /* Sources */, 401 | D9B76796184A8734000566D6 /* Frameworks */, 402 | D9B76797184A8734000566D6 /* Resources */, 403 | 7BDBC3252F114969AA6EA23A /* Copy Pods Resources */, 404 | ); 405 | buildRules = ( 406 | ); 407 | dependencies = ( 408 | ); 409 | name = Tether; 410 | productName = Tether; 411 | productReference = D9B76799184A8734000566D6 /* Tether.app */; 412 | productType = "com.apple.product-type.application"; 413 | }; 414 | /* End PBXNativeTarget section */ 415 | 416 | /* Begin PBXProject section */ 417 | D90E324D182F07DC00A6F642 /* Project object */ = { 418 | isa = PBXProject; 419 | attributes = { 420 | CLASSPREFIX = CB; 421 | LastUpgradeCheck = 0510; 422 | ORGANIZATIONNAME = "Christopher Ballinger"; 423 | TargetAttributes = { 424 | D9B76798184A8734000566D6 = { 425 | SystemCapabilities = { 426 | com.apple.BackgroundModes = { 427 | enabled = 1; 428 | }; 429 | }; 430 | }; 431 | }; 432 | }; 433 | buildConfigurationList = D90E3250182F07DC00A6F642 /* Build configuration list for PBXProject "Tether" */; 434 | compatibilityVersion = "Xcode 3.2"; 435 | developmentRegion = English; 436 | hasScannedForEncodings = 0; 437 | knownRegions = ( 438 | en, 439 | Base, 440 | ); 441 | mainGroup = D90E324C182F07DC00A6F642; 442 | productRefGroup = D90E3256182F07DC00A6F642 /* Products */; 443 | projectDirPath = ""; 444 | projectReferences = ( 445 | { 446 | ProductGroup = D9FA3182190DB9A0003CA4E0 /* Products */; 447 | ProjectRef = D9FA3181190DB9A0003CA4E0 /* badvpn.xcodeproj */; 448 | }, 449 | ); 450 | projectRoot = ""; 451 | targets = ( 452 | D90E3254182F07DC00A6F642 /* TetherMac */, 453 | D9B76798184A8734000566D6 /* Tether */, 454 | D9792EED18FB58E2002F2E28 /* com.chrisballinger.CBTunService */, 455 | ); 456 | }; 457 | /* End PBXProject section */ 458 | 459 | /* Begin PBXReferenceProxy section */ 460 | D9FA3186190DB9A0003CA4E0 /* tun2socks */ = { 461 | isa = PBXReferenceProxy; 462 | fileType = "compiled.mach-o.executable"; 463 | path = tun2socks; 464 | remoteRef = D9FA3185190DB9A0003CA4E0 /* PBXContainerItemProxy */; 465 | sourceTree = BUILT_PRODUCTS_DIR; 466 | }; 467 | /* End PBXReferenceProxy section */ 468 | 469 | /* Begin PBXResourcesBuildPhase section */ 470 | D90E3253182F07DC00A6F642 /* Resources */ = { 471 | isa = PBXResourcesBuildPhase; 472 | buildActionMask = 2147483647; 473 | files = ( 474 | D90E3263182F07DC00A6F642 /* InfoPlist.strings in Resources */, 475 | D90E3271182F07DC00A6F642 /* Images.xcassets in Resources */, 476 | D90E3269182F07DC00A6F642 /* Credits.rtf in Resources */, 477 | D90E326F182F07DC00A6F642 /* MainMenu.xib in Resources */, 478 | D90E3298182F18CC00A6F642 /* CBDeviceWindowController.xib in Resources */, 479 | ); 480 | runOnlyForDeploymentPostprocessing = 0; 481 | }; 482 | D9B76797184A8734000566D6 /* Resources */ = { 483 | isa = PBXResourcesBuildPhase; 484 | buildActionMask = 2147483647; 485 | files = ( 486 | D9B767A5184A8734000566D6 /* InfoPlist.strings in Resources */, 487 | D9B767AD184A8734000566D6 /* Images.xcassets in Resources */, 488 | ); 489 | runOnlyForDeploymentPostprocessing = 0; 490 | }; 491 | /* End PBXResourcesBuildPhase section */ 492 | 493 | /* Begin PBXShellScriptBuildPhase section */ 494 | 551353FA86374048AD71A2B9 /* Copy Pods Resources */ = { 495 | isa = PBXShellScriptBuildPhase; 496 | buildActionMask = 2147483647; 497 | files = ( 498 | ); 499 | inputPaths = ( 500 | ); 501 | name = "Copy Pods Resources"; 502 | outputPaths = ( 503 | ); 504 | runOnlyForDeploymentPostprocessing = 0; 505 | shellPath = /bin/sh; 506 | shellScript = "\"${SRCROOT}/Pods/Pods-TetherMac-resources.sh\"\n"; 507 | showEnvVarsInLog = 0; 508 | }; 509 | 7BDBC3252F114969AA6EA23A /* Copy Pods Resources */ = { 510 | isa = PBXShellScriptBuildPhase; 511 | buildActionMask = 2147483647; 512 | files = ( 513 | ); 514 | inputPaths = ( 515 | ); 516 | name = "Copy Pods Resources"; 517 | outputPaths = ( 518 | ); 519 | runOnlyForDeploymentPostprocessing = 0; 520 | shellPath = /bin/sh; 521 | shellScript = "\"${SRCROOT}/Pods/Pods-Tether-resources.sh\"\n"; 522 | showEnvVarsInLog = 0; 523 | }; 524 | 8D5DF3B886B344518F0ABB94 /* Check Pods Manifest.lock */ = { 525 | isa = PBXShellScriptBuildPhase; 526 | buildActionMask = 2147483647; 527 | files = ( 528 | ); 529 | inputPaths = ( 530 | ); 531 | name = "Check Pods Manifest.lock"; 532 | outputPaths = ( 533 | ); 534 | runOnlyForDeploymentPostprocessing = 0; 535 | shellPath = /bin/sh; 536 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 537 | showEnvVarsInLog = 0; 538 | }; 539 | DEF537F12E604F69A35A5614 /* Check Pods Manifest.lock */ = { 540 | isa = PBXShellScriptBuildPhase; 541 | buildActionMask = 2147483647; 542 | files = ( 543 | ); 544 | inputPaths = ( 545 | ); 546 | name = "Check Pods Manifest.lock"; 547 | outputPaths = ( 548 | ); 549 | runOnlyForDeploymentPostprocessing = 0; 550 | shellPath = /bin/sh; 551 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 552 | showEnvVarsInLog = 0; 553 | }; 554 | /* End PBXShellScriptBuildPhase section */ 555 | 556 | /* Begin PBXSourcesBuildPhase section */ 557 | D90E3251182F07DC00A6F642 /* Sources */ = { 558 | isa = PBXSourcesBuildPhase; 559 | buildActionMask = 2147483647; 560 | files = ( 561 | D9B767D6184A9432000566D6 /* USBMuxDeviceConnection.m in Sources */, 562 | D9B767C9184A88BA000566D6 /* main-mac.m in Sources */, 563 | D9B767D9184A978A000566D6 /* USBMuxDevice.m in Sources */, 564 | D90E326C182F07DC00A6F642 /* CBMacAppDelegate.m in Sources */, 565 | D90E3297182F18CC00A6F642 /* CBDeviceWindowController.m in Sources */, 566 | D931A61418304D1200593FF9 /* CBDeviceConnection.m in Sources */, 567 | D9D8110A182F8B80003DCCBB /* USBMuxClient.m in Sources */, 568 | D9FEA98118EA6E6C00EA736D /* CBNetworkServiceEditor.m in Sources */, 569 | ); 570 | runOnlyForDeploymentPostprocessing = 0; 571 | }; 572 | D9792EEA18FB58E2002F2E28 /* Sources */ = { 573 | isa = PBXSourcesBuildPhase; 574 | buildActionMask = 2147483647; 575 | files = ( 576 | D9792EF718FB593A002F2E28 /* PrivilegedAgent.m in Sources */, 577 | D9792EF818FB593A002F2E28 /* PrivilegedServiceDelegate.m in Sources */, 578 | D9792EF918FB593A002F2E28 /* main.m in Sources */, 579 | ); 580 | runOnlyForDeploymentPostprocessing = 0; 581 | }; 582 | D9B76795184A8734000566D6 /* Sources */ = { 583 | isa = PBXSourcesBuildPhase; 584 | buildActionMask = 2147483647; 585 | files = ( 586 | D9B767A7184A8734000566D6 /* main.m in Sources */, 587 | D9B767AB184A8734000566D6 /* CBAppDelegate.m in Sources */, 588 | D9B767CC184A8991000566D6 /* CBRootViewController.m in Sources */, 589 | ); 590 | runOnlyForDeploymentPostprocessing = 0; 591 | }; 592 | /* End PBXSourcesBuildPhase section */ 593 | 594 | /* Begin PBXTargetDependency section */ 595 | D9792EFB18FB59C4002F2E28 /* PBXTargetDependency */ = { 596 | isa = PBXTargetDependency; 597 | target = D9792EED18FB58E2002F2E28 /* com.chrisballinger.CBTunService */; 598 | targetProxy = D9792EFA18FB59C4002F2E28 /* PBXContainerItemProxy */; 599 | }; 600 | D9FA3188190DBA1B003CA4E0 /* PBXTargetDependency */ = { 601 | isa = PBXTargetDependency; 602 | name = tun2socks; 603 | targetProxy = D9FA3187190DBA1B003CA4E0 /* PBXContainerItemProxy */; 604 | }; 605 | /* End PBXTargetDependency section */ 606 | 607 | /* Begin PBXVariantGroup section */ 608 | D90E3261182F07DC00A6F642 /* InfoPlist.strings */ = { 609 | isa = PBXVariantGroup; 610 | children = ( 611 | D90E3262182F07DC00A6F642 /* en */, 612 | ); 613 | name = InfoPlist.strings; 614 | sourceTree = ""; 615 | }; 616 | D90E3267182F07DC00A6F642 /* Credits.rtf */ = { 617 | isa = PBXVariantGroup; 618 | children = ( 619 | D90E3268182F07DC00A6F642 /* en */, 620 | ); 621 | name = Credits.rtf; 622 | sourceTree = ""; 623 | }; 624 | D90E326D182F07DC00A6F642 /* MainMenu.xib */ = { 625 | isa = PBXVariantGroup; 626 | children = ( 627 | D90E326E182F07DC00A6F642 /* Base */, 628 | ); 629 | name = MainMenu.xib; 630 | sourceTree = ""; 631 | }; 632 | D9B767A3184A8734000566D6 /* InfoPlist.strings */ = { 633 | isa = PBXVariantGroup; 634 | children = ( 635 | D9B767A4184A8734000566D6 /* en */, 636 | ); 637 | name = InfoPlist.strings; 638 | sourceTree = ""; 639 | }; 640 | /* End PBXVariantGroup section */ 641 | 642 | /* Begin XCBuildConfiguration section */ 643 | D90E3284182F07DC00A6F642 /* Debug */ = { 644 | isa = XCBuildConfiguration; 645 | buildSettings = { 646 | ALWAYS_SEARCH_USER_PATHS = NO; 647 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 648 | CLANG_CXX_LIBRARY = "libc++"; 649 | CLANG_ENABLE_OBJC_ARC = YES; 650 | CLANG_WARN_BOOL_CONVERSION = YES; 651 | CLANG_WARN_CONSTANT_CONVERSION = YES; 652 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 653 | CLANG_WARN_EMPTY_BODY = YES; 654 | CLANG_WARN_ENUM_CONVERSION = YES; 655 | CLANG_WARN_INT_CONVERSION = YES; 656 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 657 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 658 | COPY_PHASE_STRIP = NO; 659 | GCC_C_LANGUAGE_STANDARD = gnu99; 660 | GCC_DYNAMIC_NO_PIC = NO; 661 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 662 | GCC_OPTIMIZATION_LEVEL = 0; 663 | GCC_PREPROCESSOR_DEFINITIONS = ( 664 | "DEBUG=1", 665 | "$(inherited)", 666 | ); 667 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 668 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 669 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 670 | GCC_WARN_UNDECLARED_SELECTOR = YES; 671 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 672 | GCC_WARN_UNUSED_FUNCTION = YES; 673 | GCC_WARN_UNUSED_VARIABLE = YES; 674 | MACOSX_DEPLOYMENT_TARGET = 10.9; 675 | ONLY_ACTIVE_ARCH = YES; 676 | SDKROOT = macosx; 677 | }; 678 | name = Debug; 679 | }; 680 | D90E3285182F07DC00A6F642 /* Release */ = { 681 | isa = XCBuildConfiguration; 682 | buildSettings = { 683 | ALWAYS_SEARCH_USER_PATHS = NO; 684 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 685 | CLANG_CXX_LIBRARY = "libc++"; 686 | CLANG_ENABLE_OBJC_ARC = YES; 687 | CLANG_WARN_BOOL_CONVERSION = YES; 688 | CLANG_WARN_CONSTANT_CONVERSION = YES; 689 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 690 | CLANG_WARN_EMPTY_BODY = YES; 691 | CLANG_WARN_ENUM_CONVERSION = YES; 692 | CLANG_WARN_INT_CONVERSION = YES; 693 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 694 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 695 | COPY_PHASE_STRIP = YES; 696 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 697 | ENABLE_NS_ASSERTIONS = NO; 698 | GCC_C_LANGUAGE_STANDARD = gnu99; 699 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 700 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 701 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 702 | GCC_WARN_UNDECLARED_SELECTOR = YES; 703 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 704 | GCC_WARN_UNUSED_FUNCTION = YES; 705 | GCC_WARN_UNUSED_VARIABLE = YES; 706 | MACOSX_DEPLOYMENT_TARGET = 10.9; 707 | SDKROOT = macosx; 708 | }; 709 | name = Release; 710 | }; 711 | D90E3287182F07DC00A6F642 /* Debug */ = { 712 | isa = XCBuildConfiguration; 713 | baseConfigurationReference = 35C98DE2A22046F89D5AE95A /* Pods-TetherMac.xcconfig */; 714 | buildSettings = { 715 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 716 | CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application"; 717 | COMBINE_HIDPI_IMAGES = YES; 718 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 719 | GCC_PREFIX_HEADER = "Tether/TetherMac-Prefix.pch"; 720 | HEADER_SEARCH_PATHS = ( 721 | "$(inherited)", 722 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 723 | "$(SRCROOT)/Submodules/libusbmuxd/include", 724 | "$(SRCROOT)/Submodules/CocoaAsyncSocket/GCD", 725 | ); 726 | INFOPLIST_FILE = "Tether/TetherMac-Info.plist"; 727 | LIBRARY_SEARCH_PATHS = ( 728 | "$(inherited)", 729 | "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Tether-fesemxykvcaanucpsmrkosdeoujg/Build/Products/Debug", 730 | ); 731 | PRODUCT_NAME = "$(TARGET_NAME)"; 732 | WRAPPER_EXTENSION = app; 733 | }; 734 | name = Debug; 735 | }; 736 | D90E3288182F07DC00A6F642 /* Release */ = { 737 | isa = XCBuildConfiguration; 738 | baseConfigurationReference = 35C98DE2A22046F89D5AE95A /* Pods-TetherMac.xcconfig */; 739 | buildSettings = { 740 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 741 | CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application"; 742 | COMBINE_HIDPI_IMAGES = YES; 743 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 744 | GCC_PREFIX_HEADER = "Tether/TetherMac-Prefix.pch"; 745 | HEADER_SEARCH_PATHS = ( 746 | "$(inherited)", 747 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 748 | "$(SRCROOT)/Submodules/libusbmuxd/include", 749 | "$(SRCROOT)/Submodules/CocoaAsyncSocket/GCD", 750 | ); 751 | INFOPLIST_FILE = "Tether/TetherMac-Info.plist"; 752 | LIBRARY_SEARCH_PATHS = ( 753 | "$(inherited)", 754 | "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/Tether-fesemxykvcaanucpsmrkosdeoujg/Build/Products/Debug", 755 | ); 756 | PRODUCT_NAME = "$(TARGET_NAME)"; 757 | WRAPPER_EXTENSION = app; 758 | }; 759 | name = Release; 760 | }; 761 | D9792EF518FB58E2002F2E28 /* Debug */ = { 762 | isa = XCBuildConfiguration; 763 | buildSettings = { 764 | CLANG_ENABLE_MODULES = YES; 765 | CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application"; 766 | GCC_PREPROCESSOR_DEFINITIONS = ( 767 | "DEBUG=1", 768 | "$(inherited)", 769 | ); 770 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 771 | OTHER_LDFLAGS = ( 772 | "-sectcreate", 773 | __TEXT, 774 | __info_plist, 775 | "CBTunService/CBTunService-Info.plist", 776 | "-sectcreate", 777 | __TEXT, 778 | __launchd_plist, 779 | "CBTunService/CBTunService-Launchd.plist", 780 | ); 781 | PRODUCT_NAME = "$(TARGET_NAME)"; 782 | }; 783 | name = Debug; 784 | }; 785 | D9792EF618FB58E2002F2E28 /* Release */ = { 786 | isa = XCBuildConfiguration; 787 | buildSettings = { 788 | CLANG_ENABLE_MODULES = YES; 789 | CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application"; 790 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 791 | OTHER_LDFLAGS = ( 792 | "-sectcreate", 793 | __TEXT, 794 | __info_plist, 795 | "CBTunService/CBTunService-Info.plist", 796 | "-sectcreate", 797 | __TEXT, 798 | __launchd_plist, 799 | "CBTunService/CBTunService-Launchd.plist", 800 | ); 801 | PRODUCT_NAME = "$(TARGET_NAME)"; 802 | }; 803 | name = Release; 804 | }; 805 | D9B767C1184A8735000566D6 /* Debug */ = { 806 | isa = XCBuildConfiguration; 807 | baseConfigurationReference = 3AD9B7FDD45A42F390016C26 /* Pods-Tether.xcconfig */; 808 | buildSettings = { 809 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 810 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 811 | CLANG_ENABLE_MODULES = YES; 812 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 813 | FRAMEWORK_SEARCH_PATHS = ( 814 | "$(inherited)", 815 | "$(DEVELOPER_FRAMEWORKS_DIR)", 816 | ); 817 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 818 | GCC_PREFIX_HEADER = "Tether/Tether-Prefix.pch"; 819 | GCC_PREPROCESSOR_DEFINITIONS = ( 820 | "DEBUG=1", 821 | "$(inherited)", 822 | ); 823 | INFOPLIST_FILE = "Tether/Tether-Info.plist"; 824 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 825 | PRODUCT_NAME = "$(TARGET_NAME)"; 826 | SDKROOT = iphoneos; 827 | TARGETED_DEVICE_FAMILY = "1,2"; 828 | WRAPPER_EXTENSION = app; 829 | }; 830 | name = Debug; 831 | }; 832 | D9B767C2184A8735000566D6 /* Release */ = { 833 | isa = XCBuildConfiguration; 834 | baseConfigurationReference = 3AD9B7FDD45A42F390016C26 /* Pods-Tether.xcconfig */; 835 | buildSettings = { 836 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 837 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 838 | CLANG_ENABLE_MODULES = YES; 839 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 840 | FRAMEWORK_SEARCH_PATHS = ( 841 | "$(inherited)", 842 | "$(DEVELOPER_FRAMEWORKS_DIR)", 843 | ); 844 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 845 | GCC_PREFIX_HEADER = "Tether/Tether-Prefix.pch"; 846 | INFOPLIST_FILE = "Tether/Tether-Info.plist"; 847 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 848 | PRODUCT_NAME = "$(TARGET_NAME)"; 849 | SDKROOT = iphoneos; 850 | TARGETED_DEVICE_FAMILY = "1,2"; 851 | VALIDATE_PRODUCT = YES; 852 | WRAPPER_EXTENSION = app; 853 | }; 854 | name = Release; 855 | }; 856 | /* End XCBuildConfiguration section */ 857 | 858 | /* Begin XCConfigurationList section */ 859 | D90E3250182F07DC00A6F642 /* Build configuration list for PBXProject "Tether" */ = { 860 | isa = XCConfigurationList; 861 | buildConfigurations = ( 862 | D90E3284182F07DC00A6F642 /* Debug */, 863 | D90E3285182F07DC00A6F642 /* Release */, 864 | ); 865 | defaultConfigurationIsVisible = 0; 866 | defaultConfigurationName = Release; 867 | }; 868 | D90E3286182F07DC00A6F642 /* Build configuration list for PBXNativeTarget "TetherMac" */ = { 869 | isa = XCConfigurationList; 870 | buildConfigurations = ( 871 | D90E3287182F07DC00A6F642 /* Debug */, 872 | D90E3288182F07DC00A6F642 /* Release */, 873 | ); 874 | defaultConfigurationIsVisible = 0; 875 | defaultConfigurationName = Release; 876 | }; 877 | D9792EF418FB58E2002F2E28 /* Build configuration list for PBXNativeTarget "com.chrisballinger.CBTunService" */ = { 878 | isa = XCConfigurationList; 879 | buildConfigurations = ( 880 | D9792EF518FB58E2002F2E28 /* Debug */, 881 | D9792EF618FB58E2002F2E28 /* Release */, 882 | ); 883 | defaultConfigurationIsVisible = 0; 884 | defaultConfigurationName = Release; 885 | }; 886 | D9B767C0184A8735000566D6 /* Build configuration list for PBXNativeTarget "Tether" */ = { 887 | isa = XCConfigurationList; 888 | buildConfigurations = ( 889 | D9B767C1184A8735000566D6 /* Debug */, 890 | D9B767C2184A8735000566D6 /* Release */, 891 | ); 892 | defaultConfigurationIsVisible = 0; 893 | defaultConfigurationName = Release; 894 | }; 895 | /* End XCConfigurationList section */ 896 | }; 897 | rootObject = D90E324D182F07DC00A6F642 /* Project object */; 898 | } 899 | -------------------------------------------------------------------------------- /Tether.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tether.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Tether.xcworkspace/xcshareddata/Tether.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 68D77D00-2CCB-40B7-8B7B-AC1AAFC4B246 9 | IDESourceControlProjectName 10 | Tether 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 0ED34DCF-5560-47B6-B675-5A8237DA9A1A 14 | ssh://github.com/chrisballinger/Tether-iOS.git 15 | 1B8752AE-100F-4DFD-AA86-355CF0392E0A 16 | ssh://github.com/chrisballinger/ProxyKit.git 17 | 72CEDF93-3DC8-4ED5-8D90-D887BCE9A1C6 18 | ssh://github.com/robbiehanson/CocoaAsyncSocket.git 19 | 7BC55E3C-50A9-4F6E-BE4C-D4B5F011EC6B 20 | ssh://github.com/chrisballinger/badvpn.git 21 | B1DFC0A1-0D57-426D-AE3F-E8DABD0942E5 22 | ssh://github.com/libimobiledevice/libplist.git 23 | C72E8FC4-C6BC-42E4-A89B-F36567CFEAE4 24 | ssh://github.com/libimobiledevice/libusbmuxd.git 25 | 26 | IDESourceControlProjectPath 27 | Tether.xcworkspace 28 | IDESourceControlProjectRelativeInstallPathDictionary 29 | 30 | 0ED34DCF-5560-47B6-B675-5A8237DA9A1A 31 | .. 32 | 1B8752AE-100F-4DFD-AA86-355CF0392E0A 33 | ../Submodules/ProxyKit 34 | 72CEDF93-3DC8-4ED5-8D90-D887BCE9A1C6 35 | ../Submodules/CocoaAsyncSocket 36 | 7BC55E3C-50A9-4F6E-BE4C-D4B5F011EC6B 37 | ../Submodules/badvpn 38 | B1DFC0A1-0D57-426D-AE3F-E8DABD0942E5 39 | ../Submodules/libplist 40 | C72E8FC4-C6BC-42E4-A89B-F36567CFEAE4 41 | ../Submodules/libusbmuxd 42 | 43 | IDESourceControlProjectURL 44 | ssh://github.com/chrisballinger/Tether-iOS.git 45 | IDESourceControlProjectVersion 46 | 110 47 | IDESourceControlProjectWCCIdentifier 48 | 0ED34DCF-5560-47B6-B675-5A8237DA9A1A 49 | IDESourceControlProjectWCConfigurations 50 | 51 | 52 | IDESourceControlRepositoryExtensionIdentifierKey 53 | public.vcs.git 54 | IDESourceControlWCCIdentifierKey 55 | 7BC55E3C-50A9-4F6E-BE4C-D4B5F011EC6B 56 | IDESourceControlWCCName 57 | badvpn 58 | 59 | 60 | IDESourceControlRepositoryExtensionIdentifierKey 61 | public.vcs.git 62 | IDESourceControlWCCIdentifierKey 63 | 72CEDF93-3DC8-4ED5-8D90-D887BCE9A1C6 64 | IDESourceControlWCCName 65 | CocoaAsyncSocket 66 | 67 | 68 | IDESourceControlRepositoryExtensionIdentifierKey 69 | public.vcs.git 70 | IDESourceControlWCCIdentifierKey 71 | B1DFC0A1-0D57-426D-AE3F-E8DABD0942E5 72 | IDESourceControlWCCName 73 | libplist 74 | 75 | 76 | IDESourceControlRepositoryExtensionIdentifierKey 77 | public.vcs.git 78 | IDESourceControlWCCIdentifierKey 79 | C72E8FC4-C6BC-42E4-A89B-F36567CFEAE4 80 | IDESourceControlWCCName 81 | libusbmuxd 82 | 83 | 84 | IDESourceControlRepositoryExtensionIdentifierKey 85 | public.vcs.git 86 | IDESourceControlWCCIdentifierKey 87 | 1B8752AE-100F-4DFD-AA86-355CF0392E0A 88 | IDESourceControlWCCName 89 | ProxyKit 90 | 91 | 92 | IDESourceControlRepositoryExtensionIdentifierKey 93 | public.vcs.git 94 | IDESourceControlWCCIdentifierKey 95 | 0ED34DCF-5560-47B6-B675-5A8237DA9A1A 96 | IDESourceControlWCCName 97 | Tether-iOS 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Tether/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | Default 522 | 523 | 524 | 525 | 526 | 527 | 528 | Left to Right 529 | 530 | 531 | 532 | 533 | 534 | 535 | Right to Left 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | Default 547 | 548 | 549 | 550 | 551 | 552 | 553 | Left to Right 554 | 555 | 556 | 557 | 558 | 559 | 560 | Right to Left 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | -------------------------------------------------------------------------------- /Tether/CBAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CBAppDelegate.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CBAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Tether/CBAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CBAppDelegate.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "CBAppDelegate.h" 10 | #import "SOCKSProxy.h" 11 | #import "CBRootViewController.h" 12 | 13 | @implementation CBAppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | self.window.backgroundColor = [UIColor whiteColor]; 20 | self.window.rootViewController = [[CBRootViewController alloc] init]; 21 | [self.window makeKeyAndVisible]; 22 | 23 | return YES; 24 | } 25 | 26 | - (void)applicationWillResignActive:(UIApplication *)application 27 | { 28 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 29 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 30 | } 31 | 32 | - (void)applicationDidEnterBackground:(UIApplication *)application 33 | { 34 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 35 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 36 | } 37 | 38 | - (void)applicationWillEnterForeground:(UIApplication *)application 39 | { 40 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 41 | } 42 | 43 | - (void)applicationDidBecomeActive:(UIApplication *)application 44 | { 45 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 46 | } 47 | 48 | - (void)applicationWillTerminate:(UIApplication *)application 49 | { 50 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Tether/CBDeviceConnection.h: -------------------------------------------------------------------------------- 1 | // 2 | // CBDeviceConnection.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/10/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "USBMuxClient.h" 11 | #import "USBMuxDeviceConnection.h" 12 | #import "GCDAsyncSocket.h" 13 | 14 | @class CBDeviceConnection; 15 | 16 | @protocol CBDeviceConnectionDelegate 17 | @optional 18 | - (void) connection:(CBDeviceConnection*)connection didWriteDataToLength:(NSUInteger)length; 19 | - (void) connection:(CBDeviceConnection*)connection didReadData:(NSData*)data; 20 | @end 21 | 22 | @interface CBDeviceConnection : NSObject 23 | 24 | @property (nonatomic, strong) USBMuxDeviceConnection *deviceConnection; 25 | @property (nonatomic, strong) GCDAsyncSocket *socket; 26 | @property (nonatomic, weak) id delegate; 27 | @property (nonatomic) dispatch_queue_t delegateQueue; 28 | 29 | - (id) initWithDeviceConnection:(USBMuxDeviceConnection*)connection socket:(GCDAsyncSocket*)socket; 30 | 31 | - (void) disconnect; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Tether/CBDeviceConnection.m: -------------------------------------------------------------------------------- 1 | // 2 | // CBDeviceConnection.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/10/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "CBDeviceConnection.h" 10 | 11 | #define DEVICE_CONNECTION_RECEIVE_TAG 100 12 | #define LOCAL_SOCKET_READ_TAG 200 13 | #define LOCAL_SOCKET_WRITE_TAG 201 14 | 15 | @implementation CBDeviceConnection 16 | 17 | - (void) dealloc { 18 | [self disconnect]; 19 | } 20 | 21 | - (id) initWithDeviceConnection:(USBMuxDeviceConnection*)connection socket:(GCDAsyncSocket*)socket { 22 | if (self = [super init]) { 23 | _deviceConnection = connection; 24 | _deviceConnection.delegate = self; 25 | _socket = socket; 26 | _socket.delegate = self; 27 | [_socket readDataWithTimeout:-1 tag:LOCAL_SOCKET_READ_TAG]; 28 | self.delegateQueue = dispatch_get_main_queue(); 29 | } 30 | return self; 31 | } 32 | 33 | - (void) socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { 34 | //NSLog(@"local socket %@ did read %ld data: %@", sock, tag, data); 35 | [_deviceConnection writeData:data tag:tag]; 36 | [_deviceConnection readDataWithTimeout:-1 tag:tag]; 37 | [sock readDataWithTimeout:-1 tag:LOCAL_SOCKET_READ_TAG]; 38 | } 39 | 40 | - (void) socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag { 41 | //NSLog(@"local socket %@ did write data with tag: %ld", sock, tag); 42 | [_socket readDataWithTimeout:-1 tag:LOCAL_SOCKET_WRITE_TAG]; 43 | } 44 | 45 | - (void) connection:(USBMuxDeviceConnection*)connection didReadData:(NSData *)data tag:(long)tag { 46 | //NSLog(@"connection %@ did receive data %ld: %@", connection, tag, data); 47 | [_socket writeData:data withTimeout:-1 tag:LOCAL_SOCKET_WRITE_TAG]; 48 | [connection readDataWithTimeout:-1 tag:tag]; 49 | if (_delegate && [_delegate respondsToSelector:@selector(connection:didReadData:)]) { 50 | [_delegate connection:self didReadData:data]; 51 | } 52 | } 53 | 54 | - (void) connection:(USBMuxDeviceConnection*)connection didWriteDataToLength:(NSUInteger)length tag:(long)tag { 55 | //NSLog(@"connection %@ did write data %ld to length: %lu", connection, tag, (unsigned long)length); 56 | if (_delegate && [_delegate respondsToSelector:@selector(connection:didWriteDataToLength:)]) { 57 | [_delegate connection:self didWriteDataToLength:length]; 58 | } 59 | } 60 | 61 | 62 | - (void) disconnect { 63 | if (self.deviceConnection) { 64 | [self.deviceConnection disconnect]; 65 | self.deviceConnection.delegate = nil; 66 | self.deviceConnection = nil; 67 | } 68 | if (self.socket) { 69 | [self.socket disconnect]; 70 | self.socket.delegate = nil; 71 | self.socket = nil; 72 | } 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /Tether/CBDeviceWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CBDeviceWindowController.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/9/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "USBMuxClient.h" 11 | #import "GCDAsyncSocket.h" 12 | #import "CBDeviceConnection.h" 13 | 14 | @interface CBDeviceWindowController : NSWindowController 15 | 16 | @property (strong) IBOutlet NSTableView *deviceTableView; 17 | @property (nonatomic, strong) NSMutableOrderedSet *devices; 18 | @property (strong) IBOutlet NSButton *connectButton; 19 | @property (strong) IBOutlet NSButton *refreshButton; 20 | @property (nonatomic, strong) GCDAsyncSocket *listeningSocket; 21 | @property (nonatomic, strong) NSMutableDictionary *deviceConnections; 22 | @property (strong) IBOutlet NSTextField *remotePortField; 23 | @property (strong) IBOutlet NSTextField *localPortField; 24 | @property (nonatomic, strong) USBMuxDevice *selectedDevice; 25 | 26 | @property (nonatomic) NSUInteger totalBytesRead; 27 | @property (nonatomic) NSUInteger totalBytesWritten; 28 | 29 | - (IBAction)refreshButtonPressed:(id)sender; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Tether/CBDeviceWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CBDeviceWindowController.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/9/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "CBDeviceWindowController.h" 10 | #import "USBMuxClient.h" 11 | #import "USBMuxDevice.h" 12 | #import "CBDeviceConnection.h" 13 | #import 14 | #import 15 | #import "Actions.h" 16 | 17 | const static uint16_t kDefaultLocalPortNumber = 8000; 18 | const static uint16_t kDefaultRemotePortNumber = 8123; 19 | 20 | @interface CBDeviceWindowController () 21 | @end 22 | 23 | @implementation CBDeviceWindowController 24 | @synthesize devices, deviceTableView, listeningSocket, remotePortField, localPortField, deviceConnections; 25 | 26 | - (void) device:(USBMuxDevice *)device statusDidChange:(USBDeviceStatus)deviceStatus { 27 | NSLog(@"device: %@ status: %d", device.udid, deviceStatus); 28 | if (deviceStatus == kUSBMuxDeviceStatusAdded) { 29 | [devices addObject:device]; 30 | } else if (deviceStatus == kUSBMuxDeviceStatusRemoved) { 31 | [self setConnections:nil forDevice:device]; 32 | } 33 | [self refreshSelectedDevice]; 34 | } 35 | 36 | - (NSMutableSet*) connectionsForDevice:(USBMuxDevice*)device { 37 | NSString *udid = [device.udid copy]; 38 | NSMutableSet *connections = [deviceConnections objectForKey:udid]; 39 | if (!connections) { 40 | connections = [NSMutableSet set]; 41 | [deviceConnections setObject:connections forKey:udid]; 42 | } 43 | return [deviceConnections objectForKey:device.udid]; 44 | } 45 | 46 | - (void) setConnections:(NSMutableSet*)connections forDevice:(USBMuxDevice*)device { 47 | if (!connections) { 48 | NSMutableSet *connections = [self.deviceConnections objectForKey:device.udid]; 49 | [connections enumerateObjectsUsingBlock:^(CBDeviceConnection *connection, BOOL *stop) { 50 | [connection disconnect]; 51 | }]; 52 | [self.deviceConnections removeObjectForKey:device.udid]; 53 | return; 54 | } 55 | [self.deviceConnections setObject:connections forKey:device.udid]; 56 | } 57 | 58 | - (void) disconnectConnectionsForDevice:(USBMuxDevice*)device { 59 | [self setConnections:nil forDevice:device]; 60 | } 61 | 62 | - (void) refreshSelectedDevice { 63 | [deviceTableView reloadData]; 64 | if (self.deviceTableView.numberOfSelectedRows == 0 && self.devices.count > 0) { 65 | self.selectedDevice = devices[0]; 66 | } 67 | if (self.selectedDevice) { 68 | NSUInteger selectedIndex = [devices indexOfObject:self.selectedDevice]; 69 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:selectedIndex]; 70 | [deviceTableView selectRowIndexes:indexSet byExtendingSelection:NO]; 71 | } 72 | } 73 | 74 | 75 | - (NSString*) windowNibName { 76 | return NSStringFromClass([self class]); 77 | } 78 | 79 | - (id)initWithWindow:(NSWindow *)window 80 | { 81 | self = [super initWithWindow:window]; 82 | if (self) { 83 | self.devices = [NSMutableOrderedSet orderedSetWithCapacity:1]; 84 | self.deviceConnections = [NSMutableDictionary dictionary]; 85 | self.totalBytesRead = 0; 86 | self.totalBytesWritten = 0; 87 | } 88 | return self; 89 | } 90 | 91 | - (void)windowDidLoad 92 | { 93 | [super windowDidLoad]; 94 | 95 | self.deviceTableView.dataSource = self; 96 | self.deviceTableView.delegate = self; 97 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 98 | [USBMuxClient sharedClient].delegate = self; 99 | [self performSelector:@selector(refreshButtonPressed:) withObject:nil afterDelay:0.1]; // for whatever reason 100 | 101 | NSString *helperLabel = @"com.chrisballinger.CBTunService"; 102 | 103 | NSError *error = nil; 104 | if (![self blessHelperWithLabel:helperLabel error:&error]) { 105 | NSLog(@"Failed to bless helper. Error: %@", error); 106 | } 107 | 108 | NSXPCConnection *connection = [[NSXPCConnection alloc] initWithMachServiceName:helperLabel options:NSXPCConnectionPrivileged]; 109 | connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(TunHandler)]; 110 | [connection resume]; 111 | 112 | id tunHandler = [connection remoteObjectProxyWithErrorHandler:^(NSError *error) { 113 | NSLog(@"Something bad happened, %@", [error description]); 114 | }]; 115 | [tunHandler openTun:^(NSFileHandle *tun, NSError *error) { 116 | if (tun) { 117 | [tunHandler readData:^(NSData *data, NSError *error) { 118 | if (data) { 119 | NSLog(@"read data: %@", data); 120 | } else { 121 | NSLog(@"dataread err: %@", error); 122 | } 123 | }]; 124 | NSLog(@"Got handle: %@\nfd: %d", tun, tun.fileDescriptor); 125 | } else { 126 | NSLog(@"Couldn't get handle: %@", error); 127 | } 128 | }]; 129 | 130 | } 131 | 132 | // HexFiend has a great example how to do this properly 133 | - (BOOL)blessHelperWithLabel:(NSString *)label 134 | error:(NSError **)error { 135 | 136 | BOOL result = NO; 137 | 138 | /* Always remove the job if we've previously submitted it. This is to help with versioning (we always install the latest tool). It also avoids conflicts where the installed tool was signed with a different key (i.e. someone building Hex Fiend while also having run the signed distribution). A potentially negative consequence is that we have to authenticate every launch, but that is actually a benefit, because it serves as a sort of notification that user's action requires elevated privileges, instead of just (potentially silently) doing it. */ 139 | BOOL helperIsAlreadyInstalled = NO; 140 | CFDictionaryRef existingJob = SMJobCopyDictionary(kSMDomainSystemLaunchd, (__bridge CFStringRef)(label)); 141 | if (existingJob) { 142 | helperIsAlreadyInstalled = YES; 143 | CFRelease(existingJob); 144 | } 145 | 146 | AuthorizationItem authItems[2] = {{ kSMRightBlessPrivilegedHelper, 0, NULL, 0 }, { kSMRightModifySystemDaemons, 0, NULL, 0 }}; 147 | AuthorizationRights authRights = { (helperIsAlreadyInstalled ? 2 : 1), authItems }; 148 | AuthorizationFlags flags = kAuthorizationFlagDefaults | 149 | kAuthorizationFlagInteractionAllowed | 150 | kAuthorizationFlagPreAuthorize | 151 | kAuthorizationFlagExtendRights; 152 | 153 | AuthorizationRef authRef = NULL; 154 | 155 | /* Obtain the right to install privileged helper tools (kSMRightBlessPrivilegedHelper). */ 156 | OSStatus status = AuthorizationCreate(&authRights, kAuthorizationEmptyEnvironment, flags, &authRef); 157 | if (status != errAuthorizationSuccess) { 158 | if (error) { 159 | if (status == errAuthorizationCanceled) { 160 | *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]; 161 | } else { 162 | NSString *description = [NSString stringWithFormat:@"Failed to create AuthorizationRef (error code %ld).", (long)status]; 163 | *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadNoPermissionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:description, NSLocalizedDescriptionKey, nil]]; 164 | } 165 | } 166 | return NO; 167 | } 168 | 169 | /* This does all the work of verifying the helper tool against the application 170 | * and vice-versa. Once verification has passed, the embedded launchd.plist 171 | * is extracted and placed in /Library/LaunchDaemons and then loaded. The 172 | * executable is placed in /Library/PrivilegedHelperTools. 173 | */ 174 | 175 | /* Remove the existing helper. If this fails it's not a fatal error (SMJobBless can handle the case when a job is already installed). */ 176 | if (helperIsAlreadyInstalled) { 177 | CFErrorRef localError = NULL; 178 | SMJobRemove(kSMDomainSystemLaunchd, (__bridge CFStringRef)(label), authRef, true /* wait */, &localError); 179 | if (localError) { 180 | NSLog(@"SMJobRemove() failed with error %@", localError); 181 | CFRelease(localError); 182 | } 183 | } 184 | 185 | 186 | CFErrorRef localError = NULL; 187 | result = SMJobBless(kSMDomainSystemLaunchd, (__bridge CFStringRef)label, authRef, (CFErrorRef *)&localError); 188 | if (localError) { 189 | if (error) { 190 | *error = (__bridge NSError*)localError; 191 | } 192 | CFRelease(localError); 193 | } 194 | 195 | return result; 196 | } 197 | 198 | 199 | 200 | // The only essential/required tableview dataSource method 201 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { 202 | return devices.count; 203 | } 204 | 205 | // This method is optional if you use bindings to provide the data 206 | - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { 207 | // Group our "model" object, which is a dictionary 208 | USBMuxDevice *device = [devices objectAtIndex:row]; 209 | 210 | // In IB the tableColumn has the identifier set to the same string as the keys in our dictionary 211 | NSString *identifier = [tableColumn identifier]; 212 | NSTableCellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; 213 | NSColor *textColor = [NSColor textColor]; 214 | if (!device.isVisible) { 215 | textColor = [NSColor lightGrayColor]; 216 | } 217 | cellView.textField.textColor = textColor; 218 | if ([identifier isEqualToString:@"ProductIDCell"]) { 219 | // We pass us as the owner so we can setup target/actions into this main controller object 220 | // Then setup properties on the cellView based on the column 221 | cellView.textField.stringValue = [NSString stringWithFormat:@"%d", device.productID]; 222 | return cellView; 223 | } else if ([identifier isEqualToString:@"UDIDCell"]) { 224 | cellView.textField.stringValue = device.udid; 225 | } else { 226 | NSAssert1(NO, @"Unhandled table column identifier %@", identifier); 227 | return nil; 228 | } 229 | return cellView; 230 | } 231 | 232 | - (IBAction)refreshButtonPressed:(id)sender { 233 | if (self.listeningSocket) { 234 | NSLog(@"Disconnecting local socket"); 235 | [self.listeningSocket disconnect]; 236 | self.listeningSocket.delegate = nil; 237 | self.listeningSocket = nil; 238 | } 239 | [USBMuxClient getDeviceListWithCompletion:^(NSArray *deviceList, NSError *error) { 240 | if (error) { 241 | NSLog(@"Error getting device list: %@", error.userInfo); 242 | } 243 | for (USBMuxDevice *device in deviceList) { 244 | [devices addObject:device]; 245 | } 246 | [self refreshSelectedDevice]; 247 | 248 | USBMuxDevice *device = self.selectedDevice; 249 | if (!device) { 250 | NSLog(@"No devices selected, aborting the start of local socket"); 251 | return; 252 | } 253 | 254 | self.listeningSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; 255 | error = nil; 256 | uint16_t localPort = [self customOrDefaultLocalPort]; 257 | [listeningSocket acceptOnPort:localPort error:&error]; 258 | if (error) { 259 | NSLog(@"Error listening on port %d", localPort); 260 | } 261 | NSLog(@"Listening on local port %d for new connections", localPort); 262 | }]; 263 | } 264 | 265 | - (uint16_t) customOrDefaultLocalPort { 266 | uint16_t localPort = kDefaultLocalPortNumber; 267 | uint16_t localPortFieldValue = (uint16_t)localPortField.integerValue; 268 | if (localPortFieldValue > 0) { 269 | localPort = localPortFieldValue; 270 | } 271 | return localPort; 272 | } 273 | 274 | - (uint16_t) customOrDefaultRemotePort { 275 | uint16_t remotePort = kDefaultRemotePortNumber; 276 | uint16_t remotePortFieldValue = (uint16_t)remotePortField.integerValue; 277 | if (remotePortFieldValue > 0) { 278 | remotePort = remotePortFieldValue; 279 | } 280 | return remotePort; 281 | } 282 | 283 | - (void) socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket { 284 | if (!self.selectedDevice.isVisible) { 285 | NSLog(@"selected device no longer visible, aborting connection"); 286 | [sock disconnect]; 287 | [newSocket disconnect]; 288 | return; 289 | } 290 | NSLog(@"new local connection accepted on %@:%d", [newSocket localHost], [newSocket localPort]); 291 | uint16_t remotePort = [self customOrDefaultRemotePort]; 292 | NSString *deviceUUID = [self.selectedDevice.udid copy]; 293 | 294 | [_selectedDevice connectToPort:remotePort completionBlock:^(USBMuxDeviceConnection *connection, NSError *error) { 295 | if (connection) { 296 | NSLog(@"New device connection to %@ on port %d", deviceUUID, remotePort); 297 | CBDeviceConnection *deviceConnection = [[CBDeviceConnection alloc] initWithDeviceConnection:connection socket:newSocket]; 298 | deviceConnection.delegate = self; 299 | NSMutableSet *connections = [self connectionsForDevice:connection.device]; 300 | [connections addObject:deviceConnection]; 301 | } else { 302 | NSLog(@"Error connecting to device %@ on port %d: %@", deviceUUID, remotePort, error); 303 | } 304 | }]; 305 | } 306 | 307 | - (void) connection:(CBDeviceConnection *)connection didReadData:(NSData *)data { 308 | _totalBytesRead += data.length; 309 | //NSLog(@"total bytes read: %lu", (unsigned long)_totalBytesRead); 310 | } 311 | 312 | - (void) connection:(CBDeviceConnection *)connection didWriteDataToLength:(NSUInteger)length { 313 | _totalBytesWritten += length; 314 | //NSLog(@"total bytes written: %lu", (unsigned long)_totalBytesWritten); 315 | } 316 | 317 | @end 318 | -------------------------------------------------------------------------------- /Tether/CBDeviceWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 116 | 120 | 121 | 122 | 123 | 124 | 125 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /Tether/CBMacAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CBMacAppDelegate.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/9/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CBDeviceWindowController.h" 11 | 12 | @interface CBMacAppDelegate : NSObject 13 | 14 | @property (nonatomic, strong) CBDeviceWindowController *deviceWindowController; 15 | 16 | @end -------------------------------------------------------------------------------- /Tether/CBMacAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CBMacAppDelegate.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/9/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "CBMacAppDelegate.h" 10 | #import "CBDeviceWindowController.h" 11 | 12 | @implementation CBMacAppDelegate 13 | @synthesize deviceWindowController; 14 | 15 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 16 | { 17 | self.deviceWindowController = [[CBDeviceWindowController alloc] init]; 18 | [self.deviceWindowController.window makeKeyAndOrderFront:self]; 19 | } 20 | 21 | - (void) applicationWillTerminate:(NSNotification *)notification { 22 | NSLog(@"Application will terminate"); 23 | } 24 | 25 | @end -------------------------------------------------------------------------------- /Tether/CBNetworkServiceEditor.h: -------------------------------------------------------------------------------- 1 | // 2 | // CBNetworkServiceEditor.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 3/31/14. 6 | // Copyright (c) 2014 Christopher Ballinger. All rights reserved. 7 | // 8 | // http://stackoverflow.com/a/6375307/805882 9 | 10 | #import 11 | 12 | @interface CBNetworkServiceEditor : NSObject 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Tether/CBNetworkServiceEditor.m: -------------------------------------------------------------------------------- 1 | // 2 | // CBNetworkServiceEditor.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 3/31/14. 6 | // Copyright (c) 2014 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "CBNetworkServiceEditor.h" 10 | 11 | static NSString * const kPreferencesFilePath = @"/Library/Preferences/SystemConfiguration/preferences.plist"; 12 | 13 | @interface CBNetworkServiceEditor() 14 | @property (nonatomic, strong) NSDictionary *preferencesDictionary; 15 | @end 16 | 17 | @implementation CBNetworkServiceEditor 18 | 19 | - (id) init { 20 | if (self = [super init]) { 21 | 22 | } 23 | return self; 24 | } 25 | 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Tether/CBRootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CBRootViewController.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SOCKSProxy.h" 11 | 12 | @interface CBRootViewController : UIViewController 13 | 14 | @property (nonatomic, strong) UILabel *connectionCountLabel; 15 | @property (nonatomic, strong) UILabel *totalBytesWrittenLabel; 16 | @property (nonatomic, strong) UILabel *totalBytesReadLabel; 17 | @property (nonatomic, strong) SOCKSProxy *socksProxy; 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Tether/CBRootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CBRootViewController.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "CBRootViewController.h" 10 | #import "UIView+AutoLayout.h" 11 | #import "FormatterKit/TTTUnitOfInformationFormatter.h" 12 | 13 | @interface CBRootViewController () 14 | @property (nonatomic, strong) NSTimer *refreshTimer; 15 | @property (nonatomic, strong) TTTUnitOfInformationFormatter *dataFormatter; 16 | @end 17 | 18 | @implementation CBRootViewController 19 | 20 | - (id)init 21 | { 22 | self = [super init]; 23 | if (self) { 24 | self.socksProxy = [[SOCKSProxy alloc] init]; 25 | [_socksProxy startProxyOnPort:8123]; 26 | [self setupDataFormatter]; 27 | } 28 | return self; 29 | } 30 | 31 | - (void) setupDataFormatter { 32 | self.dataFormatter = [[TTTUnitOfInformationFormatter alloc] init]; 33 | } 34 | 35 | - (void) refreshTimerDidFire:(NSTimer*)timer { 36 | NSNumber *bytesRead = @(self.socksProxy.totalBytesRead); 37 | NSNumber *bytesWritten = @(self.socksProxy.totalBytesWritten); 38 | self.totalBytesReadLabel.text = [NSString stringWithFormat:@"Bytes read: %@", [self.dataFormatter stringFromNumber:bytesRead ofUnit:TTTByte]]; 39 | self.totalBytesWrittenLabel.text = [NSString stringWithFormat:@"Bytes written: %@", [self.dataFormatter stringFromNumber:bytesWritten ofUnit:TTTByte]]; 40 | self.connectionCountLabel.text = [NSString stringWithFormat:@"Connections: %d", self.socksProxy.connectionCount]; 41 | } 42 | 43 | - (void)viewDidLoad 44 | { 45 | [super viewDidLoad]; 46 | 47 | [self setupBytesReadLabel]; 48 | [self setupBytesWrittenLabel]; 49 | [self setupConnectionCountLabel]; 50 | 51 | // Do any additional setup after loading the view. 52 | self.refreshTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(refreshTimerDidFire:) userInfo:nil repeats:YES]; 53 | 54 | } 55 | 56 | - (void) setupBytesReadLabel { 57 | self.totalBytesReadLabel = [[UILabel alloc] init]; 58 | [self setupLabel:self.totalBytesReadLabel]; 59 | [self.totalBytesReadLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:20.0f]; 60 | } 61 | 62 | - (void) setupLabel:(UILabel*)label { 63 | label.translatesAutoresizingMaskIntoConstraints = NO; 64 | [self.view addSubview:label]; 65 | [label autoSetDimensionsToSize:[self labelSize]]; 66 | [label autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:10.0f]; 67 | } 68 | 69 | - (void) setupBytesWrittenLabel { 70 | self.totalBytesWrittenLabel = [[UILabel alloc] init]; 71 | [self setupLabel:self.totalBytesWrittenLabel]; 72 | [self.totalBytesWrittenLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.totalBytesReadLabel]; 73 | } 74 | 75 | - (void) setupConnectionCountLabel { 76 | self.connectionCountLabel = [[UILabel alloc] init]; 77 | [self setupLabel:self.connectionCountLabel]; 78 | [self.connectionCountLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.totalBytesWrittenLabel]; 79 | } 80 | 81 | - (CGSize) labelSize { 82 | return CGSizeMake(200, 30); 83 | } 84 | 85 | - (void)didReceiveMemoryWarning 86 | { 87 | [super didReceiveMemoryWarning]; 88 | // Dispose of any resources that can be recreated. 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /Tether/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Tether/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /Tether/Tether-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.chrisballinger.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIBackgroundModes 28 | 29 | voip 30 | 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Tether/Tether-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Tether/TetherMac-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.chrisballinger.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2013 Christopher Ballinger. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | SMPrivilegedExecutables 32 | 33 | com.chrisballinger.CBTunService 34 | identifier com.chrisballinger.CBTunService and certificate leaf[subject.CN] = "3rd Party Mac Developer Application" 35 | 36 | NSPrincipalClass 37 | NSApplication 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tether/TetherMac-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /Tether/USBMuxClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // USBMuxClient.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/10/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(int16_t, USBDeviceStatus) { 12 | kUSBMuxDeviceStatusRemoved = 0, 13 | kUSBMuxDeviceStatusAdded = 1 14 | }; 15 | 16 | @class USBMuxDevice, USBMuxDeviceConnection; 17 | 18 | typedef void(^USBMuxDeviceCompletionBlock)(BOOL success, NSError *error); 19 | typedef void(^USBMuxDeviceDeviceListBlock)(NSArray *deviceList, NSError *error); 20 | 21 | 22 | @protocol USBMuxClientDelegate 23 | @optional 24 | - (void) device:(USBMuxDevice*)device statusDidChange:(USBDeviceStatus)deviceStatus; 25 | @end 26 | 27 | @interface USBMuxClient : NSObject 28 | 29 | /** 30 | Queue for all network calls. (defaults to global default background queue) 31 | */ 32 | @property (nonatomic) dispatch_queue_t networkQueue; 33 | 34 | /** 35 | Queue for all callbacks. (defaults to main queue) 36 | */ 37 | @property (nonatomic) dispatch_queue_t callbackQueue; 38 | 39 | 40 | @property (nonatomic, strong) NSDictionary *devices; 41 | 42 | @property (nonatomic, weak) id delegate; 43 | 44 | + (void) getDeviceListWithCompletion:(USBMuxDeviceDeviceListBlock)completionBlock; 45 | 46 | + (USBMuxClient*) sharedClient; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Tether/USBMuxClient.m: -------------------------------------------------------------------------------- 1 | // 2 | // USBMuxClient.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/10/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "USBMuxClient.h" 10 | #import "USBMuxDevice.h" 11 | #import "USBMuxDeviceConnection.h" 12 | #import 13 | 14 | static NSString * const kUSBMuxDeviceErrorDomain = @"kUSBMuxDeviceErrorDomain"; 15 | 16 | 17 | @interface USBMuxClient(Private) 18 | @property (nonatomic, strong) NSMutableDictionary *devices; 19 | + (USBMuxDevice*) nativeDeviceForDevice:(usbmuxd_device_info_t)device; 20 | @end 21 | 22 | static void usbmuxdEventCallback(const usbmuxd_event_t *event, void *user_data) { 23 | usbmuxd_device_info_t device = event->device; 24 | 25 | USBMuxDevice *nativeDevice = [USBMuxClient nativeDeviceForDevice:device]; 26 | 27 | USBDeviceStatus deviceStatus = -1; 28 | if (event->event == UE_DEVICE_ADD) { 29 | deviceStatus = kUSBMuxDeviceStatusAdded; 30 | nativeDevice.isVisible = YES; 31 | } else if (event->event == UE_DEVICE_REMOVE) { 32 | deviceStatus = kUSBMuxDeviceStatusRemoved; 33 | nativeDevice.isVisible = NO; 34 | [nativeDevice disconnect]; 35 | } 36 | 37 | id delegate = [USBMuxClient sharedClient].delegate; 38 | if (delegate && [delegate respondsToSelector:@selector(device:statusDidChange:)]) { 39 | dispatch_async([USBMuxClient sharedClient].callbackQueue, ^{ 40 | [delegate device:nativeDevice statusDidChange:deviceStatus]; 41 | }); 42 | } 43 | } 44 | 45 | @implementation USBMuxClient 46 | @synthesize delegate, callbackQueue, networkQueue, devices; 47 | 48 | - (void) dealloc { 49 | usbmuxd_unsubscribe(); 50 | } 51 | 52 | - (id) init { 53 | if (self = [super init]) { 54 | self.devices = [NSMutableDictionary dictionary]; 55 | self.networkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 56 | self.callbackQueue = dispatch_get_main_queue(); 57 | usbmuxd_subscribe(usbmuxdEventCallback, NULL); 58 | } 59 | return self; 60 | } 61 | 62 | + (NSError*) errorWithDescription:(NSString*)description code:(NSInteger)code { 63 | return [NSError errorWithDomain:kUSBMuxDeviceErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey:description}]; 64 | } 65 | 66 | + (USBMuxDevice*) nativeDeviceForDevice:(usbmuxd_device_info_t)device { 67 | NSMutableDictionary *devices = (NSMutableDictionary*)[USBMuxClient sharedClient].devices; 68 | NSString *udid = [NSString stringWithUTF8String:device.udid]; 69 | USBMuxDevice *nativeDevice = [devices objectForKey:udid]; 70 | if (!nativeDevice) { 71 | nativeDevice = [[USBMuxDevice alloc] init]; 72 | nativeDevice.udid = [NSString stringWithUTF8String:device.udid]; 73 | nativeDevice.productID = device.product_id; 74 | [devices setObject:nativeDevice forKey:nativeDevice.udid]; 75 | } 76 | nativeDevice.handle = device.handle; 77 | return nativeDevice; 78 | } 79 | 80 | + (void) getDeviceListWithCompletion:(USBMuxDeviceDeviceListBlock)completionBlock { 81 | dispatch_async([USBMuxClient sharedClient].networkQueue, ^{ 82 | usbmuxd_device_info_t *deviceList = NULL; 83 | int deviceListCount = usbmuxd_get_device_list(&deviceList); 84 | if (deviceListCount < 0 || !deviceList) { 85 | if (completionBlock) { 86 | dispatch_async([USBMuxClient sharedClient].callbackQueue, ^{ 87 | completionBlock(nil, [self errorWithDescription:@"Couldn't get device list." code:102]); 88 | }); 89 | } 90 | return; 91 | } 92 | NSMutableArray *devices = [NSMutableArray arrayWithCapacity:deviceListCount]; 93 | for (int i = 0; i < deviceListCount; i++) { 94 | usbmuxd_device_info_t device = deviceList[i]; 95 | USBMuxDevice *nativeDevice = [USBMuxClient nativeDeviceForDevice:device]; 96 | nativeDevice.isVisible = YES; 97 | [devices addObject:nativeDevice]; 98 | } 99 | 100 | if (completionBlock) { 101 | dispatch_async([USBMuxClient sharedClient].callbackQueue, ^{ 102 | completionBlock(devices, nil); 103 | }); 104 | } 105 | free(deviceList); 106 | }); 107 | } 108 | 109 | + (USBMuxClient*) sharedClient { 110 | static dispatch_once_t onceToken; 111 | static USBMuxClient *_sharedClient = nil; 112 | dispatch_once(&onceToken, ^{ 113 | _sharedClient = [[USBMuxClient alloc] init]; 114 | }); 115 | return _sharedClient; 116 | } 117 | 118 | 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /Tether/USBMuxDevice.h: -------------------------------------------------------------------------------- 1 | // 2 | // USBMuxDevice.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "USBMuxDeviceConnection.h" 11 | 12 | @interface USBMuxDevice : NSObject 13 | 14 | @property (nonatomic) NSString *udid; 15 | @property (nonatomic) int productID; 16 | @property (nonatomic) uint32_t handle; 17 | @property (nonatomic) BOOL isVisible; 18 | @property (nonatomic) dispatch_queue_t callbackQueue; 19 | 20 | /** 21 | * If successful creates a new USBMuxDeviceConnection and adds it to the set of active connections 22 | **/ 23 | - (void) connectToPort:(uint16_t)port completionBlock:(void(^)(USBMuxDeviceConnection *connection, NSError *error))completionBlock; 24 | - (void) disconnect; 25 | 26 | @end -------------------------------------------------------------------------------- /Tether/USBMuxDevice.m: -------------------------------------------------------------------------------- 1 | // 2 | // USBMuxDevice.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "USBMuxDevice.h" 10 | 11 | @interface USBMuxDevice() 12 | @property (nonatomic, strong) NSMutableSet *activeConnections; 13 | @property (nonatomic) dispatch_queue_t connectionQueue; 14 | @end 15 | 16 | @implementation USBMuxDevice 17 | 18 | - (id) init { 19 | if (self = [super init]) { 20 | _activeConnections = [NSMutableSet set]; 21 | _connectionQueue = dispatch_queue_create("USBMuxDevice connection queue", 0); 22 | _callbackQueue = dispatch_get_main_queue(); 23 | } 24 | return self; 25 | } 26 | 27 | - (void) connectToPort:(uint16_t)port completionBlock:(void(^)(USBMuxDeviceConnection *connection, NSError *error))completionBlock { 28 | USBMuxDeviceConnection *connection = [[USBMuxDeviceConnection alloc] initWithDevice:self]; 29 | connection.callbackQueue = _connectionQueue; 30 | connection.delegate = self; 31 | [connection connectToPort:port completionBlock:^(BOOL success, NSError *error) { 32 | if (success) { 33 | [_activeConnections addObject:connection]; 34 | if (completionBlock) { 35 | dispatch_async(_callbackQueue, ^{ 36 | completionBlock(connection, nil); 37 | }); 38 | } 39 | } else { 40 | if (completionBlock) { 41 | dispatch_async(_callbackQueue, ^{ 42 | completionBlock(nil, error); 43 | }); 44 | } 45 | } 46 | }]; 47 | } 48 | 49 | - (void) connectionDidDisconnect:(USBMuxDeviceConnection *)connection withError:(NSError *)error { 50 | dispatch_async(_connectionQueue, ^{ 51 | if (error) { 52 | NSLog(@"%@ did disconnect with error: %@", connection, error); 53 | } 54 | [_activeConnections removeObject:connection]; 55 | }); 56 | } 57 | 58 | - (void) disconnect { 59 | [_activeConnections enumerateObjectsUsingBlock:^(USBMuxDeviceConnection *connection, BOOL *stop) { 60 | [connection disconnect]; 61 | }]; 62 | } 63 | 64 | @end -------------------------------------------------------------------------------- /Tether/USBMuxDeviceConnection.h: -------------------------------------------------------------------------------- 1 | // 2 | // USBMuxDeviceConnection.h 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class USBMuxDeviceConnection, USBMuxDevice; 12 | 13 | @protocol USBMuxDeviceConnectionDelegate 14 | @optional 15 | - (void) connection:(USBMuxDeviceConnection*)connection didReadData:(NSData *)data tag:(long)tag; 16 | - (void) connection:(USBMuxDeviceConnection*)connection didWriteDataToLength:(NSUInteger)length tag:(long)tag; 17 | - (void) connection:(USBMuxDeviceConnection*)connection didConnectToPort:(uint16_t)port; 18 | - (void) connectionDidDisconnect:(USBMuxDeviceConnection*)connection withError:(NSError*)error; 19 | @end 20 | 21 | @interface USBMuxDeviceConnection : NSObject 22 | 23 | @property (nonatomic, weak) USBMuxDevice *device; 24 | @property (nonatomic) uint16_t port; 25 | @property (nonatomic, weak) id delegate; 26 | @property (nonatomic) dispatch_queue_t callbackQueue; 27 | @property (nonatomic) dispatch_queue_t networkReadQueue; 28 | @property (nonatomic) dispatch_queue_t networkWriteQueue; 29 | @property (nonatomic, readonly) BOOL isConnected; 30 | 31 | - (id) initWithDevice:(USBMuxDevice*)device; 32 | 33 | - (void) writeData:(NSData*)data tag:(long)tag; 34 | - (void) readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag; 35 | - (void) connectToPort:(uint16_t)port completionBlock:(void(^)(BOOL success, NSError *error))completionBlock; 36 | - (void) disconnect; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Tether/USBMuxDeviceConnection.m: -------------------------------------------------------------------------------- 1 | // 2 | // USBMuxDeviceConnection.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import "USBMuxDeviceConnection.h" 10 | #import "usbmuxd.h" 11 | #import 12 | #import "USBMuxDevice.h" 13 | 14 | @interface USBMuxDeviceConnection() 15 | @property (nonatomic) int socketFileDescriptor; 16 | @end 17 | 18 | @implementation USBMuxDeviceConnection 19 | 20 | - (id) init { 21 | if (self = [super init]) { 22 | _networkReadQueue = dispatch_queue_create("USBMuxDevice Network Read Queue", 0); 23 | _networkWriteQueue = dispatch_queue_create("USBMuxDevice Network Write Queue", 0); 24 | _callbackQueue = dispatch_get_main_queue(); 25 | _socketFileDescriptor = 0; 26 | _isConnected = NO; 27 | } 28 | return self; 29 | } 30 | 31 | - (id) initWithDevice:(USBMuxDevice*)device { 32 | if (self = [self init]) { 33 | _device = device; 34 | } 35 | return self; 36 | } 37 | 38 | - (NSError*) errorWithDescription:(NSString*)description code:(NSInteger)code { 39 | return [NSError errorWithDomain:@"com.usbmuxd.USBMuxDeviceConnection" code:code userInfo:@{NSLocalizedDescriptionKey:description}]; 40 | } 41 | 42 | - (void) connectToPort:(uint16_t)port completionBlock:(void(^)(BOOL success, NSError *error))completionBlock { 43 | dispatch_async(_networkReadQueue, ^{ 44 | _socketFileDescriptor = usbmuxd_connect(_device.handle, port); 45 | if (_socketFileDescriptor == -1) { 46 | NSError *error = [self errorWithDescription:@"Couldn't connect device." code:100]; 47 | if (completionBlock) { 48 | dispatch_async(_callbackQueue, ^{ 49 | completionBlock(NO, error); 50 | }); 51 | } 52 | [self didDisconnectWithError:error]; 53 | return; 54 | } 55 | _isConnected = YES; 56 | if (completionBlock) { 57 | dispatch_async(_callbackQueue, ^{ 58 | completionBlock(YES, nil); 59 | }); 60 | } 61 | if (_delegate && [_delegate respondsToSelector:@selector(connection:didConnectToPort:)]) { 62 | dispatch_async(_callbackQueue, ^{ 63 | [_delegate connection:self didConnectToPort:port]; 64 | }); 65 | } 66 | }); 67 | 68 | } 69 | 70 | - (void) didDisconnectWithError:(NSError*)error { 71 | if (_delegate && [_delegate respondsToSelector:@selector(connectionDidDisconnect:withError:)]) { 72 | dispatch_async(_callbackQueue, ^{ 73 | [_delegate connectionDidDisconnect:self withError:error]; 74 | }); 75 | } 76 | } 77 | 78 | - (void) disconnectWithError:(NSError*)error { 79 | _device = nil; 80 | _delegate = nil; 81 | _isConnected = NO; 82 | int disconnectValue = usbmuxd_disconnect(_socketFileDescriptor); 83 | _socketFileDescriptor = 0; 84 | if (disconnectValue == -1) { 85 | [self didDisconnectWithError:[self errorWithDescription:@"Couldn't disconnect device connection." code:101]]; 86 | } else if (disconnectValue == 0) { 87 | [self didDisconnectWithError:error]; 88 | } else { 89 | [self didDisconnectWithError:[self errorWithDescription:@"Unknown error while disconnecting device connection." code:102]]; 90 | } 91 | } 92 | 93 | - (void) disconnect { 94 | [self disconnectWithError:nil]; 95 | } 96 | 97 | 98 | - (void) writeData:(NSData*)data tag:(long)tag { 99 | if (_socketFileDescriptor == 0) { 100 | return; 101 | } 102 | dispatch_async(_networkWriteQueue, ^{ 103 | //NSLog(@"Writing data to device socket %d: %@", _socketFileDescriptor, data); 104 | uint32_t sentBytes = 0; 105 | uint32_t totalBytes = (uint32_t)data.length; 106 | int sendValue = usbmuxd_send(_socketFileDescriptor, [data bytes], totalBytes, &sentBytes); 107 | if (sendValue == 0) { 108 | if (_delegate && [_delegate respondsToSelector:@selector(connection:didWriteDataToLength:tag:)]) { 109 | dispatch_async(_callbackQueue, ^{ 110 | [_delegate connection:self didWriteDataToLength:sentBytes tag:tag]; 111 | }); 112 | } 113 | } else { 114 | [self disconnectWithError:[self errorWithDescription:@"Error writing to socket" code:103]]; 115 | } 116 | }); 117 | } 118 | 119 | - (void) readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag { 120 | if (_socketFileDescriptor == 0) { 121 | //NSLog(@"read canceled, socket is 0"); 122 | return; 123 | } 124 | dispatch_async(_networkReadQueue, ^{ 125 | uint32_t bytesAvailable = 0; 126 | uint32_t totalBytesReceived = 0; 127 | ioctl(_socketFileDescriptor, FIONREAD, &bytesAvailable); 128 | if (bytesAvailable == 0) { 129 | //NSLog(@"no bytes available for read"); 130 | bytesAvailable = 4096; 131 | } 132 | uint8_t *buffer = malloc(bytesAvailable * sizeof(uint8_t)); 133 | int readValue = -1; 134 | if (timeout == -1) { 135 | readValue = usbmuxd_recv(_socketFileDescriptor, (char*)buffer, bytesAvailable, &totalBytesReceived); 136 | } else { 137 | readValue = usbmuxd_recv_timeout(_socketFileDescriptor, (char*)buffer, bytesAvailable, &totalBytesReceived, (int)(timeout * 1000)); 138 | } 139 | if (readValue != 0 || totalBytesReceived == 0) { 140 | //NSLog(@"Error reading on socket %d: %d", _socketFileDescriptor, readValue); 141 | free(buffer); 142 | return; 143 | } 144 | NSData *receivedData = [[NSData alloc] initWithBytesNoCopy:buffer length:totalBytesReceived freeWhenDone:YES]; 145 | if (_delegate && [_delegate respondsToSelector:@selector(connection:didReadData:tag:)]) { 146 | dispatch_async(_callbackQueue, ^{ 147 | [_delegate connection:self didReadData:receivedData tag:tag]; 148 | }); 149 | } 150 | }); 151 | } 152 | 153 | 154 | @end 155 | -------------------------------------------------------------------------------- /Tether/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /Tether/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Tether/main-mac.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/9/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | return NSApplicationMain(argc, argv); 14 | } -------------------------------------------------------------------------------- /Tether/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Tether 4 | // 5 | // Created by Christopher Ballinger on 11/30/13. 6 | // Copyright (c) 2013 Christopher Ballinger. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CBAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([CBAppDelegate class])); 17 | } 18 | } 19 | --------------------------------------------------------------------------------