├── ttdnsd ├── clean.sh ├── ttdnsd_platform.h ├── ttdnsd_platform.h.cmake ├── build.sh ├── stopConsole.cpp ├── unit_test.cpp ├── CMakeLists.txt └── ttdnsd.h ├── myipaddr.h ├── Resources ├── silence.mp3 ├── Images.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ ├── Icon-76.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon-Small@2x-1.png │ │ ├── Icon-iPadPro@2x.png │ │ ├── Icon-Spotlight-40.png │ │ ├── Icon-Spotlight-40@2x.png │ │ ├── Icon-Spotlight-40@3x.png │ │ ├── Icon-Spotlight-40@2x-1.png │ │ └── Contents.json ├── Info.html ├── Info.plist └── LaunchScreen.xib ├── UIDevice_Extended.h ├── ColorC.h ├── .gitignore ├── NSLogger ├── LogLevel.h ├── LoggerCommon.h └── LoggerClient.h ├── ColorC.mm ├── MOButton.h ├── WebServer ├── PacFileResponse.h ├── HTTPResponseHandler.h ├── SynthesizeSingleton.h ├── HTTPServer.h ├── PacFileResponse.m ├── HTTPResponseHandler.m └── HTTPServer.m ├── MOGlassButton.h ├── myipaddr.c ├── SocksProxy.h ├── SocksProxyController.h ├── MOButton.mm ├── SocksProxy_Prefix.pch ├── README.md ├── AncillaryCode ├── main.mm ├── AppDelegate.h └── AppDelegate.mm ├── CLAUDE.md ├── UIDevice_Extended.mm ├── MOGlassButton.mm ├── Main.storyboard ├── COPYING.txt ├── SocksProxy.mm ├── SocksProxyController.mm └── Tethering.xcodeproj └── project.pbxproj /ttdnsd/clean.sh: -------------------------------------------------------------------------------- 1 | rm -rf build/ 2 | -------------------------------------------------------------------------------- /myipaddr.h: -------------------------------------------------------------------------------- 1 | /* 2 | */ 3 | 4 | char * myipaddr(void); -------------------------------------------------------------------------------- /Resources/silence.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/silence.mp3 -------------------------------------------------------------------------------- /ttdnsd/ttdnsd_platform.h: -------------------------------------------------------------------------------- 1 | /* configuration variable */ 2 | /* #undef NOT_HAVE_COCOA_FRAMEWORK */ 3 | -------------------------------------------------------------------------------- /ttdnsd/ttdnsd_platform.h.cmake: -------------------------------------------------------------------------------- 1 | /* configuration variable */ 2 | #cmakedefine NOT_HAVE_COCOA_FRAMEWORK 3 | -------------------------------------------------------------------------------- /Resources/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-iPadPro@2x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rickyzhang82/tethering/HEAD/Resources/Images.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png -------------------------------------------------------------------------------- /ttdnsd/build.sh: -------------------------------------------------------------------------------- 1 | mkdir -p build 2 | cd build 3 | 4 | if [ "$1" = "HAVE_COCOA" ] 5 | then 6 | cmake .. -DHAVE_COCOA=ON 7 | else 8 | cmake .. 9 | fi 10 | 11 | make VERBOSE=1 12 | -------------------------------------------------------------------------------- /UIDevice_Extended.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIDevice_Extended.h 3 | 4 | #import 5 | #import 6 | 7 | @interface UIDevice (Reachability) 8 | + (NSString *)localWiFiIPAddress; 9 | + (BOOL)isNetworkAvailable; 10 | + (BOOL) activeWLAN; 11 | + (BOOL)hasActiveWWAN; 12 | @end -------------------------------------------------------------------------------- /ttdnsd/stopConsole.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ttdnsd.h" 3 | 4 | int main(int argc, char** argv) 5 | { 6 | DNSServer* dns_srv = DNSServer::getInstance(); 7 | if(argc == 2) 8 | dns_srv->stopDNSServer(argv[1]); 9 | else 10 | dns_srv->stopDNSServer(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /ttdnsd/unit_test.cpp: -------------------------------------------------------------------------------- 1 | #include "ttdnsd.h" 2 | 3 | int main(int argc, char** argv) 4 | { 5 | DNSServer* dns_srv = DNSServer::getInstance(); 6 | if (argc ==2) 7 | dns_srv->startDNSServer(1, argv[1]); 8 | else 9 | dns_srv->startDNSServer(1); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ColorC.h: -------------------------------------------------------------------------------- 1 | // 2 | // ColorC.h 3 | // SOCKS 4 | // 5 | // Created by Daniel Sachse on 10/30/10. 6 | // Copyright 2010 coffeecoding. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | @interface UIColor(ColorC) 13 | 14 | +(UIColor *)colorFromRGBIntegers:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; 15 | 16 | @end -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .svn 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | xarchive/ 20 | 21 | #Qt unit test 22 | ttdnsd.config 23 | ttdnsd.creator 24 | ttdnsd.creator.user 25 | ttdnsd.files 26 | ttdnsd.includes 27 | -------------------------------------------------------------------------------- /NSLogger/LogLevel.h: -------------------------------------------------------------------------------- 1 | // 2 | // LogLevel.h 3 | // SOCKS 4 | // 5 | // Created by Ricky Zhang on 7/20/16. 6 | // 7 | // 8 | 9 | #ifndef LogLevel_h 10 | #define LogLevel_h 11 | 12 | //define NSLogger level 13 | #define NSLOGGER_LEVEL_ERROR 0 14 | #define NSLOGGER_LEVEL_WARNNING 1 15 | #define NSLOGGER_LEVEL_INFO 2 16 | #define NSLOGGER_LEVEL_DEBUG 3 17 | #define NSLOGGER_LEVEL_TRACE 4 18 | 19 | #endif /* LogLevel_h */ 20 | -------------------------------------------------------------------------------- /ColorC.mm: -------------------------------------------------------------------------------- 1 | // 2 | // ColorC.m 3 | // SOCKS 4 | // 5 | // Created by Daniel Sachse on 10/30/10. 6 | // Copyright 2010 coffeecoding. All rights reserved. 7 | // 8 | 9 | #import "ColorC.h" 10 | 11 | @implementation UIColor(ColorC) 12 | 13 | // create and return the new UIColor 14 | +(UIColor *)colorFromRGBIntegers:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha 15 | { 16 | CGFloat redF = red/255.0f; 17 | CGFloat greenF = green/255.0f; 18 | CGFloat blueF = blue/255.0f; 19 | CGFloat alphaF = alpha/1.0f; 20 | 21 | return [UIColor colorWithRed:redF green:greenF blue:blueF alpha:alphaF]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /MOButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // MOButton.h 3 | // SimplyTweet 4 | // 5 | // Created by Hwee-Boon Yar on Feb/13/2010. 6 | // Copyright 2010 MotionObj. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface MOButton : UIButton { 13 | UIColor* normalBackgroundColor; 14 | UIColor* highlightedBackgroundColor; 15 | UIColor* disabledBackgroundColor; 16 | } 17 | 18 | @property(nonatomic,strong) UIColor* normalBackgroundColor; 19 | @property(nonatomic,strong) UIColor* highlightedBackgroundColor; 20 | @property(nonatomic,strong) UIColor* disabledBackgroundColor; 21 | 22 | - (void)setBackgroundColor:(UIColor*)aColor forState:(UIControlState)aState; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /WebServer/PacFileResponse.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppTextFileResponse.h 3 | // TextTransfer 4 | // 5 | // Created by Matt Gallagher on 2009/07/13. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #import "HTTPResponseHandler.h" 16 | 17 | @interface PacFileResponse : HTTPResponseHandler 18 | { 19 | 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /MOGlassButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // MOGlassButton.h 3 | // SimplyTweet 4 | // 5 | // Created by Hwee-Boon Yar on Jan/31/2010. 6 | // Copyright 2010 MotionObj. All rights reserved. 7 | // 8 | // Enhanced by Daniel Sachse on 10/30/10. 9 | // Copyright 2010 coffeecoding. All rights reserved. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | #import "MOButton.h" 16 | 17 | @interface MOGlassButton : MOButton { 18 | CAGradientLayer* gradientLayer1; 19 | CAGradientLayer* gradientLayer2; 20 | CALayer* outlineLayer; 21 | } 22 | 23 | @property(nonatomic,strong) CAGradientLayer* gradientLayer1; 24 | @property(nonatomic,strong) CAGradientLayer* gradientLayer2; 25 | @property(nonatomic,strong) CALayer* outlineLayer; 26 | 27 | - (void)setupAsGreenButton; 28 | - (void)setupAsRedButton; 29 | - (void)setupAsWhiteButton; 30 | - (void)setupAsSmallGreenButton; 31 | - (void)setupAsSmallRedButton; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /ttdnsd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | macro (SETUP_LIB_BY_CMAKE lib) 2 | 3 | find_package (${lib} REQUIRED) 4 | include_directories(${${lib}_INCLUDE_DIRS}) 5 | list(APPEND PROJECT_LIBRARIES ${${lib}_LIBRARIES}) 6 | list(APPEND PROJECT_LIBRARY_DIRS ${${lib}_LIBRARY_DIRS}) 7 | 8 | endmacro(SETUP_LIB_BY_CMAKE lib) 9 | 10 | macro (SETUP_LIB_BY_PKGCONFIG lib) 11 | 12 | pkg_check_modules(${lib} REQUIRED ${lib}) 13 | include_directories(${${lib}_INCLUDE_DIRS}) 14 | list(APPEND PROJECT_LIBRARIES ${${lib}_LIBRARIES}) 15 | list(APPEND PROJECT_LIBRARY_DIRS ${${lib}_LIBRARY_DIRS}) 16 | 17 | endmacro(SETUP_LIB_BY_PKGCONFIG lib) 18 | 19 | cmake_minimum_required (VERSION 2.6) 20 | 21 | project (unit_test) 22 | 23 | find_package(Threads REQUIRED) 24 | 25 | set(SOURCES ttdnsd.mm unit_test.cpp) 26 | 27 | set(STOP_SOURCES ttdnsd.mm stopConsole.cpp) 28 | 29 | #platform check 30 | if(NOT HAVE_COCOA) 31 | set(NOT_HAVE_COCOA_FRAMEWORK 1) 32 | endif(NOT HAVE_COCOA) 33 | 34 | 35 | # platform-specific config file 36 | configure_file("${CMAKE_SOURCE_DIR}/ttdnsd_platform.h.cmake" "${CMAKE_SOURCE_DIR}/ttdnsd_platform.h") 37 | 38 | set(CMAKE_CXX_FLAGS "-Wall -g") 39 | 40 | add_executable(Console ${SOURCES}) 41 | target_link_libraries(Console ${CMAKE_THREAD_LIBS_INIT}) 42 | 43 | add_executable(stopConsole ${STOP_SOURCES}) 44 | target_link_libraries(stopConsole ${CMAKE_THREAD_LIBS_INIT}) 45 | -------------------------------------------------------------------------------- /WebServer/HTTPResponseHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResponseHandler.h 3 | // TextTransfer 4 | // 5 | // Created by Matt Gallagher on 2009/07/13. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #if TARGET_OS_IPHONE 16 | #import 17 | #import 18 | #else 19 | #import 20 | #endif 21 | 22 | @class HTTPServer; 23 | 24 | @interface HTTPResponseHandler : NSObject 25 | { 26 | CFHTTPMessageRef request; 27 | NSString *requestMethod; 28 | NSDictionary *headerFields; 29 | NSFileHandle *fileHandle; 30 | HTTPServer *server; 31 | NSURL *url; 32 | } 33 | 34 | + (NSUInteger)priority; 35 | + (void)registerHandler:(Class)handlerClass; 36 | 37 | + (HTTPResponseHandler *)handlerForRequest:(CFHTTPMessageRef)aRequest 38 | fileHandle:(NSFileHandle *)requestFileHandle 39 | server:(HTTPServer *)aServer; 40 | 41 | - (id)initWithRequest:(CFHTTPMessageRef)aRequest 42 | method:(NSString *)method 43 | url:(NSURL *)requestURL 44 | headerFields:(NSDictionary *)requestHeaderFields 45 | fileHandle:(NSFileHandle *)requestFileHandle 46 | server:(HTTPServer *)aServer; 47 | - (void)startResponse; 48 | - (NSString *)serverIPForRequest; 49 | - (void)endResponse; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /WebServer/SynthesizeSingleton.h: -------------------------------------------------------------------------------- 1 | // 2 | // SynthesizeSingleton.h 3 | // iTrackSportsBets 4 | // 5 | // Created by Matt Gallagher on 20/10/08. 6 | // Copyright 2008 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \ 16 | \ 17 | static classname *shared##classname = nil; \ 18 | \ 19 | + (classname *)shared##classname \ 20 | { \ 21 | @synchronized(self) \ 22 | { \ 23 | if (shared##classname == nil) \ 24 | { \ 25 | shared##classname = [[self alloc] init]; \ 26 | } \ 27 | } \ 28 | \ 29 | return shared##classname; \ 30 | } \ 31 | \ 32 | + (id)allocWithZone:(NSZone *)zone \ 33 | { \ 34 | @synchronized(self) \ 35 | { \ 36 | if (shared##classname == nil) \ 37 | { \ 38 | shared##classname = [super allocWithZone:zone]; \ 39 | return shared##classname; \ 40 | } \ 41 | } \ 42 | \ 43 | return nil; \ 44 | } \ 45 | \ 46 | - (id)copyWithZone:(NSZone *)zone \ 47 | { \ 48 | return self; \ 49 | } \ 50 | \ 51 | - (id)retain \ 52 | { \ 53 | return self; \ 54 | } \ 55 | \ 56 | - (NSUInteger)retainCount \ 57 | { \ 58 | return NSUIntegerMax; \ 59 | } \ 60 | \ 61 | - (void)release \ 62 | { \ 63 | } \ 64 | \ 65 | - (id)autorelease \ 66 | { \ 67 | return self; \ 68 | } 69 | -------------------------------------------------------------------------------- /WebServer/HTTPServer.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPServer.h 3 | // TextTransfer 4 | // 5 | // Created by Matt Gallagher on 2009/07/13. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #if TARGET_OS_IPHONE 16 | #import 17 | #else 18 | #import 19 | #endif 20 | 21 | typedef enum 22 | { 23 | SERVER_STATE_IDLE, 24 | SERVER_STATE_STARTING, 25 | SERVER_STATE_RUNNING, 26 | SERVER_STATE_STOPPING 27 | } HTTPServerState; 28 | 29 | static const int HTTP_SERVER_PORT = 8080; 30 | 31 | @class HTTPResponseHandler; 32 | 33 | @interface HTTPServer : NSObject 34 | { 35 | NSError *lastError; 36 | NSFileHandle *listeningHandle; 37 | CFSocketRef socket; 38 | HTTPServerState state; 39 | NSMutableDictionary *incomingRequests; 40 | NSMutableSet *responseHandlers; 41 | NSNetService *netService; 42 | } 43 | 44 | @property (nonatomic, readonly, retain) NSError *lastError; 45 | @property (readonly, assign) HTTPServerState state; 46 | @property (nonatomic, readonly) UInt32 httpServerPort; 47 | @property (nonatomic) NSInteger socksProxyPort; 48 | 49 | + (HTTPServer *)sharedHTTPServer; 50 | + (HTTPServer *)sharedHTTPServerWithSocksProxyPort: (NSInteger) socksProxyPort; 51 | 52 | - (void)start; 53 | - (void)stop; 54 | - (NSString *)getHostName; 55 | - (NSString *)getAutomaticHttpProxyUrl; 56 | 57 | - (void)closeHandler:(HTTPResponseHandler *)aHandler; 58 | 59 | @end 60 | 61 | extern NSString * const HTTPServerNotificationStateChanged; 62 | -------------------------------------------------------------------------------- /myipaddr.c: -------------------------------------------------------------------------------- 1 | /* 2 | */ 3 | 4 | #include "myipaddr.h" 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #if ! defined(IFT_ETHER) 21 | #define IFT_ETHER 0x6/* Ethernet CSMACD */ 22 | #endif 23 | 24 | char * myipaddr(void) 25 | { 26 | bool success; 27 | struct ifaddrs *addrs; 28 | const struct ifaddrs *cursor; 29 | const struct sockaddr_dl *dlAddr; 30 | const uint8_t *base; 31 | const struct ifaddrs * en0cursor=NULL; 32 | 33 | success = getifaddrs(&addrs) == 0; 34 | if (success) { 35 | cursor = addrs; 36 | while (cursor != NULL) { 37 | if ((cursor->ifa_flags & IFF_LOOPBACK) == 0 ) { 38 | #ifdef DEBUG 39 | printf("%s ", (char *)cursor->ifa_name); 40 | printf("%s\n",inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)); 41 | #endif 42 | if(!strcmp((char*)cursor->ifa_name,"en0")) 43 | en0cursor=cursor; 44 | } 45 | if ( (cursor->ifa_addr->sa_family == AF_LINK) 46 | && (((const struct sockaddr_dl *) cursor->ifa_addr)->sdl_type ==IFT_ETHER) 47 | ) { 48 | dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr; 49 | // fprintf(stderr, " sdl_nlen = %d\n", dlAddr->sdl_nlen); 50 | // fprintf(stderr, " sdl_alen = %d\n", dlAddr->sdl_alen); 51 | base = (const uint8_t *) &dlAddr->sdl_data[dlAddr->sdl_nlen]; 52 | #ifdef DEBUG 53 | { 54 | int i; 55 | printf(" MAC address "); 56 | for (i = 0; i < dlAddr->sdl_alen; i++) { 57 | if (i != 0) { 58 | printf(":"); 59 | } 60 | printf("%02x", base[i]); 61 | } 62 | printf("\n"); 63 | } 64 | #endif 65 | } 66 | cursor = cursor->ifa_next; 67 | } 68 | } 69 | if(addrs) 70 | freeifaddrs(addrs); 71 | if(en0cursor!=NULL) { 72 | char *s = inet_ntoa(((struct sockaddr_in *)en0cursor->ifa_addr)->sin_addr); 73 | if (strcmp(s,"6.3.6.0")) 74 | return s; 75 | } 76 | return "no WiFi"; 77 | } 78 | -------------------------------------------------------------------------------- /Resources/Info.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Untitled 6 | 7 | 18 | 19 | 20 |
Copyright (C) 2009,2010 Ehud Ben-Reuven, Christopher Bess, Daniel Sachse and others...
21 |
License: GPL v2
22 |
www.symfi.mobi
23 |
cbess.blogspot.com
24 |
www.coffeecoding.com
25 | 26 | This app is a SOCKS Proxy Server. 27 | It allows you to connect your laptop to the Internet through the 3G/Edge connection of your iPhone or iPad. 28 | In order for this to work you need to follow few steps (instructions for Mac): 29 |
    30 |
  • Step 1: Mac: Start an ad-hoc Wi-Fi network: 31 |
      32 |
    • System Preferences → Network → AirPort
    • 33 |
    • Click on Network Name and select Create Network
    • 34 |
    • Choose a name for your network (e.g. mywifi) and confirm it with OK and Apply
    • 35 |
    36 |
  • 37 |
  • Step 2: iPhone: Connect your iPhone to the ad-hoc wifi network: 38 |
      39 |
    • Settings → Wi-Fi
    • 40 |
    • Select your ad-hoc network
    • 41 |
    42 |
  • 43 |
  • Step 3: iPhone: Start the SOCKS Proxy Server:
  • 44 |
      45 |
    • Run this Tethering app on your iPhone
    • 46 |
    • Press Start
    • 47 |
    48 |
  • Step 4: Mac: Configure your Mac to use SOCKS: 49 |
      50 |
    • System Preferences → Network → Advanced... → Proxies → SOCKS Proxy
    • 51 |
    • In the SOCKS Proxy Server field enter the address and port that appear on your iPhone screen
    • 52 |
    • Press OK and Apply
    • 53 | 54 |
    55 | 56 | 57 | -------------------------------------------------------------------------------- /Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIcons 12 | 13 | CFBundleIcons~ipad 14 | 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | ${PRODUCT_NAME} 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.7 25 | CFBundleSignature 26 | ???? 27 | CFBundleVersion 28 | 1.7 29 | LSApplicationCategoryType 30 | 31 | NSBonjourServices 32 | 33 | _socks._tcp. 34 | _http._tcp. 35 | _nslogger._tcp 36 | _nslogger-ssl._tcp 37 | 38 | NSLocalNetworkUsageDescription 39 | Tethering uses local network to host DNS, Sokcs5 Proxy, HTTP pac files 40 | UIBackgroundModes 41 | 42 | audio 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIStatusBarStyle 49 | UIStatusBarStyleLightContent 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | UIViewControllerBasedStatusBarAppearance 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /SocksProxy.h: -------------------------------------------------------------------------------- 1 | /* 2 | # SOCKS - SOCKS Proxy for iPhone 3 | # Copyright (C) 2009 Ehud Ben-Reuven 4 | # udi@benreuven.com 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation version 2. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA. 18 | */ 19 | #import 20 | 21 | enum { 22 | kSendBufferSize = 100000, 23 | kReceiveBufferSize = 200000 24 | }; 25 | 26 | @protocol SocksProxyDelegate 27 | - (void)_updateStatus:(NSString *)statusString; 28 | - (void)_sendreceiveDidStart; 29 | - (void) _sendreceiveDidStopWithStatus:(NSString *)statusString; 30 | - (void)_downloadData:(NSInteger)bytes; 31 | - (void)_uploadData:(NSInteger)bytes; 32 | @end 33 | 34 | @interface SocksProxy : NSObject 35 | { 36 | NSInputStream * _receivenetworkStream; 37 | NSOutputStream * _sendnetworkStream; 38 | NSOutputStream * _remoteSendNetworkStream; 39 | NSInputStream * _remoteReceiveNetworkStream; 40 | id __weak delegate; 41 | uint8_t _sendbuffer[kSendBufferSize]; 42 | size_t _sendbufferOffset; 43 | size_t _sendbufferLimit; 44 | uint8_t _receivebuffer[kReceiveBufferSize]; 45 | size_t _receivebufferOffset; 46 | size_t _receivebufferLimit; 47 | NSUInteger _protocolLocation; 48 | NSString * _remoteName; 49 | } 50 | 51 | @property (nonatomic, weak) id delegate; 52 | @property (nonatomic, readonly) BOOL isSendingReceiving; 53 | 54 | - (void)stopSendReceiveWithStatus:(NSString *)statusString; 55 | - (BOOL)startSendReceive:(int)fd; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /SocksProxyController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SOCKS - SOCKS Proxy for iPhone 3 | // Copyright (C) 2009 Ehud Ben-Reuven 4 | // udi@benreuven.com 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation version 2. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA. 18 | // 19 | // Enhanced by Daniel Sachse on 10/30/10. 20 | // Copyright 2010 coffeecoding. All rights reserved. 21 | // 22 | 23 | #import 24 | #import "SocksProxy.h" 25 | #import "HTTPServer.h" 26 | #include "ttdnsd.h" 27 | //Max concurrent coonections 28 | #define MAX_CONNECTIONS 100 29 | 30 | @class MOGlassButton; 31 | 32 | @interface SocksProxyController : UITableViewController 33 | { 34 | MOGlassButton * _startOrStopButton; 35 | 36 | NSNetService * _netService; 37 | CFSocketRef _listeningSocket; 38 | 39 | NSInteger _nConnections; 40 | IBOutlet UITableView * proxyTableView; 41 | 42 | @private 43 | NSString *currentStatusText; 44 | NSInteger currentPort; 45 | NSString *currentAddress; 46 | NSInteger currentOpenConnections; 47 | NSInteger currentConnectionCount; 48 | DNSServer * _DNSServer; 49 | HTTPServer * _HTTPServer; 50 | 51 | } 52 | 53 | @property (nonatomic, copy) NSString *currentStatusText; 54 | @property (nonatomic, copy) NSString *httpAutoProxyURL; 55 | @property (nonatomic, assign) NSInteger currentPort; 56 | @property (nonatomic, copy) NSString *currentAddress; 57 | @property (nonatomic, assign) NSInteger currentOpenConnections; 58 | @property (nonatomic, assign) NSInteger currentConnectionCount; 59 | @property (nonatomic, assign) NSInteger uploadData; 60 | @property (nonatomic, assign) NSInteger downloadData; 61 | @property (nonatomic, strong) IBOutlet MOGlassButton * startOrStopButton; 62 | 63 | - (IBAction)startOrStopAction:(id)sender; 64 | 65 | - (void)refreshProxyTable; 66 | @end 67 | -------------------------------------------------------------------------------- /MOButton.mm: -------------------------------------------------------------------------------- 1 | // 2 | // MOButton.m 3 | // SimplyTweet 4 | // 5 | // Created by Hwee-Boon Yar on Feb/13/2010. 6 | // Copyright 2010 MotionObj. All rights reserved. 7 | // 8 | // Enhanced by Daniel Sachse on 10/30/10. 9 | // Copyright 2010 coffeecoding. All rights reserved. 10 | // 11 | 12 | #import "MOButton.h" 13 | 14 | #import 15 | 16 | @implementation MOButton 17 | 18 | @synthesize normalBackgroundColor; 19 | @synthesize highlightedBackgroundColor; 20 | @synthesize disabledBackgroundColor; 21 | 22 | // Have to set up handlers for various touch events. Can't rely on UIButton.highlighted and enabled property because highlighted is still YES when touch up. 23 | - (void)setupStateChangeHandlers { 24 | [self addTarget:self action:@selector(buttonUp:event:) forControlEvents:(UIControlEventTouchUpOutside|UIControlEventTouchUpInside|UIControlEventTouchCancel|UIControlEventTouchDragExit)]; 25 | [self addTarget:self action:@selector(buttonDown:event:) forControlEvents:UIControlEventTouchDown|UIControlEventTouchDragEnter]; 26 | } 27 | 28 | 29 | - (id)initWithFrame:(CGRect)aRect { 30 | if (self = [super initWithFrame:aRect]) { 31 | [self setupStateChangeHandlers]; 32 | } 33 | 34 | return self; 35 | } 36 | 37 | 38 | - (void)awakeFromNib { 39 | [self setupStateChangeHandlers]; 40 | } 41 | 42 | 43 | 44 | 45 | - (void)setBackgroundColor:(UIColor*)aColor forState:(UIControlState)aState { 46 | switch (aState) { 47 | case UIControlStateNormal: 48 | self.normalBackgroundColor = aColor; 49 | if (self.enabled) self.layer.backgroundColor = self.normalBackgroundColor.CGColor; 50 | break; 51 | case UIControlStateHighlighted: 52 | self.highlightedBackgroundColor = aColor; 53 | break; 54 | case UIControlStateDisabled: 55 | self.disabledBackgroundColor = aColor; 56 | if (!self.enabled) self.layer.backgroundColor = self.disabledBackgroundColor.CGColor; 57 | break; 58 | default: 59 | break; 60 | } 61 | } 62 | 63 | 64 | - (void)setEnabled:(BOOL)yesOrNo { 65 | [super setEnabled:yesOrNo]; 66 | self.layer.backgroundColor = yesOrNo? self.normalBackgroundColor.CGColor: self.disabledBackgroundColor.CGColor; 67 | } 68 | 69 | #pragma mark Events 70 | 71 | - (void)buttonUp:(id)aButton event:(id)event { 72 | self.layer.backgroundColor = self.normalBackgroundColor.CGColor; 73 | } 74 | 75 | 76 | - (void)buttonDown:(id)aButton event:(id)event { 77 | self.layer.backgroundColor = self.highlightedBackgroundColor.CGColor; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /SocksProxy_Prefix.pch: -------------------------------------------------------------------------------- 1 | /* 2 | * SocksProxy_Prefix.pch 3 | * SOCKS 4 | * 5 | * Created by C. Bess on 9/5/10. 6 | * Copyright 2010 Christopher Bess. All rights reserved. 7 | * 8 | */ 9 | 10 | #ifdef __OBJC__ 11 | #import "UIDevice_Extended.h" 12 | #endif 13 | 14 | #include "LogLevel.h" 15 | 16 | #define USE_NSLOGGER_LIB 1 17 | 18 | 19 | #ifdef DEBUG 20 | 21 | 22 | #ifdef USE_NSLOGGER_LIB 23 | 24 | #include "LoggerClient.h" 25 | 26 | #define LOG_NETWORK_DNS(level, ...) LogMessageF(__FILE__,__LINE__,__FUNCTION__,@"network:dns",level,__VA_ARGS__) 27 | 28 | #define LOG_NETWORK_DNS_VA(level, format, va_args) LogMessageF_va(__FILE__,__LINE__,__FUNCTION__,@"network:dns",level, format, va_args) 29 | 30 | #define LOG_NETWORK_SOCKS(level, ...) LogMessageF(__FILE__,__LINE__,__FUNCTION__,@"network:socks",level,__VA_ARGS__) 31 | 32 | #define LOG_NETWORK_HTTP(level, ...) LogMessageF(__FILE__,__LINE__,__FUNCTION__,@"network:http",level,__VA_ARGS__) 33 | 34 | #define LOG_GENERAL(level, ...) LogMessageF(__FILE__,__LINE__,__FUNCTION__,@"general",level,__VA_ARGS__) 35 | 36 | #define LOG_GRAPHICS(level, ...) LogMessageF(__FILE__,__LINE__,__FUNCTION__,@"graphics",level,__VA_ARGS__) 37 | 38 | #else 39 | 40 | #define LOG_NETWORK_DNS(level, ...) NSLog(__VA_ARGS__) 41 | 42 | #define LOG_NETWORK_DNS_VA(level, format, va_args) NSLogv(format, va_args) 43 | 44 | #define LOG_NETWORK_SOCKS(level, ...) NSLog(__VA_ARGS__) 45 | 46 | #define LOG_NETWORK_HTTP(level, ...) NSLog(__VA_ARGS__) 47 | 48 | #define LOG_GENERAL(level, ...) NSLog(__VA_ARGS__) 49 | 50 | #define LOG_GRAPHICS(level, ...) NSLog(__VA_ARGS__) 51 | 52 | #endif 53 | 54 | #else 55 | #define LOG_NETWORK_DNS(...) do{}while(0) 56 | #define LOG_NETWORK_DNS_VA(level, format, va_args) do{}while(0) 57 | #define LOG_NETWORK_SOCKS(...) do{}while(0) 58 | #define LOG_NETWORK_HTTP(...) do{}while(0) 59 | #define LOG_GENERAL(...) do{}while(0) 60 | #define LOG_GRAPHICS(...) do{}while(0) 61 | #endif 62 | 63 | #if defined(DEBUG) && !defined(NDEBUG) && defined(USE_NSLOGGER_LIB) 64 | #undef assert 65 | #if __DARWIN_UNIX03 66 | #define assert(e) \ 67 | (__builtin_expect(!(e), 0) ? (CFShow(CFSTR("assert going to fail, connect NSLogger NOW\n")), LoggerFlush(NULL,YES), __assert_rtn(__func__, __FILE__, __LINE__, #e)) : (void)0) 68 | #else 69 | #define assert(e) \ 70 | (__builtin_expect(!(e), 0) ? (CFShow(CFSTR("assert going to fail, connect NSLogger NOW\n")), LoggerFlush(NULL,YES), __assert(#e, __FILE__, __LINE__)) : (void)0) 71 | #endif 72 | #endif 73 | 74 | 75 | -------------------------------------------------------------------------------- /Resources/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "Icon-Small@2x-1.png", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "Icon-Small@3x.png", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "size" : "40x40", 27 | "idiom" : "iphone", 28 | "filename" : "Icon-Spotlight-40@2x-1.png", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "Icon-Spotlight-40@3x.png", 35 | "scale" : "3x" 36 | }, 37 | { 38 | "size" : "60x60", 39 | "idiom" : "iphone", 40 | "filename" : "Icon-60@2x.png", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "idiom" : "iphone", 46 | "filename" : "Icon-60@3x.png", 47 | "scale" : "3x" 48 | }, 49 | { 50 | "idiom" : "ipad", 51 | "size" : "20x20", 52 | "scale" : "1x" 53 | }, 54 | { 55 | "idiom" : "ipad", 56 | "size" : "20x20", 57 | "scale" : "2x" 58 | }, 59 | { 60 | "size" : "29x29", 61 | "idiom" : "ipad", 62 | "filename" : "Icon-Small.png", 63 | "scale" : "1x" 64 | }, 65 | { 66 | "size" : "29x29", 67 | "idiom" : "ipad", 68 | "filename" : "Icon-Small@2x.png", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "size" : "40x40", 73 | "idiom" : "ipad", 74 | "filename" : "Icon-Spotlight-40.png", 75 | "scale" : "1x" 76 | }, 77 | { 78 | "size" : "40x40", 79 | "idiom" : "ipad", 80 | "filename" : "Icon-Spotlight-40@2x.png", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "size" : "76x76", 85 | "idiom" : "ipad", 86 | "filename" : "Icon-76.png", 87 | "scale" : "1x" 88 | }, 89 | { 90 | "size" : "76x76", 91 | "idiom" : "ipad", 92 | "filename" : "Icon-76@2x.png", 93 | "scale" : "2x" 94 | }, 95 | { 96 | "size" : "83.5x83.5", 97 | "idiom" : "ipad", 98 | "filename" : "Icon-iPadPro@2x.png", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "idiom" : "ios-marketing", 103 | "size" : "1024x1024", 104 | "scale" : "1x" 105 | } 106 | ], 107 | "info" : { 108 | "version" : 1, 109 | "author" : "xcode" 110 | } 111 | } -------------------------------------------------------------------------------- /Resources/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This iOS App was forked from [an abandoned project](https://code.google.com/p/iphone-socks-proxy/). The current goal is to make this iOS App great again. Please read [my user guide](https://github.com/rickyzhang82/tethering/wiki). 2 | 3 | Protecting the World against the tyranny 4 | ======================================== 5 | 6 | Please consider making your donation to the National Bank of Ukraine. The fundraiser [National Bank of Ukraine or NBU](https://en.wikipedia.org/wiki/National_Bank_of_Ukraine) is the central bank of Ukraine. You could help freedom fighters and Ukrainian civilians in humanitarian crisis: 7 | 8 | - [Funds for Ukraine’s Armed Forces](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi) 9 | - [Funds for Humanitarian Assistance to Ukrainians Affected by Russia’s Aggression](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-rahunok-dlya-gumanitarnoyi-dopomogi-ukrayintsyam-postrajdalim-vid-rosiyskoyi-agresiyi) 10 | 11 | If you are against funding bombs and arms, you could also donate to [Come Back Alive Charity](https://www.comebackalive.in.ua) which helps the Ukrainian armed forces with defense including medical assistance and rehabilitation. The organization is transparent with the donation and its spending. 12 | 13 | - [Come Back Alive Charity](https://www.comebackalive.in.ua/donate) 14 | 15 | Thank you for your support. 16 | 17 | Ricky 18 | 19 | Change log 20 | 21 | ---- 22 | 23 | Release V1.8 24 | * Added a request to access local wifi network. Please enable it in your privacy setting. 25 | * Added infos of Bonjour services for socks5, http PAC files, NSLogger. 26 | 27 | Release V1.7 28 | * Add unlimited background. Feel free to close screen to save battery. Thanks @bsuh for his patch. 29 | * Finally, we have a pull request to change ugly UI to a new modern look. Thanks @rickybloomfield for his patch. 30 | 31 | Release V1.6 32 | * Fix problem when remote network is faster than local network. Thanks @optimoid and @bsuh for their patch and bug report. 33 | * Refactor socks proxy message debug log. 34 | 35 | Release V1.5 36 | * Refactor DNS message log 37 | * Verify compatible with iOS 9.3 38 | 39 | Release V1.4 40 | * Support iPad tethering. Add http server to host socks.pac file 41 | * Fix several memory leak issues. 42 | 43 | Release V1.3 44 | * Update NSLogger API compatible with iOS 8 45 | 46 | Release V1.2 47 | * Convert xib to storyboard 48 | * Fix Failed to compile: ttdnsd_platform.h not found error 49 | 50 | Release V1.1 51 | * Fix retrieve wifi IP address bug. 52 | * Replace naive logging with NSLogger logging API 53 | * Enable ARC and use modern Objective-C literal 54 | 55 | Release v1.0. 56 | * Support DNS server and Socks5 proxy server. 57 | * Fix crash problem when wifi is not connected. 58 | * Listenning socket reuse address and port if previous TCP connection in TIME_WAIT state. 59 | --- 60 | -------------------------------------------------------------------------------- /AncillaryCode/main.mm: -------------------------------------------------------------------------------- 1 | /* 2 | File: main.m 3 | 4 | Contains: Application main. 5 | 6 | Written by: DTS 7 | 8 | Copyright: Copyright (c) 2009 Apple Inc. All Rights Reserved. 9 | 10 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 11 | ("Apple") in consideration of your agreement to the following 12 | terms, and your use, installation, modification or 13 | redistribution of this Apple software constitutes acceptance of 14 | these terms. If you do not agree with these terms, please do 15 | not use, install, modify or redistribute this Apple software. 16 | 17 | In consideration of your agreement to abide by the following 18 | terms, and subject to these terms, Apple grants you a personal, 19 | non-exclusive license, under Apple's copyrights in this 20 | original Apple software (the "Apple Software"), to use, 21 | reproduce, modify and redistribute the Apple Software, with or 22 | without modifications, in source and/or binary forms; provided 23 | that if you redistribute the Apple Software in its entirety and 24 | without modifications, you must retain this notice and the 25 | following text and disclaimers in all such redistributions of 26 | the Apple Software. Neither the name, trademarks, service marks 27 | or logos of Apple Inc. may be used to endorse or promote 28 | products derived from the Apple Software without specific prior 29 | written permission from Apple. Except as expressly stated in 30 | this notice, no other rights or licenses, express or implied, 31 | are granted by Apple herein, including but not limited to any 32 | patent rights that may be infringed by your derivative works or 33 | by other works in which the Apple Software may be incorporated. 34 | 35 | The Apple Software is provided by Apple on an "AS IS" basis. 36 | APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING 37 | WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 38 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING 39 | THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 40 | COMBINATION WITH YOUR PRODUCTS. 41 | 42 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, 43 | INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 44 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 45 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY 46 | OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 47 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY 48 | OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 49 | OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF 50 | SUCH DAMAGE. 51 | 52 | */ 53 | 54 | #import 55 | #import "AppDelegate.h" 56 | 57 | int main(int argc, char **argv) 58 | { 59 | @autoreleasepool { 60 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AncillaryCode/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: AppDelegate.h 3 | 4 | Contains: Main app controller. 5 | 6 | Written by: DTS 7 | 8 | Copyright: Copyright (c) 2009 Apple Inc. All Rights Reserved. 9 | 10 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 11 | ("Apple") in consideration of your agreement to the following 12 | terms, and your use, installation, modification or 13 | redistribution of this Apple software constitutes acceptance of 14 | these terms. If you do not agree with these terms, please do 15 | not use, install, modify or redistribute this Apple software. 16 | 17 | In consideration of your agreement to abide by the following 18 | terms, and subject to these terms, Apple grants you a personal, 19 | non-exclusive license, under Apple's copyrights in this 20 | original Apple software (the "Apple Software"), to use, 21 | reproduce, modify and redistribute the Apple Software, with or 22 | without modifications, in source and/or binary forms; provided 23 | that if you redistribute the Apple Software in its entirety and 24 | without modifications, you must retain this notice and the 25 | following text and disclaimers in all such redistributions of 26 | the Apple Software. Neither the name, trademarks, service marks 27 | or logos of Apple Inc. may be used to endorse or promote 28 | products derived from the Apple Software without specific prior 29 | written permission from Apple. Except as expressly stated in 30 | this notice, no other rights or licenses, express or implied, 31 | are granted by Apple herein, including but not limited to any 32 | patent rights that may be infringed by your derivative works or 33 | by other works in which the Apple Software may be incorporated. 34 | 35 | The Apple Software is provided by Apple on an "AS IS" basis. 36 | APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING 37 | WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 38 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING 39 | THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 40 | COMBINATION WITH YOUR PRODUCTS. 41 | 42 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, 43 | INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 44 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 45 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY 46 | OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 47 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY 48 | OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 49 | OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF 50 | SUCH DAMAGE. 51 | 52 | */ 53 | 54 | #import 55 | 56 | @class SocksProxyController; 57 | 58 | @interface AppDelegate : NSObject 59 | { 60 | UIWindow * _window; 61 | UITabBarController * _tabs; 62 | SocksProxyController * _viewController; 63 | } 64 | 65 | @property (nonatomic, strong) IBOutlet UIWindow * window; 66 | @property (nonatomic, strong) IBOutlet UITabBarController * tabs; 67 | @property (nonatomic, strong) IBOutlet SocksProxyController * viewController; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # CLAUDE.md 2 | 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 | 5 | ## Overview 6 | 7 | Tethering is an iOS application that provides SOCKS5 proxy, DNS server, and HTTP PAC file hosting capabilities. Originally forked from an abandoned iPhone SOCKS proxy project, it enables network tethering functionality on iOS devices. 8 | 9 | ## Build and Development Commands 10 | 11 | ### Xcode Project 12 | - **Main project**: Open `Tethering.xcodeproj` in Xcode 13 | - **Build target**: Tethering.app for iOS 14 | - **Main storyboard**: `Main.storyboard` 15 | - **Info.plist**: Located at `Resources/Info.plist` 16 | 17 | ### DNS Component (ttdnsd) 18 | The DNS server component has its own build system: 19 | 20 | ```bash 21 | # Build DNS component 22 | cd ttdnsd 23 | ./build.sh # Standard build 24 | ./build.sh HAVE_COCOA # Build with Cocoa framework support 25 | 26 | # Clean build artifacts 27 | ./clean.sh 28 | ``` 29 | 30 | The DNS component uses CMake: 31 | - **CMakeLists.txt**: `ttdnsd/CMakeLists.txt` 32 | - **Build output**: Creates `Console` and `stopConsole` executables 33 | 34 | ## Architecture Overview 35 | 36 | ### Core Components 37 | 38 | 1. **SocksProxyController** (`SocksProxyController.h/.mm`) 39 | - Main controller managing the SOCKS5 proxy service 40 | - Implements `SocksProxyDelegate` and `NSNetServiceDelegate` 41 | - Handles Bonjour service registration 42 | - Manages connection state and statistics 43 | 44 | 2. **SocksProxy** (`SocksProxy.h/.mm`) 45 | - Individual SOCKS5 connection handler 46 | - Implements stream-based proxy forwarding 47 | - Manages send/receive buffers (100KB send, 200KB receive) 48 | 49 | 3. **HTTPServer** (`WebServer/HTTPServer.h/.m`) 50 | - HTTP server for PAC file hosting (port 8080) 51 | - Provides automatic proxy configuration 52 | - Implements singleton pattern via `+sharedHTTPServer` 53 | 54 | 4. **DNS Server** (`ttdnsd/`) 55 | - TCP DNS daemon based on Tor's ttdnsd 56 | - Written in C++ with Objective-C++ wrapper 57 | - Handles DNS queries for the proxy setup 58 | 59 | 5. **WebServer Components** 60 | - **HTTPResponseHandler**: Handles individual HTTP requests 61 | - **PacFileResponse**: Serves PAC (Proxy Auto-Configuration) files 62 | 63 | ### Key Features 64 | 65 | - **Bonjour Services**: Registers `_socks._tcp.`, `_http._tcp.`, `_nslogger._tcp` services 66 | - **Background Audio**: Uses silent audio to maintain background execution 67 | - **Network Permissions**: Requires local network access permission (iOS 14+) 68 | - **Multi-platform UI**: Supports both iPhone and iPad orientations 69 | 70 | ### App Configuration 71 | 72 | - **Bundle ID**: Configured via `$(PRODUCT_BUNDLE_IDENTIFIER)` 73 | - **Version**: Currently 1.7 (defined in Info.plist) 74 | - **Background Modes**: Audio playback for persistent operation 75 | - **Network Services**: DNS (port varies), SOCKS5 (port varies), HTTP PAC (port 8080) 76 | 77 | ### Dependencies 78 | 79 | - **System Frameworks**: UIKit, Foundation, CoreGraphics, QuartzCore, CFNetwork, SystemConfiguration, SafariServices, AVFoundation 80 | - **Custom UI**: MOButton and MOGlassButton for enhanced button styling 81 | - **Logging**: NSLogger integration for remote logging 82 | - **Color Management**: ColorC utility for color operations 83 | 84 | ## File Organization 85 | 86 | - **Root**: Main application files (controllers, proxies, utilities) 87 | - **AncillaryCode/**: App delegate and main entry point 88 | - **Resources/**: Assets, storyboard, Info.plist, launch screen 89 | - **WebServer/**: HTTP server implementation 90 | - **NSLogger/**: Remote logging framework 91 | - **ttdnsd/**: DNS server component with separate build system 92 | 93 | The project follows iOS app conventions with Objective-C++ implementation for core networking components. -------------------------------------------------------------------------------- /UIDevice_Extended.mm: -------------------------------------------------------------------------------- 1 | /* 2 | Erica Sadun, http://ericasadun.com 3 | iPhone Developer's Cookbook, 3.0 Edition 4 | BSD License for anything not specifically marked as developed by a third party. 5 | Apple's code excluded. 6 | Use at your own risk 7 | */ 8 | 9 | #import 10 | #include 11 | #include 12 | #include 13 | #include 14 | #import "UIDevice_Extended.h" 15 | 16 | SCNetworkConnectionFlags connectionFlags; 17 | 18 | @implementation UIDevice (Reachability) 19 | // Matt Brown's get WiFi IP addy solution 20 | // http://mattbsoftware.blogspot.com/2009/04/how-to-get-ip-address-of-iphone-os-v221.html 21 | + (NSString *) ipAddressWithPredicate:(NSPredicate *)isMatchNetworkInterfaceName 22 | { 23 | BOOL success; 24 | NSString * wifiIPAddress = nil; 25 | struct ifaddrs * addrList = NULL; 26 | const struct ifaddrs * cursor; 27 | 28 | success = getifaddrs(&addrList) == 0; 29 | if (success) 30 | { 31 | for (cursor = addrList; cursor != NULL; cursor = cursor->ifa_next) 32 | { 33 | // the second test keeps from picking up the loopback address 34 | if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0) 35 | { 36 | NSString *name = @(cursor->ifa_name); 37 | 38 | if ([isMatchNetworkInterfaceName evaluateWithObject:name]) 39 | { 40 | wifiIPAddress = [NSString stringWithUTF8String: 41 | (inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr))]; 42 | break; 43 | } 44 | } 45 | } 46 | 47 | freeifaddrs(addrList); 48 | } 49 | return wifiIPAddress; 50 | } 51 | 52 | + (NSString *) localWiFiIPAddress 53 | { 54 | NSString * wifiIPAddress = nil; 55 | 56 | NSPredicate * isMatchWIFIInterfaceName = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"en\\d+"]; 57 | // Get wifi adapter IP adress 58 | wifiIPAddress = [[self class] ipAddressWithPredicate:isMatchWIFIInterfaceName]; 59 | 60 | if (wifiIPAddress == nil) 61 | { 62 | // Get hotspot IP address, if the bridge presents 63 | NSPredicate * isMatchHotspotInterfaceName = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"bridge\\d+"]; 64 | wifiIPAddress = [[self class] ipAddressWithPredicate:isMatchHotspotInterfaceName]; 65 | } 66 | 67 | return wifiIPAddress; 68 | } 69 | 70 | #pragma mark Checking Connections 71 | 72 | + (void) pingReachabilityInternal 73 | { 74 | BOOL ignoresAdHocWiFi = NO; 75 | struct sockaddr_in ipAddress; 76 | bzero(&ipAddress, sizeof(ipAddress)); 77 | ipAddress.sin_len = sizeof(ipAddress); 78 | ipAddress.sin_family = AF_INET; 79 | ipAddress.sin_addr.s_addr = htonl(ignoresAdHocWiFi ? INADDR_ANY : IN_LINKLOCALNETNUM); 80 | 81 | // Recover reachability flags 82 | SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&ipAddress); 83 | BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &connectionFlags); 84 | CFRelease(defaultRouteReachability); 85 | 86 | if (!didRetrieveFlags) 87 | { 88 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"Error. Could not recover network reachability flags"); 89 | } 90 | } 91 | 92 | + (BOOL)isNetworkAvailable 93 | { 94 | [self pingReachabilityInternal]; 95 | 96 | BOOL isReachable = ((connectionFlags & kSCNetworkFlagsReachable) != 0); 97 | BOOL needsConnection = ((connectionFlags & kSCNetworkFlagsConnectionRequired) != 0); 98 | 99 | return (isReachable && !needsConnection) ? YES : NO; 100 | } 101 | 102 | + (BOOL)hasActiveWWAN 103 | { 104 | if (![self isNetworkAvailable]) 105 | return NO; 106 | 107 | return ((connectionFlags & kSCNetworkReachabilityFlagsIsWWAN) != 0); 108 | } 109 | 110 | + (BOOL) activeWLAN 111 | { 112 | return ([UIDevice localWiFiIPAddress] != nil); 113 | } 114 | @end 115 | -------------------------------------------------------------------------------- /AncillaryCode/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | /* 2 | File: AppDelegate.m 3 | 4 | Contains: Main app controller. 5 | 6 | Written by: DTS 7 | 8 | Copyright: Copyright (c) 2009 Apple Inc. All Rights Reserved. 9 | 10 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 11 | ("Apple") in consideration of your agreement to the following 12 | terms, and your use, installation, modification or 13 | redistribution of this Apple software constitutes acceptance of 14 | these terms. If you do not agree with these terms, please do 15 | not use, install, modify or redistribute this Apple software. 16 | 17 | In consideration of your agreement to abide by the following 18 | terms, and subject to these terms, Apple grants you a personal, 19 | non-exclusive license, under Apple's copyrights in this 20 | original Apple software (the "Apple Software"), to use, 21 | reproduce, modify and redistribute the Apple Software, with or 22 | without modifications, in source and/or binary forms; provided 23 | that if you redistribute the Apple Software in its entirety and 24 | without modifications, you must retain this notice and the 25 | following text and disclaimers in all such redistributions of 26 | the Apple Software. Neither the name, trademarks, service marks 27 | or logos of Apple Inc. may be used to endorse or promote 28 | products derived from the Apple Software without specific prior 29 | written permission from Apple. Except as expressly stated in 30 | this notice, no other rights or licenses, express or implied, 31 | are granted by Apple herein, including but not limited to any 32 | patent rights that may be infringed by your derivative works or 33 | by other works in which the Apple Software may be incorporated. 34 | 35 | The Apple Software is provided by Apple on an "AS IS" basis. 36 | APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING 37 | WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 38 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING 39 | THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 40 | COMBINATION WITH YOUR PRODUCTS. 41 | 42 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, 43 | INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 44 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 45 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY 46 | OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 47 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY 48 | OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 49 | OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF 50 | SUCH DAMAGE. 51 | 52 | */ 53 | 54 | #import "AppDelegate.h" 55 | #import "SocksProxyController.h" 56 | 57 | @implementation AppDelegate 58 | 59 | @synthesize window = _window; 60 | @synthesize tabs = _tabs; 61 | @synthesize viewController = _viewController; 62 | 63 | - (void)applicationDidFinishLaunching:(UIApplication *)application 64 | { 65 | #pragma unused(application) 66 | assert(self.window != nil); 67 | 68 | [self.window addSubview:self.viewController.view]; 69 | 70 | [[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:0.082 green:0.492 blue:0.980 alpha:1.0]]; 71 | NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[UIFont systemFontOfSize:20 weight:UIFontWeightLight], NSFontAttributeName, [UIColor whiteColor], NSForegroundColorAttributeName, nil]; 72 | [[UINavigationBar appearance] setTitleTextAttributes:attributes]; 73 | 74 | [self.window makeKeyAndVisible]; 75 | } 76 | @end 77 | -------------------------------------------------------------------------------- /MOGlassButton.mm: -------------------------------------------------------------------------------- 1 | // 2 | // MOGlassButton.m 3 | // SimplyTweet 4 | // 5 | // Created by Hwee-Boon Yar on Jan/31/2010. 6 | // Copyright 2010 MotionObj. All rights reserved. 7 | // 8 | // Enhanced by Daniel Sachse on 10/30/10. 9 | // Copyright 2010 coffeecoding. All rights reserved. 10 | // 11 | 12 | #import "MOGlassButton.h" 13 | #import "ColorC.h" 14 | 15 | @implementation MOGlassButton 16 | 17 | @synthesize gradientLayer1; 18 | @synthesize gradientLayer2; 19 | @synthesize outlineLayer; 20 | 21 | 22 | - (void)setupLayers { 23 | self.layer.cornerRadius = 8.0f; 24 | self.layer.masksToBounds = YES; 25 | self.layer.borderColor = [[UIColor colorFromRGBIntegers:100 green:103 blue:107 alpha:1.0f] CGColor]; 26 | self.layer.borderWidth = 1.0f; 27 | 28 | self.gradientLayer1 = [[CAGradientLayer alloc] init]; 29 | gradientLayer1.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height/2); 30 | gradientLayer1.colors = @[(id)[[UIColor colorFromRGBIntegers:255 green:255 blue:255 alpha:0.45f] CGColor], (id)[[UIColor colorFromRGBIntegers:255 green:235 blue:255 alpha:0.1f] CGColor]]; 31 | [self.layer insertSublayer:gradientLayer1 atIndex:0]; 32 | 33 | self.gradientLayer2 = [[CAGradientLayer alloc] init]; 34 | gradientLayer2.frame = CGRectMake(0, self.frame.size.height/2, self.frame.size.width, self.frame.size.height/2); 35 | gradientLayer2.colors = @[(id)[[UIColor colorFromRGBIntegers:205 green:205 blue:205 alpha:0.0f] CGColor], (id)[[UIColor colorFromRGBIntegers:235 green:215 blue:215 alpha:0.2f] CGColor]]; 36 | 37 | self.outlineLayer = [[CALayer alloc] init]; 38 | outlineLayer.frame = CGRectMake(0, 1, self.frame.size.width, self.frame.size.height); 39 | outlineLayer.borderColor = [[UIColor colorFromRGBIntegers:255 green:255 blue:255 alpha:1.0f] CGColor]; 40 | outlineLayer.borderWidth = 1.0f; 41 | outlineLayer.borderWidth = 1.0f; 42 | outlineLayer.opacity = 0.2f; 43 | } 44 | 45 | 46 | - (id)initWithFrame:(CGRect)aRect { 47 | if (self = [super initWithFrame:aRect]) { 48 | [self setupLayers]; 49 | } 50 | 51 | return self; 52 | } 53 | 54 | 55 | - (void)awakeFromNib { 56 | [super awakeFromNib]; 57 | } 58 | 59 | 60 | 61 | 62 | - (void)layoutSubviews { 63 | [super layoutSubviews]; 64 | } 65 | 66 | #pragma mark Default Button Background Colors 67 | 68 | - (void)setupForStandardButtons { 69 | [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 70 | [self setTitleColor:[UIColor colorFromRGBIntegers:205 green:212 blue:220 alpha:1.0f] forState:UIControlStateDisabled]; 71 | self.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightLight]; 72 | } 73 | 74 | 75 | - (void)setupAsGreenButton { 76 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:24 green:157 blue:22 alpha:1.0f] forState:UIControlStateNormal]; 77 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:9 green:54 blue:14 alpha:1.0f] forState:UIControlStateHighlighted]; 78 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:24 green:157 blue:22 alpha:1.0f] forState:UIControlStateDisabled]; 79 | [self setupForStandardButtons]; 80 | } 81 | 82 | 83 | - (void)setupAsRedButton { 84 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:160 green:1 blue:20 alpha:1.0f] forState:UIControlStateNormal]; 85 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:120 green:0 blue:0 alpha:1.0f] forState:UIControlStateHighlighted]; 86 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:160 green:1 blue:20 alpha:1.0f] forState:UIControlStateDisabled]; 87 | [self setupForStandardButtons]; 88 | } 89 | 90 | - (void)setupAsWhiteButton { 91 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:160 green:160 blue:160 alpha:1.0f] forState:UIControlStateNormal]; 92 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:80 green:80 blue:80 alpha:1.0f] forState:UIControlStateHighlighted]; 93 | [self setBackgroundColor:[UIColor colorFromRGBIntegers:160 green:160 blue:160 alpha:1.0f] forState:UIControlStateDisabled]; 94 | [self setupForStandardButtons]; 95 | } 96 | 97 | 98 | - (void)setupAsSmallGreenButton { 99 | [self setupAsGreenButton]; 100 | self.titleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightLight]; 101 | } 102 | 103 | 104 | - (void)setupAsSmallRedButton { 105 | [self setupAsRedButton]; 106 | self.titleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightLight]; 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /WebServer/PacFileResponse.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppTextFileResponse.m 3 | // TextTransfer 4 | // 5 | // Created by Matt Gallagher on 2009/07/13. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #import "PacFileResponse.h" 16 | #import "HTTPServer.h" 17 | 18 | @implementation PacFileResponse 19 | 20 | // 21 | // load 22 | // 23 | // Implementing the load method and invoking 24 | // [HTTPResponseHandler registerHandler:self] causes HTTPResponseHandler 25 | // to register this class in the list of registered HTTP response handlers. 26 | // 27 | + (void)load 28 | { 29 | [HTTPResponseHandler registerHandler:self]; 30 | } 31 | 32 | // 33 | // canHandleRequest:method:url:headerFields: 34 | // 35 | // Class method to determine if the response handler class can handle 36 | // a given request. 37 | // 38 | // Parameters: 39 | // aRequest - the request 40 | // requestMethod - the request method 41 | // requestURL - the request URL 42 | // requestHeaderFields - the request headers 43 | // 44 | // returns YES (if the handler can handle the request), NO (otherwise) 45 | // 46 | + (BOOL)canHandleRequest:(CFHTTPMessageRef)aRequest 47 | method:(NSString *)requestMethod 48 | url:(NSURL *)requestURL 49 | headerFields:(NSDictionary *)requestHeaderFields 50 | { 51 | return YES; 52 | } 53 | 54 | // 55 | // startResponse 56 | // 57 | // Since this is a simple response, we handle it synchronously by sending 58 | // everything at once. 59 | // 60 | - (void)startResponse 61 | { 62 | NSData *fileData = nil; 63 | NSString *currentIP = [self serverIPForRequest]; 64 | 65 | NSString *requestPath = [url path]; 66 | 67 | if ([@"/socks.pac" isEqualToString:requestPath] && currentIP) { 68 | fileData = [[NSString stringWithFormat: 69 | @"function FindProxyForURL(url, host) { return \"SOCKS %@:%ld\"; }", 70 | currentIP, (long)server.socksProxyPort] dataUsingEncoding:NSUTF8StringEncoding]; 71 | } 72 | 73 | if ([@"/socks5.pac" isEqualToString:requestPath] && currentIP) { 74 | fileData = [[NSString stringWithFormat: 75 | @"function FindProxyForURL(url, host) { return \"SOCKS5 %@:%ld\"; }", 76 | currentIP, (long)server.socksProxyPort] dataUsingEncoding:NSUTF8StringEncoding]; 77 | } 78 | 79 | if (fileData) { 80 | CFHTTPMessageRef response = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 81 | 200, 82 | NULL, 83 | kCFHTTPVersion1_1); 84 | 85 | CFHTTPMessageSetHeaderFieldValue(response, 86 | (CFStringRef)@"Content-Type", 87 | (CFStringRef)@"application/x-ns-proxy-autoconfig"); 88 | CFHTTPMessageSetHeaderFieldValue(response, 89 | (CFStringRef)@"Connection", 90 | (CFStringRef)@"close"); 91 | CFHTTPMessageSetHeaderFieldValue(response, 92 | (CFStringRef)@"Content-Length", 93 | (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", (unsigned long)[fileData length]]); 94 | 95 | CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response); 96 | 97 | @try 98 | { 99 | [fileHandle writeData:(__bridge NSData *)headerData]; 100 | [fileHandle writeData:fileData]; 101 | } 102 | @catch (NSException *exception) 103 | { 104 | // Ignore the exception, it normally just means the client 105 | // closed the connection from the other end. 106 | } 107 | @finally 108 | { 109 | CFRelease(headerData); 110 | CFRelease(response); 111 | [server closeHandler:self]; 112 | } 113 | } else { 114 | CFHTTPMessageRef response = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 115 | currentIP ? 404 : 500, 116 | NULL, 117 | kCFHTTPVersion1_1); 118 | 119 | CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response); 120 | 121 | @try 122 | { 123 | [fileHandle writeData:(__bridge NSData *)headerData]; 124 | } 125 | @catch (NSException *exception) 126 | { 127 | // Ignore the exception, it normally just means the client 128 | // closed the connection from the other end. 129 | } 130 | @finally 131 | { 132 | CFRelease(headerData); 133 | [server closeHandler:self]; 134 | } 135 | } 136 | } 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 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 | -------------------------------------------------------------------------------- /NSLogger/LoggerCommon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LoggerCommon.h 3 | * 4 | * version 1.9.5 26-DEC-2018 5 | * 6 | * Definitions common to NSLogger Viewer and NSLoggerClient 7 | * for the binary messages format 8 | * https://github.com/fpillet/NSLogger 9 | * 10 | * BSD license follows (http://www.opensource.org/licenses/bsd-license.php) 11 | * 12 | * Copyright (c) 2010-2019 Florent Pillet All Rights Reserved. 13 | * 14 | * Redistribution and use in source and binary forms, with or without modification, 15 | * are permitted provided that the following conditions are met: 16 | * 17 | * Redistributions of source code must retain the above copyright notice, 18 | * this list of conditions and the following disclaimer. Redistributions in 19 | * binary form must reproduce the above copyright notice, this list of 20 | * conditions and the following disclaimer in the documentation and/or other 21 | * materials provided with the distribution. Neither the name of Florent 22 | * Pillet nor the names of its contributors may be used to endorse or promote 23 | * products derived from this software without specific prior written 24 | * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 25 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 26 | * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 30 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | /* NSLogger native binary message format: 39 | * Each message is a dictionary encoded in a compact format. All values are stored 40 | * in network order (big endian). A message is made of several "parts", which are 41 | * typed chunks of data, each with a specific purpose (partKey), data type (partType) 42 | * and data size (partSize). 43 | * 44 | * uint32_t totalSize (total size for the whole message excluding this 4-byte count) 45 | * uint16_t partCount (number of parts below) 46 | * [repeat partCount times]: 47 | * uint8_t partKey the part key 48 | * uint8_t partType (string, binary, image, int16, int32, int64) 49 | * uint32_t partSize (only for string, binary and image types, others are implicit) 50 | * .. `partSize' data bytes 51 | * 52 | * Complete message is usually made of: 53 | * - a PART_KEY_MESSAGE_TYPE (mandatory) which contains one of the LOGMSG_TYPE_* values 54 | * - a PART_KEY_TIMESTAMP_S (mandatory) which is the timestamp returned by gettimeofday() (seconds from 01.01.1970 00:00) 55 | * - a PART_KEY_TIMESTAMP_MS (optional) complement of the timestamp seconds, in milliseconds 56 | * - a PART_KEY_TIMESTAMP_US (optional) complement of the timestamp seconds and milliseconds, in microseconds 57 | * - a PART_KEY_THREAD_ID (mandatory) the ID of the user thread that produced the log entry 58 | * - a PART_KEY_TAG (optional) a tag that helps categorizing and filtering logs from your application, and shows up in viewer logs 59 | * - a PART_KEY_LEVEL (optional) a log level that helps filtering logs from your application (see as few or as much detail as you need) 60 | * - a PART_KEY_MESSAGE which is the message text, binary data or image 61 | * - a PART_KEY_MESSAGE_SEQ which is the message sequence number (message# sent by client) 62 | * - a PART_KEY_FILENAME (optional) with the filename from which the log was generated 63 | * - a PART_KEY_LINENUMBER (optional) the linenumber in the filename at which the log was generated 64 | * - a PART_KEY_FUNCTIONNAME (optional) the function / method / selector from which the log was generated 65 | * - if logging an image, PART_KEY_IMAGE_WIDTH and PART_KEY_IMAGE_HEIGHT let the desktop know the image size without having to actually decode it 66 | */ 67 | 68 | // Constants for the "part key" field 69 | #define PART_KEY_MESSAGE_TYPE 0 70 | #define PART_KEY_TIMESTAMP_S 1 // "seconds" component of timestamp 71 | #define PART_KEY_TIMESTAMP_MS 2 // milliseconds component of timestamp (optional, mutually exclusive with PART_KEY_TIMESTAMP_US) 72 | #define PART_KEY_TIMESTAMP_US 3 // microseconds component of timestamp (optional, mutually exclusive with PART_KEY_TIMESTAMP_MS) 73 | #define PART_KEY_THREAD_ID 4 74 | #define PART_KEY_TAG 5 75 | #define PART_KEY_LEVEL 6 76 | #define PART_KEY_MESSAGE 7 77 | #define PART_KEY_IMAGE_WIDTH 8 // messages containing an image should also contain a part with the image size 78 | #define PART_KEY_IMAGE_HEIGHT 9 // (this is mainly for the desktop viewer to compute the cell size without having to immediately decode the image) 79 | #define PART_KEY_MESSAGE_SEQ 10 // the sequential number of this message which indicates the order in which messages are generated 80 | #define PART_KEY_FILENAME 11 // when logging, message can contain a file name 81 | #define PART_KEY_LINENUMBER 12 // as well as a line number 82 | #define PART_KEY_FUNCTIONNAME 13 // and a function or method name 83 | 84 | // Constants for parts in LOGMSG_TYPE_CLIENTINFO 85 | #define PART_KEY_CLIENT_NAME 20 86 | #define PART_KEY_CLIENT_VERSION 21 87 | #define PART_KEY_OS_NAME 22 88 | #define PART_KEY_OS_VERSION 23 89 | #define PART_KEY_CLIENT_MODEL 24 // For iPhone, device model (i.e 'iPhone', 'iPad', etc) 90 | #define PART_KEY_UNIQUEID 25 // for remote device identification, part of LOGMSG_TYPE_CLIENTINFO 91 | 92 | // Area starting at which you may define your own constants 93 | #define PART_KEY_USER_DEFINED 100 94 | 95 | // Constants for the "partType" field 96 | #define PART_TYPE_STRING 0 // Strings are stored as UTF-8 data 97 | #define PART_TYPE_BINARY 1 // A block of binary data 98 | #define PART_TYPE_INT16 2 99 | #define PART_TYPE_INT32 3 100 | #define PART_TYPE_INT64 4 101 | #define PART_TYPE_IMAGE 5 // An image, stored in PNG format 102 | 103 | // Data values for the PART_KEY_MESSAGE_TYPE parts 104 | #define LOGMSG_TYPE_LOG 0 // A standard log message 105 | #define LOGMSG_TYPE_BLOCKSTART 1 // The start of a "block" (a group of log entries) 106 | #define LOGMSG_TYPE_BLOCKEND 2 // The end of the last started "block" 107 | #define LOGMSG_TYPE_CLIENTINFO 3 // Information about the client app 108 | #define LOGMSG_TYPE_DISCONNECT 4 // Pseudo-message on the desktop side to identify client disconnects 109 | #define LOGMSG_TYPE_MARK 5 // Pseudo-message that defines a "mark" that users can place in the log flow 110 | 111 | // Default Bonjour service identifiers 112 | #define LOGGER_SERVICE_TYPE_SSL CFSTR("_nslogger-ssl._tcp") 113 | #define LOGGER_SERVICE_TYPE CFSTR("_nslogger._tcp") 114 | -------------------------------------------------------------------------------- /ttdnsd/ttdnsd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The Tor TCP DNS Daemon 3 | * 4 | * Copyright (c) Collin R. Mulliner 5 | * Copyright (c) 2010, The Tor Project, Inc. 6 | * 7 | */ 8 | 9 | 10 | #ifndef TTDNSDH 11 | #define TTDNSDH 12 | 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "ttdnsd_platform.h" 32 | 33 | #ifdef NOT_HAVE_COCOA_FRAMEWORK 34 | #include 35 | #include "../NSLogger/LogLevel.h" 36 | #endif 37 | 38 | 39 | const char TTDNSD_VERSION[]= "v1.0"; 40 | 41 | // number of parallel connected tcp peers 42 | const int MAX_PEERS = 1; 43 | // request timeout 44 | const int MAX_TIME = 3; /* QUASIBUG 3 seconds is too short! */ 45 | // number of trys per request (not used so far) 46 | const int MAX_TRY = 1; 47 | // maximal number of nameservers 48 | const int MAX_NAMESERVERS = 32; 49 | // request queue size (use a prime number for hashing) 50 | const int MAX_REQUESTS = 499; 51 | // 199, 1009 52 | // max line size for configuration processing 53 | const int MAX_LINE_SIZE = 1025; 54 | //maximum lenght of IPV4 address 55 | const int MAX_IPV4_ADDR_LENGTH = 20; 56 | //maximum TCP fd write retry times 57 | const int MAX_TCP_WRITE_TIME = 10; 58 | 59 | // Magic numbers 60 | const int RECV_BUF_SIZE = 1502; 61 | 62 | const int DEFAULT_DNS_PORT = 53; 63 | const char DEFAULT_DNS_IP[]= "8.8.8.8"; 64 | const int DEFAULT_BIND_PORT = 53; 65 | const char DEFAULT_BIND_IP[]= "127.0.0.1"; 66 | const char DEFAULT_SOCKS5_IP[]= "192.168.1.3"; 67 | const int DEFAULT_SOCKS5_PORT = 1080; 68 | const char MAGIC_STRING_STOP_DNS[] = "Time for home!"; 69 | const char DEFAULT_MAGIC_IPV4_ADDR[] = "0.0.0.0"; 70 | 71 | #define HELP_STR ""\ 72 | "syntax: ttdnsd [bpfPCcdlhV]\n"\ 73 | "\t-b\t\tlocal IP to bind to\n"\ 74 | "\t-p\t\tbind to port\n"\ 75 | "\t-f\t\tfilename to read resolver IP(s) from\n"\ 76 | "\t-P\t\tfile to store process ID - pre-chroot\n"\ 77 | "\t-C\t\tchroot(2) to \n"\ 78 | "\t-c\t\t\tDON'T chroot(2) to /var/lib/ttdnsd\n"\ 79 | "\t-d\t\t\tDEBUG (don't fork and print debug)\n"\ 80 | "\t-l\t\t\twrite debug log to: " DEFAULT_LOG "\n"\ 81 | "\t-h\t\t\tprint this helpful text and exit\n"\ 82 | "\t-V\t\t\tprint version and exit\n\n"\ 83 | "export TSOCKS_CONF_FILE to point to config file inside the chroot\n"\ 84 | "\n" 85 | typedef enum{ 86 | DNS_SERVER_STARTING = 0, 87 | DNS_SERVER_STARTED, 88 | DNS_SERVER_TERMINATING, 89 | DNS_SERVER_TERMINATED 90 | } DNS_SERVER_STATE; 91 | 92 | typedef enum { 93 | DEAD = 0, 94 | CONNECTING, 95 | CONNECTING2, 96 | CONNECTED, 97 | SOCKS5_CONNECTING, 98 | SOCKS5_AUTH_WAIT, 99 | SOCKS5_CMD_WAIT 100 | } CON_STATE; 101 | 102 | typedef enum { 103 | WAITING = 0, 104 | SENT 105 | } REQ_STATE; 106 | 107 | struct request_t { 108 | struct sockaddr_in a; /* client’s IP/port */ 109 | socklen_t al; 110 | unsigned char b[1502]; /**< request buffer */ 111 | int bl; /**< bytes in request buffer */ 112 | uint id; /**< dns request id */ 113 | int rid; /**< real dns request id */ 114 | REQ_STATE active; /**< 1=sent, 0=waiting for tcp to become connected */ 115 | time_t timeout; /**< timeout of request */ 116 | }; 117 | 118 | struct peer_t 119 | { 120 | struct sockaddr_in tcp; 121 | struct sockaddr_in socks5_tcp; 122 | int tcp_fd; 123 | time_t timeout; 124 | CON_STATE con; /**< connection state 0=dead, 1=connecting..., 3=connected */ 125 | unsigned char b[RECV_BUF_SIZE]; /**< receive buffer */ 126 | int bl; /**< bytes in receive buffer */ // bl? Why don't we call this bytes_in_recv_buf or something meaningful? 127 | }; 128 | 129 | class DNSServer{ 130 | 131 | public: 132 | 133 | static DNSServer* getInstance(){ 134 | 135 | if(dns_instance == NULL) 136 | 137 | dns_instance = new DNSServer(); 138 | 139 | return dns_instance; 140 | } 141 | 142 | ~DNSServer(); 143 | /*Start DNS server in posix thread*/ 144 | int startDNSServer(int _isDebugMode = 1, 145 | const char* _localDNSIP = DEFAULT_MAGIC_IPV4_ADDR, 146 | const char* _remoteDNSIP = DEFAULT_DNS_IP, 147 | int _localDNSPort = DEFAULT_BIND_PORT, 148 | int _remoteDNSPort = DEFAULT_DNS_PORT, 149 | time_t _remoteDNSTimeout = MAX_TIME, 150 | int _isSockify = 0, 151 | const char* _remoteSockProxyIP = DEFAULT_SOCKS5_IP, 152 | int _remoteSockProxyPort = DEFAULT_SOCKS5_PORT); 153 | 154 | void stopDNSServer(); 155 | 156 | void stopDNSServer(const char* localDNSIP); 157 | 158 | DNS_SERVER_STATE getDNSServerState(); 159 | 160 | protected: 161 | 162 | DNSServer(); 163 | 164 | const char * peer_display(struct peer_t *p); 165 | int peer_connect(struct peer_t *p, struct in_addr ns); 166 | int peer_connected(struct peer_t *p); 167 | int peer_sendreq(struct peer_t *p, struct request_t *r); 168 | int peer_readres(struct peer_t *p); 169 | void peer_mark_as_dead(struct peer_t *p); 170 | void peer_handleoutstanding(struct peer_t *p); 171 | 172 | struct peer_t *peer_select(void); 173 | struct in_addr ns_select(void); 174 | 175 | int request_find(uint id); 176 | int request_add(struct request_t *r); 177 | int _start_server(); 178 | void _stop_server(); 179 | int _nonblocking_send(int fd, void* buff, int len); 180 | void process_incoming_request(struct request_t *tmp); 181 | 182 | const char * peer_socks5_display(struct peer_t *p); 183 | int peer_socks5_connect(struct peer_t *p, struct in_addr socks5_addr, struct in_addr ns_addr); 184 | int peer_socks5_connected(struct peer_t *p); 185 | int peer_socks5_snd_auth_neg(struct peer_t *p); 186 | int peer_socks5_rcv_auth_process(struct peer_t *p); 187 | int peer_socks5_snd_cmd(struct peer_t *p); 188 | int peer_socks5_rcv_cmd_process(struct peer_t *p); 189 | struct in_addr socks5_proxy_select(void); 190 | 191 | #ifndef NOT_HAVE_COCOA_FRAMEWORK 192 | int print_level(int level, const char * __restrict format, ...); 193 | #endif 194 | 195 | static void * _dns_srv_thread_wrapper(void*){ 196 | 197 | DNSServer * dns_srv = DNSServer::getInstance(); 198 | 199 | dns_srv->_start_server(); 200 | 201 | return 0; 202 | } 203 | 204 | struct in_addr nameservers; /**< nameservers pool */ 205 | 206 | struct peer_t peers[MAX_PEERS]; /**< TCP peers */ 207 | struct request_t requests[MAX_REQUESTS]; /**< request queue */ 208 | int udp_fd; /**< port 53 socket */ 209 | 210 | int isSockify; /*Flag to determine if TCP should be sockify*/ 211 | 212 | char *remoteSocksIP; 213 | 214 | int remoteSocksPort; 215 | 216 | char *remoteDNSIP; 217 | 218 | int remoteDNSPort; 219 | 220 | char *localDNSIP; 221 | 222 | int localDNSPort; 223 | 224 | int isDebugMode; 225 | 226 | time_t remoteDNSTimeout; 227 | 228 | static DNSServer * dns_instance; 229 | 230 | volatile DNS_SERVER_STATE dnsState; 231 | 232 | }; 233 | 234 | #endif 235 | 236 | 237 | -------------------------------------------------------------------------------- /WebServer/HTTPResponseHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPResponseHandler.m 3 | // TextTransfer 4 | // 5 | // Created by Matt Gallagher on 2009/07/13. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #import "HTTPResponseHandler.h" 16 | #import "HTTPServer.h" 17 | #import "PacFileResponse.h" 18 | #import 19 | #import 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | @implementation HTTPResponseHandler 26 | 27 | static NSMutableArray *registeredHandlers = nil; 28 | 29 | // 30 | // priority 31 | // 32 | // The priority determines which request handlers are given the option to 33 | // handle a request first. The highest number goes first, with the base class 34 | // (HTTPResponseHandler) implementing a 501 error response at priority 0 35 | // (the lowest priorty). 36 | // 37 | // Even if subclasses have a 0 priority, they will always receive precedence 38 | // over the base class, since the base class' implementation is intended as 39 | // an error condition only. 40 | // 41 | // returns the priority. 42 | // 43 | + (NSUInteger)priority 44 | { 45 | return 0; 46 | } 47 | 48 | // 49 | // load 50 | // 51 | // Implementing the load method and invoking 52 | // [HTTPResponseHandler registerHandler:self] causes HTTPResponseHandler 53 | // to register this class in the list of registered HTTP response handlers. 54 | // 55 | + (void)load 56 | { 57 | [HTTPResponseHandler registerHandler:self]; 58 | } 59 | 60 | // 61 | // registerHandler: 62 | // 63 | // Inserts the HTTPResponseHandler class into the priority list. 64 | // 65 | + (void)registerHandler:(Class)handlerClass 66 | { 67 | if (registeredHandlers == nil) 68 | { 69 | registeredHandlers = [[NSMutableArray alloc] init]; 70 | } 71 | 72 | NSUInteger i; 73 | NSUInteger count = [registeredHandlers count]; 74 | for (i = 0; i < count; i++) 75 | { 76 | if ([handlerClass priority] >= [[registeredHandlers objectAtIndex:i] priority]) 77 | { 78 | break; 79 | } 80 | } 81 | [registeredHandlers insertObject:handlerClass atIndex:i]; 82 | } 83 | 84 | // 85 | // canHandleRequest:method:url:headerFields: 86 | // 87 | // Class method to determine if the response handler class can handle 88 | // a given request. 89 | // 90 | // Parameters: 91 | // aRequest - the request 92 | // requestMethod - the request method 93 | // requestURL - the request URL 94 | // requestHeaderFields - the request headers 95 | // 96 | // returns YES (if the handler can handle the request), NO (otherwise) 97 | // 98 | + (BOOL)canHandleRequest:(CFHTTPMessageRef)aRequest 99 | method:(NSString *)requestMethod 100 | url:(NSURL *)requestURL 101 | headerFields:(NSDictionary *)requestHeaderFields 102 | { 103 | return YES; 104 | } 105 | 106 | // 107 | // handlerClassForRequest:method:url:headerFields: 108 | // 109 | // Important method to edit for your application. 110 | // 111 | // This method determines (from the HTTP request message, URL and headers) 112 | // which 113 | // 114 | // Parameters: 115 | // aRequest - the CFHTTPMessageRef, with data at least as far as the end 116 | // of the headers 117 | // requestMethod - the request method (GET, POST, PUT, DELETE etc) 118 | // requestURL - the URL (likely only contains a path) 119 | // requestHeaderFields - the parsed header fields 120 | // 121 | // returns the class to handle the request, or nil if no handler exists. 122 | // 123 | + (Class)handlerClassForRequest:(CFHTTPMessageRef)aRequest 124 | method:(NSString *)requestMethod 125 | url:(NSURL *)requestURL 126 | headerFields:(NSDictionary *)requestHeaderFields 127 | { 128 | for (Class handlerClass in registeredHandlers) 129 | { 130 | if ([handlerClass canHandleRequest:aRequest 131 | method:requestMethod 132 | url:requestURL 133 | headerFields:requestHeaderFields]) 134 | { 135 | return handlerClass; 136 | } 137 | } 138 | 139 | return nil; 140 | } 141 | 142 | // 143 | // handleRequest:fileHandle:server: 144 | // 145 | // This method parses the request method and header components, invokes 146 | // +[handlerClassForRequest:method:url:headerFields:] to determine a handler 147 | // class (if any) and creates the handler. 148 | // 149 | // Parameters: 150 | // aRequest - the CFHTTPMessageRef request requiring a response 151 | // requestFileHandle - the file handle for the incoming request (still 152 | // open and possibly receiving data) and for the outgoing response 153 | // aServer - the server that is invoking us 154 | // 155 | // returns the initialized handler (if one can handle the request) or nil 156 | // (if no valid handler exists). 157 | // 158 | + (HTTPResponseHandler *)handlerForRequest:(CFHTTPMessageRef)aRequest 159 | fileHandle:(NSFileHandle *)requestFileHandle 160 | server:(HTTPServer *)aServer 161 | { 162 | NSDictionary *requestHeaderFields = 163 | (__bridge_transfer NSDictionary *)CFHTTPMessageCopyAllHeaderFields(aRequest); 164 | NSURL *requestURL = 165 | (__bridge_transfer NSURL *)CFHTTPMessageCopyRequestURL(aRequest); 166 | NSString *method = 167 | (__bridge_transfer NSString *)CFHTTPMessageCopyRequestMethod(aRequest); 168 | 169 | Class classForRequest = 170 | [self handlerClassForRequest:aRequest 171 | method:method 172 | url:requestURL 173 | headerFields:requestHeaderFields]; 174 | 175 | HTTPResponseHandler *handler = 176 | [[classForRequest alloc] 177 | initWithRequest:aRequest 178 | method:method 179 | url:requestURL 180 | headerFields:requestHeaderFields 181 | fileHandle:requestFileHandle 182 | server:aServer]; 183 | 184 | return handler; 185 | } 186 | 187 | // 188 | // initWithRequest:method:url:headerFields:fileHandle:server: 189 | // 190 | // Init method for the handler. This method is mostly just a value copy operation 191 | // so that the parts of the request don't need to be reparsed. 192 | // 193 | // Parameters: 194 | // aRequest - the CFHTTPMessageRef 195 | // method - the request method 196 | // requestURL - the URL 197 | // requestHeaderFields - the CFHTTPMessageRef header fields 198 | // requestFileHandle - the incoming request file handle, also used for 199 | // the outgoing response. 200 | // aServer - the server that spawned us 201 | // 202 | // returns the initialized object 203 | // 204 | - (id)initWithRequest:(CFHTTPMessageRef)aRequest 205 | method:(NSString *)method 206 | url:(NSURL *)requestURL 207 | headerFields:(NSDictionary *)requestHeaderFields 208 | fileHandle:(NSFileHandle *)requestFileHandle 209 | server:(HTTPServer *)aServer 210 | { 211 | self = [super init]; 212 | if (self != nil) 213 | { 214 | request = (CFHTTPMessageRef)CFRetain(aRequest); 215 | requestMethod = method; 216 | url = requestURL; 217 | headerFields = requestHeaderFields; 218 | fileHandle = requestFileHandle; 219 | server = aServer; 220 | 221 | [[NSNotificationCenter defaultCenter] 222 | addObserver:self 223 | selector:@selector(receiveIncomingDataNotification:) 224 | name:NSFileHandleDataAvailableNotification 225 | object:fileHandle]; 226 | 227 | [fileHandle waitForDataInBackgroundAndNotify]; 228 | } 229 | return self; 230 | } 231 | 232 | // 233 | // startResponse 234 | // 235 | // Begin sending a response over the fileHandle. Trivial cases can 236 | // synchronously return a response but everything else should spawn a thread 237 | // or otherwise asynchronously start returning the response data. 238 | // 239 | // THIS IS THE PRIMARY METHOD FOR SUBCLASSES TO OVERRIDE. YOU DO NOT NEED 240 | // TO INVOKE SUPER FOR THIS METHOD. 241 | // 242 | // This method should only be invoked from HTTPServer (it needs to add the 243 | // object to its responseHandlers before this method is invoked). 244 | // 245 | // [server closeHandler:self] should be invoked when done sending data. 246 | // 247 | - (void)startResponse 248 | { 249 | CFHTTPMessageRef response = 250 | CFHTTPMessageCreateResponse( 251 | kCFAllocatorDefault, 501, NULL, kCFHTTPVersion1_1); 252 | CFHTTPMessageSetHeaderFieldValue( 253 | response, (CFStringRef)@"Content-Type", (CFStringRef)@"text/html"); 254 | CFHTTPMessageSetHeaderFieldValue( 255 | response, (CFStringRef)@"Connection", (CFStringRef)@"close"); 256 | CFHTTPMessageSetBody( 257 | response, 258 | (__bridge CFDataRef)[[NSString stringWithFormat: 259 | @"501 - Not Implemented" 260 | @"

    501 - Not Implemented

    " 261 | @"

    No handler exists to handle %@.

    ", 262 | [url absoluteString]] 263 | dataUsingEncoding:NSUTF8StringEncoding]); 264 | CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response); 265 | @try 266 | { 267 | [fileHandle writeData:(__bridge NSData *)headerData]; 268 | } 269 | @catch (NSException *exception) 270 | { 271 | // Ignore the exception, it normally just means the client 272 | // closed the connection from the other end. 273 | } 274 | @finally 275 | { 276 | CFRelease(headerData); 277 | CFRelease(response); 278 | [server closeHandler:self]; 279 | } 280 | } 281 | 282 | - (NSString *)serverIPForRequest 283 | { 284 | return [UIDevice localWiFiIPAddress]; 285 | } 286 | 287 | // 288 | // endResponse 289 | // 290 | // Closes the outgoing file handle. 291 | // 292 | // You should not invoke this method directly. It should only be invoked from 293 | // HTTPServer (it needs to remove the object from its responseHandlers before 294 | // this method is invoked). To close a reponse handler, use 295 | // [server closeHandler:responseHandler]. 296 | // 297 | // Subclasses should stop any other activity when this method is invoked and 298 | // invoke super to close the file handle. 299 | // 300 | // If the connection is persistent, you must set fileHandle to nil (without 301 | // closing the file) to prevent the connection getting closed by this method. 302 | // 303 | - (void)endResponse 304 | { 305 | if (fileHandle) 306 | { 307 | [[NSNotificationCenter defaultCenter] 308 | removeObserver:self 309 | name:NSFileHandleDataAvailableNotification 310 | object:fileHandle]; 311 | [fileHandle closeFile]; 312 | fileHandle = nil; 313 | } 314 | server = nil; 315 | } 316 | 317 | // 318 | // receiveIncomingDataNotification: 319 | // 320 | // Continues to receive incoming data for the connection. Remember that the 321 | // first data past the end of the headers may already have been read into 322 | // the request. 323 | // 324 | // Override this method to read the complete HTTP Request Body. This is a 325 | // complicated process if you want to handle both Content-Length and all common 326 | // Transfer-Encodings, so I haven't implemented it. 327 | // 328 | // If you want to handle persistent connections, you would need careful handling 329 | // to determine the end of the request, seek the fileHandle so it points 330 | // to the byte immediately after then end of this request, and then send an 331 | // NSFileHandleConnectionAcceptedNotification notification with the fileHandle 332 | // as the NSFileHandleNotificationFileHandleItem in the userInfo dictionary 333 | // back to the server to handle the fileHandle as a new incoming request again 334 | // (before setting fileHandle to nil so the connection won't get closed when this 335 | // handler ends). 336 | // 337 | // Parameters: 338 | // notification - notification that more data is available 339 | // 340 | - (void)receiveIncomingDataNotification:(NSNotification *)notification 341 | { 342 | NSFileHandle *incomingFileHandle = [notification object]; 343 | NSData *data = [incomingFileHandle availableData]; 344 | 345 | if ([data length] == 0) 346 | { 347 | [server closeHandler:self]; 348 | } 349 | 350 | // 351 | // This is a default implementation and simply ignores all data. 352 | // If you need the HTTP body, you need to override this method to continue 353 | // accumulating data. Don't forget that new data may need to be combined 354 | // with any HTTP body data that may have already been received in the 355 | // "request" body. 356 | // 357 | 358 | [incomingFileHandle waitForDataInBackgroundAndNotify]; 359 | } 360 | 361 | // 362 | // dealloc 363 | // 364 | // Stops the response if still running. 365 | // 366 | - (void)dealloc 367 | { 368 | if (server) 369 | { 370 | [self endResponse]; 371 | } 372 | 373 | CFRelease(request); 374 | request = nil; 375 | 376 | requestMethod = nil; 377 | 378 | url = nil; 379 | 380 | headerFields = nil; 381 | 382 | } 383 | 384 | @end 385 | -------------------------------------------------------------------------------- /WebServer/HTTPServer.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPServer.m 3 | // TextTransfer 4 | // 5 | // Created by Matt Gallagher on 2009/07/13. 6 | // Copyright 2009 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file, free of charge, in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | // 08-11-2015 Add ARC support and remove singleton template 16 | // 17 | #import "HTTPServer.h" 18 | #import 19 | #import 20 | #if TARGET_OS_IPHONE 21 | #import 22 | #endif 23 | #import "HTTPResponseHandler.h" 24 | 25 | NSString * const HTTPServerNotificationStateChanged = @"ServerNotificationStateChanged"; 26 | 27 | // 28 | // Internal methods and properties: 29 | // The "lastError" and "state" are only writable by the server itself. 30 | // 31 | @interface HTTPServer () 32 | @property (nonatomic, readwrite, retain) NSError *lastError; 33 | @property (readwrite, assign) HTTPServerState state; 34 | @end 35 | 36 | @implementation HTTPServer 37 | 38 | @synthesize lastError; 39 | @synthesize state; 40 | 41 | +(HTTPServer* )sharedHTTPServer 42 | { 43 | static HTTPServer* sharedHTTPServer = nil; 44 | @synchronized(self) 45 | { 46 | if (sharedHTTPServer == nil) 47 | { 48 | sharedHTTPServer = [[HTTPServer alloc] init]; 49 | } 50 | } 51 | 52 | return sharedHTTPServer; 53 | } 54 | 55 | + (HTTPServer *)sharedHTTPServerWithSocksProxyPort: (NSInteger) socksProxyPort 56 | { 57 | static HTTPServer* sharedHTTPServerWithSocksProxyPort = nil; 58 | @synchronized(self) 59 | { 60 | if (sharedHTTPServerWithSocksProxyPort == nil) 61 | { 62 | sharedHTTPServerWithSocksProxyPort = [[HTTPServer alloc] initWithSocksProxyPort:socksProxyPort]; 63 | } 64 | } 65 | 66 | return sharedHTTPServerWithSocksProxyPort; 67 | } 68 | 69 | // 70 | // init 71 | // 72 | // Set the initial state and allocate the responseHandlers and incomingRequests 73 | // collections. 74 | // 75 | // returns the initialized server object. 76 | // 77 | - (id)init 78 | { 79 | self = [super init]; 80 | if (self != nil) 81 | { 82 | self.state = SERVER_STATE_IDLE; 83 | responseHandlers = [[NSMutableSet alloc] init]; 84 | incomingRequests =[NSMutableDictionary dictionary]; 85 | } 86 | return self; 87 | } 88 | 89 | - (id)initWithSocksProxyPort: (NSInteger)socksProxyPort 90 | { 91 | self = [super init]; 92 | if (self != nil) 93 | { 94 | self.state = SERVER_STATE_IDLE; 95 | self.socksProxyPort = socksProxyPort; 96 | responseHandlers = [[NSMutableSet alloc] init]; 97 | incomingRequests =[NSMutableDictionary dictionary]; 98 | } 99 | return self; 100 | } 101 | 102 | -(void)startBonjourServices 103 | { 104 | netService = [[NSNetService alloc] initWithDomain:@"local" type:@"_http._tcp." name:@"" port:self.httpServerPort]; 105 | netService.delegate = self; 106 | [netService publish]; 107 | } 108 | 109 | -(void)stopBonjourServices 110 | { 111 | [netService stop]; 112 | netService = nil; 113 | } 114 | 115 | // 116 | // setLastError: 117 | // 118 | // Custom setter method. Stops the server and 119 | // 120 | // Parameters: 121 | // anError - the new error value (nil to clear) 122 | // 123 | - (void)setLastError:(NSError *)anError 124 | { 125 | lastError = anError; 126 | 127 | if (lastError == nil) 128 | { 129 | return; 130 | } 131 | 132 | [self stop]; 133 | 134 | self.state = SERVER_STATE_IDLE; 135 | LOG_NETWORK_HTTP(NSLOGGER_LEVEL_ERROR, @"HTTPServer error: %@", self.lastError); 136 | } 137 | 138 | // 139 | // errorWithName: 140 | // 141 | // Stops the server and sets the last error to "errorName", localized using the 142 | // HTTPServerErrors.strings file (if present). 143 | // 144 | // Parameters: 145 | // errorName - the description used for the error 146 | // 147 | - (void)errorWithName:(NSString *)errorName 148 | { 149 | self.lastError = [NSError 150 | errorWithDomain:@"HTTPServerError" 151 | code:0 152 | userInfo: 153 | [NSDictionary dictionaryWithObject: 154 | NSLocalizedStringFromTable( 155 | errorName, 156 | @"", 157 | @"HTTPServerErrors") 158 | forKey:NSLocalizedDescriptionKey]]; 159 | } 160 | 161 | // 162 | // setState: 163 | // 164 | // Changes the server state and posts a notification (if the state changes). 165 | // 166 | // Parameters: 167 | // newState - the new state for the server 168 | // 169 | - (void)setState:(HTTPServerState)newState 170 | { 171 | if (state == newState) 172 | { 173 | return; 174 | } 175 | 176 | state = newState; 177 | 178 | [[NSNotificationCenter defaultCenter] 179 | postNotificationName:HTTPServerNotificationStateChanged 180 | object:self]; 181 | } 182 | 183 | // 184 | // start 185 | // 186 | // Creates the socket and starts listening for connections on it. 187 | // 188 | - (void)start 189 | { 190 | self.lastError = nil; 191 | self.state = SERVER_STATE_STARTING; 192 | 193 | socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, 194 | IPPROTO_TCP, 0, NULL, NULL); 195 | if (!socket) 196 | { 197 | [self errorWithName:@"Unable to create socket."]; 198 | return; 199 | } 200 | 201 | int reuse = true; 202 | int fileDescriptor = CFSocketGetNative(socket); 203 | if (setsockopt(fileDescriptor, SOL_SOCKET, SO_REUSEADDR, 204 | (void *)&reuse, sizeof(int)) != 0) 205 | { 206 | [self errorWithName:@"Unable to set socket options."]; 207 | //TODO: log error with NSLogger 208 | return; 209 | } 210 | 211 | struct sockaddr_in address; 212 | memset(&address, 0, sizeof(address)); 213 | address.sin_len = sizeof(address); 214 | address.sin_family = AF_INET; 215 | address.sin_addr.s_addr = htonl(INADDR_ANY); 216 | address.sin_port = htons(self.httpServerPort); 217 | CFDataRef addressData = 218 | CFDataCreate(NULL, (const UInt8 *)&address, sizeof(address)); 219 | 220 | if (CFSocketSetAddress(socket, addressData) != kCFSocketSuccess) 221 | { 222 | [self errorWithName:@"Unable to bind socket to address."]; 223 | CFRelease(addressData); 224 | //TODO: log error with NSLogger 225 | return; 226 | } 227 | 228 | listeningHandle = [[NSFileHandle alloc] 229 | initWithFileDescriptor:fileDescriptor 230 | closeOnDealloc:YES]; 231 | 232 | [[NSNotificationCenter defaultCenter] 233 | addObserver:self 234 | selector:@selector(receiveIncomingConnectionNotification:) 235 | name:NSFileHandleConnectionAcceptedNotification 236 | object:nil]; 237 | [listeningHandle acceptConnectionInBackgroundAndNotify]; 238 | 239 | self.state = SERVER_STATE_RUNNING; 240 | [self startBonjourServices]; 241 | 242 | CFRelease(addressData); 243 | } 244 | 245 | // 246 | // stopReceivingForFileHandle:close: 247 | // 248 | // If a file handle is accumulating the header for a new connection, this 249 | // method will close the handle, stop listening to it and release the 250 | // accumulated memory. 251 | // 252 | // Parameters: 253 | // incomingFileHandle - the file handle for the incoming request 254 | // closeFileHandle - if YES, the file handle will be closed, if no it is 255 | // assumed that an HTTPResponseHandler will close it when done. 256 | // 257 | - (void)stopReceivingForFileHandle:(NSFileHandle *)incomingFileHandle 258 | close:(BOOL)closeFileHandle 259 | { 260 | if (closeFileHandle) 261 | { 262 | [incomingFileHandle closeFile]; 263 | } 264 | 265 | [[NSNotificationCenter defaultCenter] 266 | removeObserver:self 267 | name:NSFileHandleDataAvailableNotification 268 | object:incomingFileHandle]; 269 | [incomingRequests removeObjectForKey:incomingFileHandle]; 270 | } 271 | 272 | // 273 | // stop 274 | // 275 | // Stops the server. 276 | // 277 | - (void)stop 278 | { 279 | self.state = SERVER_STATE_STOPPING; 280 | 281 | [[NSNotificationCenter defaultCenter] 282 | removeObserver:self 283 | name:NSFileHandleConnectionAcceptedNotification 284 | object:nil]; 285 | 286 | [responseHandlers removeAllObjects]; 287 | 288 | [listeningHandle closeFile]; 289 | listeningHandle = nil; 290 | 291 | for (NSFileHandle *incomingFileHandle in 292 | [(NSDictionary *)incomingRequests copy]) 293 | { 294 | [self stopReceivingForFileHandle:incomingFileHandle close:YES]; 295 | } 296 | 297 | if (socket) 298 | { 299 | CFSocketInvalidate(socket); 300 | CFRelease(socket); 301 | socket = nil; 302 | } 303 | 304 | self.state = SERVER_STATE_IDLE; 305 | 306 | [self stopBonjourServices]; 307 | 308 | } 309 | 310 | // 311 | // receiveIncomingConnectionNotification: 312 | // 313 | // Receive the notification for a new incoming request. This method starts 314 | // receiving data from the incoming request's file handle and creates a 315 | // new CFHTTPMessageRef to store the incoming data.. 316 | // 317 | // Parameters: 318 | // notification - the new connection notification 319 | // 320 | - (void)receiveIncomingConnectionNotification:(NSNotification *)notification 321 | { 322 | NSDictionary *userInfo = [notification userInfo]; 323 | NSFileHandle *incomingFileHandle = 324 | [userInfo objectForKey:NSFileHandleNotificationFileHandleItem]; 325 | 326 | if(incomingFileHandle) 327 | { 328 | [incomingRequests setObject:(__bridge_transfer id)CFHTTPMessageCreateEmpty(kCFAllocatorDefault, TRUE) 329 | forKey:(id)incomingFileHandle]; 330 | 331 | [[NSNotificationCenter defaultCenter] 332 | addObserver:self 333 | selector:@selector(receiveIncomingDataNotification:) 334 | name:NSFileHandleDataAvailableNotification 335 | object:incomingFileHandle]; 336 | 337 | [incomingFileHandle waitForDataInBackgroundAndNotify]; 338 | } 339 | 340 | [listeningHandle acceptConnectionInBackgroundAndNotify]; 341 | } 342 | 343 | // 344 | // receiveIncomingDataNotification: 345 | // 346 | // Receive new data for an incoming connection. 347 | // 348 | // Once enough data is received to fully parse the HTTP headers, 349 | // a HTTPResponseHandler will be spawned to generate a response. 350 | // 351 | // Parameters: 352 | // notification - data received notification 353 | // 354 | - (void)receiveIncomingDataNotification:(NSNotification *)notification 355 | { 356 | NSFileHandle *incomingFileHandle = [notification object]; 357 | NSData *data = [incomingFileHandle availableData]; 358 | 359 | if ([data length] == 0) 360 | { 361 | [self stopReceivingForFileHandle:incomingFileHandle close:NO]; 362 | return; 363 | } 364 | 365 | CFHTTPMessageRef incomingRequest = 366 | (__bridge CFHTTPMessageRef)[incomingRequests objectForKey: incomingFileHandle]; 367 | 368 | if (!incomingRequest) 369 | { 370 | [self stopReceivingForFileHandle:incomingFileHandle close:YES]; 371 | return; 372 | } 373 | 374 | if (!CFHTTPMessageAppendBytes( 375 | incomingRequest, 376 | [data bytes], 377 | [data length])) 378 | { 379 | [self stopReceivingForFileHandle:incomingFileHandle close:YES]; 380 | return; 381 | } 382 | 383 | if(CFHTTPMessageIsHeaderComplete(incomingRequest)) 384 | { 385 | HTTPResponseHandler *handler = 386 | [HTTPResponseHandler 387 | handlerForRequest:incomingRequest 388 | fileHandle:incomingFileHandle 389 | server:self]; 390 | 391 | [responseHandlers addObject:handler]; 392 | [self stopReceivingForFileHandle:incomingFileHandle close:NO]; 393 | 394 | [handler startResponse]; 395 | return; 396 | } 397 | 398 | [incomingFileHandle waitForDataInBackgroundAndNotify]; 399 | } 400 | 401 | // 402 | // closeHandler: 403 | // 404 | // Shuts down a response handler and removes it from the set of handlers. 405 | // 406 | // Parameters: 407 | // aHandler - the handler to shut down. 408 | // 409 | - (void)closeHandler:(HTTPResponseHandler *)aHandler 410 | { 411 | [aHandler endResponse]; 412 | [responseHandlers removeObject:aHandler]; 413 | } 414 | 415 | - (UInt32)httpServerPort 416 | { 417 | return HTTP_SERVER_PORT; 418 | } 419 | 420 | - (NSString *)getHostName 421 | { 422 | if([self state] == SERVER_STATE_RUNNING) 423 | { 424 | char baseHostName[256]; 425 | int success = gethostname(baseHostName, 255); 426 | if (success != 0) return nil; 427 | baseHostName[255] = '\0'; 428 | 429 | #if !TARGET_IPHONE_SIMULATOR 430 | return [NSString stringWithFormat:@"%s.local", baseHostName]; 431 | #else 432 | return [NSString stringWithFormat:@"%s", baseHostName]; 433 | #endif 434 | } 435 | 436 | return nil; 437 | } 438 | 439 | - (NSString *)getAutomaticHttpProxyUrl 440 | { 441 | if([self state] == SERVER_STATE_RUNNING) 442 | { 443 | NSString *url = [NSString stringWithFormat:@"http://%@:%u/socks.pac", 444 | [self getHostName], [self httpServerPort]]; 445 | return url; 446 | } 447 | 448 | return nil; 449 | } 450 | 451 | @end 452 | -------------------------------------------------------------------------------- /NSLogger/LoggerClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LoggerClient.h 3 | * 4 | * version 1.9.7 09-JAN-2019 5 | * 6 | * Part of NSLogger (client side) 7 | * https://github.com/fpillet/NSLogger 8 | * 9 | * BSD license follows (http://www.opensource.org/licenses/bsd-license.php) 10 | * 11 | * Copyright (c) 2010-2019 Florent Pillet All Rights Reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without modification, 14 | * are permitted provided that the following conditions are met: 15 | * 16 | * Redistributions of source code must retain the above copyright notice, 17 | * this list of conditions and the following disclaimer. Redistributions in 18 | * binary form must reproduce the above copyright notice, this list of 19 | * conditions and the following disclaimer in the documentation and/or other 20 | * materials provided with the distribution. Neither the name of Florent 21 | * Pillet nor the names of its contributors may be used to endorse or promote 22 | * products derived from this software without specific prior written 23 | * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 24 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 25 | * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | */ 36 | #import 37 | #import 38 | #import 39 | #import 40 | #import 41 | #import 42 | #import 43 | #if !TARGET_OS_IPHONE 44 | #import 45 | #endif 46 | 47 | // This define is here so that user application can test whether NSLogger Client is 48 | // being included in the project, and potentially configure their macros accordingly 49 | #define NSLOGGER_WAS_HERE 1 50 | 51 | /* ----------------------------------------------------------------- 52 | * Logger option flags & default options 53 | * ----------------------------------------------------------------- 54 | */ 55 | enum { 56 | kLoggerOption_LogToConsole = 0x01, 57 | kLoggerOption_BufferLogsUntilConnection = 0x02, 58 | kLoggerOption_BrowseBonjour = 0x04, 59 | kLoggerOption_BrowseOnlyLocalDomain = 0x08, 60 | kLoggerOption_UseSSL = 0x10, 61 | kLoggerOption_CaptureSystemConsole = 0x20, 62 | kLoggerOption_BrowsePeerToPeer = 0x40 63 | }; 64 | 65 | #define LOGGER_DEFAULT_OPTIONS (kLoggerOption_BufferLogsUntilConnection | \ 66 | kLoggerOption_BrowseBonjour | \ 67 | kLoggerOption_BrowsePeerToPeer | \ 68 | kLoggerOption_BrowseOnlyLocalDomain | \ 69 | kLoggerOption_UseSSL | \ 70 | kLoggerOption_CaptureSystemConsole) 71 | 72 | // The Logger struct is no longer public, use the new LoggerGet[...] functions instead 73 | typedef struct Logger Logger; 74 | 75 | /* ----------------------------------------------------------------- 76 | * LOGGING FUNCTIONS 77 | * ----------------------------------------------------------------- 78 | */ 79 | 80 | #ifdef __cplusplus 81 | extern "C" { 82 | #endif 83 | 84 | // Prevents the linker from stripping NSLogger functions 85 | // This is mainly for linked frameworks to be able to use NSLogger dynamically. 86 | // If you DO WANT this functionality, you need to define NSLOGGER_ALLOW_NOSTRIP 87 | // somewhere in the header files included before this one. 88 | #ifdef NSLOGGER_ALLOW_NOSTRIP 89 | #define NSLOGGER_NOSTRIP __attribute__((used)) 90 | #else 91 | #define NSLOGGER_NOSTRIP 92 | #endif 93 | 94 | #define NSLOGGER_IGNORE_NULLABILITY_BEGIN \ 95 | _Pragma("clang diagnostic push") \ 96 | _Pragma("clang diagnostic ignored \"-Wnullability-completeness\"") 97 | 98 | #define NSLOGGER_IGNORE_NULLABILITY_END \ 99 | _Pragma("clang diagnostic pop") 100 | 101 | NSLOGGER_IGNORE_NULLABILITY_BEGIN 102 | 103 | // Set the default logger which will be the one used when passing NULL for logge 104 | extern void LoggerSetDefaultLogger(Logger *aLogger) NSLOGGER_NOSTRIP; 105 | 106 | // Get the default logger, create one if it does not exist 107 | extern Logger *LoggerGetDefaultLogger(void) NSLOGGER_NOSTRIP; 108 | 109 | // Checks whether the default logger exists, returns it if YES, otherwise do NO create one 110 | extern Logger *LoggerCheckDefaultLogger(void) NSLOGGER_NOSTRIP; 111 | 112 | // Initialize a new logger, set as default logger if this is the first one 113 | // Options default to: 114 | // - logging to console = NO 115 | // - buffer until connection = YES 116 | // - browse Bonjour = YES 117 | // - browse only locally on Bonjour = YES 118 | extern Logger* LoggerInit(void) NSLOGGER_NOSTRIP; 119 | 120 | // Set logger options if you don't want the default options (see above) 121 | extern void LoggerSetOptions(Logger *logger, uint32_t options) NSLOGGER_NOSTRIP; 122 | extern uint32_t LoggerGetOptions(Logger *logger) NSLOGGER_NOSTRIP; 123 | 124 | // Set Bonjour logging names, so you can force the logger to use a specific service type 125 | // or direct logs to the machine on your network which publishes a specific name 126 | extern void LoggerSetupBonjour(Logger *logger, CFStringRef bonjourServiceType, CFStringRef bonjourServiceName) NSLOGGER_NOSTRIP; 127 | extern CFStringRef LoggerGetBonjourServiceType(Logger *logger) NSLOGGER_NOSTRIP; 128 | extern CFStringRef LoggerGetBonjourServiceName(Logger *logger) NSLOGGER_NOSTRIP; 129 | 130 | // Set Bonjour logging name to be the username who compiled the LoggerClient.m file. 131 | // This is useful when several NSLogger users are on the same network. This can only be 132 | // used when NSLogger is integrated as source code or via with CocoaPods. 133 | extern void LoggerSetupBonjourForBuildUser(void) NSLOGGER_NOSTRIP; 134 | 135 | // Directly set the viewer host (hostname or IP address) and port we want to connect to. If set, LoggerStart() will 136 | // try to connect there first before trying Bonjour 137 | extern void LoggerSetViewerHost(Logger *logger, CFStringRef hostName, UInt32 port) NSLOGGER_NOSTRIP; 138 | extern CFStringRef LoggerGetViewerHostName(Logger *logger) NSLOGGER_NOSTRIP; 139 | extern UInt32 LoggerGetViewerPort(Logger *logger) NSLOGGER_NOSTRIP; 140 | 141 | // Configure the logger to use a local file for buffering, instead of memory. 142 | // - If you initially set a buffer file after logging started but while a logger connection 143 | // has not been acquired, the contents of the log queue will be written to the buffer file 144 | // the next time a logging function is called, or when LoggerStop() is called. 145 | // - If you want to change the buffering file after logging started, you should first 146 | // call LoggerStop() the call LoggerSetBufferFile(). Note that all logs stored in the previous 147 | // buffer file WON'T be transferred to the new file in this case. 148 | extern void LoggerSetBufferFile(Logger *logger, CFStringRef absolutePath) NSLOGGER_NOSTRIP; 149 | extern CFStringRef LoggerGetBufferFile(Logger *logger) NSLOGGER_NOSTRIP; 150 | 151 | // Activate the logger, try connecting. You can pass NULL to start the default logger, 152 | // it will return a pointer to it. 153 | extern Logger* LoggerStart(Logger *logger) NSLOGGER_NOSTRIP; 154 | 155 | //extern void LoggerConnectToHost(CFDataRef address, int port); 156 | 157 | // Deactivate and free the logger. 158 | extern void LoggerStop(Logger *logger) NSLOGGER_NOSTRIP; 159 | 160 | // Pause the current thread until all messages from the logger have been transmitted 161 | // this is useful to use before an assert() aborts your program. If waitForConnection is YES, 162 | // LoggerFlush() will block even if the client is not currently connected to the desktop 163 | // viewer. You should be using NO most of the time, but in some cases it can be useful. 164 | extern void LoggerFlush(Logger *logger, BOOL waitForConnection) NSLOGGER_NOSTRIP; 165 | 166 | /* Logging functions. Each function exists in four versions: 167 | * 168 | * - one without a Logger instance (uses default logger) and without filename/line/function (no F suffix) 169 | * - one without a Logger instance but with filename/line/function (F suffix) 170 | * - one with a Logger instance (use a specific Logger) and without filename/line/function (no F suffix) 171 | * - one with a Logger instance (use a specific Logger) and with filename/line/function (F suffix) 172 | * 173 | * The exception being the single LogMessageCompat() function which is designed to be a drop-in replacement for NSLog() 174 | * 175 | */ 176 | 177 | // Log a message, calling format compatible with NSLog 178 | extern void LogMessageCompat(NSString *format, ...) NSLOGGER_NOSTRIP; 179 | 180 | // Log a message without any formatting (just log the given string) 181 | extern void LogMessageRaw(NSString *message) NSLOGGER_NOSTRIP; 182 | extern void LogMessageRawF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *message) NSLOGGER_NOSTRIP; 183 | extern void LogMessageRawToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *message) NSLOGGER_NOSTRIP; 184 | 185 | // Log a message. domain can be nil if default domain. 186 | extern void LogMessage(NSString *domain, int level, NSString *format, ...) NS_FORMAT_FUNCTION(3,4) NSLOGGER_NOSTRIP; 187 | extern void LogMessageF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...) NS_FORMAT_FUNCTION(6,7) NSLOGGER_NOSTRIP; 188 | extern void LogMessageTo(Logger *logger, NSString *domain, int level, NSString *format, ...) NS_FORMAT_FUNCTION(4,5) NSLOGGER_NOSTRIP; 189 | extern void LogMessageToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, ...) NS_FORMAT_FUNCTION(7,8) NSLOGGER_NOSTRIP; 190 | 191 | // Log a message. domain can be nil if default domain (versions with va_list format args instead of ...) 192 | extern void LogMessage_va(NSString *domain, int level, NSString *format, va_list args) NS_FORMAT_FUNCTION(3,0) NSLOGGER_NOSTRIP; 193 | extern void LogMessageF_va(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args) NS_FORMAT_FUNCTION(6,0) NSLOGGER_NOSTRIP; 194 | extern void LogMessageTo_va(Logger *logger, NSString *domain, int level, NSString *format, va_list args) NS_FORMAT_FUNCTION(4,0) NSLOGGER_NOSTRIP; 195 | extern void LogMessageToF_va(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSString *format, va_list args) NS_FORMAT_FUNCTION(7,0) NSLOGGER_NOSTRIP; 196 | 197 | // Send binary data to remote logger 198 | extern void LogData(NSString *domain, int level, NSData *data) NSLOGGER_NOSTRIP; 199 | extern void LogDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data) NSLOGGER_NOSTRIP; 200 | extern void LogDataTo(Logger *logger, NSString *domain, int level, NSData *data) NSLOGGER_NOSTRIP; 201 | extern void LogDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, NSData *data) NSLOGGER_NOSTRIP; 202 | 203 | // Send image data to remote logger 204 | extern void LogImageData(NSString *domain, int level, int width, int height, NSData *data) NSLOGGER_NOSTRIP; 205 | extern void LogImageDataF(const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data) NSLOGGER_NOSTRIP; 206 | extern void LogImageDataTo(Logger *logger, NSString *domain, int level, int width, int height, NSData *data) NSLOGGER_NOSTRIP; 207 | extern void LogImageDataToF(Logger *logger, const char *filename, int lineNumber, const char *functionName, NSString *domain, int level, int width, int height, NSData *data) NSLOGGER_NOSTRIP; 208 | 209 | // Mark the start of a block. This allows the remote logger to group blocks together 210 | extern void LogStartBlock(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NSLOGGER_NOSTRIP; 211 | extern void LogStartBlockTo(Logger *logger, NSString *format, ...) NS_FORMAT_FUNCTION(2,3) NSLOGGER_NOSTRIP; 212 | 213 | // Mark the end of a block 214 | extern void LogEndBlock(void) NSLOGGER_NOSTRIP; 215 | extern void LogEndBlockTo(Logger *logger) NSLOGGER_NOSTRIP; 216 | 217 | // Log a marker (text can be null) 218 | extern void LogMarker(NSString *text) NSLOGGER_NOSTRIP; 219 | extern void LogMarkerTo(Logger *logger, NSString *text) NSLOGGER_NOSTRIP; 220 | 221 | NSLOGGER_IGNORE_NULLABILITY_END 222 | 223 | // Swift fastpath logging functions 224 | extern void LogMessage_noFormat(NSString * _Nullable filename, 225 | NSInteger lineNumber, 226 | NSString * _Nullable functionName, 227 | NSString * _Nullable domain, 228 | NSInteger level, 229 | NSString * _Nonnull message) NSLOGGER_NOSTRIP; 230 | 231 | extern void LogImage_noFormat(NSString * _Nullable filename, 232 | NSInteger lineNumber, 233 | NSString * _Nullable functionName, 234 | NSString * _Nullable domain, 235 | NSInteger level, 236 | NSInteger width, 237 | NSInteger height, 238 | NSData * _Nonnull data) NSLOGGER_NOSTRIP; 239 | 240 | extern void LogData_noFormat(NSString * _Nullable filename, 241 | NSInteger lineNumber, 242 | NSString * _Nullable functionName, 243 | NSString * _Nullable domain, 244 | NSInteger level, 245 | NSData * _Nonnull data) NSLOGGER_NOSTRIP; 246 | 247 | #ifdef __cplusplus 248 | }; 249 | #endif 250 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | -------------------------------------------------------------------------------- /SocksProxy.mm: -------------------------------------------------------------------------------- 1 | /* 2 | # SOCKS - SOCKS Proxy for iPhone 3 | # Copyright (C) 2009 Ehud Ben-Reuven 4 | # udi@benreuven.com 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation version 2. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA. 18 | */ 19 | #import "SocksProxy.h" 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | @interface SocksProxy () 27 | - (void)socksProtocol:(NSString*)streamName; 28 | 29 | // Properties that don't need to be seen by the outside world. 30 | 31 | @property (nonatomic, strong) NSInputStream * receivenetworkStream; 32 | @property (nonatomic, strong) NSOutputStream * sendnetworkStream; 33 | @property (nonatomic, strong) NSOutputStream * remoteSendNetworkStream; 34 | @property (nonatomic, strong) NSInputStream * remoteReceiveNetworkStream; 35 | @property (nonatomic, readonly) uint8_t * sendbuffer; 36 | @property (nonatomic, assign) size_t sendbufferOffset; 37 | @property (nonatomic, assign) size_t sendbufferLimit; 38 | @property (nonatomic, readonly) uint8_t * receivebuffer; 39 | @property (nonatomic, assign) size_t receivebufferOffset; 40 | @property (nonatomic, assign) size_t receivebufferLimit; 41 | @property (nonatomic, assign) NSUInteger protocolLocation; 42 | @property (nonatomic, strong) NSString * remoteName; 43 | @property (nonatomic, assign) bool shouldReceiveRemote; 44 | @end 45 | 46 | @implementation SocksProxy 47 | 48 | #pragma mark * Core transfer code 49 | 50 | // This is the code that actually does the networking. 51 | 52 | @synthesize receivenetworkStream = _receivenetworkStream; 53 | @synthesize sendnetworkStream = _sendnetworkStream; 54 | @synthesize remoteSendNetworkStream = _remoteSendNetworkStream; 55 | @synthesize remoteReceiveNetworkStream = _remoteReceiveNetworkStream; 56 | @synthesize sendbufferOffset = _sendbufferOffset; 57 | @synthesize sendbufferLimit = _sendbufferLimit; 58 | @synthesize receivebufferOffset = _receivebufferOffset; 59 | @synthesize receivebufferLimit = _receivebufferLimit; 60 | @synthesize protocolLocation = _protocolLocation; 61 | @synthesize delegate; 62 | @synthesize remoteName = _remoteName; 63 | // Because buffer is declared as an array, you have to use a custom getter. 64 | // A synthesised getter doesn't compile. 65 | 66 | - (uint8_t *)sendbuffer 67 | { 68 | return self->_sendbuffer; 69 | } 70 | - (uint8_t *)receivebuffer 71 | { 72 | return self->_receivebuffer; 73 | } 74 | 75 | 76 | - (BOOL)isSendingReceiving 77 | { 78 | return (self.receivenetworkStream != nil) || (self.sendnetworkStream != nil); 79 | } 80 | 81 | - (BOOL)startSendReceive:(int)fd 82 | { 83 | CFReadStreamRef readStream; 84 | CFWriteStreamRef writeStream; 85 | 86 | if(fd < 0) 87 | return NO; 88 | 89 | self.receivebufferOffset = 0; 90 | self.receivebufferLimit = 0; 91 | self.sendbufferOffset = 0; 92 | self.sendbufferLimit = 0; 93 | self.remoteName=nil; 94 | self.protocolLocation=0; 95 | self.receivenetworkStream = nil; 96 | self.sendnetworkStream = nil; 97 | self.remoteSendNetworkStream = nil; 98 | self.remoteReceiveNetworkStream = nil; 99 | 100 | // Open a stream based on the existing socket file descriptor. Then configure 101 | // the stream for async operation. 102 | 103 | CFStreamCreatePairWithSocket(NULL, fd, &readStream, &writeStream); 104 | if(readStream == NULL) 105 | return NO; 106 | if(writeStream == NULL) 107 | return NO; 108 | 109 | self.receivenetworkStream = (NSInputStream *) CFBridgingRelease(readStream); 110 | self.sendnetworkStream = (NSOutputStream *) CFBridgingRelease(writeStream); 111 | 112 | [self.receivenetworkStream setProperty:(id)kCFBooleanTrue forKey:(NSString *)kCFStreamPropertyShouldCloseNativeSocket]; 113 | [self.sendnetworkStream setProperty:(id)kCFBooleanTrue forKey:(NSString *)kCFStreamPropertyShouldCloseNativeSocket]; 114 | 115 | self.receivenetworkStream.delegate = self; 116 | self.sendnetworkStream.delegate = self; 117 | [self.receivenetworkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 118 | [self.sendnetworkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 119 | 120 | [self.receivenetworkStream open]; 121 | [self.sendnetworkStream open]; 122 | 123 | // Tell the UI we're receiving. 124 | 125 | [self.delegate _sendreceiveDidStart]; 126 | return YES; 127 | } 128 | 129 | - (void)stopSendReceiveWithStatus:(NSString *)statusString 130 | { 131 | if (statusString == nil) 132 | { 133 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_INFO, @"stop with no status"); 134 | if (self.receivebufferOffset != self.receivebufferLimit) { 135 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"We still have %lu data left in receivebuffer",self.receivebufferLimit-self.receivebufferOffset); 136 | return; 137 | } 138 | if (self.sendbufferLimit != self.sendbufferOffset) { 139 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"We still have %lu data left in sendbuffer", self.sendbufferLimit - self.sendbufferOffset); 140 | return; 141 | } 142 | }else{ 143 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_INFO, @"stop with status %@", statusString); 144 | } 145 | 146 | if (self.receivenetworkStream != nil) { 147 | self.receivenetworkStream.delegate = nil; 148 | [self.receivenetworkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 149 | [self.receivenetworkStream close]; 150 | } 151 | 152 | if (self.sendnetworkStream != nil) { 153 | [self.sendnetworkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 154 | self.sendnetworkStream.delegate = nil; 155 | [self.sendnetworkStream close]; 156 | } 157 | 158 | //remote send 159 | if (self.remoteSendNetworkStream != nil) { 160 | [self.remoteSendNetworkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 161 | self.remoteSendNetworkStream.delegate = nil; 162 | [self.remoteSendNetworkStream close]; 163 | } 164 | 165 | //remote receive 166 | if (self.remoteReceiveNetworkStream != nil) { 167 | [self.remoteReceiveNetworkStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 168 | self.remoteReceiveNetworkStream.delegate = nil; 169 | [self.remoteReceiveNetworkStream close]; 170 | } 171 | 172 | self.receivebufferOffset = 0; 173 | self.receivebufferLimit = 0; 174 | self.sendbufferOffset = 0; 175 | self.sendbufferLimit = 0; 176 | self.remoteName=nil; 177 | self.protocolLocation=0; 178 | self.receivenetworkStream = nil; 179 | self.sendnetworkStream = nil; 180 | self.remoteSendNetworkStream = nil; 181 | self.remoteReceiveNetworkStream = nil; 182 | 183 | [self.delegate _sendreceiveDidStopWithStatus:statusString]; 184 | } 185 | 186 | #pragma mark * Internal transfer code 187 | - (void)checkSendBuffer:(NSString*)streamName 188 | { 189 | if (self.sendbufferOffset==self.sendbufferLimit) { 190 | self.sendbufferOffset=0; 191 | self.sendbufferLimit=0; 192 | } 193 | } 194 | - (void)sendBuffer:(NSString*)streamName 195 | { 196 | if (![self.sendnetworkStream hasSpaceAvailable]){ 197 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"sendnetworkStream has NO space available for %@", streamName); 198 | return; 199 | } 200 | if (self.sendbufferOffset == self.sendbufferLimit){ 201 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"sendBuffer has no new data to send for %@", streamName); 202 | return; 203 | } 204 | 205 | NSInteger bytesWritten = self.sendbufferLimit - self.sendbufferOffset; 206 | 207 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"attempt to sendBuffer %ld for %@", (long)bytesWritten, streamName); 208 | 209 | bytesWritten = [self.sendnetworkStream write:&self.sendbuffer[self.sendbufferOffset] 210 | maxLength:bytesWritten]; 211 | 212 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Actually sendBuffer write %ld for %@", (long)bytesWritten, streamName); 213 | 214 | assert(bytesWritten != 0); 215 | if (bytesWritten == -1) { 216 | NSError *err = [self.sendnetworkStream streamError]; 217 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"ERROR: sendBuffer - stream %@ with error code %ld, domain %@, userInfo %@", 218 | streamName, (long)[err code], [err domain], [err userInfo]); 219 | [self stopSendReceiveWithStatus:@"Network write error"]; 220 | } else { 221 | self.sendbufferOffset += bytesWritten; 222 | } 223 | [self checkSendBuffer: streamName]; 224 | } 225 | - (void)readReceiveNetwork:(NSString*)streamName 226 | { 227 | NSInteger bytesRead = kReceiveBufferSize-self.receivebufferLimit; 228 | if (bytesRead == 0) { 229 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"receive buffer is full for %@", streamName); 230 | return; 231 | } 232 | bytesRead = [self.receivenetworkStream read:&self.receivebuffer[self.receivebufferLimit] 233 | maxLength:bytesRead]; 234 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Actually readReceiveNetwork read %ld for %@",(long)bytesRead, streamName); 235 | if (bytesRead == -1) { 236 | NSError *err = [self.receivenetworkStream streamError]; 237 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"ERROR: readReceiveNetwork - stream %@ with error code %ld, domain %@, userInfo %@", 238 | streamName, (long)[err code], [err domain], [err userInfo]); 239 | [self stopSendReceiveWithStatus:@"Network read error"]; 240 | } else if (bytesRead == 0) { 241 | [self stopSendReceiveWithStatus:nil]; 242 | } else { 243 | self.receivebufferLimit+=bytesRead; 244 | [self socksProtocol: streamName]; 245 | } 246 | 247 | } 248 | - (void)readRemoteReceiveNetwork:(NSString *)streamName 249 | { 250 | // data is coming from the remote site 251 | NSInteger bytesRead=kSendBufferSize-self.sendbufferLimit; 252 | if (bytesRead == 0){ 253 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"remote receive buffer is full for %@", streamName); 254 | //invoke readRemoteReceiveNetwork after sendBuffer method when sendBuffer is full 255 | self.shouldReceiveRemote = YES; 256 | return; 257 | } 258 | bytesRead = [self.remoteReceiveNetworkStream read:&self.sendbuffer[self.sendbufferLimit] 259 | maxLength:bytesRead]; 260 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Actually readRemoteReceiveNetwork read %ld for %@",(long)bytesRead, streamName); 261 | if (bytesRead == -1) { 262 | NSError *err = [self.remoteReceiveNetworkStream streamError]; 263 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"ERROR: readRemoteReceiveNetwork - stream %@ with error code %ld, domain %@, userInfo %@", 264 | streamName, (long)[err code], [err domain], [err userInfo]); 265 | [self stopSendReceiveWithStatus:@"Remote network read error"]; 266 | } else if (bytesRead == 0) { 267 | [self stopSendReceiveWithStatus:nil]; 268 | } else { 269 | self.shouldReceiveRemote = NO; 270 | self.sendbufferLimit+=bytesRead; 271 | [self.delegate _downloadData:bytesRead]; 272 | [self sendBuffer: streamName]; 273 | } 274 | } 275 | - (void)checkReceiveBuffer:(NSString*)streamName 276 | { 277 | if (self.receivebufferOffset==self.receivebufferLimit) { 278 | self.receivebufferOffset=0; 279 | self.receivebufferLimit=0; 280 | } 281 | if ([self.receivenetworkStream hasBytesAvailable]) { 282 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"receivenetworkStream has more data for %@. going to read.", streamName); 283 | [self readReceiveNetwork: streamName]; 284 | } 285 | } 286 | - (void)sendremoteBuffer:(NSString*)streamName 287 | { 288 | if (![self.remoteSendNetworkStream hasSpaceAvailable]) 289 | return; 290 | 291 | if (self.receivebufferOffset == self.receivebufferLimit) 292 | return; 293 | NSInteger bytesWritten=self.receivebufferLimit - self.receivebufferOffset; 294 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"attempt to sendremoteBuffer %ld for %@", (long)bytesWritten, streamName); 295 | bytesWritten = [self.remoteSendNetworkStream write:&self.receivebuffer[self.receivebufferOffset] 296 | maxLength:bytesWritten]; 297 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Actually sendremoteBuffer write %ld for %@", (long)bytesWritten, streamName); 298 | assert(bytesWritten != 0); 299 | if (bytesWritten == -1) { 300 | NSError *err = [self.remoteSendNetworkStream streamError]; 301 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"ERROR: sendremoteBuffer - stream %@ with error code %ld, domain %@, userInfo %@", 302 | streamName, (long)[err code], [err domain], [err userInfo]); 303 | [self stopSendReceiveWithStatus:@"Remote network write error"]; 304 | } else { 305 | self.receivebufferOffset += bytesWritten; 306 | [self.delegate _uploadData:bytesWritten]; 307 | } 308 | [self checkReceiveBuffer: streamName]; 309 | } 310 | 311 | 312 | -(uint)sendData:(uint8_t *)buf size:(uint)n 313 | { 314 | if (n>kSendBufferSize-self.sendbufferLimit) 315 | n = kSendBufferSize-self.sendbufferLimit; 316 | if (n>0) { 317 | memcpy(&(self.sendbuffer[self.sendbufferLimit]), buf, (size_t)n); 318 | self.sendbufferLimit+=n; 319 | } 320 | return n; 321 | } 322 | 323 | - (void)socksProtocol:(NSString*)streamName 324 | { 325 | NSUInteger lastProtocolLocation = -1; 326 | while (self.receivebufferLimit > self.receivebufferOffset) { 327 | 328 | uint8_t *s = self.receivebuffer + self.receivebufferOffset; 329 | uint8_t *e = self.receivebuffer + self.receivebufferLimit; 330 | 331 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"protocol %lu %d", (unsigned long)self.protocolLocation, e - s); 332 | 333 | // if the protocol did not advance then it is an indication that we dont 334 | // have enough data in self.receivebuffer 335 | // we should exit this handler and wait for it to be called again with more 336 | if(lastProtocolLocation == self.protocolLocation) { 337 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Wait for more data %lu",(unsigned long)lastProtocolLocation); 338 | break; 339 | } 340 | lastProtocolLocation=self.protocolLocation; 341 | 342 | switch (self.protocolLocation) { 343 | case 0: {// The initial greeting from the client is 344 | // SOCKS protocl version 345 | if(e-s<1) break; 346 | uint8_t socks_version = *s++; 347 | if (socks_version!=5) { 348 | [self stopSendReceiveWithStatus:@"Unsupported SOCKS protocol"]; 349 | break; 350 | } 351 | 352 | //number of authentication methods supported 353 | if (e-s<1) break; 354 | uint8_t nauth = *s++; 355 | 356 | //authentication methods 357 | if(e-s>24), 418 | 0xff&(ipaddr>>16), 419 | 0xff&(ipaddr>>8), 420 | 0xff&(ipaddr>>0) 421 | ]; 422 | } else if(addr_type==3) { 423 | if(e-s<1) break; 424 | size_t n=*s++; 425 | char saddr[2048]; 426 | if (n>=sizeof(saddr)-1) { 427 | memcpy(saddr,"too long",9); 428 | rc=1; 429 | } else { 430 | memcpy(saddr, s, n); 431 | } 432 | s+=n; 433 | saddr[n]=0; 434 | addr=[NSString stringWithCString:saddr encoding:[NSString defaultCStringEncoding]]; 435 | } else {//address type not supported 436 | rc=8; 437 | } 438 | 439 | //port 440 | if(e-s<2) break; 441 | int port = ntohs(*(ushort *)s); 442 | s+=2; 443 | 444 | //update address 445 | NSString *remoteAddress = addr; 446 | if (!remoteAddress) 447 | remoteAddress = @"unkown host"; 448 | self.remoteName=[NSString stringWithFormat:@"%@:%d",remoteAddress,port]; 449 | [self.delegate _updateStatus:self.remoteName]; 450 | 451 | //execute the command 452 | if (command == 1) { 453 | CFHostRef host; 454 | if(!rc){ 455 | host = CFHostCreateWithName(NULL,(__bridge CFStringRef)addr); 456 | if (host == NULL) { 457 | rc=4; //host unreachable 458 | } 459 | } 460 | CFReadStreamRef readStream; 461 | CFWriteStreamRef writeStream; 462 | if(!rc) { 463 | (void) CFStreamCreatePairWithSocketToCFHost(NULL,host,port, &readStream, &writeStream); 464 | if (!readStream || !writeStream) { 465 | rc=5;// connection refused by destination host 466 | } 467 | CFRelease(host); 468 | } 469 | if(!rc) { 470 | self.remoteReceiveNetworkStream = (NSInputStream *)CFBridgingRelease(readStream); 471 | self.remoteReceiveNetworkStream.delegate = self; 472 | [self.remoteReceiveNetworkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 473 | [self.remoteReceiveNetworkStream open]; 474 | 475 | self.remoteSendNetworkStream = (NSOutputStream *)CFBridgingRelease(writeStream); 476 | self.remoteSendNetworkStream.delegate = self; 477 | [self.remoteSendNetworkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 478 | [self.remoteSendNetworkStream open]; 479 | } 480 | } else {//command not supported / protocol error 481 | rc = 7; 482 | } 483 | 484 | 485 | //send a reply 486 | uint8_t buf[3]; 487 | buf[0]=socks_version; 488 | buf[1]=rc; 489 | buf[2]=0;//reserved 490 | 491 | if ([self sendData:buf size:3] != 3) { 492 | [self stopSendReceiveWithStatus:@"Cant send reply 1"]; 493 | break; 494 | } 495 | uint n=s-addrstart; 496 | if ([self sendData:addrstart size:n] != n) { 497 | [self stopSendReceiveWithStatus:@"Cant send reply 2"]; 498 | break; 499 | } 500 | [self sendBuffer: streamName]; 501 | 502 | //advance buffer/protocol 503 | self.receivebufferOffset=s-self.receivebuffer; 504 | if(!rc) 505 | self.protocolLocation++; 506 | else { 507 | self.protocolLocation=0; 508 | } 509 | 510 | //send any data we already have to remote host 511 | if(!rc) 512 | [self sendremoteBuffer: streamName]; 513 | } break; 514 | default: { 515 | [self sendremoteBuffer: streamName]; 516 | } break; 517 | } 518 | } 519 | [self checkReceiveBuffer: streamName]; 520 | } 521 | 522 | - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode 523 | // An NSStream delegate callback that's called when events happen on our 524 | // network stream. 525 | { 526 | if (aStream==nil) { 527 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"nil stream from hadleEvent."); 528 | return; 529 | } 530 | NSString *streamName; 531 | // C-Client (laptop) P-Proxy (iPhone) S-Server (remote server) 532 | if (aStream == self.receivenetworkStream) { 533 | streamName = @"C>P"; 534 | } else if (aStream == self.sendnetworkStream) { 535 | streamName = @"P>C"; 536 | } else if (aStream == self.remoteReceiveNetworkStream) { 537 | streamName = @"S>P"; 538 | } else if (aStream == self.remoteSendNetworkStream) { 539 | streamName = @"P>S"; 540 | } else { 541 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"Unknown stream"); 542 | return; 543 | } 544 | if (self.remoteName) { 545 | streamName = [NSString stringWithFormat:@"%@ %@",streamName,self.remoteName]; 546 | } 547 | 548 | switch (eventCode) { 549 | case NSStreamEventOpenCompleted: { 550 | 551 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Open %@", streamName); 552 | 553 | [self.delegate _updateStatus:@"Opened connection"]; 554 | } break; 555 | case NSStreamEventHasBytesAvailable: { 556 | 557 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Receive %@", streamName); 558 | 559 | if (aStream == self.remoteReceiveNetworkStream) { 560 | // data comming from remote server 561 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"going to read %@", streamName); 562 | [self readRemoteReceiveNetwork: streamName]; 563 | break; 564 | } else if (aStream == self.receivenetworkStream) { 565 | // data comming from local client 566 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"going to read %@", streamName); 567 | [self readReceiveNetwork: streamName]; 568 | } 569 | } break; 570 | case NSStreamEventHasSpaceAvailable: { 571 | 572 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Send %@", streamName); 573 | 574 | if (aStream == self.remoteSendNetworkStream) { 575 | //remote host is ready to receive data 576 | [self sendremoteBuffer: streamName]; 577 | // The sending may have freed up space that can be used to move data from the Computer side to the Server side 578 | if (self.receivebufferLimit > self.receivebufferOffset) { 579 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Processing more data for %@", streamName); 580 | [self socksProtocol: streamName]; 581 | } 582 | break; 583 | } else if (aStream == self.sendnetworkStream) { 584 | //local host is ready to receive data 585 | [self sendBuffer: streamName]; 586 | if (self.shouldReceiveRemote) { 587 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"remoteReceiveNetworkStream has more data for %@. going to read", streamName); 588 | [self readRemoteReceiveNetwork: streamName]; 589 | } 590 | } 591 | } break; 592 | case NSStreamEventErrorOccurred: { 593 | NSError *err = [aStream streamError]; 594 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"Error stream %@ with error code %ld, domain %@, userInfo %@", streamName, (long)[err code], [err domain], [err userInfo]); 595 | [self stopSendReceiveWithStatus:@"Stream open error"]; 596 | } break; 597 | case NSStreamEventEndEncountered: { 598 | // ignore 599 | 600 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"End %@",streamName); 601 | 602 | } break; 603 | default: { 604 | assert(NO); 605 | } break; 606 | } 607 | } 608 | @end 609 | -------------------------------------------------------------------------------- /SocksProxyController.mm: -------------------------------------------------------------------------------- 1 | // 2 | // SOCKS - SOCKS Proxy for iPhone 3 | // Copyright (C) 2009 Ehud Ben-Reuven 4 | // udi@benreuven.com 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation version 2. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,USA. 18 | // 19 | // Enhanced by Daniel Sachse on 10/30/10. 20 | // Copyright 2010 coffeecoding. All rights reserved. 21 | // 22 | 23 | #import "SocksProxyController.h" 24 | #import "AppDelegate.h" 25 | #import "UIDevice_Extended.h" 26 | #import "MOGlassButton.h" 27 | 28 | #import 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | @interface SocksProxyController () 37 | 38 | // Properties that don't need to be seen by the outside world. 39 | 40 | @property (nonatomic, readonly) BOOL isSocksProxyStarted; 41 | @property (nonatomic, strong) NSNetService * netService; 42 | @property (nonatomic, assign) CFSocketRef listeningSocket; 43 | @property (nonatomic, assign) NSInteger nConnections; 44 | @property (nonatomic, strong) NSMutableArray* sendreceiveStream; 45 | @property (nonatomic, strong) AVPlayer* bgPlayer; 46 | 47 | // Forward declarations 48 | 49 | - (void)_stopSocksProxyServer:(NSString *)reason; 50 | 51 | @end 52 | 53 | /*! 54 | * Specifies the sections of the table 55 | */ 56 | typedef enum { 57 | SocksProxyTableSectionGeneral, 58 | SocksProxyTableSectionConnections, 59 | SocksProxyTableSectionCount 60 | } SocksProxyTableSection; 61 | 62 | /*! 63 | * Specifies the rows of the table sections 64 | */ 65 | typedef enum { 66 | SocksProxyTableRowAddress, 67 | SocksProxyTableRowPort, 68 | SocksProxyTableHttpAutoProxyUrl, 69 | // connections section 70 | SocksProxyTableRowConnections = 0, 71 | SocksProxyTableRowConnectionsOpen, 72 | SocksProxyTableRowUpload, 73 | SocksProxyTableRowDownload, 74 | SocksProxyTableRowStatus 75 | } SocksProxyTableRow; 76 | 77 | @implementation SocksProxyController 78 | @synthesize nConnections = _nConnections; 79 | // Because sendreceiveStream is declared as an array, you have to use a custom getter. 80 | // A synthesised getter doesn't compile. 81 | @synthesize bgPlayer; 82 | 83 | 84 | - (NSMutableArray*)sendreceiveStream 85 | { 86 | if(_sendreceiveStream == nil) 87 | _sendreceiveStream = [[NSMutableArray alloc]init]; 88 | return _sendreceiveStream; 89 | } 90 | 91 | 92 | #pragma mark - Status management 93 | 94 | // These methods are used by the core transfer code to update the UI. 95 | 96 | - (void)_sockProxyServerDidStartOnPort:(int)port 97 | { 98 | assert( (port > 0) && (port < 65536) ); 99 | 100 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; 101 | 102 | // Enable proximity sensor (public as of 3.0) 103 | [UIDevice currentDevice].proximityMonitoringEnabled = YES; 104 | 105 | // Enable backgrounding 106 | // Set AVAudioSession 107 | NSError *sessionError = nil; 108 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 109 | [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&sessionError]; 110 | #else 111 | NSLog(@"Warning: iOS 6 is required for background audio hiding."); 112 | [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&sessionError]; 113 | #endif 114 | AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[[NSBundle mainBundle] URLForResource:@"silence" withExtension:@"mp3"]]; 115 | 116 | [self setBgPlayer:[[AVPlayer alloc] initWithPlayerItem:item]]; 117 | [[self bgPlayer] setActionAtItemEnd:AVPlayerActionAtItemEndNone]; 118 | [[self bgPlayer] play]; 119 | 120 | self.currentAddress = [UIDevice localWiFiIPAddress]; 121 | self.currentPort = port; 122 | self.currentStatusText = NSLocalizedString(@"Started", nil); 123 | [self.startOrStopButton setTitle:NSLocalizedString(@"Stop", nil) 124 | forState:UIControlStateNormal]; 125 | [self.startOrStopButton setupAsRedButton]; 126 | 127 | [self refreshProxyTable]; 128 | 129 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_INFO, @"Server Started"); 130 | } 131 | 132 | - (void)_serverDidStopWithReason:(NSString *)reason 133 | { 134 | if (reason == nil) { 135 | reason = NSLocalizedString(@"Stopped", nil); 136 | } 137 | 138 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; 139 | 140 | // Enable device sleep mode 141 | [UIApplication sharedApplication].idleTimerDisabled = NO; 142 | 143 | // Disable proximity sensor (public as of 3.0) 144 | [UIDevice currentDevice].proximityMonitoringEnabled = NO; 145 | 146 | // Disable backgrounding 147 | [self setBgPlayer:nil]; 148 | 149 | self.currentAddress = @""; 150 | self.httpAutoProxyURL = @""; 151 | self.currentPort = 0; 152 | self.currentStatusText = reason; 153 | [self.startOrStopButton setTitle:NSLocalizedString(@"Start" , nil) 154 | forState:UIControlStateNormal]; 155 | [self.startOrStopButton setupAsGreenButton]; 156 | 157 | [self refreshProxyTable]; 158 | 159 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_INFO, @"Server Stopped: %@", reason); 160 | } 161 | 162 | 163 | - (NSInteger)countOpen 164 | { 165 | int countOpen = 0; 166 | for(SocksProxy* asocksProxy in self.sendreceiveStream) 167 | { 168 | if ( ! [asocksProxy isSendingReceiving]) 169 | ++countOpen; 170 | } 171 | return countOpen; 172 | } 173 | 174 | 175 | - (void)_sendreceiveDidStart 176 | { 177 | self.currentStatusText = NSLocalizedString(@"Receiving", nil); 178 | 179 | NSInteger countOpen = [self countOpen]; 180 | self.currentOpenConnections = countOpen; 181 | 182 | [self refreshProxyTable]; 183 | } 184 | 185 | 186 | - (void)_updateStatus:(NSString *)statusString 187 | { 188 | assert(statusString != nil); 189 | 190 | self.currentStatusText = statusString; 191 | 192 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"Status: %@", statusString); 193 | 194 | } 195 | 196 | 197 | - (void)_sendreceiveDidStopWithStatus:(NSString *)statusString 198 | { 199 | if (statusString == nil) { 200 | statusString = NSLocalizedString(@"Receive succeeded", nil); 201 | } 202 | self.currentStatusText = statusString; 203 | NSInteger countOpen = [self countOpen]; 204 | self.currentOpenConnections = countOpen; 205 | 206 | [self refreshProxyTable]; 207 | 208 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_INFO, @"Connection ended %ld %ld: %@", (long)countOpen, (long)self.nConnections, statusString); 209 | } 210 | 211 | 212 | - (void)_downloadData:(NSInteger)bytes 213 | { 214 | self.downloadData += bytes/1024; 215 | 216 | [self refreshProxyTable]; 217 | } 218 | 219 | 220 | - (void)_uploadData:(NSInteger)bytes 221 | { 222 | self.uploadData += bytes/1024; 223 | 224 | [self refreshProxyTable]; 225 | } 226 | #pragma mark - Core transfer code 227 | 228 | // This is the code that actually does the networking. 229 | 230 | @synthesize netService = _netService; 231 | @synthesize listeningSocket = _listeningSocket; 232 | 233 | 234 | - (BOOL)isSocksProxyStarted 235 | { 236 | return (self.netService != nil); 237 | } 238 | 239 | // Have to write our own setter for listeningSocket because CF gets grumpy 240 | // if you message NULL. 241 | 242 | - (void)setListeningSocket:(CFSocketRef)newValue 243 | { 244 | if (newValue != self->_listeningSocket) { 245 | if (self->_listeningSocket != NULL) { 246 | CFRelease(self->_listeningSocket); 247 | } 248 | self->_listeningSocket = newValue; 249 | if (self->_listeningSocket != NULL) { 250 | CFRetain(self->_listeningSocket); 251 | } 252 | } 253 | } 254 | 255 | 256 | - (void)_acceptConnection:(int)fd 257 | { 258 | SocksProxy *proxy = nil; 259 | BOOL isFoundFreeProxy = NO; 260 | int totalNumProxy = 0; 261 | 262 | for(proxy in self.sendreceiveStream) 263 | { 264 | if(![proxy isSendingReceiving]) 265 | { 266 | isFoundFreeProxy = YES; 267 | break; 268 | } 269 | totalNumProxy++; 270 | } 271 | 272 | if(!isFoundFreeProxy) { 273 | if(totalNumProxy>MAX_CONNECTIONS) { 274 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_WARNNING, @"Reach maximum number of concurrent SOCKS connectionss."); 275 | close(fd); 276 | return; 277 | } 278 | 279 | proxy = [SocksProxy new]; 280 | proxy.delegate = self; 281 | [self.sendreceiveStream addObject:proxy]; 282 | 283 | ++self.nConnections; 284 | self.currentConnectionCount = self.nConnections; 285 | } 286 | 287 | //recount open connection 288 | int countOpen = 0; 289 | 290 | for (SocksProxy* asocksProxy in self.sendreceiveStream) 291 | { 292 | if (![asocksProxy isSendingReceiving]) 293 | ++countOpen; 294 | } 295 | 296 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_INFO, @"Accept connection %d %ld", countOpen, (long)self.nConnections); 297 | 298 | if (![proxy startSendReceive:fd]) 299 | close(fd); 300 | 301 | [self refreshProxyTable]; 302 | } 303 | 304 | 305 | static void AcceptCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) 306 | // Called by CFSocket when someone connects to our listening socket. 307 | // This implementation just bounces the request up to Objective-C. 308 | { 309 | SocksProxyController * obj; 310 | 311 | #pragma unused(type) 312 | assert(type == kCFSocketAcceptCallBack); 313 | #pragma unused(address) 314 | // assert(address == NULL); 315 | assert(data != NULL); 316 | 317 | obj = (__bridge SocksProxyController *) info; 318 | assert(obj != nil); 319 | 320 | #pragma unused(s) 321 | assert(s == obj->_listeningSocket); 322 | 323 | [obj _acceptConnection:*(int *)data]; 324 | } 325 | 326 | 327 | - (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary *)errorDict 328 | // A NSNetService delegate callback that's called if our Bonjour registration 329 | // fails. 330 | // 331 | // We only show the error in the status bar and output to the log. 332 | { 333 | #pragma unused(sender) 334 | assert(sender == self.netService); 335 | 336 | NSString *msg = [NSString stringWithFormat:@"sock Bonjour registration failed: error code %@", 337 | errorDict[NSNetServicesErrorCode]]; 338 | [self _updateStatus:msg]; 339 | LOG_NETWORK_HTTP(NSLOGGER_LEVEL_ERROR, @"%@", msg); 340 | } 341 | 342 | - (void)_startServers 343 | { 344 | //start socks proxy server 345 | [self _startSocksProxyServer]; 346 | //start DNS server 347 | _DNSServer = DNSServer::getInstance(); 348 | const char * ipv4Addr = [currentAddress cStringUsingEncoding:NSASCIIStringEncoding]; 349 | _DNSServer->startDNSServer(0, ipv4Addr); 350 | //start HTTP server that advertise socks.pac 351 | _HTTPServer = [HTTPServer sharedHTTPServerWithSocksProxyPort:currentPort]; 352 | HTTPServerState currentHTTPServerState = [_HTTPServer state] ; 353 | if (currentHTTPServerState == SERVER_STATE_IDLE || 354 | currentHTTPServerState == SERVER_STATE_STOPPING) 355 | [_HTTPServer start]; 356 | 357 | if ([_HTTPServer state] == SERVER_STATE_RUNNING && 358 | _DNSServer->getDNSServerState() == DNS_SERVER_STARTED && 359 | self.isSocksProxyStarted) 360 | [self _serversDidStart]; 361 | } 362 | 363 | - (void)_stopServers:(NSString *)reason 364 | { 365 | [self _stopSocksProxyServer:reason]; 366 | _DNSServer = DNSServer::getInstance(); 367 | _DNSServer->stopDNSServer(); 368 | _HTTPServer = [HTTPServer sharedHTTPServerWithSocksProxyPort:currentPort]; 369 | [_HTTPServer stop]; 370 | } 371 | 372 | - (void)_serversDidStart 373 | { 374 | self.httpAutoProxyURL = [_HTTPServer getAutomaticHttpProxyUrl]; 375 | } 376 | 377 | - (void)_startSocksProxyServer 378 | { 379 | BOOL success; 380 | int err; 381 | int fd; 382 | int junk; 383 | struct sockaddr_in addr; 384 | int port; 385 | const int on = 1; 386 | 387 | self.nConnections = 0; 388 | // Create a listening socket and use CFSocket to integrate it into our 389 | // runloop. We bind to port 0, which causes the kernel to give us 390 | // any free port, then use getsockname to find out what port number we 391 | // actually got. 392 | 393 | port = 0; 394 | 395 | fd = socket(AF_INET, SOCK_STREAM, 0); 396 | success = (fd != -1); 397 | 398 | if (success) { 399 | // set scoket to reuse port and ignore TIME_WAIT state 400 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 401 | 402 | memset(&addr, 0, sizeof(addr)); 403 | addr.sin_len = sizeof(addr); 404 | addr.sin_family = AF_INET; 405 | addr.sin_addr.s_addr = INADDR_ANY; 406 | 407 | int iport; 408 | int ports[] = {1080,3128,-1}; 409 | for (iport = 0 ; ports[iport] >= 0 ; ++iport) { 410 | port=ports[iport]; 411 | addr.sin_port = htons(port); 412 | err = bind(fd, (const struct sockaddr *) &addr, sizeof(addr)); 413 | success = (err == 0); 414 | if (success) 415 | break; 416 | else{ 417 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"Socks Server failed to bind port (%d), errono (%d)", port, errno); 418 | } 419 | } 420 | } 421 | if (success) { 422 | err = listen(fd, 5); 423 | success = (err == 0); 424 | }else{ 425 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"Socks Server failed to bind to address, errno(%d)", errno); 426 | } 427 | 428 | if (success) { 429 | socklen_t addrLen; 430 | 431 | addrLen = sizeof(addr); 432 | err = getsockname(fd, (struct sockaddr *) &addr, &addrLen); 433 | success = (err == 0); 434 | 435 | if (success) { 436 | assert(addrLen == sizeof(addr)); 437 | port = ntohs(addr.sin_port); 438 | } 439 | }else{ 440 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_ERROR, @"Socks Server failed to listen, errno(%d)", errno); 441 | } 442 | 443 | if (success) { 444 | CFSocketContext context = { 0, (__bridge void*)self, NULL, NULL, NULL }; 445 | 446 | self.listeningSocket = CFSocketCreateWithNative( 447 | NULL, 448 | fd, 449 | kCFSocketAcceptCallBack, 450 | AcceptCallback, 451 | &context 452 | ); 453 | success = (self.listeningSocket != NULL); 454 | 455 | if (success) { 456 | CFRunLoopSourceRef rls; 457 | 458 | CFRelease(self.listeningSocket); // to balance the create 459 | 460 | fd = -1; // listeningSocket is now responsible for closing fd 461 | 462 | rls = CFSocketCreateRunLoopSource(NULL, self.listeningSocket, 0); 463 | assert(rls != NULL); 464 | 465 | CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 466 | 467 | CFRelease(rls); 468 | } 469 | } 470 | 471 | // Now register our service with Bonjour. See the comments in -netService:didNotPublish: 472 | // for more info about this simplifying assumption. 473 | 474 | if (success) { 475 | self.netService = [[NSNetService alloc] initWithDomain:@"local" 476 | type:@"_socks._tcp." 477 | name:@"" 478 | port:port]; 479 | success = (self.netService != nil); 480 | } 481 | if (success) { 482 | self.netService.delegate = self; 483 | 484 | [self.netService publishWithOptions:NSNetServiceNoAutoRename]; 485 | 486 | // continues in -netServiceDidPublish: or -netService:didNotPublish: ... 487 | } 488 | 489 | // Clean up after failure. 490 | 491 | if ( success ) { 492 | assert(port != 0); 493 | [self _sockProxyServerDidStartOnPort:port]; 494 | } else { 495 | [self _stopServers:@"Start failed"]; 496 | if (fd != -1) { 497 | junk = close(fd); 498 | assert(junk == 0); 499 | } 500 | } 501 | } 502 | 503 | 504 | - (void)_stopSocksProxyServer:(NSString *)reason 505 | { 506 | for (SocksProxy* asocksProxy in self.sendreceiveStream) 507 | { 508 | if ([asocksProxy isSendingReceiving]) 509 | [asocksProxy stopSendReceiveWithStatus:@"Cancelled"]; 510 | } 511 | 512 | [self.sendreceiveStream removeAllObjects]; 513 | 514 | if (self.netService != nil) { 515 | [self.netService stop]; 516 | self.netService = nil; 517 | } 518 | if (self.listeningSocket != NULL) { 519 | CFSocketInvalidate(self.listeningSocket); 520 | self.listeningSocket = NULL; 521 | } 522 | [self _serverDidStopWithReason:reason]; 523 | } 524 | 525 | 526 | #pragma mark - Actions 527 | 528 | - (IBAction)startOrStopAction:(id)sender 529 | { 530 | #pragma unused(sender) 531 | if (self.isSocksProxyStarted) { 532 | [self _stopServers:nil]; 533 | } else { 534 | 535 | if(self.currentAddress == nil) 536 | self.currentAddress = [UIDevice localWiFiIPAddress]; 537 | 538 | if(currentAddress != nil){ 539 | [self _startServers]; 540 | }else{ 541 | [self _updateStatus:@"Please connect to wifi."]; 542 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_WARNNING, @"No local IP can be retrieved. iPhone may not connect to wifi network\n"); 543 | } 544 | 545 | } 546 | 547 | [self refreshProxyTable]; 548 | } 549 | 550 | 551 | #pragma mark - View controller boilerplate 552 | 553 | @synthesize currentPort; 554 | @synthesize currentAddress; 555 | @synthesize httpAutoProxyURL; 556 | @synthesize currentOpenConnections; 557 | @synthesize currentConnectionCount; 558 | @synthesize downloadData, uploadData; 559 | @synthesize currentStatusText;// = _statusLabel; 560 | @synthesize startOrStopButton = _startOrStopButton; 561 | 562 | 563 | 564 | - (void)refreshProxyTable 565 | { 566 | [proxyTableView reloadData]; 567 | } 568 | 569 | 570 | - (void)applicationDidEnterForeground:(NSNotification *)n 571 | { 572 | LOG_NETWORK_SOCKS(NSLOGGER_LEVEL_DEBUG, @"refreshing ip address"); 573 | 574 | // refresh the IP address, just in case 575 | self.currentAddress = [UIDevice localWiFiIPAddress]; 576 | [self refreshProxyTable]; 577 | } 578 | 579 | 580 | - (void)viewDidLoad 581 | { 582 | [super viewDidLoad]; 583 | 584 | [[NSNotificationCenter defaultCenter] addObserver:self 585 | selector:@selector(applicationDidEnterForeground:) 586 | name:UIApplicationWillEnterForegroundNotification 587 | object:nil]; 588 | assert(self.startOrStopButton != nil); 589 | 590 | self.currentStatusText = NSLocalizedString(@"Tap Start to start the server", nil); 591 | 592 | [self.startOrStopButton setupAsGreenButton]; 593 | 594 | self.view.backgroundColor = [UIColor groupTableViewBackgroundColor]; 595 | 596 | self.title = @"Tethering"; 597 | 598 | // Add info button 599 | UIButton *infoLightButton = [UIButton buttonWithType:UIButtonTypeInfoDark]; 600 | infoLightButton.tintColor = [UIColor whiteColor]; 601 | [infoLightButton addTarget:self action:@selector(showInfo) forControlEvents:UIControlEventTouchUpInside]; 602 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:infoLightButton]; 603 | } 604 | 605 | 606 | - (void)viewDidUnload 607 | { 608 | [super viewDidUnload]; 609 | self.startOrStopButton = nil; 610 | } 611 | 612 | 613 | - (void)dealloc 614 | { 615 | [self _stopServers:nil]; 616 | } 617 | 618 | - (UIStatusBarStyle)preferredStatusBarStyle { 619 | return UIStatusBarStyleLightContent; 620 | } 621 | 622 | #pragma mark - Custom Methods 623 | 624 | - (void)showInfo { 625 | NSString *URLString = @"https://github.com/rickyzhang82/tethering/wiki"; 626 | if ([SFSafariViewController class] != nil) { 627 | // Use SFSafariViewController 628 | SFSafariViewController *sfvc = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:URLString]]; 629 | sfvc.delegate = self; 630 | sfvc.view.tintColor = [UIColor colorWithRed:0.082 green:0.492 blue:0.980 alpha:1.0]; 631 | [self presentViewController:sfvc animated:YES completion:nil]; 632 | } else { 633 | // Open in Mobile Safari 634 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:URLString] 635 | options:@{} 636 | completionHandler:nil]; 637 | } 638 | } 639 | 640 | #pragma mark - SFSafariViewController delegate methods 641 | -(void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully { 642 | // Load finished 643 | } 644 | 645 | -(void)safariViewControllerDidFinish:(SFSafariViewController *)controller { 646 | // Done button pressed 647 | } 648 | 649 | #pragma mark - Table View Data Source Methods 650 | 651 | - (NSString *)tableView:(UITableView *)table titleForHeaderInSection:(NSInteger)section 652 | { 653 | #pragma unused(table) 654 | /* 655 | if (section == SocksProxyTableSectionConnections) 656 | return @"Connections"; 657 | */ 658 | return nil; 659 | } 660 | 661 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)table 662 | { 663 | #pragma unused(table) 664 | 665 | return SocksProxyTableSectionCount; 666 | } 667 | 668 | - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section 669 | { 670 | #pragma unused(table) 671 | 672 | switch (section) 673 | { 674 | case SocksProxyTableSectionGeneral: 675 | return 3; 676 | 677 | case SocksProxyTableSectionConnections: 678 | return 5; 679 | } 680 | 681 | return 0; 682 | } 683 | 684 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 685 | { 686 | //cell.selected = NO; 687 | [tableView deselectRowAtIndexPath:indexPath animated:NO]; 688 | } 689 | 690 | - (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath 691 | { 692 | #pragma unused(table) 693 | static NSString * cellId = @"cellid"; 694 | 695 | UITableViewCellStyle cellStyle = UITableViewCellStyleValue2; 696 | if (indexPath.section == SocksProxyTableSectionGeneral) 697 | { 698 | cellStyle = UITableViewCellStyleSubtitle; 699 | } 700 | 701 | UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:cellStyle 702 | reuseIdentifier:cellId]; 703 | cell.accessoryType = UITableViewCellAccessoryNone; 704 | cell.accessoryView = nil; 705 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 706 | 707 | if (indexPath.section == SocksProxyTableSectionGeneral) 708 | { 709 | cell.textLabel.textColor = [UIColor colorWithRed:0.082 green:0.492 blue:0.980 alpha:1.0]; 710 | } 711 | 712 | NSString *text = nil; // the caption 713 | NSString *detailText = nil; 714 | 715 | switch (indexPath.section) 716 | { 717 | case (SocksProxyTableSectionGeneral): 718 | switch (indexPath.row) 719 | { 720 | case (SocksProxyTableRowAddress): 721 | { 722 | text = @"socks address"; 723 | detailText = self.currentAddress; 724 | if (self.currentAddress.length == 0) 725 | detailText = @"n/a"; 726 | } 727 | break; 728 | 729 | case (SocksProxyTableRowPort): 730 | { 731 | text = @"socks port"; 732 | if (self.currentPort) 733 | detailText = [@(self.currentPort) stringValue]; 734 | else 735 | detailText = @"n/a"; 736 | } 737 | break; 738 | case (SocksProxyTableHttpAutoProxyUrl): 739 | { 740 | text = @"automatic proxy"; 741 | detailText = self.httpAutoProxyURL; 742 | if (self.httpAutoProxyURL.length == 0) 743 | detailText = @"n/a"; 744 | } 745 | break; 746 | } 747 | break; 748 | 749 | case (SocksProxyTableSectionConnections): 750 | switch (indexPath.row) 751 | { 752 | case (SocksProxyTableRowConnectionsOpen): 753 | { 754 | text = @"open"; 755 | detailText = [@(self.currentOpenConnections) stringValue]; 756 | } 757 | break; 758 | 759 | case (SocksProxyTableRowConnections): 760 | { 761 | text = @"count"; 762 | detailText = [@(self.currentConnectionCount) stringValue]; 763 | } 764 | break; 765 | 766 | case (SocksProxyTableRowDownload): 767 | { 768 | text = @"down"; 769 | detailText = [@(self.downloadData) stringValue]; 770 | } 771 | break; 772 | 773 | case (SocksProxyTableRowUpload): 774 | { 775 | text = @"up"; 776 | detailText = [@(self.uploadData) stringValue]; 777 | } 778 | break; 779 | 780 | case (SocksProxyTableRowStatus): 781 | { 782 | text = @"status"; 783 | detailText = self.currentStatusText; 784 | cell.detailTextLabel.numberOfLines = 0; 785 | cell.detailTextLabel.lineBreakMode = NSLineBreakByCharWrapping; 786 | } 787 | break; 788 | } 789 | break; 790 | } 791 | 792 | // set the field label title 793 | cell.textLabel.text = text; 794 | 795 | // set the cell text 796 | cell.detailTextLabel.text = detailText; 797 | 798 | return cell; 799 | } 800 | 801 | 802 | @end 803 | -------------------------------------------------------------------------------- /Tethering.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; }; 11 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 12 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 13 | 25EE9D541D601EC700774FFF /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25EE9D531D601EC700774FFF /* SafariServices.framework */; }; 14 | 25EE9D561D601F8B00774FFF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 25EE9D551D601F8B00774FFF /* Images.xcassets */; }; 15 | 25EE9D581D601F9100774FFF /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 25EE9D571D601F9100774FFF /* LaunchScreen.xib */; }; 16 | 49720A8B127C1B37001873A0 /* ColorC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49720A8A127C1B37001873A0 /* ColorC.mm */; }; 17 | 49847DDD12664F03001645B5 /* MOButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49847DDA12664F03001645B5 /* MOButton.mm */; }; 18 | 49847DDE12664F03001645B5 /* MOGlassButton.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49847DDC12664F03001645B5 /* MOGlassButton.mm */; }; 19 | 49847E0012665213001645B5 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49847DFF12665213001645B5 /* QuartzCore.framework */; }; 20 | 54122F1B10D88D4900836166 /* SocksProxyController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54122F1A10D88D4900836166 /* SocksProxyController.mm */; }; 21 | 542A644F1241261A003497CD /* UIDevice_Extended.mm in Sources */ = {isa = PBXBuildFile; fileRef = 542A644D1241261A003497CD /* UIDevice_Extended.mm */; }; 22 | 5463365810DABA8E00D3A3AE /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5463365410DABA8E00D3A3AE /* AppDelegate.mm */; }; 23 | 5463365A10DABA8E00D3A3AE /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5463365710DABA8E00D3A3AE /* main.mm */; }; 24 | 54A0F9C6124127CC008878EF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54A0F9C5124127CC008878EF /* SystemConfiguration.framework */; }; 25 | 905DD2691C896C69000EA271 /* silence.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 905DD2681C896C69000EA271 /* silence.mp3 */; }; 26 | 90F2B7121C5B3F5000CFB28B /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90F2B7111C5B3F5000CFB28B /* AVFoundation.framework */; }; 27 | 9C310C061826EF0000299F00 /* ttdnsd.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C310C051826EF0000299F00 /* ttdnsd.mm */; }; 28 | 9C3FB27A183FEB97001B81FA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C3FB279183FEB97001B81FA /* Main.storyboard */; }; 29 | 9C4CAB051AD73ABB0025CFE1 /* PacFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C4CAB001AD73ABB0025CFE1 /* PacFileResponse.m */; }; 30 | 9C4CAB061AD73ABB0025CFE1 /* HTTPResponseHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C4CAB021AD73ABB0025CFE1 /* HTTPResponseHandler.m */; }; 31 | 9C4CAB071AD73ABB0025CFE1 /* HTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C4CAB041AD73ABB0025CFE1 /* HTTPServer.m */; }; 32 | 9C95E98618393629004559EB /* LoggerClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C95E98418393629004559EB /* LoggerClient.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 33 | E40F66010FB1E38600D92710 /* SocksProxy.mm in Sources */ = {isa = PBXBuildFile; fileRef = E40F65FF0FB1E38600D92710 /* SocksProxy.mm */; }; 34 | E40F66BA0FB3029A00D92710 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E40F66B90FB3029A00D92710 /* CFNetwork.framework */; }; 35 | E4D5443B0FAB4B1600630176 /* Info.html in Resources */ = {isa = PBXBuildFile; fileRef = E4D5443A0FAB4B1600630176 /* Info.html */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 40 | 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 41 | 1D6058910D05DD3D006BFB54 /* Tethering.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tethering.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 43 | 25EE9D531D601EC700774FFF /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = System/Library/Frameworks/SafariServices.framework; sourceTree = SDKROOT; }; 44 | 25EE9D551D601F8B00774FFF /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 45 | 25EE9D571D601F9100774FFF /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; 46 | 49720A89127C1B37001873A0 /* ColorC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorC.h; sourceTree = ""; }; 47 | 49720A8A127C1B37001873A0 /* ColorC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ColorC.mm; sourceTree = ""; }; 48 | 49847DD912664F03001645B5 /* MOButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOButton.h; sourceTree = ""; }; 49 | 49847DDA12664F03001645B5 /* MOButton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOButton.mm; sourceTree = ""; }; 50 | 49847DDB12664F03001645B5 /* MOGlassButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MOGlassButton.h; sourceTree = ""; }; 51 | 49847DDC12664F03001645B5 /* MOGlassButton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MOGlassButton.mm; sourceTree = ""; }; 52 | 49847DFF12665213001645B5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 53 | 54074CF2124127320036116E /* SocksProxy_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocksProxy_Prefix.pch; sourceTree = ""; }; 54 | 54122F1A10D88D4900836166 /* SocksProxyController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SocksProxyController.mm; sourceTree = ""; }; 55 | 54122F1F10D88DBE00836166 /* SocksProxyController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocksProxyController.h; sourceTree = ""; }; 56 | 542A644C1241261A003497CD /* UIDevice_Extended.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIDevice_Extended.h; sourceTree = ""; }; 57 | 542A644D1241261A003497CD /* UIDevice_Extended.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UIDevice_Extended.mm; sourceTree = ""; }; 58 | 5463365310DABA8E00D3A3AE /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = AncillaryCode/AppDelegate.h; sourceTree = ""; }; 59 | 5463365410DABA8E00D3A3AE /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = AncillaryCode/AppDelegate.mm; sourceTree = ""; }; 60 | 5463365710DABA8E00D3A3AE /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = main.mm; path = AncillaryCode/main.mm; sourceTree = ""; }; 61 | 54A0F9C5124127CC008878EF /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 62 | 905DD2681C896C69000EA271 /* silence.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = silence.mp3; sourceTree = ""; }; 63 | 90F2B7111C5B3F5000CFB28B /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 64 | 9C182A351828295F00F3F950 /* ttdnsd_platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ttdnsd_platform.h; path = ttdnsd/ttdnsd_platform.h; sourceTree = ""; }; 65 | 9C198A7D2E5BE6B3003D12A6 /* CLAUDE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CLAUDE.md; sourceTree = SOURCE_ROOT; }; 66 | 9C198A7E2E5BE6D7003D12A6 /* COPYING.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = COPYING.txt; sourceTree = SOURCE_ROOT; }; 67 | 9C198A7F2E5BE6D7003D12A6 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; 68 | 9C310C041826EF0000299F00 /* ttdnsd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ttdnsd.h; path = ttdnsd/ttdnsd.h; sourceTree = ""; }; 69 | 9C310C051826EF0000299F00 /* ttdnsd.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ttdnsd.mm; path = ttdnsd/ttdnsd.mm; sourceTree = ""; }; 70 | 9C3FB279183FEB97001B81FA /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 71 | 9C4CAAFE1AD73ABB0025CFE1 /* SynthesizeSingleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SynthesizeSingleton.h; path = WebServer/SynthesizeSingleton.h; sourceTree = ""; }; 72 | 9C4CAAFF1AD73ABB0025CFE1 /* PacFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PacFileResponse.h; path = WebServer/PacFileResponse.h; sourceTree = ""; }; 73 | 9C4CAB001AD73ABB0025CFE1 /* PacFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PacFileResponse.m; path = WebServer/PacFileResponse.m; sourceTree = ""; }; 74 | 9C4CAB011AD73ABB0025CFE1 /* HTTPResponseHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPResponseHandler.h; path = WebServer/HTTPResponseHandler.h; sourceTree = ""; }; 75 | 9C4CAB021AD73ABB0025CFE1 /* HTTPResponseHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPResponseHandler.m; path = WebServer/HTTPResponseHandler.m; sourceTree = ""; }; 76 | 9C4CAB031AD73ABB0025CFE1 /* HTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPServer.h; path = WebServer/HTTPServer.h; sourceTree = ""; }; 77 | 9C4CAB041AD73ABB0025CFE1 /* HTTPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPServer.m; path = WebServer/HTTPServer.m; sourceTree = ""; }; 78 | 9C95E98318393629004559EB /* LoggerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LoggerClient.h; path = NSLogger/LoggerClient.h; sourceTree = ""; }; 79 | 9C95E98418393629004559EB /* LoggerClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LoggerClient.m; path = NSLogger/LoggerClient.m; sourceTree = ""; }; 80 | 9C95E98518393629004559EB /* LoggerCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LoggerCommon.h; path = NSLogger/LoggerCommon.h; sourceTree = ""; }; 81 | 9CBABD221D3FEA9E00A8A382 /* LogLevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LogLevel.h; path = NSLogger/LogLevel.h; sourceTree = ""; }; 82 | E40F65FF0FB1E38600D92710 /* SocksProxy.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SocksProxy.mm; sourceTree = ""; }; 83 | E40F66000FB1E38600D92710 /* SocksProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocksProxy.h; sourceTree = ""; }; 84 | E40F66B90FB3029A00D92710 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 85 | E4D544010FAB45DC00630176 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86 | E4D5443A0FAB4B1600630176 /* Info.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Info.html; sourceTree = ""; wrapsLines = 1; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | 25EE9D541D601EC700774FFF /* SafariServices.framework in Frameworks */, 95 | 90F2B7121C5B3F5000CFB28B /* AVFoundation.framework in Frameworks */, 96 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 97 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 98 | 1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */, 99 | E40F66BA0FB3029A00D92710 /* CFNetwork.framework in Frameworks */, 100 | 54A0F9C6124127CC008878EF /* SystemConfiguration.framework in Frameworks */, 101 | 49847E0012665213001645B5 /* QuartzCore.framework in Frameworks */, 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | /* End PBXFrameworksBuildPhase section */ 106 | 107 | /* Begin PBXGroup section */ 108 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 1D6058910D05DD3D006BFB54 /* Tethering.app */, 112 | ); 113 | name = Products; 114 | sourceTree = ""; 115 | }; 116 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 9C198A7C2E5BE5F4003D12A6 /* Docs */, 120 | 9C1900741AD729A00022F53D /* Classes */, 121 | 54074CF1124126F10036116E /* Other Sources */, 122 | E4D543FE0FAB45DC00630176 /* Resources */, 123 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 124 | 19C28FACFE9D520D11CA2CBB /* Products */, 125 | ); 126 | name = CustomTemplate; 127 | sourceTree = ""; 128 | }; 129 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 25EE9D531D601EC700774FFF /* SafariServices.framework */, 133 | 90F2B7111C5B3F5000CFB28B /* AVFoundation.framework */, 134 | 49847DFF12665213001645B5 /* QuartzCore.framework */, 135 | E40F66B90FB3029A00D92710 /* CFNetwork.framework */, 136 | 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */, 137 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 138 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 139 | 54A0F9C5124127CC008878EF /* SystemConfiguration.framework */, 140 | ); 141 | name = Frameworks; 142 | sourceTree = ""; 143 | }; 144 | 54074CEF124126A70036116E /* View Controllers */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 54122F1F10D88DBE00836166 /* SocksProxyController.h */, 148 | 54122F1A10D88D4900836166 /* SocksProxyController.mm */, 149 | ); 150 | name = "View Controllers"; 151 | sourceTree = ""; 152 | }; 153 | 54074CF1124126F10036116E /* Other Sources */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 54074CF2124127320036116E /* SocksProxy_Prefix.pch */, 157 | 5463365310DABA8E00D3A3AE /* AppDelegate.h */, 158 | 5463365410DABA8E00D3A3AE /* AppDelegate.mm */, 159 | 5463365710DABA8E00D3A3AE /* main.mm */, 160 | 9C3FB279183FEB97001B81FA /* Main.storyboard */, 161 | ); 162 | name = "Other Sources"; 163 | sourceTree = ""; 164 | }; 165 | 54074CF4124127690036116E /* xibs */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | ); 169 | name = xibs; 170 | sourceTree = ""; 171 | }; 172 | 9C1900741AD729A00022F53D /* Classes */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 9C1900771AD737BD0022F53D /* Utility */, 176 | 9C1900761AD737220022F53D /* Network */, 177 | 9C1900751AD729D10022F53D /* UI */, 178 | 54074CEF124126A70036116E /* View Controllers */, 179 | ); 180 | name = Classes; 181 | sourceTree = ""; 182 | }; 183 | 9C1900751AD729D10022F53D /* UI */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 49847DD912664F03001645B5 /* MOButton.h */, 187 | 49847DDA12664F03001645B5 /* MOButton.mm */, 188 | 49847DDB12664F03001645B5 /* MOGlassButton.h */, 189 | 49847DDC12664F03001645B5 /* MOGlassButton.mm */, 190 | 49720A89127C1B37001873A0 /* ColorC.h */, 191 | 49720A8A127C1B37001873A0 /* ColorC.mm */, 192 | ); 193 | name = UI; 194 | sourceTree = ""; 195 | }; 196 | 9C1900761AD737220022F53D /* Network */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | E40F66000FB1E38600D92710 /* SocksProxy.h */, 200 | E40F65FF0FB1E38600D92710 /* SocksProxy.mm */, 201 | 542A644C1241261A003497CD /* UIDevice_Extended.h */, 202 | 542A644D1241261A003497CD /* UIDevice_Extended.mm */, 203 | 9C4CAAFD1AD73A860025CFE1 /* WebServer */, 204 | 9C310C031826EEE900299F00 /* DNSServer */, 205 | ); 206 | name = Network; 207 | sourceTree = ""; 208 | }; 209 | 9C1900771AD737BD0022F53D /* Utility */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | 9C95E9821839353D004559EB /* NSLogger */, 213 | ); 214 | name = Utility; 215 | sourceTree = ""; 216 | }; 217 | 9C198A7C2E5BE5F4003D12A6 /* Docs */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | 9C198A7E2E5BE6D7003D12A6 /* COPYING.txt */, 221 | 9C198A7F2E5BE6D7003D12A6 /* README.md */, 222 | 9C198A7D2E5BE6B3003D12A6 /* CLAUDE.md */, 223 | ); 224 | path = Docs; 225 | sourceTree = ""; 226 | }; 227 | 9C310C031826EEE900299F00 /* DNSServer */ = { 228 | isa = PBXGroup; 229 | children = ( 230 | 9C182A351828295F00F3F950 /* ttdnsd_platform.h */, 231 | 9C310C041826EF0000299F00 /* ttdnsd.h */, 232 | 9C310C051826EF0000299F00 /* ttdnsd.mm */, 233 | ); 234 | name = DNSServer; 235 | sourceTree = ""; 236 | }; 237 | 9C4CAAFD1AD73A860025CFE1 /* WebServer */ = { 238 | isa = PBXGroup; 239 | children = ( 240 | 9C4CAAFE1AD73ABB0025CFE1 /* SynthesizeSingleton.h */, 241 | 9C4CAAFF1AD73ABB0025CFE1 /* PacFileResponse.h */, 242 | 9C4CAB001AD73ABB0025CFE1 /* PacFileResponse.m */, 243 | 9C4CAB011AD73ABB0025CFE1 /* HTTPResponseHandler.h */, 244 | 9C4CAB021AD73ABB0025CFE1 /* HTTPResponseHandler.m */, 245 | 9C4CAB031AD73ABB0025CFE1 /* HTTPServer.h */, 246 | 9C4CAB041AD73ABB0025CFE1 /* HTTPServer.m */, 247 | ); 248 | name = WebServer; 249 | sourceTree = ""; 250 | }; 251 | 9C95E9821839353D004559EB /* NSLogger */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 9C95E98318393629004559EB /* LoggerClient.h */, 255 | 9C95E98418393629004559EB /* LoggerClient.m */, 256 | 9C95E98518393629004559EB /* LoggerCommon.h */, 257 | 9CBABD221D3FEA9E00A8A382 /* LogLevel.h */, 258 | ); 259 | name = NSLogger; 260 | sourceTree = ""; 261 | }; 262 | E4D543FE0FAB45DC00630176 /* Resources */ = { 263 | isa = PBXGroup; 264 | children = ( 265 | 25EE9D551D601F8B00774FFF /* Images.xcassets */, 266 | 25EE9D571D601F9100774FFF /* LaunchScreen.xib */, 267 | 905DD2681C896C69000EA271 /* silence.mp3 */, 268 | 54074CF4124127690036116E /* xibs */, 269 | E4D544010FAB45DC00630176 /* Info.plist */, 270 | E4D5443A0FAB4B1600630176 /* Info.html */, 271 | ); 272 | path = Resources; 273 | sourceTree = ""; 274 | }; 275 | /* End PBXGroup section */ 276 | 277 | /* Begin PBXNativeTarget section */ 278 | 1D6058900D05DD3D006BFB54 /* Tethering */ = { 279 | isa = PBXNativeTarget; 280 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Tethering" */; 281 | buildPhases = ( 282 | 1D60588D0D05DD3D006BFB54 /* Resources */, 283 | 1D60588E0D05DD3D006BFB54 /* Sources */, 284 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 285 | ); 286 | buildRules = ( 287 | ); 288 | dependencies = ( 289 | ); 290 | name = Tethering; 291 | productName = TrivialStreamTransfer; 292 | productReference = 1D6058910D05DD3D006BFB54 /* Tethering.app */; 293 | productType = "com.apple.product-type.application"; 294 | }; 295 | /* End PBXNativeTarget section */ 296 | 297 | /* Begin PBXProject section */ 298 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 299 | isa = PBXProject; 300 | attributes = { 301 | LastUpgradeCheck = 1020; 302 | TargetAttributes = { 303 | 1D6058900D05DD3D006BFB54 = { 304 | DevelopmentTeam = L527N68YVE; 305 | SystemCapabilities = { 306 | com.apple.BackgroundModes = { 307 | enabled = 1; 308 | }; 309 | }; 310 | }; 311 | }; 312 | }; 313 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Tethering" */; 314 | compatibilityVersion = "Xcode 3.2"; 315 | developmentRegion = English; 316 | hasScannedForEncodings = 1; 317 | knownRegions = ( 318 | English, 319 | Japanese, 320 | French, 321 | German, 322 | ); 323 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 324 | projectDirPath = ""; 325 | projectRoot = ""; 326 | targets = ( 327 | 1D6058900D05DD3D006BFB54 /* Tethering */, 328 | ); 329 | }; 330 | /* End PBXProject section */ 331 | 332 | /* Begin PBXResourcesBuildPhase section */ 333 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 334 | isa = PBXResourcesBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | 25EE9D581D601F9100774FFF /* LaunchScreen.xib in Resources */, 338 | 25EE9D561D601F8B00774FFF /* Images.xcassets in Resources */, 339 | 9C3FB27A183FEB97001B81FA /* Main.storyboard in Resources */, 340 | E4D5443B0FAB4B1600630176 /* Info.html in Resources */, 341 | 905DD2691C896C69000EA271 /* silence.mp3 in Resources */, 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | /* End PBXResourcesBuildPhase section */ 346 | 347 | /* Begin PBXSourcesBuildPhase section */ 348 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 349 | isa = PBXSourcesBuildPhase; 350 | buildActionMask = 2147483647; 351 | files = ( 352 | 9C95E98618393629004559EB /* LoggerClient.m in Sources */, 353 | 9C4CAB061AD73ABB0025CFE1 /* HTTPResponseHandler.m in Sources */, 354 | 9C310C061826EF0000299F00 /* ttdnsd.mm in Sources */, 355 | E40F66010FB1E38600D92710 /* SocksProxy.mm in Sources */, 356 | 54122F1B10D88D4900836166 /* SocksProxyController.mm in Sources */, 357 | 5463365810DABA8E00D3A3AE /* AppDelegate.mm in Sources */, 358 | 5463365A10DABA8E00D3A3AE /* main.mm in Sources */, 359 | 9C4CAB051AD73ABB0025CFE1 /* PacFileResponse.m in Sources */, 360 | 542A644F1241261A003497CD /* UIDevice_Extended.mm in Sources */, 361 | 49847DDD12664F03001645B5 /* MOButton.mm in Sources */, 362 | 49847DDE12664F03001645B5 /* MOGlassButton.mm in Sources */, 363 | 9C4CAB071AD73ABB0025CFE1 /* HTTPServer.m in Sources */, 364 | 49720A8B127C1B37001873A0 /* ColorC.mm in Sources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | /* End PBXSourcesBuildPhase section */ 369 | 370 | /* Begin XCBuildConfiguration section */ 371 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 372 | isa = XCBuildConfiguration; 373 | buildSettings = { 374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 375 | CLANG_ENABLE_OBJC_ARC = YES; 376 | "CODE_SIGN_ENTITLEMENTS[sdk=*]" = ""; 377 | CODE_SIGN_IDENTITY = "iPhone Developer"; 378 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 379 | DEVELOPMENT_TEAM = L527N68YVE; 380 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 381 | GCC_PREFIX_HEADER = SocksProxy_Prefix.pch; 382 | INFOPLIST_FILE = Resources/Info.plist; 383 | IPHONEOS_DEPLOYMENT_TARGET = 16.6; 384 | OTHER_CFLAGS = "-DDEBUG"; 385 | PRODUCT_BUNDLE_IDENTIFIER = com.whoever.Tethering.imac; 386 | PRODUCT_NAME = Tethering; 387 | PROVISIONING_PROFILE = ""; 388 | SDKROOT = iphoneos; 389 | TARGETED_DEVICE_FAMILY = "1,2"; 390 | }; 391 | name = Debug; 392 | }; 393 | 1D6058950D05DD3E006BFB54 /* Release */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 397 | CLANG_ENABLE_OBJC_ARC = YES; 398 | CODE_SIGN_IDENTITY = "iPhone Developer"; 399 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 400 | DEVELOPMENT_TEAM = L527N68YVE; 401 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 402 | GCC_PREFIX_HEADER = SocksProxy_Prefix.pch; 403 | INFOPLIST_FILE = Resources/Info.plist; 404 | IPHONEOS_DEPLOYMENT_TARGET = 16.6; 405 | ONLY_ACTIVE_ARCH = YES; 406 | OTHER_CFLAGS = ""; 407 | PRODUCT_BUNDLE_IDENTIFIER = com.whoever.Tethering.imac; 408 | PRODUCT_NAME = Tethering; 409 | PROVISIONING_PROFILE = ""; 410 | "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; 411 | SDKROOT = iphoneos; 412 | TARGETED_DEVICE_FAMILY = "1,2"; 413 | }; 414 | name = Release; 415 | }; 416 | C01FCF4F08A954540054247B /* Debug */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | ALWAYS_SEARCH_USER_PATHS = NO; 420 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 421 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 422 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 423 | CLANG_WARN_BOOL_CONVERSION = YES; 424 | CLANG_WARN_COMMA = YES; 425 | CLANG_WARN_CONSTANT_CONVERSION = YES; 426 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 427 | CLANG_WARN_EMPTY_BODY = YES; 428 | CLANG_WARN_ENUM_CONVERSION = YES; 429 | CLANG_WARN_INFINITE_RECURSION = YES; 430 | CLANG_WARN_INT_CONVERSION = YES; 431 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 432 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 433 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 434 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 435 | CLANG_WARN_STRICT_PROTOTYPES = YES; 436 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 437 | CLANG_WARN_UNREACHABLE_CODE = YES; 438 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 439 | "CODE_SIGN_ENTITLEMENTS[sdk=*]" = ""; 440 | CODE_SIGN_IDENTITY = "iPhone Developer"; 441 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 442 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 443 | DEPLOYMENT_POSTPROCESSING = NO; 444 | ENABLE_STRICT_OBJC_MSGSEND = YES; 445 | ENABLE_TESTABILITY = YES; 446 | GCC_C_LANGUAGE_STANDARD = c99; 447 | GCC_DYNAMIC_NO_PIC = NO; 448 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 449 | GCC_NO_COMMON_BLOCKS = YES; 450 | GCC_OPTIMIZATION_LEVEL = 0; 451 | GCC_PREPROCESSOR_DEFINITIONS = ""; 452 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 453 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 454 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 455 | GCC_WARN_PROTOTYPE_CONVERSION = NO; 456 | GCC_WARN_SHADOW = YES; 457 | GCC_WARN_UNDECLARED_SELECTOR = YES; 458 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 459 | GCC_WARN_UNUSED_FUNCTION = YES; 460 | GCC_WARN_UNUSED_LABEL = YES; 461 | GCC_WARN_UNUSED_PARAMETER = YES; 462 | GCC_WARN_UNUSED_VALUE = YES; 463 | GCC_WARN_UNUSED_VARIABLE = YES; 464 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 465 | ONLY_ACTIVE_ARCH = YES; 466 | OTHER_CFLAGS = "-DDEBUG"; 467 | PROVISIONING_PROFILE = ""; 468 | SDKROOT = iphoneos; 469 | WARNING_CFLAGS = ( 470 | "-Wall", 471 | "-Wextra", 472 | "-Wfloat-equal", 473 | "-Wpointer-arith", 474 | "-Wstrict-prototypes", 475 | "-Wold-style-definition", 476 | ); 477 | }; 478 | name = Debug; 479 | }; 480 | C01FCF5008A954540054247B /* Release */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | ALWAYS_SEARCH_USER_PATHS = NO; 484 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 485 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 486 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 487 | CLANG_WARN_BOOL_CONVERSION = YES; 488 | CLANG_WARN_COMMA = YES; 489 | CLANG_WARN_CONSTANT_CONVERSION = YES; 490 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 491 | CLANG_WARN_EMPTY_BODY = YES; 492 | CLANG_WARN_ENUM_CONVERSION = YES; 493 | CLANG_WARN_INFINITE_RECURSION = YES; 494 | CLANG_WARN_INT_CONVERSION = YES; 495 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 496 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 497 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 498 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 499 | CLANG_WARN_STRICT_PROTOTYPES = YES; 500 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 501 | CLANG_WARN_UNREACHABLE_CODE = YES; 502 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 503 | CODE_SIGN_IDENTITY = "iPhone Developer"; 504 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 505 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 506 | DEPLOYMENT_POSTPROCESSING = YES; 507 | ENABLE_STRICT_OBJC_MSGSEND = YES; 508 | GCC_C_LANGUAGE_STANDARD = c99; 509 | GCC_DYNAMIC_NO_PIC = YES; 510 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 511 | GCC_NO_COMMON_BLOCKS = YES; 512 | GCC_OPTIMIZATION_LEVEL = s; 513 | GCC_PREPROCESSOR_DEFINITIONS = NDEBUG; 514 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 515 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 516 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 517 | GCC_WARN_PROTOTYPE_CONVERSION = NO; 518 | GCC_WARN_SHADOW = YES; 519 | GCC_WARN_UNDECLARED_SELECTOR = YES; 520 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 521 | GCC_WARN_UNUSED_FUNCTION = YES; 522 | GCC_WARN_UNUSED_LABEL = YES; 523 | GCC_WARN_UNUSED_PARAMETER = YES; 524 | GCC_WARN_UNUSED_VALUE = YES; 525 | GCC_WARN_UNUSED_VARIABLE = YES; 526 | IPHONEOS_DEPLOYMENT_TARGET = 14.2; 527 | ONLY_ACTIVE_ARCH = YES; 528 | OTHER_CFLAGS = "-DDEBUG"; 529 | PROVISIONING_PROFILE = ""; 530 | SDKROOT = iphoneos; 531 | WARNING_CFLAGS = ( 532 | "-Wall", 533 | "-Wextra", 534 | "-Wfloat-equal", 535 | "-Wpointer-arith", 536 | "-Wstrict-prototypes", 537 | "-Wold-style-definition", 538 | ); 539 | }; 540 | name = Release; 541 | }; 542 | /* End XCBuildConfiguration section */ 543 | 544 | /* Begin XCConfigurationList section */ 545 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Tethering" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | 1D6058940D05DD3E006BFB54 /* Debug */, 549 | 1D6058950D05DD3E006BFB54 /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Tethering" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | C01FCF4F08A954540054247B /* Debug */, 558 | C01FCF5008A954540054247B /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | defaultConfigurationName = Release; 562 | }; 563 | /* End XCConfigurationList section */ 564 | }; 565 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 566 | } 567 | --------------------------------------------------------------------------------