├── img └── proximac-logo.png ├── proximac-cli ├── tree.c ├── js0n.h ├── jconf.h ├── local.h ├── socks5.h ├── utils.c ├── jconf.c ├── js0n.c ├── utils.h ├── local.c └── tree.h ├── proximac.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── proximac.xccheckout └── project.pbxproj ├── proximac ├── proximac.h ├── Info.plist ├── proximac.c └── tree.h ├── .gitignore ├── README.md └── LICENSE /img/proximac-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csujedihy/proximac/HEAD/img/proximac-logo.png -------------------------------------------------------------------------------- /proximac-cli/tree.c: -------------------------------------------------------------------------------- 1 | // 2 | // tree.c 3 | // tcplognke 4 | // 5 | // Created by jedihy on 15-5-15. 6 | // 7 | // 8 | 9 | #include 10 | #include "tree.h" 11 | 12 | 13 | -------------------------------------------------------------------------------- /proximac.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /proximac/proximac.h: -------------------------------------------------------------------------------- 1 | // 2 | // proximac.h 3 | // proximac 4 | // 5 | // Created by jedihy on 15-5-17. 6 | // Copyright (c) 2015年 jedihy. All rights reserved. 7 | // 8 | 9 | #ifndef proximac_proximac_h 10 | #define proximac_proximac_h 11 | 12 | #define MYBUNDLEID "com.proximac.kext" 13 | #define PROXIMAC_TCP_FILTER_HANDLE 0x2e33677d 14 | #define PROXIMAC_MODE_OFF 0 15 | #define PROXIMAC_MODE_ON 1 16 | #define PROXIMAC_MODE_ALL 2 17 | #define LOCALHOST 0x100007f 18 | #define MYAPPNAME "proximac-cli" 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /proximac-cli/js0n.h: -------------------------------------------------------------------------------- 1 | // key = string to match or null 2 | // klen = key length (or 0), or if null key then len is the array offset value 3 | // json = json object or array 4 | // jlen = length of json 5 | // vlen = where to store return value length 6 | // returns pointer to value and sets len to value length, or 0 if not found 7 | // any parse error will set vlen to the position of the error 8 | #include 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | const char *js0n(const char *key, size_t klen, 13 | const char *json, size_t jlen, size_t *vlen); 14 | #ifdef __cplusplus 15 | } /* extern "C" */ 16 | #endif 17 | -------------------------------------------------------------------------------- /proximac-cli/jconf.h: -------------------------------------------------------------------------------- 1 | // 2 | // jconf.h 3 | // jedisocks 4 | // 5 | // Created by jedihy on 15-2-25. 6 | // Copyright (c) 2015年 jedihy. All rights reserved. 7 | // 8 | 9 | #ifndef jedisocks_jconf_h 10 | #define jedisocks_jconf_h 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "tree.h" 17 | 18 | typedef struct { 19 | uint16_t localport; 20 | char* local_address; 21 | char* proximac_listen_address; 22 | char* process_name; 23 | char* username; 24 | char* password; 25 | uint16_t proximac_port; 26 | int pid; 27 | int total_process_num; 28 | int vpn_mode; 29 | int proxyapp_hash; 30 | } conf_t; 31 | 32 | extern void read_conf(char* configfile, conf_t* conf); 33 | #endif 34 | -------------------------------------------------------------------------------- /proximac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.csujedi.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | KEXT 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | NSHumanReadableCopyright 24 | Copyright © 2015年 jedihy. All rights reserved. 25 | OSBundleLibraries 26 | 27 | com.apple.kpi.bsd 28 | 8.0.0 29 | com.apple.kpi.libkern 30 | 8.0.0 31 | com.apple.kpi.mach 32 | 8.0.0 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /proximac.xcodeproj/project.xcworkspace/xcshareddata/proximac.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | B8E96CB9-EF14-44E8-AE41-A8EB1C6B4427 9 | IDESourceControlProjectName 10 | proximac 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 8BD223DEF30FBE5E513BC5235F66567CE49ADFB9 14 | github.com:csujedihy/proximac.git 15 | 16 | IDESourceControlProjectPath 17 | proximac.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 8BD223DEF30FBE5E513BC5235F66567CE49ADFB9 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:csujedihy/proximac.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 8BD223DEF30FBE5E513BC5235F66567CE49ADFB9 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 8BD223DEF30FBE5E513BC5235F66567CE49ADFB9 36 | IDESourceControlWCCName 37 | proximac 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /proximac-cli/local.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCAL_H_ 2 | #define LOCAL_H_ 3 | 4 | #define BUF_SIZE 2048 5 | #define CTL_CLOSE 0x04 6 | #define CTL_INIT 0x01 7 | #define CTL_NORMAL 0 8 | 9 | #define LOCALHOST "127.0.0.1" 10 | 11 | // packet related MACROs 12 | #define MAX_PKT_SIZE 8192 13 | #define ID_LEN 4 14 | #define PKT_LEN 2 15 | #define RSV_LEN 1 16 | #define DATALEN_LEN 2 17 | #define ATYP_LEN 1 18 | #define ADDRLEN_LEN 1 19 | #define PORT_LEN 2 20 | #define HDR_LEN (ID_LEN + RSV_LEN + DATALEN_LEN) 21 | #define EXP_TO_RECV_LEN (ID_LEN + RSV_LEN + DATALEN_LEN) 22 | 23 | // remote connection status MACROs 24 | #define RC_OFF 0 25 | #define RC_ESTABLISHING 1 26 | #define RC_OK 2 27 | #define MAX_RC_NUM 32 28 | 29 | // PF sockopt 30 | #define PROXIMAC_ON 1 31 | #define HOOK_PID 2 32 | #define PIDLIST_STATUS 3 33 | #define PROXIMAC_OFF 4 34 | #define NOT_TO_HOOK 5 35 | 36 | #include "tree.h" 37 | 38 | struct pid { 39 | RB_ENTRY(pid) rb_link; 40 | int pid; 41 | char* name; 42 | }; 43 | 44 | RB_HEAD(pid_tree, pid); 45 | RB_PROTOTYPE(pid_tree, pid, rb_link, pid_cmp); 46 | extern struct pid_tree pid_list; 47 | 48 | int tell_kernel_to_hook(); 49 | 50 | typedef struct { 51 | uv_write_t req; 52 | uv_buf_t buf; 53 | } write_req_t; 54 | 55 | typedef struct { 56 | uv_tcp_t handle; 57 | } listener_t; 58 | 59 | struct remote_ctx; 60 | 61 | typedef struct server_ctx { 62 | uv_tcp_t server_handle; 63 | uv_tcp_t remote_handle; 64 | int server_stage; 65 | int remote_stage; 66 | int remote_auth_stage; 67 | char remote_addr[256]; 68 | char addrlen; 69 | uint16_t port; 70 | char* buf; 71 | size_t buf_len; 72 | struct remote_ctx* remote_ctx; 73 | } server_ctx_t; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | #CTAGS files and Mac OSX trashes 32 | *.tags 33 | *.tag 34 | *.swp 35 | .DS_Store 36 | .tags_sorted_by_file 37 | xcuserdata/* 38 | 39 | 40 | 41 | # Xcode 42 | # 43 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 44 | 45 | ## Build generated 46 | build/ 47 | DerivedData/ 48 | 49 | ## Various settings 50 | *.pbxuser 51 | !default.pbxuser 52 | *.mode1v3 53 | !default.mode1v3 54 | *.mode2v3 55 | !default.mode2v3 56 | *.perspectivev3 57 | !default.perspectivev3 58 | xcuserdata/ 59 | 60 | ## Other 61 | *.moved-aside 62 | *.xcuserstate 63 | 64 | ## Obj-C/Swift specific 65 | *.hmap 66 | *.ipa 67 | 68 | # CocoaPods 69 | # 70 | # We recommend against adding the Pods directory to your .gitignore. However 71 | # you should judge for yourself, the pros and cons are mentioned at: 72 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 73 | # 74 | Pods/ 75 | 76 | # Carthage 77 | # 78 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 79 | # Carthage/Checkouts 80 | 81 | Carthage/Build 82 | 83 | # fastlane 84 | # 85 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 86 | # screenshots whenever they are needed. 87 | # For more information about the recommended setup visit: 88 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 89 | 90 | fastlane/report.xml 91 | fastlane/screenshots 92 | -------------------------------------------------------------------------------- /proximac-cli/socks5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socks5.h - Define SOCKS5's header 3 | * 4 | * Copyright (C) 2013, clowwindy 5 | * 6 | * This file is part of the shadowsocks-libev. 7 | * 8 | * shadowsocks-libev is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * shadowsocks-libev is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pdnsd; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef _SOCKS5_H 24 | #define _SOCKS5_H 25 | 26 | #define REP_OK 0 27 | #define SVERSION 0x05 28 | #define CONNECT 0x01 29 | #define ATYP_OK 0x01 30 | #define ATYP_IPV4 0x01 31 | #define ATYP_DOMAIN 0x03 32 | #define IPV6 0x04 33 | #define CMD_NOT_SUPPORTED 0x07 34 | #define HEXZERO 0x00 35 | #define SOCKS5_FISRT_REQ_SIZE 3 36 | #define SOCKS5_FISRT_RESP_SIZE 2 37 | 38 | #pragma pack(1) 39 | 40 | // struct method_select_request { 41 | // char ver; 42 | // char nmethods; 43 | // char methods[255]; 44 | // }; 45 | 46 | typedef struct method_select_response { 47 | char ver; 48 | char method; 49 | } method_select_response_t; 50 | 51 | typedef struct socks5_req_or_resp { 52 | char ver; 53 | char cmd_or_resp; 54 | char rsv; 55 | char atyp; 56 | char ipv4_A; 57 | char ipv4_B; 58 | char ipv4_C; 59 | char ipv4_D; 60 | char port_lsb; 61 | char port_hsb; 62 | } socks5_req_or_resp_t; 63 | 64 | #endif //_SOCKS5_H 65 | 66 | -------------------------------------------------------------------------------- /proximac-cli/utils.c: -------------------------------------------------------------------------------- 1 | // 2 | // utils.c 3 | // proximac 4 | // 5 | // Created by jedihy on 15-5-12. 6 | // Copyright (c) 2015年 jedihy. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "utils.h" 14 | 15 | void usage() { 16 | printf("\ 17 | Proximac v2.0\n\ 18 | developed by Jedihy csujedi@icloud.com\n\ 19 | usage:\n\ 20 | proximac\n\ 21 | -c Path of configuration file that is written in JSON\n\ 22 | -d daemon mode\n\ 23 | "); 24 | } 25 | 26 | void init_daemon() { 27 | pid_t pid; 28 | 29 | /* Fork off the parent process */ 30 | pid = fork(); 31 | 32 | /* An error occurred */ 33 | if (pid < 0) 34 | exit(EXIT_FAILURE); 35 | 36 | /* Success: Let the parent terminate */ 37 | if (pid > 0) 38 | exit(EXIT_SUCCESS); 39 | 40 | /* On success: The child process becomes session leader */ 41 | if (setsid() < 0) 42 | exit(EXIT_FAILURE); 43 | 44 | /* Catch, ignore and handle signals */ 45 | //TODO: Implement a working signal handler */ 46 | signal(SIGCHLD, SIG_IGN); 47 | signal(SIGHUP, SIG_IGN); 48 | 49 | /* Fork off for the second time*/ 50 | pid = fork(); 51 | 52 | /* An error occurred */ 53 | if (pid < 0) 54 | exit(EXIT_FAILURE); 55 | 56 | /* Success: Let the parent terminate */ 57 | if (pid > 0) 58 | exit(EXIT_SUCCESS); 59 | 60 | /* Set new file permissions */ 61 | umask(0); 62 | 63 | /* Change the working directory to the root directory */ 64 | /* or another appropriated directory */ 65 | chdir("./"); 66 | } 67 | 68 | // for performance tunning 69 | struct timeval GetTimeStamp() { 70 | struct timeval tv; 71 | gettimeofday(&tv,NULL); 72 | return tv; 73 | } 74 | 75 | unsigned int hash(char *str) 76 | { 77 | unsigned int h; 78 | unsigned char *p; 79 | unsigned int i; 80 | #define MULTIPLIER 33 81 | h = 0; 82 | i = 0; 83 | for (p = (unsigned char*)str; (*p != '\0')&&(i < 16); p++,i++) 84 | h = MULTIPLIER * h + *p; 85 | #undef MULTIPLIER 86 | return h; // or, h % ARRAY_SIZE; 87 | } 88 | -------------------------------------------------------------------------------- /proximac-cli/jconf.c: -------------------------------------------------------------------------------- 1 | // 2 | // jconf.c 3 | // proximac 4 | // 5 | // Created by jedihy on 15-5-12. 6 | // Copyright (c) 2015年 jedihy. All rights reserved. 7 | // 8 | 9 | #include "tree.h" 10 | #include "js0n.h" 11 | #include "utils.h" 12 | #include "jconf.h" 13 | #include "local.h" 14 | 15 | void read_conf(char* configfile, conf_t* conf) 16 | { 17 | const char* val = NULL; 18 | char* configbuf = NULL; 19 | char localport_buf[6] = { 0 }; 20 | char proximac_port_buf[6] = { 0 }; 21 | char vpn_mode_buf[6] = { 0 }; 22 | size_t vlen = 0; 23 | 24 | /* need to reset these bufs to zero */ 25 | 26 | FILE* f = fopen(configfile, "rb"); 27 | if (f == NULL) { 28 | FATAL("Invalid config path."); 29 | } 30 | 31 | fseek(f, 0, SEEK_END); 32 | long pos = ftell(f); 33 | fseek(f, 0, SEEK_SET); 34 | 35 | configbuf = malloc(pos + 1); 36 | if (configbuf == NULL) { 37 | FATAL("No enough memory."); 38 | } 39 | 40 | size_t nread = fread(configbuf, pos, 1, f); 41 | if (!nread) { 42 | FATAL("Failed to read the config file."); 43 | } 44 | fclose(f); 45 | 46 | configbuf[pos] = '\0'; // end of string 47 | 48 | #define JSONPARSE(str) \ 49 | val = js0n(str, strlen(str), configbuf, (int)pos, &vlen); \ 50 | if (val != NULL) 51 | 52 | JSONPARSE("process_name") 53 | { 54 | int index = 0; 55 | const char* buf; 56 | LOGI("Process List:"); 57 | while ((buf = js0n(NULL, index, val, (int)pos, &vlen)) != NULL) { 58 | index++; 59 | #define MAX_PROC_NAME_LEN 16 60 | struct pid* pid_to_insert = malloc(sizeof(struct pid)); 61 | pid_to_insert->name = calloc(1, vlen + 1); 62 | memcpy(pid_to_insert->name, buf, vlen); 63 | pid_to_insert->name[vlen] = '\0'; 64 | pid_to_insert->pid = hash(pid_to_insert->name); 65 | RB_INSERT(pid_tree, &pid_list, pid_to_insert); 66 | LOGI("%d. %s hash %d", index, pid_to_insert->name, pid_to_insert->pid); 67 | } 68 | 69 | conf->total_process_num = index; 70 | } 71 | 72 | JSONPARSE("proximac_port") 73 | { 74 | memcpy(proximac_port_buf, val, vlen); 75 | conf->proximac_port = atoi(proximac_port_buf); 76 | } 77 | 78 | JSONPARSE("VPN_mode") 79 | { 80 | memcpy(vpn_mode_buf, val, vlen); 81 | conf->vpn_mode = atoi(vpn_mode_buf); 82 | } 83 | 84 | JSONPARSE("proxyapp_name") 85 | { 86 | struct pid* proxyapp_hash = malloc(sizeof(struct pid)); 87 | proxyapp_hash->name = calloc(1, vlen + 1); 88 | memcpy(proxyapp_hash->name, val, vlen); 89 | proxyapp_hash->name[vlen] = '\0'; 90 | proxyapp_hash->pid = hash(proxyapp_hash->name); 91 | LOGI("Proxy App name is %s", proxyapp_hash->name); 92 | LOGD("Proxy App name is %s, hash %d", proxyapp_hash->name, proxyapp_hash->pid); 93 | 94 | conf->proxyapp_hash = proxyapp_hash->pid; 95 | free(proxyapp_hash); 96 | } 97 | 98 | JSONPARSE("local_port") 99 | { 100 | memcpy(localport_buf, val, vlen); 101 | conf->localport = atoi(localport_buf); 102 | } 103 | 104 | JSONPARSE("local_address") 105 | { 106 | conf->local_address = (char*)malloc(vlen + 1); 107 | memcpy(conf->local_address, val, vlen); 108 | conf->local_address[vlen] = '\0'; 109 | } 110 | 111 | JSONPARSE("username") 112 | { 113 | conf->username = (char*)malloc(vlen + 1); 114 | memcpy(conf->username, val, vlen); 115 | conf->username[vlen] = '\0'; 116 | } 117 | 118 | JSONPARSE("password") 119 | { 120 | conf->password = (char*)malloc(vlen + 1); 121 | memcpy(conf->password, val, vlen); 122 | conf->password[vlen] = '\0'; 123 | } 124 | 125 | #undef JSONPARSE 126 | 127 | free(configbuf); 128 | } 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](https://raw.githubusercontent.com/csujedihy/proximac/master/img/proximac-logo.png) 2 | 3 | #### Overview 4 | 5 | Proximac is an command-line open-source alternative to Proxifier. With Proximac, it can force App to use SOCKS5 proxy. In the other words, it can forward any App's traffic to a certain SOCKS5 proxy. Moreover, Proximac now can forward all network traffic in your system to a proxy which means you may not need a VPN to do this job. I hope more developers can join this project. 6 | 7 | ###### :blush: Welcome to contribute code to this project! If you have any idea, feel free to contact me! 8 | 9 | Features: 10 | 11 | 1. Support global traffic forwarding (VPN mode). 12 | 2. Support SOCKS5 authentication using username/password. 13 | 14 | Note: Proximac only works on Mac OSX. 15 | 16 | #### Usage 17 | 1. If you plan to use Proximac on OSX 10.10+, please run ```sudo nvram boot-args="debug=0x146 kext-dev-mode=1"```. For 10.11, do Restart -> Press COMMAND + R -> Recovery Mode -> Terminal -> csrutil enable --without kext --without debug. 18 | 19 | 1. Install libuv first. Run ```brew install libuv``` or whatever works 20 | 2. Run ```curl -fsSL https://raw.githubusercontent.com/proximac-org/proximac-install/master/install.py |sudo python ``` 21 | 3. Set up your config file which indicates Proximac's work mode (VPN or per-App) and proxy configuration 22 | 4. Run ```proximac start -c [path of your config file]``` to start Proximac 23 | 5. Run ```proximac stop``` to stop Proximac 24 | 25 | #### How to build from source 26 | NOTE: Proximac is based on libuv. So, before compile this project, make sure [libuv](https://github.com/libuv/libuv) was successfully installed: 27 | 28 | $ git clone https://github.com/libuv/libuv.git 29 | $ cd libuv 30 | $ sh autogen.sh 31 | $ ./configure 32 | $ make install 33 | 34 | Then, open Xcode project file and build it. 35 | 36 | 37 | 38 | #### An example of the config file 39 | We use almost the same config file as shadowsocks do but add new arguments. (**Not in VPN mode**) 40 | 41 | ``` 42 | { 43 | "process_name": 44 | ["Unibox", "Google Chrome", "Thunder"], 45 | "local_port":1080, 46 | "local_address":"127.0.0.1", 47 | "proximac_port":8558, 48 | "username":"foo", 49 | "password":"bar" 50 | } 51 | ``` 52 | Note: 53 | 54 | ***process_name*** are names of processes that you want to force to use SOCKS5 proxy, which can be found in ***Contents/MacOS*** folder inside those Apps (right click on Apps to get inside). 55 | 56 | ***local_address*** and ***local_port*** is the ip address and the listen port of your SOCKS5 proxy, respectively. 57 | 58 | Leave ***proximac_port*** alone because this is now hardcoded in kext source. ***username*** and ***password*** are for SOCKS5 proxy required authentication if needed. If your SOCKS5 proxy does not require authentification, just remove these two lines. 59 | 60 | There is another example (**VPN mode**) 61 | 62 | ``` 63 | { 64 | "local_port":1080, 65 | "local_address":"127.0.0.1", 66 | "proximac_port":8558, 67 | "VPN_mode":1, 68 | "proxyapp_name":"ShadowsocksX" 69 | } 70 | ``` 71 | Set ***VPN_mode*** to 1 to enable VPN mode. 72 | Set ***proxyapp_name*** to your proxy's process name in case network traffic are trapped in a loop or we can call it a white-list but now Proximac only supports one proxy. 73 | 74 | #### References 75 | This software is partly based on projects below. 76 | 77 | 1. [Shadowsocks-libev](https://github.com/shadowsocks/shadowsocks-libev): libev port of shadowsocks. 78 | 2. [Shadowsocks-libuv](https://github.com/dndx/shadowsocks-libuv): A Lightweight and Super Fast Server for shadowsocks. 79 | 3. [libuv](https://github.com/libuv/libuv): Cross-platform asynchronous I/O. 80 | 4. [js0n](https://github.com/quartzjer/js0n): Flexible Zero-Footprint JSON Parser in C. 81 | 5. [tcplognke](https://developer.apple.com/legacy/library/samplecode/tcplognke/Introduction/Intro.html#//apple_ref/doc/uid/DTS10003669): The tcplognke demonstrates the implementation of a network socket filter for processing incoming and outgoing http packets using the new Kernel Programming Interfaces. 82 | 6. [drcom4mac](https://code.google.com/p/drcom4mac/): As my kext dev guide book. 83 | 84 | #### Copyright: 85 | This project is under GPL v3.0. 86 | 87 | 88 | #### Contact: 89 | csujedi at icloud dot com 90 | -------------------------------------------------------------------------------- /proximac-cli/js0n.c: -------------------------------------------------------------------------------- 1 | // by jeremie miller - 2014 2 | // public domain or MIT license, contributions/improvements welcome via github at https://github.com/quartzjer/js0n 3 | 4 | #include // one strncmp() is used to do key comparison, and a strlen(key) if no len passed in 5 | 6 | // gcc started warning for the init syntax used here, is not helpful so don't generate the spam, supressing the warning is really inconsistently supported across versions 7 | #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) 8 | #pragma GCC diagnostic push 9 | #endif 10 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 11 | #pragma GCC diagnostic ignored "-Wpragmas" 12 | #pragma GCC diagnostic ignored "-Winitializer-overrides" 13 | #pragma GCC diagnostic ignored "-Woverride-init" 14 | 15 | // only at depth 1, track start pointers to match key/value 16 | #define PUSH(i) if(depth == 1) { if(!index) { val = cur+i; }else{ if(klen && index == 1) start = cur+i; else index--; } } 17 | 18 | // determine if key matches or value is complete 19 | #define CAP(i) if(depth == 1) { if(val && !index) {*vlen = (size_t)((cur+i+1) - val); return val;}; if(klen && start) {index = (klen == (size_t)(cur-start) && strncmp(key,start,klen)==0) ? 0 : 2; start = 0;} } 20 | 21 | // this makes a single pass across the json bytes, using each byte as an index into a jump table to build an index and transition state 22 | const char *js0n(const char *key, size_t klen, 23 | const char *json, size_t jlen, size_t *vlen) 24 | { 25 | const char *val = 0; 26 | const char *cur, *end, *start; 27 | size_t index = 1; 28 | int depth = 0; 29 | int utf8_remain = 0; 30 | static void *gostruct[] = 31 | { 32 | [0 ... 255] = &&l_bad, 33 | ['\t'] = &&l_loop, [' '] = &&l_loop, ['\r'] = &&l_loop, ['\n'] = &&l_loop, 34 | ['"'] = &&l_qup, 35 | [':'] = &&l_loop,[','] = &&l_loop, 36 | ['['] = &&l_up, [']'] = &&l_down, // tracking [] and {} individually would allow fuller validation but is really messy 37 | ['{'] = &&l_up, ['}'] = &&l_down, 38 | ['-'] = &&l_bare, [48 ... 57] = &&l_bare, // 0-9 39 | [65 ... 90] = &&l_bare, // A-Z 40 | [97 ... 122] = &&l_bare // a-z 41 | }; 42 | static void *gobare[] = 43 | { 44 | [0 ... 31] = &&l_bad, 45 | [32 ... 126] = &&l_loop, // could be more pedantic/validation-checking 46 | ['\t'] = &&l_unbare, [' '] = &&l_unbare, ['\r'] = &&l_unbare, ['\n'] = &&l_unbare, 47 | [','] = &&l_unbare, [']'] = &&l_unbare, ['}'] = &&l_unbare, [':'] = &&l_unbare, 48 | [127 ... 255] = &&l_bad 49 | }; 50 | static void *gostring[] = 51 | { 52 | [0 ... 31] = &&l_bad, [127] = &&l_bad, 53 | [32 ... 126] = &&l_loop, 54 | ['\\'] = &&l_esc, ['"'] = &&l_qdown, 55 | [128 ... 191] = &&l_bad, 56 | [192 ... 223] = &&l_utf8_2, 57 | [224 ... 239] = &&l_utf8_3, 58 | [240 ... 247] = &&l_utf8_4, 59 | [248 ... 255] = &&l_bad 60 | }; 61 | static void *goutf8_continue[] = 62 | { 63 | [0 ... 127] = &&l_bad, 64 | [128 ... 191] = &&l_utf_continue, 65 | [192 ... 255] = &&l_bad 66 | }; 67 | static void *goesc[] = 68 | { 69 | [0 ... 255] = &&l_bad, 70 | ['"'] = &&l_unesc, ['\\'] = &&l_unesc, ['/'] = &&l_unesc, ['b'] = &&l_unesc, 71 | ['f'] = &&l_unesc, ['n'] = &&l_unesc, ['r'] = &&l_unesc, ['t'] = &&l_unesc, ['u'] = &&l_unesc 72 | }; 73 | void **go = gostruct; 74 | 75 | if(!json || jlen <= 0 || !vlen) return 0; 76 | *vlen = 0; 77 | 78 | // no key is array mode, klen provides requested index 79 | if(!key) 80 | { 81 | index = klen; 82 | klen = 0; 83 | }else{ 84 | if(klen <= 0) klen = strlen(key); // convenience 85 | } 86 | 87 | for(start=cur=json,end=cur+jlen; cur 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) 161 | #pragma GCC diagnostic pop 162 | #endif 163 | -------------------------------------------------------------------------------- /proximac-cli/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_H 2 | #define _UTILS_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern FILE * logfile; 12 | 13 | #if __GNUC__ >= 3 14 | #define likely(x) __builtin_expect(!!(x), 1) 15 | #define unlikely(x) __builtin_expect(!!(x), 0) 16 | #else 17 | #define likely(x) (x) 18 | #define unlikely(x) (x) 19 | #endif 20 | 21 | #define TIME_FORMAT "%Y-%m-%d %H:%M:%S" 22 | #define COLORDEF_GREEM \e[01;32m 23 | #define COLORDEF_WHITE \e[0m 24 | #define USE_LOGFILE(ident) \ 25 | do { \ 26 | if (ident != NULL) { logfile = fopen(ident, "w+"); } } \ 27 | while (0) 28 | 29 | #define CLOSE_LOGFILE \ 30 | do { \ 31 | if (logfile != NULL) { fclose(logfile); } } \ 32 | while (0) 33 | 34 | #define TRY_CLOSE(server_ctx, handle, cb) do { \ 35 | if (!uv_is_closing((uv_handle_t*) &server_ctx->remote_handle) \ 36 | && !uv_is_closing((uv_handle_t*) &server_ctx->server_handle)) { \ 37 | uv_close((uv_handle_t*) handle, cb); \ 38 | } \ 39 | } while (0) 40 | 41 | #define ERROR_UV(msg, code) do { \ 42 | fprintf(stderr, "%s: [%s: %s]\n", msg, uv_err_name((code)), uv_strerror((code))); \ 43 | assert(0); \ 44 | } while(0) 45 | 46 | #define ERROR(msg) do { \ 47 | fprintf(stderr, "%s\n", msg); \ 48 | assert(0); \ 49 | } while(0) 50 | 51 | 52 | 53 | #define _LOG(color, tag, format, ...) \ 54 | do { \ 55 | if (logfile != NULL) { \ 56 | time_t now = time(NULL); \ 57 | char timestr[20]; \ 58 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 59 | fprintf(logfile, " %s " tag ": " format "\n", timestr, \ 60 | ## __VA_ARGS__); \ 61 | fflush(logfile); \ 62 | } \ 63 | else { \ 64 | time_t now = time(NULL); \ 65 | char timestr[20]; \ 66 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 67 | fprintf(stderr, color " %s " tag ": \e[0m" format "\n", timestr, \ 68 | ## __VA_ARGS__); \ 69 | fflush(stderr); \ 70 | } \ 71 | } \ 72 | while (0) 73 | 74 | #define LOGI(format, ...) \ 75 | do { \ 76 | time_t now = time(NULL); \ 77 | char timestr[20]; \ 78 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 79 | fprintf(stderr, "\x1b[32m" " %s INFO: \e[0m" format "\n", timestr, \ 80 | ## __VA_ARGS__); \ 81 | fflush(stderr); \ 82 | } \ 83 | while (0) 84 | 85 | #define LOGD(format, ...) _LOG("\x1b[32m", "Debug", format, ##__VA_ARGS__) 86 | #define LOGW(format, ...) _LOG("\x1b[33m", "Warning", format, ##__VA_ARGS__) 87 | #define LOGE(format, ...) _LOG("\x1b[31m", "Error", format, ##__VA_ARGS__) 88 | #define FATAL(format, ...) _LOG("\x1b[31m", "Fatal", format, ##__VA_ARGS__) 89 | 90 | #define SHOW_BUFFER(buf, len) \ 91 | do { \ 92 | for (int i = 0; ipacket.session_id = ntohl((uint32_t)ctx->packet.session_id); \ 133 | } while(0) 134 | 135 | // built-in link list MACROs, originated from libcork 136 | #define list_init(list) \ 137 | do { \ 138 | (list)->head.next = &(list)->head; \ 139 | (list)->head.prev = &(list)->head; \ 140 | } while (0) 141 | 142 | #define list_add_after(prev, elem) \ 143 | do { \ 144 | (elem)->prev = (prev); \ 145 | (elem)->next = (prev)->next; \ 146 | (prev)->next->prev = (elem); \ 147 | (prev)->next = (elem); \ 148 | } while (0) 149 | 150 | #define list_add_before(succ, elem) \ 151 | do { \ 152 | (elem)->prev = (succ)->prev; \ 153 | (elem)->next = (succ); \ 154 | (succ)->prev->next = (elem); \ 155 | (succ)->prev = (elem); \ 156 | } while (0) 157 | 158 | #define list_add_to_tail(list, elem) \ 159 | list_add_before(&(list)->head, elem); 160 | 161 | #define list_add_to_head(list, elem) \ 162 | list_add_after(&(list)->head, elem); 163 | 164 | #define list_get_head_elem(list) \ 165 | (((list)->head.next == &(list)->head)? NULL: (list)->head.next) 166 | 167 | #define list_remove_elem(elem) \ 168 | do { \ 169 | (elem)->prev->next = (elem)->next; \ 170 | (elem)->next->prev = (elem)->prev; \ 171 | } while (0) 172 | 173 | #define list_get_start(list) \ 174 | ((list)->head.next) 175 | 176 | #define list_elem_is_end(list, element) \ 177 | ((element) == &(list)->head) 178 | 179 | void usage(); 180 | struct timeval GetTimeStamp(); 181 | void setup_signal_handler(uv_loop_t *loop); 182 | void signal_handler(uv_signal_t *handle, int signum); 183 | void init_daemon(); 184 | unsigned int hash(char *str); 185 | 186 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /proximac.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C13D4B481B086B13009F90A7 /* proximac.h in Headers */ = {isa = PBXBuildFile; fileRef = C13D4B471B086B13009F90A7 /* proximac.h */; }; 11 | C163FE841B09134800149D9A /* local.c in Sources */ = {isa = PBXBuildFile; fileRef = C163FE791B09134800149D9A /* local.c */; }; 12 | C163FE851B09134800149D9A /* jconf.c in Sources */ = {isa = PBXBuildFile; fileRef = C163FE7C1B09134800149D9A /* jconf.c */; }; 13 | C163FE861B09134800149D9A /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = C163FE7D1B09134800149D9A /* utils.c */; }; 14 | C163FE871B09134800149D9A /* tree.c in Sources */ = {isa = PBXBuildFile; fileRef = C163FE7E1B09134800149D9A /* tree.c */; }; 15 | C163FE881B09134800149D9A /* js0n.c in Sources */ = {isa = PBXBuildFile; fileRef = C163FE811B09134800149D9A /* js0n.c */; }; 16 | C163FE8A1B09137400149D9A /* libuv.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C163FE891B09137400149D9A /* libuv.1.dylib */; }; 17 | C17919201B0854380013F649 /* proximac.c in Sources */ = {isa = PBXBuildFile; fileRef = C179191F1B0854380013F649 /* proximac.c */; }; 18 | C17919271B0858480013F649 /* tree.h in Headers */ = {isa = PBXBuildFile; fileRef = C17919261B0858480013F649 /* tree.h */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXCopyFilesBuildPhase section */ 22 | C163FE431B0912C300149D9A /* CopyFiles */ = { 23 | isa = PBXCopyFilesBuildPhase; 24 | buildActionMask = 2147483647; 25 | dstPath = /usr/share/man/man1/; 26 | dstSubfolderSpec = 0; 27 | files = ( 28 | ); 29 | runOnlyForDeploymentPostprocessing = 1; 30 | }; 31 | /* End PBXCopyFilesBuildPhase section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | C13D4B471B086B13009F90A7 /* proximac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = proximac.h; sourceTree = ""; }; 35 | C163FE451B0912C300149D9A /* proximac-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "proximac-cli"; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | C163FE791B09134800149D9A /* local.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = local.c; path = "proximac-cli/local.c"; sourceTree = SOURCE_ROOT; }; 37 | C163FE7A1B09134800149D9A /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utils.h; path = "proximac-cli/utils.h"; sourceTree = SOURCE_ROOT; }; 38 | C163FE7B1B09134800149D9A /* local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = local.h; path = "proximac-cli/local.h"; sourceTree = SOURCE_ROOT; }; 39 | C163FE7C1B09134800149D9A /* jconf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = jconf.c; path = "proximac-cli/jconf.c"; sourceTree = SOURCE_ROOT; }; 40 | C163FE7D1B09134800149D9A /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utils.c; path = "proximac-cli/utils.c"; sourceTree = SOURCE_ROOT; }; 41 | C163FE7E1B09134800149D9A /* tree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tree.c; path = "proximac-cli/tree.c"; sourceTree = SOURCE_ROOT; }; 42 | C163FE7F1B09134800149D9A /* jconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jconf.h; path = "proximac-cli/jconf.h"; sourceTree = SOURCE_ROOT; }; 43 | C163FE801B09134800149D9A /* tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tree.h; path = "proximac-cli/tree.h"; sourceTree = SOURCE_ROOT; }; 44 | C163FE811B09134800149D9A /* js0n.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = js0n.c; path = "proximac-cli/js0n.c"; sourceTree = SOURCE_ROOT; }; 45 | C163FE821B09134800149D9A /* js0n.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = js0n.h; path = "proximac-cli/js0n.h"; sourceTree = SOURCE_ROOT; }; 46 | C163FE831B09134800149D9A /* socks5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = socks5.h; path = "proximac-cli/socks5.h"; sourceTree = SOURCE_ROOT; }; 47 | C163FE891B09137400149D9A /* libuv.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libuv.1.dylib; path = ../../../../../../usr/local/lib/libuv.1.dylib; sourceTree = SOURCE_ROOT; }; 48 | C179191A1B0854380013F649 /* proximac.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = proximac.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | C179191E1B0854380013F649 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | C179191F1B0854380013F649 /* proximac.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = proximac.c; sourceTree = ""; }; 51 | C17919261B0858480013F649 /* tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tree.h; path = proximac/tree.h; sourceTree = SOURCE_ROOT; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | C163FE421B0912C300149D9A /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | C163FE8A1B09137400149D9A /* libuv.1.dylib in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | C17919161B0854380013F649 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | C163FE461B0912C300149D9A /* proximac-cli */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | C163FE791B09134800149D9A /* local.c */, 77 | C163FE7A1B09134800149D9A /* utils.h */, 78 | C163FE7B1B09134800149D9A /* local.h */, 79 | C163FE7C1B09134800149D9A /* jconf.c */, 80 | C163FE7D1B09134800149D9A /* utils.c */, 81 | C163FE7E1B09134800149D9A /* tree.c */, 82 | C163FE7F1B09134800149D9A /* jconf.h */, 83 | C163FE801B09134800149D9A /* tree.h */, 84 | C163FE811B09134800149D9A /* js0n.c */, 85 | C163FE821B09134800149D9A /* js0n.h */, 86 | C163FE831B09134800149D9A /* socks5.h */, 87 | ); 88 | path = "proximac-cli"; 89 | sourceTree = ""; 90 | }; 91 | C17919101B0854380013F649 = { 92 | isa = PBXGroup; 93 | children = ( 94 | C163FE891B09137400149D9A /* libuv.1.dylib */, 95 | C179191C1B0854380013F649 /* proximac */, 96 | C163FE461B0912C300149D9A /* proximac-cli */, 97 | C179191B1B0854380013F649 /* Products */, 98 | ); 99 | sourceTree = ""; 100 | }; 101 | C179191B1B0854380013F649 /* Products */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | C179191A1B0854380013F649 /* proximac.kext */, 105 | C163FE451B0912C300149D9A /* proximac-cli */, 106 | ); 107 | name = Products; 108 | sourceTree = ""; 109 | }; 110 | C179191C1B0854380013F649 /* proximac */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | C17919261B0858480013F649 /* tree.h */, 114 | C13D4B471B086B13009F90A7 /* proximac.h */, 115 | C179191F1B0854380013F649 /* proximac.c */, 116 | C179191D1B0854380013F649 /* Supporting Files */, 117 | ); 118 | path = proximac; 119 | sourceTree = SOURCE_ROOT; 120 | }; 121 | C179191D1B0854380013F649 /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | C179191E1B0854380013F649 /* Info.plist */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXHeadersBuildPhase section */ 132 | C17919171B0854380013F649 /* Headers */ = { 133 | isa = PBXHeadersBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | C17919271B0858480013F649 /* tree.h in Headers */, 137 | C13D4B481B086B13009F90A7 /* proximac.h in Headers */, 138 | ); 139 | runOnlyForDeploymentPostprocessing = 0; 140 | }; 141 | /* End PBXHeadersBuildPhase section */ 142 | 143 | /* Begin PBXNativeTarget section */ 144 | C163FE441B0912C300149D9A /* proximac-cli */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = C163FE4B1B0912C300149D9A /* Build configuration list for PBXNativeTarget "proximac-cli" */; 147 | buildPhases = ( 148 | C163FE411B0912C300149D9A /* Sources */, 149 | C163FE421B0912C300149D9A /* Frameworks */, 150 | C163FE431B0912C300149D9A /* CopyFiles */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = "proximac-cli"; 157 | productName = "proximac-cli"; 158 | productReference = C163FE451B0912C300149D9A /* proximac-cli */; 159 | productType = "com.apple.product-type.tool"; 160 | }; 161 | C17919191B0854380013F649 /* proximac */ = { 162 | isa = PBXNativeTarget; 163 | buildConfigurationList = C17919231B0854380013F649 /* Build configuration list for PBXNativeTarget "proximac" */; 164 | buildPhases = ( 165 | C17919151B0854380013F649 /* Sources */, 166 | C17919161B0854380013F649 /* Frameworks */, 167 | C17919171B0854380013F649 /* Headers */, 168 | C17919181B0854380013F649 /* Resources */, 169 | ); 170 | buildRules = ( 171 | ); 172 | dependencies = ( 173 | ); 174 | name = proximac; 175 | productName = proximac; 176 | productReference = C179191A1B0854380013F649 /* proximac.kext */; 177 | productType = "com.apple.product-type.kernel-extension"; 178 | }; 179 | /* End PBXNativeTarget section */ 180 | 181 | /* Begin PBXProject section */ 182 | C17919111B0854380013F649 /* Project object */ = { 183 | isa = PBXProject; 184 | attributes = { 185 | LastUpgradeCheck = 0610; 186 | ORGANIZATIONNAME = jedihy; 187 | TargetAttributes = { 188 | C163FE441B0912C300149D9A = { 189 | CreatedOnToolsVersion = 6.1.1; 190 | }; 191 | C17919191B0854380013F649 = { 192 | CreatedOnToolsVersion = 6.1.1; 193 | }; 194 | }; 195 | }; 196 | buildConfigurationList = C17919141B0854380013F649 /* Build configuration list for PBXProject "proximac" */; 197 | compatibilityVersion = "Xcode 3.2"; 198 | developmentRegion = English; 199 | hasScannedForEncodings = 0; 200 | knownRegions = ( 201 | en, 202 | ); 203 | mainGroup = C17919101B0854380013F649; 204 | productRefGroup = C179191B1B0854380013F649 /* Products */; 205 | projectDirPath = ""; 206 | projectRoot = ""; 207 | targets = ( 208 | C17919191B0854380013F649 /* proximac */, 209 | C163FE441B0912C300149D9A /* proximac-cli */, 210 | ); 211 | }; 212 | /* End PBXProject section */ 213 | 214 | /* Begin PBXResourcesBuildPhase section */ 215 | C17919181B0854380013F649 /* Resources */ = { 216 | isa = PBXResourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXResourcesBuildPhase section */ 223 | 224 | /* Begin PBXSourcesBuildPhase section */ 225 | C163FE411B0912C300149D9A /* Sources */ = { 226 | isa = PBXSourcesBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | C163FE871B09134800149D9A /* tree.c in Sources */, 230 | C163FE851B09134800149D9A /* jconf.c in Sources */, 231 | C163FE881B09134800149D9A /* js0n.c in Sources */, 232 | C163FE861B09134800149D9A /* utils.c in Sources */, 233 | C163FE841B09134800149D9A /* local.c in Sources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | C17919151B0854380013F649 /* Sources */ = { 238 | isa = PBXSourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | C17919201B0854380013F649 /* proximac.c in Sources */, 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | }; 245 | /* End PBXSourcesBuildPhase section */ 246 | 247 | /* Begin XCBuildConfiguration section */ 248 | C163FE491B0912C300149D9A /* Debug */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | GCC_PREPROCESSOR_DEFINITIONS = ( 252 | "DEBUG=1", 253 | "$(inherited)", 254 | ); 255 | HEADER_SEARCH_PATHS = ( 256 | "$(inherited)", 257 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 258 | /usr/local/include, 259 | /usr/include, 260 | ); 261 | LIBRARY_SEARCH_PATHS = ( 262 | /usr/local/lib, 263 | /usr/lib, 264 | ); 265 | PRODUCT_NAME = "$(TARGET_NAME)"; 266 | USER_HEADER_SEARCH_PATHS = ""; 267 | }; 268 | name = Debug; 269 | }; 270 | C163FE4A1B0912C300149D9A /* Release */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | HEADER_SEARCH_PATHS = ( 274 | "$(inherited)", 275 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 276 | /usr/local/include, 277 | /usr/include, 278 | ); 279 | LIBRARY_SEARCH_PATHS = ( 280 | /usr/local/lib, 281 | /usr/lib, 282 | ); 283 | PRODUCT_NAME = "$(TARGET_NAME)"; 284 | USER_HEADER_SEARCH_PATHS = ""; 285 | }; 286 | name = Release; 287 | }; 288 | C17919211B0854380013F649 /* Debug */ = { 289 | isa = XCBuildConfiguration; 290 | buildSettings = { 291 | ALWAYS_SEARCH_USER_PATHS = NO; 292 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 293 | CLANG_CXX_LIBRARY = "libc++"; 294 | CLANG_ENABLE_MODULES = YES; 295 | CLANG_ENABLE_OBJC_ARC = YES; 296 | CLANG_WARN_BOOL_CONVERSION = YES; 297 | CLANG_WARN_CONSTANT_CONVERSION = YES; 298 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 299 | CLANG_WARN_EMPTY_BODY = YES; 300 | CLANG_WARN_ENUM_CONVERSION = YES; 301 | CLANG_WARN_INT_CONVERSION = YES; 302 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 303 | CLANG_WARN_UNREACHABLE_CODE = YES; 304 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 305 | COPY_PHASE_STRIP = NO; 306 | ENABLE_STRICT_OBJC_MSGSEND = YES; 307 | GCC_C_LANGUAGE_STANDARD = gnu99; 308 | GCC_DYNAMIC_NO_PIC = NO; 309 | GCC_OPTIMIZATION_LEVEL = 0; 310 | GCC_PREPROCESSOR_DEFINITIONS = ( 311 | "DEBUG=1", 312 | "$(inherited)", 313 | ); 314 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 315 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 316 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 317 | GCC_WARN_UNDECLARED_SELECTOR = YES; 318 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 319 | GCC_WARN_UNUSED_FUNCTION = YES; 320 | GCC_WARN_UNUSED_VARIABLE = YES; 321 | MACOSX_DEPLOYMENT_TARGET = 10.12; 322 | MTL_ENABLE_DEBUG_INFO = YES; 323 | ONLY_ACTIVE_ARCH = YES; 324 | SDKROOT = macosx; 325 | }; 326 | name = Debug; 327 | }; 328 | C17919221B0854380013F649 /* Release */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ALWAYS_SEARCH_USER_PATHS = NO; 332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 333 | CLANG_CXX_LIBRARY = "libc++"; 334 | CLANG_ENABLE_MODULES = YES; 335 | CLANG_ENABLE_OBJC_ARC = YES; 336 | CLANG_WARN_BOOL_CONVERSION = YES; 337 | CLANG_WARN_CONSTANT_CONVERSION = YES; 338 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 339 | CLANG_WARN_EMPTY_BODY = YES; 340 | CLANG_WARN_ENUM_CONVERSION = YES; 341 | CLANG_WARN_INT_CONVERSION = YES; 342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 343 | CLANG_WARN_UNREACHABLE_CODE = YES; 344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 345 | COPY_PHASE_STRIP = YES; 346 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 347 | ENABLE_NS_ASSERTIONS = NO; 348 | ENABLE_STRICT_OBJC_MSGSEND = YES; 349 | GCC_C_LANGUAGE_STANDARD = gnu99; 350 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 351 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 352 | GCC_WARN_UNDECLARED_SELECTOR = YES; 353 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 354 | GCC_WARN_UNUSED_FUNCTION = YES; 355 | GCC_WARN_UNUSED_VARIABLE = YES; 356 | MACOSX_DEPLOYMENT_TARGET = 10.12; 357 | MTL_ENABLE_DEBUG_INFO = NO; 358 | SDKROOT = macosx; 359 | }; 360 | name = Release; 361 | }; 362 | C17919241B0854380013F649 /* Debug */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | CODE_SIGN_IDENTITY = ""; 366 | INFOPLIST_FILE = proximac/Info.plist; 367 | MODULE_NAME = com.csujedi.proximac; 368 | MODULE_START = proximac_start; 369 | MODULE_STOP = proximac_stop; 370 | MODULE_VERSION = 1.0.1; 371 | PRODUCT_NAME = "$(TARGET_NAME)"; 372 | WRAPPER_EXTENSION = kext; 373 | }; 374 | name = Debug; 375 | }; 376 | C17919251B0854380013F649 /* Release */ = { 377 | isa = XCBuildConfiguration; 378 | buildSettings = { 379 | CODE_SIGN_IDENTITY = ""; 380 | INFOPLIST_FILE = proximac/Info.plist; 381 | MODULE_NAME = com.csujedi.proximac; 382 | MODULE_START = proximac_start; 383 | MODULE_STOP = proximac_stop; 384 | MODULE_VERSION = 1.0.1; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | WRAPPER_EXTENSION = kext; 387 | }; 388 | name = Release; 389 | }; 390 | /* End XCBuildConfiguration section */ 391 | 392 | /* Begin XCConfigurationList section */ 393 | C163FE4B1B0912C300149D9A /* Build configuration list for PBXNativeTarget "proximac-cli" */ = { 394 | isa = XCConfigurationList; 395 | buildConfigurations = ( 396 | C163FE491B0912C300149D9A /* Debug */, 397 | C163FE4A1B0912C300149D9A /* Release */, 398 | ); 399 | defaultConfigurationIsVisible = 0; 400 | defaultConfigurationName = Release; 401 | }; 402 | C17919141B0854380013F649 /* Build configuration list for PBXProject "proximac" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | C17919211B0854380013F649 /* Debug */, 406 | C17919221B0854380013F649 /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | C17919231B0854380013F649 /* Build configuration list for PBXNativeTarget "proximac" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | C17919241B0854380013F649 /* Debug */, 415 | C17919251B0854380013F649 /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | /* End XCConfigurationList section */ 421 | }; 422 | rootObject = C17919111B0854380013F649 /* Project object */; 423 | } 424 | -------------------------------------------------------------------------------- /proximac-cli/local.c: -------------------------------------------------------------------------------- 1 | // local.c 2 | // proximac 3 | // 4 | // Created by jedihy on 15-5-12. 5 | // Copyright (c) 2015年 jedihy. All rights reserved. 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "jconf.h" 26 | #include "local.h" 27 | #include "utils.h" 28 | #include "socks5.h" 29 | 30 | conf_t conf; 31 | FILE* logfile = NULL; 32 | uv_loop_t* loop = NULL; 33 | int log_to_file = 0; 34 | int gSocket = -1; 35 | int gSocket_for_release = -1; 36 | 37 | #define MYBUNDLEID "com.proximac.kext" 38 | 39 | // callback functions 40 | static void server_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf); 41 | static void server_read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); 42 | static void remote_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf); 43 | static void remote_read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); 44 | static void remote_write_cb(uv_write_t* req, int status); 45 | static void server_after_close_cb(uv_handle_t* handle); 46 | static void server_accept_cb(uv_stream_t* server, int status); 47 | static void remote_after_close_cb(uv_handle_t* handle); 48 | static void connect_to_remote_cb(uv_connect_t* req, int status); 49 | static void final_after_close_cb(uv_handle_t* handle); 50 | 51 | // pid rb-tree structure 52 | /* Red-black tree of pid to be Hooked for proximac */ 53 | struct pid_tree pid_list; 54 | 55 | static inline int 56 | pid_cmp(const struct pid* tree_a, const struct pid* tree_b) 57 | { 58 | if (tree_a->pid == tree_b->pid) 59 | return 0; 60 | return tree_a->pid < tree_b->pid ? -1 : 1; 61 | } 62 | 63 | RB_GENERATE(pid_tree, pid, rb_link, pid_cmp); 64 | static void final_after_close_cb(uv_handle_t* handle) 65 | { 66 | LOGW("final_after_close_cb"); 67 | server_ctx_t* server_ctx = handle->data; 68 | if (server_ctx->buf != NULL) 69 | free(server_ctx->buf); 70 | free(server_ctx); 71 | } 72 | 73 | static void server_after_close_cb(uv_handle_t* handle) 74 | { 75 | 76 | server_ctx_t* server_ctx = handle->data; 77 | uv_read_stop((uv_stream_t*)&server_ctx->remote_handle); 78 | uv_close((uv_handle_t*)(void*)&server_ctx->remote_handle, final_after_close_cb); 79 | } 80 | 81 | static void remote_after_close_cb(uv_handle_t* handle) 82 | { 83 | server_ctx_t* server_ctx = handle->data; 84 | uv_read_stop((uv_stream_t*)&server_ctx->server_handle); 85 | uv_close((uv_handle_t*)(void*)&server_ctx->server_handle, final_after_close_cb); 86 | } 87 | 88 | static void remote_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) 89 | { 90 | *buf = uv_buf_init((char*)malloc(BUF_SIZE), BUF_SIZE); 91 | assert(buf->base != NULL); 92 | } 93 | 94 | static void remote_read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) 95 | { 96 | server_ctx_t* server_ctx = stream->data; 97 | if (nread <= 0) { 98 | if (nread == 0) { 99 | if (buf->len > 0) 100 | free(buf->base); 101 | return; 102 | } 103 | TRY_CLOSE(server_ctx, &server_ctx->remote_handle, remote_after_close_cb); 104 | } 105 | else { 106 | 107 | if (server_ctx->remote_stage == 0) { 108 | if (server_ctx->remote_auth_stage == 0) { 109 | if ((buf->base[0] == 0x05 && buf->base[1] == 0x00)) { 110 | LOGD("negotiate successfully!"); 111 | goto neg_ok; 112 | } 113 | else if (buf->base[0] == 0x05 && buf->base[1] == 0x02) { 114 | LOGD("socks5 server response 05 02 auth is required (OK)"); 115 | // now send auth. info to SOCKS5 proxy 116 | write_req_t* wr = (write_req_t*)malloc(sizeof(write_req_t)); 117 | wr->req.data = server_ctx; 118 | unsigned char username_len = strlen(conf.username); 119 | unsigned char password_len = strlen(conf.password); 120 | int len = 1 /* fixed 1 byte */ + 2 /* 2 bytes for username and password */ + username_len + password_len; 121 | char* socks5req = malloc(len); 122 | socks5req[0] = 0x01; /* version of auth */ 123 | socks5req[1] = username_len; 124 | memcpy(socks5req + 2, conf.username, username_len); 125 | socks5req[2 + username_len] = password_len; 126 | memcpy(socks5req + 2 + username_len + 1, conf.password, password_len); 127 | wr->buf = uv_buf_init(socks5req, len); 128 | uv_write(&wr->req, (uv_stream_t*)&server_ctx->remote_handle, &wr->buf, 1, remote_write_cb); 129 | server_ctx->remote_auth_stage = 1; 130 | } 131 | } 132 | else if (server_ctx->remote_auth_stage == 1) { 133 | if (buf->base[0] == 0x01 && buf->base[1] == 0x00) { 134 | LOGD("auth succeed!"); 135 | goto neg_ok; 136 | } 137 | else { 138 | LOGD("auth fail: error username or password!"); 139 | TRY_CLOSE(server_ctx, &server_ctx->remote_handle, remote_after_close_cb); 140 | free(buf->base); 141 | return; 142 | } 143 | } 144 | } 145 | else if (server_ctx->remote_stage == 1) { 146 | if (buf->base[0] == 0x05) { 147 | LOGD("socks5 server works"); 148 | server_ctx->server_stage = 1; 149 | write_req_t* wr = (write_req_t*)malloc(sizeof(write_req_t)); 150 | if (server_ctx->buf_len) { 151 | char* tmpbuf = malloc(server_ctx->buf_len); 152 | memcpy(tmpbuf, server_ctx->buf, server_ctx->buf_len); 153 | free(server_ctx->buf); 154 | server_ctx->buf = NULL; 155 | wr->req.data = server_ctx; 156 | wr->buf = uv_buf_init(tmpbuf, server_ctx->buf_len); 157 | uv_write(&wr->req, (uv_stream_t*)&server_ctx->remote_handle, &wr->buf, 1, remote_write_cb); 158 | } 159 | uv_read_start((uv_stream_t*)&server_ctx->server_handle, server_alloc_cb, server_read_cb); 160 | server_ctx->remote_stage = 2; 161 | } 162 | } 163 | else if (server_ctx->remote_stage == 2) { 164 | write_req_t* wr = (write_req_t*)malloc(sizeof(write_req_t)); 165 | wr->req.data = server_ctx; 166 | wr->buf = uv_buf_init(buf->base, nread); 167 | uv_write(&wr->req, (uv_stream_t*)&server_ctx->server_handle, &wr->buf, 1, remote_write_cb); 168 | } 169 | } 170 | return; 171 | 172 | neg_ok: 173 | server_ctx->remote_stage = 1; 174 | write_req_t* wr = (write_req_t*)malloc(sizeof(write_req_t)); 175 | wr->req.data = server_ctx; 176 | int len = 4 + 1 + server_ctx->addrlen + sizeof(server_ctx->port); 177 | char* socks5req = malloc(len); 178 | socks5req[0] = 0x05; 179 | socks5req[1] = 0x01; 180 | socks5req[2] = 0x00; 181 | socks5req[3] = 0x03; 182 | socks5req[4] = server_ctx->addrlen; 183 | memcpy(socks5req + 5, server_ctx->remote_addr, server_ctx->addrlen); 184 | uint16_t port = htons(server_ctx->port); 185 | memcpy(socks5req + 5 + server_ctx->addrlen, &port, sizeof(server_ctx->port)); 186 | wr->buf = uv_buf_init(socks5req, len); 187 | uv_write(&wr->req, (uv_stream_t*)&server_ctx->remote_handle, &wr->buf, 1, remote_write_cb); 188 | } 189 | 190 | static void remote_write_cb(uv_write_t* req, int status) 191 | { 192 | write_req_t* wr = (write_req_t*)req; 193 | server_ctx_t* server_ctx = req->data; 194 | if (status) { 195 | if (status != UV_ECANCELED) { 196 | LOGW("remote_write_cb TRY_CLOSE"); 197 | if (req->handle == &server_ctx->server_handle) { 198 | TRY_CLOSE(server_ctx, &server_ctx->server_handle, server_after_close_cb); 199 | } 200 | else { 201 | TRY_CLOSE(server_ctx, &server_ctx->remote_handle, remote_after_close_cb); 202 | } 203 | } 204 | } 205 | 206 | assert(wr->req.type == UV_WRITE); 207 | /* Free the read/write buffer and the request */ 208 | free(wr->buf.base); 209 | free(wr); 210 | } 211 | 212 | static void connect_to_remote_cb(uv_connect_t* req, int status) 213 | { 214 | server_ctx_t* server_ctx = (server_ctx_t*)req->data; 215 | 216 | if (status) { 217 | // cleanup 218 | if (status != UV_ECANCELED) { 219 | TRY_CLOSE(server_ctx, &server_ctx->remote_handle, remote_after_close_cb); 220 | } 221 | free(req); 222 | return; 223 | } 224 | 225 | uv_read_start(req->handle, remote_alloc_cb, remote_read_cb); 226 | write_req_t* wr = (write_req_t*)malloc(sizeof(write_req_t)); 227 | wr->req.data = server_ctx; 228 | char* socks5req = malloc(3); 229 | socks5req[0] = 0x05; 230 | socks5req[1] = 0x01; 231 | if (conf.username == NULL || conf.password == NULL) 232 | socks5req[2] = 0x00; 233 | else 234 | socks5req[2] = 0x02; 235 | wr->buf = uv_buf_init(socks5req, 3); 236 | uv_write(&wr->req, (uv_stream_t*)&server_ctx->remote_handle, &wr->buf, 1, remote_write_cb); 237 | } 238 | 239 | static void server_accept_cb(uv_stream_t* server, int status) 240 | { 241 | if (status) { 242 | LOGE("server accept failed!"); 243 | return; 244 | } 245 | server_ctx_t* server_ctx = calloc(1, sizeof(server_ctx_t)); 246 | // calloc set all members to zero! 247 | 248 | server_ctx->server_handle.data = server_ctx; 249 | server_ctx->remote_handle.data = server_ctx; 250 | uv_tcp_init(loop, &server_ctx->server_handle); 251 | uv_tcp_init(loop, &server_ctx->remote_handle); 252 | uv_tcp_nodelay(&server_ctx->server_handle, 1); 253 | LOGW("server_accept_cb %s %d", server_ctx->remote_addr, server_ctx->remote_handle.type); 254 | int r = uv_accept(server, (uv_stream_t*)&server_ctx->server_handle); 255 | if (r) { 256 | fprintf(stderr, "accepting connection failed %d", r); 257 | uv_close((uv_handle_t*)&server_ctx->server_handle, NULL); 258 | } 259 | 260 | uv_read_start((uv_stream_t*)&server_ctx->server_handle, server_alloc_cb, 261 | server_read_cb); 262 | } 263 | 264 | static void server_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) 265 | { 266 | *buf = uv_buf_init((char*)malloc(BUF_SIZE), BUF_SIZE); 267 | assert(buf->base != NULL); 268 | } 269 | 270 | static void server_read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) 271 | { 272 | server_ctx_t* server_ctx = stream->data; 273 | 274 | if (nread <= 0) { 275 | if (nread == 0) { 276 | if (buf->len > 0) 277 | free(buf->base); 278 | return; 279 | } 280 | 281 | TRY_CLOSE(server_ctx, &server_ctx->server_handle, server_after_close_cb); 282 | } 283 | else { 284 | if (server_ctx->server_stage == 0) { 285 | 286 | uv_read_stop(stream); 287 | server_ctx->buf = buf->base; 288 | server_ctx->buf_len = nread; 289 | server_ctx->addrlen = server_ctx->buf[0]; 290 | memcpy(server_ctx->remote_addr, server_ctx->buf + sizeof(char), server_ctx->addrlen); 291 | memcpy(&server_ctx->port, server_ctx->buf + 1 + server_ctx->addrlen, sizeof(server_ctx->port)); 292 | unsigned long tmpbuf_len = nread - server_ctx->addrlen - 1 - sizeof(server_ctx->port); 293 | if (tmpbuf_len) { 294 | char* tmpbuf = malloc(tmpbuf_len); 295 | memcpy(tmpbuf, server_ctx->buf + server_ctx->addrlen + 1 + sizeof(server_ctx->port), tmpbuf_len); 296 | 297 | server_ctx->buf_len = tmpbuf_len; 298 | server_ctx->buf = tmpbuf; 299 | } 300 | else { 301 | server_ctx->buf_len = 0; 302 | server_ctx->buf = NULL; 303 | } 304 | 305 | free(buf->base); 306 | 307 | 308 | struct sockaddr_in remote_addr; 309 | memset(&remote_addr, 0, sizeof(remote_addr)); 310 | uv_ip4_addr(conf.local_address, conf.localport, &remote_addr); 311 | 312 | uv_connect_t* remote_conn_req = calloc(1, sizeof(uv_connect_t)); 313 | remote_conn_req->data = server_ctx; 314 | uv_tcp_connect(remote_conn_req, &server_ctx->remote_handle, (struct sockaddr*)&remote_addr, connect_to_remote_cb); 315 | } 316 | else if (server_ctx->server_stage == 1) { 317 | write_req_t* wr = (write_req_t*)malloc(sizeof(write_req_t)); 318 | wr->req.data = server_ctx; 319 | wr->buf = uv_buf_init(buf->base, nread); 320 | uv_write(&wr->req, (uv_stream_t*)&server_ctx->remote_handle, &wr->buf, 1, remote_write_cb); 321 | } 322 | } 323 | } 324 | 325 | int tell_kernel_to_unhook() 326 | { 327 | errno_t retval = 0; 328 | 329 | int result = 0; 330 | unsigned int size = sizeof(result); 331 | retval = getsockopt(gSocket, SYSPROTO_CONTROL, PROXIMAC_OFF, &result, &size); 332 | if (-1 == retval) { 333 | LOGI("getsockopt failure PROXIMAC_OFF"); 334 | exit(EXIT_FAILURE); 335 | } 336 | else if (EINPROGRESS == retval) { 337 | LOGI("ERROR: Maybe Proximac is unregistering filters..."); 338 | } 339 | 340 | if (result == EINPROGRESS) { 341 | LOGI("Proximac is unregistering filters..."); 342 | LOGI("Wait a few sec to for Proximac to release kernel resources"); 343 | } 344 | 345 | return 0; 346 | } 347 | 348 | int tell_kernel_to_hook() 349 | { 350 | struct ctl_info ctl_info; 351 | struct sockaddr_ctl sc; 352 | errno_t retval = 0; 353 | 354 | gSocket = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); 355 | if (gSocket < 0) { 356 | LOGI("socket() failed."); 357 | exit(EXIT_FAILURE); 358 | } 359 | 360 | bzero(&ctl_info, sizeof(struct ctl_info)); 361 | 362 | strcpy(ctl_info.ctl_name, MYBUNDLEID); 363 | if (ioctl(gSocket, CTLIOCGINFO, &ctl_info) == -1) { 364 | LOGE("ioctl CTLIOCGINFO"); 365 | exit(EXIT_FAILURE); 366 | } 367 | 368 | bzero(&sc, sizeof(struct sockaddr_ctl)); 369 | sc.sc_len = sizeof(struct sockaddr_ctl); 370 | sc.sc_family = AF_SYSTEM; 371 | sc.ss_sysaddr = SYSPROTO_CONTROL; 372 | sc.sc_id = ctl_info.ctl_id; 373 | sc.sc_unit = 0; 374 | 375 | if (connect(gSocket, (struct sockaddr*)&sc, sizeof(struct sockaddr_ctl))) { 376 | LOGI("Connection to kernel failed. The kernel module may not be correctly loaded."); 377 | exit(EXIT_FAILURE); 378 | } 379 | 380 | 381 | int vpn_mode = 0; 382 | if (conf.vpn_mode == 1) 383 | vpn_mode = 1; 384 | 385 | retval = setsockopt(gSocket, SYSPROTO_CONTROL, PROXIMAC_ON, &vpn_mode, sizeof(vpn_mode)); 386 | if (retval) { 387 | LOGE("setsockopt failure PROXIMAC_ON"); 388 | return retval; 389 | } 390 | 391 | if (vpn_mode == 1) { 392 | retval = setsockopt(gSocket, SYSPROTO_CONTROL, NOT_TO_HOOK, &conf.proxyapp_hash, sizeof(conf.proxyapp_hash)); 393 | if (retval) { 394 | LOGE("setsockopt failure NOT_TO_HOOK"); 395 | return retval; 396 | } 397 | } 398 | 399 | struct pid* pid_tmp = NULL; 400 | int pidset_checksum = 0; 401 | RB_FOREACH(pid_tmp, pid_tree, &pid_list) 402 | { 403 | retval = setsockopt(gSocket, SYSPROTO_CONTROL, HOOK_PID, &pid_tmp->pid, sizeof(pid_tmp->pid)); 404 | if (retval) { 405 | LOGE("setsockopt failure HOOK_PID"); 406 | return retval; 407 | } 408 | pidset_checksum += pid_tmp->pid; 409 | } 410 | 411 | int pidget_checksum = 0; 412 | unsigned int size = sizeof(pidget_checksum); 413 | retval = getsockopt(gSocket, SYSPROTO_CONTROL, HOOK_PID, &pidget_checksum, &size); 414 | if (retval) { 415 | LOGE("getsockopt HOOK_PID failure"); 416 | return retval; 417 | } 418 | 419 | if (pidget_checksum == pidset_checksum) 420 | LOGI("Hook Succeed!"); 421 | else 422 | LOGI("Hook Fail! pidget_checksum = %d pidset_checksum = %d", pidget_checksum, pidset_checksum); 423 | 424 | int pid_num = 0; 425 | size = sizeof(pid_num); 426 | 427 | retval = getsockopt(gSocket, SYSPROTO_CONTROL, PIDLIST_STATUS, &pid_num, &size); 428 | if (retval) { 429 | LOGE("getsockopt PIDLIST_STATUS failure"); 430 | return retval; 431 | } 432 | 433 | if (conf.vpn_mode == 1) 434 | LOGI("All traffic will be redirected to this SOCKS5 proxy"); 435 | else 436 | LOGI("The total number of process that will be hooked = %d", pid_num); 437 | 438 | return retval; 439 | } 440 | 441 | void signal_handler_ctl_z(uv_signal_t* handle, int signum) 442 | { 443 | LOGI("Terminal signal captured! Exiting and turning off kernel extension..."); 444 | tell_kernel_to_unhook(); 445 | uv_loop_t* loop = handle->data; 446 | uv_signal_stop(handle); 447 | uv_stop(loop); 448 | exit(0); 449 | } 450 | 451 | void signal_handler_ctl_c(uv_signal_t* handle, int signum) 452 | { 453 | LOGI("Ctrl+C pressed, tell kernel to UnHook socket"); 454 | tell_kernel_to_unhook(); 455 | uv_loop_t* loop = handle->data; 456 | uv_signal_stop(handle); 457 | uv_stop(loop); 458 | exit(0); 459 | } 460 | 461 | int main(int argc, char** argv) 462 | { 463 | int c, option_index = 0, daemon = 0; 464 | char* configfile = NULL; 465 | char* logfile_path = "./proximac.log"; 466 | RB_INIT(&pid_list); 467 | opterr = 0; 468 | static struct option long_options[] = { 469 | { 0, 0, 0, 0 } 470 | }; 471 | 472 | while ((c = getopt_long(argc, argv, "c:d", 473 | long_options, &option_index)) != -1) { 474 | switch (c) { 475 | case 'd': { 476 | daemon = 1; 477 | break; 478 | } 479 | case 'c': { 480 | configfile = optarg; 481 | break; 482 | } 483 | default: { 484 | opterr = 1; 485 | break; 486 | } 487 | } 488 | } 489 | 490 | if (opterr == 1 || configfile == NULL) { 491 | fprintf(stderr, "No config file specified!\n"); 492 | usage(); 493 | exit(EXIT_FAILURE); 494 | } 495 | 496 | if (log_to_file) { 497 | USE_LOGFILE(logfile_path); 498 | } 499 | 500 | if (configfile) { 501 | read_conf(configfile, &conf); 502 | } 503 | 504 | int r = tell_kernel_to_hook(); 505 | if (r) { 506 | if (r == EAGAIN) 507 | FATAL("Please wait a few seconds for Proximac release resources in kernel (normally in 10 sec)"); 508 | else 509 | FATAL("kernel cannot hook this PID due to various reasons"); 510 | } 511 | 512 | if (daemon == 1) 513 | init_daemon(); 514 | 515 | 516 | 517 | struct sockaddr_in bind_addr; 518 | loop = malloc(sizeof *loop); 519 | uv_loop_init(loop); 520 | listener_t* listener = calloc(1, sizeof(server_ctx_t)); 521 | listener->handle.data = listener; 522 | uv_tcp_init(loop, &listener->handle); 523 | uv_tcp_nodelay(&listener->handle, 1); 524 | 525 | r = uv_ip4_addr("127.0.0.1", conf.proximac_port, &bind_addr); 526 | if (r) 527 | LOGE("Translate address error"); 528 | r = uv_tcp_bind(&listener->handle, (struct sockaddr*)&bind_addr, 0); 529 | if (r) 530 | LOGI("Bind error"); 531 | r = uv_listen((uv_stream_t*)&listener->handle, 128 /*backlog*/, server_accept_cb); 532 | if (r) 533 | LOGI("Listen error"); 534 | LOGI("Listening on %d", conf.proximac_port); 535 | 536 | signal(SIGPIPE, SIG_IGN); 537 | uv_signal_t sigint, sigstp, sigkil, sigterm; 538 | sigkil.data = loop; 539 | sigint.data = loop; 540 | sigstp.data = loop; 541 | sigterm.data = loop; 542 | uv_signal_init(loop, &sigint); 543 | uv_signal_init(loop, &sigstp); 544 | uv_signal_init(loop, &sigkil); 545 | uv_signal_init(loop, &sigterm); 546 | uv_signal_start(&sigint, signal_handler_ctl_z, SIGKILL); 547 | uv_signal_start(&sigint, signal_handler_ctl_c, SIGINT); 548 | uv_signal_start(&sigstp, signal_handler_ctl_z, SIGTSTP); 549 | uv_signal_start(&sigterm, signal_handler_ctl_z, SIGTERM); 550 | 551 | uv_run(loop, UV_RUN_DEFAULT); 552 | uv_loop_close(loop); 553 | free(loop); 554 | CLOSE_LOGFILE; 555 | return 0; 556 | } 557 | -------------------------------------------------------------------------------- /proximac/proximac.c: -------------------------------------------------------------------------------- 1 | // 2 | // proximac.c 3 | // proximac 4 | // 5 | // Created by jedihy on 15-5-17. 6 | // Copyright (c) 2015年 jedihy. All rights reserved. 7 | // 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 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 | 30 | 31 | #include "tree.h" 32 | #include "proximac.h" 33 | 34 | // Global variables without lock protection 35 | static kern_ctl_ref g_proximac_ctl_ref = NULL; 36 | static int g_pid_num = 0; 37 | static int g_proximac_mode = PROXIMAC_MODE_OFF; 38 | static int g_proxy_hash = 0; 39 | 40 | static bool g_proximac_tcp_filter_registered = false; 41 | static bool g_proximac_tcp_unreg_started = false; 42 | static bool g_proximac_tcp_unreg_completed = false; 43 | 44 | // R/W locks 45 | static lck_grp_t * g_lock_grp = NULL; 46 | static lck_rw_t * g_pidlist_lock = NULL; // protect g_pid_num and pid_list 47 | static lck_rw_t * g_mode_lock = NULL; 48 | 49 | /* List of pid to free added for proximac */ 50 | SLIST_HEAD(pid_slist, pid); 51 | static struct pid_slist pid_freelist; 52 | 53 | /* Red-black tree of pid to be Hooked for proximac */ 54 | struct pid { 55 | RB_ENTRY(pid) rb_link; 56 | int pid; 57 | int value; 58 | SLIST_ENTRY(pid) slist_link; 59 | }; 60 | 61 | RB_HEAD(pid_tree, pid); 62 | 63 | static struct pid_tree pid_list; 64 | 65 | static inline int 66 | pid_cmp(const struct pid *tree_a, const struct pid *tree_b) 67 | { 68 | if (tree_a->pid == tree_b->pid) 69 | return 0; 70 | return tree_a->pid < tree_b->pid? -1:1; 71 | } 72 | 73 | RB_PROTOTYPE(pid_tree, pid, rb_link, pid_cmp); 74 | RB_GENERATE(pid_tree, pid, rb_link, pid_cmp); 75 | 76 | // declare kernel init and exit functions 77 | kern_return_t proximac_start(kmod_info_t * ki, void *data); 78 | kern_return_t proximac_stop(kmod_info_t *ki, void *data); 79 | 80 | // declare locks related functions 81 | static errno_t init_locks(); 82 | static errno_t init_lock_grp(); 83 | static errno_t alloc_rwlock(lck_rw_t ** lock_ptr); 84 | 85 | // declare controller callbacks 86 | static errno_t proximac_ctl_connect_cb(kern_ctl_ref kctlref, struct sockaddr_ctl *sac, void **unitinfo); 87 | static errno_t proximac_ctl_setopt_cb(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len); 88 | static errno_t proximac_ctl_getopt_cb(kern_ctl_ref kctlref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t *len); 89 | 90 | // declare filter related callbacks 91 | static void 92 | proximac_tcp_unregistered_cb(sflt_handle handle); 93 | static errno_t 94 | proximac_tcp_attach_cb(void ** cookie, socket_t so); 95 | static void 96 | proximac_tcp_detach_cb(void * cookie, socket_t so); 97 | static errno_t 98 | proximac_tcp_connect_out_cb(void * cookie, socket_t so, const struct sockaddr * to); 99 | static void 100 | proximac_tcp_notify_cb(void *cookie, socket_t so, sflt_event_t event, void *param); 101 | 102 | // other functions 103 | static errno_t install_proximac_tcp_filter(); 104 | static errno_t uninstall_proximac_tcp_filter(); 105 | 106 | #pragma mark Customized printf function 107 | #define LOGI(format, ...) do { \ 108 | printf("[Proximac]: " format "\n", ## __VA_ARGS__); \ 109 | } while (0) 110 | 111 | #pragma mark Lock-related functions 112 | static void 113 | release_lock(lck_rw_t * lock) 114 | { 115 | // Make sure g_lock_grp is not NULL 116 | assert(g_lock_grp); 117 | 118 | if (lock) 119 | { 120 | lck_rw_free(lock, g_lock_grp); 121 | } 122 | } 123 | 124 | static void 125 | release_locks() 126 | { 127 | if (g_mode_lock) 128 | release_lock(g_mode_lock); 129 | 130 | if (g_pidlist_lock) 131 | release_lock(g_pidlist_lock); 132 | 133 | g_mode_lock = g_pidlist_lock = NULL; 134 | 135 | if (g_lock_grp) 136 | { 137 | lck_grp_free(g_lock_grp); 138 | g_lock_grp = NULL; 139 | } 140 | } 141 | 142 | static errno_t 143 | alloc_rwlock(lck_rw_t ** lock_ptr) 144 | { 145 | errno_t retval = 0; 146 | lck_attr_t * lock_attr = NULL; 147 | 148 | // Make sure g_lock_grp is not NULL 149 | assert(g_lock_grp); 150 | 151 | lock_attr = lck_attr_alloc_init(); 152 | if (NULL == lock_attr) 153 | { 154 | LOGI("lck_attr_alloc_init() failed"); 155 | retval = ENOMEM; 156 | goto out; 157 | } 158 | 159 | *lock_ptr = lck_rw_alloc_init(g_lock_grp, lock_attr); 160 | if (NULL == *lock_ptr) 161 | { 162 | LOGI("lck_rw_alloc_init() failed"); 163 | retval = ENOMEM; 164 | goto out; 165 | } 166 | 167 | out: 168 | if (lock_attr) 169 | lck_attr_free(lock_attr); 170 | 171 | return retval; 172 | } 173 | 174 | static errno_t init_locks() { 175 | errno_t retval = 0; 176 | retval = init_lock_grp(); 177 | if (retval) { 178 | LOGI("init_lock_grp error errorno = %d", retval); 179 | return retval; 180 | } 181 | 182 | retval = alloc_rwlock(&g_pidlist_lock); 183 | if (retval) { 184 | LOGI("alloc_rwlock error for g_pidlist_lock errorno = %d", retval); 185 | return retval; 186 | } 187 | 188 | retval = alloc_rwlock(&g_mode_lock); 189 | if (retval) { 190 | LOGI("alloc_rwlock for g_mode_lock error errorno = %d", retval); 191 | return retval; 192 | } 193 | 194 | return retval; 195 | } 196 | 197 | static errno_t init_lock_grp() { 198 | errno_t result = 0; 199 | 200 | // Lock group should be initialized only once. 201 | assert(NULL == g_lock_grp); 202 | 203 | lck_grp_attr_t * lock_grp_attr = lck_grp_attr_alloc_init(); 204 | if (NULL == lock_grp_attr) 205 | { 206 | LOGI("lck_grp_attr_alloc_init() failed"); 207 | result = ENOMEM; 208 | goto out; 209 | } 210 | 211 | g_lock_grp = lck_grp_alloc_init("proximac", lock_grp_attr); 212 | if (NULL == g_lock_grp) 213 | { 214 | LOGI("lck_grp_alloc_init() failed"); 215 | result = ENOMEM; 216 | goto out; 217 | } 218 | 219 | out: 220 | if (lock_grp_attr) 221 | lck_grp_attr_free(lock_grp_attr); 222 | 223 | return result; 224 | } 225 | 226 | #pragma mark Controller-related functions 227 | static struct kern_ctl_reg proximac_ctl_reg = { 228 | MYBUNDLEID, /* use a reverse dns name which includes a name unique to your comany */ 229 | 0, /* set to 0 for dynamically assigned control ID - CTL_FLAG_REG_ID_UNIT not set */ 230 | 0, /* ctl_unit - ignored when CTL_FLAG_REG_ID_UNIT not set */ 231 | 0, /* privileged access required to access this filter */ 232 | 0, /* use default send size buffer */ 233 | 0, /* use default receive size buffer */ 234 | proximac_ctl_connect_cb, /* called when a connection request is accepted (requied field)*/ 235 | NULL, /* called when a connection becomes disconnected */ 236 | NULL, /* ctl_send_func - handles data sent from the client to kernel control */ 237 | proximac_ctl_setopt_cb, /* called when the user process makes the setsockopt call */ 238 | proximac_ctl_getopt_cb /* called when the user process makes the getsockopt call */ 239 | }; 240 | 241 | static errno_t install_proximac_controller() { 242 | errno_t retval = 0; 243 | 244 | if (g_proximac_ctl_ref) { 245 | LOGI("proximac controller is already installed"); 246 | return 0; 247 | } 248 | 249 | retval = ctl_register(&proximac_ctl_reg, &g_proximac_ctl_ref); 250 | 251 | if (0 == retval) { 252 | LOGI("Controller has been installed successfully"); 253 | } 254 | else 255 | LOGI("ctl_register fialed errorno = %d", retval); 256 | 257 | return retval; 258 | 259 | } 260 | 261 | static errno_t 262 | uninstall_proximac_controller() 263 | { 264 | errno_t retval = 0; 265 | 266 | if (g_proximac_ctl_ref) 267 | { 268 | retval = ctl_deregister(g_proximac_ctl_ref); 269 | if (retval) 270 | { 271 | LOGI("ctl_deregister() error errorno = %d", retval); 272 | } 273 | else 274 | { 275 | g_proximac_ctl_ref = NULL; 276 | LOGI("Proximac controller has been unregistered."); 277 | } 278 | } 279 | else 280 | { 281 | LOGI("Proximac controller has not been registered."); 282 | } 283 | return retval; 284 | } 285 | 286 | static errno_t proximac_ctl_connect_cb( 287 | kern_ctl_ref kctlref, 288 | struct sockaddr_ctl *sac, 289 | void **unitinfo) 290 | { 291 | // just leave connect cb alone 292 | LOGI("connected to client"); 293 | return 0; 294 | } 295 | 296 | #define PROXIMAC_ON 1 297 | #define HOOK_PID 2 298 | #define PIDLIST_STATUS 3 299 | #define PROXIMAC_OFF 4 300 | #define NOT_TO_HOOK 5 301 | 302 | static errno_t proximac_ctl_setopt_cb( 303 | kern_ctl_ref kctlref, 304 | u_int32_t unit, 305 | void *unitinfo, 306 | int opt, 307 | void *data, 308 | size_t len) 309 | { 310 | int retval = 0; 311 | int intval; 312 | switch (opt) { 313 | case PROXIMAC_ON: 314 | { 315 | lck_rw_lock_exclusive(g_pidlist_lock); 316 | if (g_pid_num != 0) { 317 | 318 | struct pid *pid_tmp; 319 | RB_FOREACH(pid_tmp, pid_tree, &pid_list) { 320 | SLIST_INSERT_HEAD(&pid_freelist, pid_tmp, slist_link); 321 | } 322 | 323 | while (!SLIST_EMPTY(&pid_freelist)) { 324 | pid_tmp = SLIST_FIRST(&pid_freelist); 325 | SLIST_REMOVE_HEAD(&pid_freelist, slist_link); 326 | RB_REMOVE(pid_tree, &pid_list, pid_tmp); 327 | if (pid_tmp) 328 | _FREE(pid_tmp, M_TEMP); 329 | g_pid_num--; 330 | } 331 | 332 | if (g_pid_num == 0) 333 | LOGI("pid list is cleared\n"); 334 | 335 | } else 336 | LOGI("empty pid list"); 337 | 338 | lck_rw_unlock_exclusive(g_pidlist_lock); 339 | 340 | lck_rw_lock_exclusive(g_mode_lock); 341 | 342 | 343 | // install socket filters 344 | if (g_proximac_mode == PROXIMAC_MODE_OFF) { 345 | retval = install_proximac_tcp_filter(); 346 | if (retval) { 347 | LOGI("install TCP filters error errorno = %d", retval); 348 | lck_rw_unlock_exclusive(g_mode_lock); 349 | return retval; 350 | } 351 | intval = *(int *)data; 352 | if(intval == 1){ 353 | g_proximac_mode = PROXIMAC_MODE_ALL; 354 | LOGI("In VPN mode"); 355 | } 356 | else 357 | g_proximac_mode = PROXIMAC_MODE_ON; 358 | } 359 | lck_rw_unlock_exclusive(g_mode_lock); 360 | } 361 | break; 362 | // case PROXIMAC_OFF: 363 | // lck_rw_lock_exclusive(g_mode_lock); 364 | // g_proximac_mode = PROXIMAC_MODE_OFF; 365 | // lck_rw_unlock_exclusive(g_mode_lock); 366 | // retval = uninstall_proximac_tcp_filter(); 367 | // LOGI("PROXIMAC_OFF cmd received ret = %d", retval); 368 | // return retval; 369 | // break; 370 | case HOOK_PID: 371 | { 372 | if (len < sizeof(int)) { 373 | retval = EINVAL; 374 | break; 375 | } 376 | intval = *(int*)data; 377 | lck_rw_lock_exclusive(g_pidlist_lock); 378 | struct pid *pid_to_insert = _MALLOC(sizeof(struct pid), M_TEMP, M_WAITOK| M_ZERO); 379 | pid_to_insert->pid = intval; 380 | RB_INSERT(pid_tree, &pid_list, pid_to_insert); 381 | LOGI("client sets pid %d to be hooked\n", pid_to_insert->pid); 382 | g_pid_num++; 383 | lck_rw_unlock_exclusive(g_pidlist_lock); 384 | break; 385 | } 386 | case NOT_TO_HOOK: 387 | { 388 | if (len < sizeof(int)) { 389 | retval = EINVAL; 390 | break; 391 | } 392 | 393 | intval = *(int*)data; 394 | lck_rw_lock_exclusive(g_mode_lock); 395 | g_proxy_hash = intval; 396 | LOGI("proxy's hash has been set to %d", g_proxy_hash); 397 | lck_rw_unlock_exclusive(g_mode_lock); 398 | break; 399 | 400 | } 401 | default: 402 | break; 403 | } 404 | 405 | return retval; 406 | } 407 | 408 | static errno_t proximac_ctl_getopt_cb( 409 | kern_ctl_ref kctlref, 410 | u_int32_t unit, 411 | void *unitinfo, 412 | int opt, 413 | void *data, 414 | size_t *len) 415 | { 416 | errno_t retval = 0; 417 | size_t valsize = lmin(sizeof(int), *len);; 418 | void *buf; 419 | switch (opt) { 420 | case PIDLIST_STATUS: 421 | lck_rw_lock_exclusive(g_pidlist_lock); 422 | LOGI("pid number = %d\n", g_pid_num); 423 | buf = &g_pid_num; 424 | lck_rw_unlock_exclusive(g_pidlist_lock); 425 | break; 426 | case HOOK_PID: 427 | lck_rw_lock_exclusive(g_pidlist_lock); 428 | struct pid *pid_tmp = NULL; 429 | int pidget_checksum = 0; 430 | RB_FOREACH(pid_tmp, pid_tree, &pid_list) { 431 | pidget_checksum += pid_tmp->pid; 432 | } 433 | lck_rw_unlock_exclusive(g_pidlist_lock); 434 | buf = &pidget_checksum; 435 | LOGI("pidget_checksum = %d\n", pidget_checksum); 436 | break; 437 | case PROXIMAC_OFF: 438 | { 439 | int result = 0; 440 | lck_rw_lock_exclusive(g_mode_lock); 441 | g_proximac_mode = PROXIMAC_MODE_OFF; 442 | lck_rw_unlock_exclusive(g_mode_lock); 443 | result = uninstall_proximac_tcp_filter(); 444 | buf = &result; 445 | LOGI("PROXIMAC_OFF@getsockopt cmd received ret = %d", retval); 446 | break; 447 | } 448 | default: 449 | retval = ENOTSUP; 450 | break; 451 | } 452 | 453 | if (retval == 0) { 454 | *len = valsize; 455 | if (data != NULL) 456 | bcopy(buf, data, valsize); 457 | } 458 | 459 | return retval; 460 | } 461 | 462 | #pragma mark TCP filter related functions 463 | typedef struct proximac_cookie { 464 | int pidhash_value; /* pid hash value */ 465 | union { 466 | struct sockaddr_in addr4; /* ipv4 remote addr */ 467 | struct sockaddr_in6 addr6; /* ipv6 remote addr */ 468 | } remote_addr; 469 | int protocol; /* IPv4 or IPv6 */ 470 | int forward_flag; /* Forward Flag */ 471 | int pid; 472 | } proximac_cookie_t; 473 | 474 | const static struct sflt_filter proximac_tcp_filter = { 475 | PROXIMAC_TCP_FILTER_HANDLE, /* sflt_handle */ 476 | SFLT_GLOBAL, /* sf_flags */ 477 | MYBUNDLEID, /* sf_name - cannot be nil else param err results */ 478 | proximac_tcp_unregistered_cb, /* sf_unregistered_func */ 479 | proximac_tcp_attach_cb, /* sf_attach_func - cannot be nil else param err results */ 480 | proximac_tcp_detach_cb, /* sf_detach_func - cannot be nil else param err results */ 481 | proximac_tcp_notify_cb, /* sf_notify_func */ 482 | NULL, /* sf_getpeername_func */ 483 | NULL, /* sf_getsockname_func */ 484 | NULL, /* sf_data_in_func */ 485 | NULL, /* sf_data_out_func */ 486 | NULL, /* sf_connect_in_func */ 487 | proximac_tcp_connect_out_cb, /* sf_connect_out_func */ 488 | NULL, /* sf_bind_func */ 489 | NULL, /* sf_setoption_func */ 490 | NULL, /* sf_getoption_func */ 491 | NULL, /* sf_listen_func */ 492 | NULL /* sf_ioctl_func */ 493 | }; 494 | 495 | /* pid hash function */ 496 | unsigned int pid_hash(char *str) 497 | { 498 | unsigned int h; 499 | unsigned char *p; 500 | #define MULTIPLIER 33 501 | h = 0; 502 | for (p = (unsigned char*)str; *p != '\0'; p++) 503 | h = MULTIPLIER * h + *p; 504 | return h; // or, h % ARRAY_SIZE; 505 | } 506 | 507 | 508 | static void 509 | proximac_tcp_detach_cb(void * cookie, socket_t so) 510 | { 511 | assert(cookie); 512 | // free cookie 513 | _FREE(cookie, M_TEMP); 514 | LOGI("Proximac TCP filter has been detached from a socket"); 515 | } 516 | 517 | static errno_t 518 | proximac_tcp_connect_out_cb( 519 | void * cookie, 520 | socket_t so, 521 | const struct sockaddr * to) 522 | { 523 | proximac_cookie_t * proximac_cookie = (proximac_cookie_t *)cookie; 524 | assert(cookie); 525 | 526 | lck_rw_lock_shared(g_mode_lock); 527 | if (g_proximac_mode == PROXIMAC_MODE_OFF) 528 | { 529 | lck_rw_unlock_shared(g_mode_lock); 530 | return 0; 531 | } 532 | lck_rw_unlock_shared(g_mode_lock); 533 | 534 | // Make sure address family is correct 535 | assert(to->sa_family == AF_INET); 536 | assert(sizeof(struct sockaddr_in) <= to->sa_len); 537 | assert((to->sa_family == AF_INET) || (to->sa_family == AF_INET6)); /* verify that the address is AF_INET/AF_INET6 */ 538 | assert (sizeof(proximac_cookie->remote_addr.addr4) >= to->sa_len); /* verify that there is enough room to store data */ 539 | 540 | /* save the remote address in the tli_remote field */ 541 | bcopy(to, &(proximac_cookie->remote_addr.addr4), to->sa_len); 542 | struct sockaddr_in *remote_addr; 543 | remote_addr = (struct sockaddr_in*)to; 544 | proximac_cookie->remote_addr.addr4.sin_port = ntohs(proximac_cookie->remote_addr.addr4.sin_port); 545 | 546 | /* see if this is a local stream, then we just ignore */ 547 | int local_tcp_flag = 0; 548 | if (remote_addr->sin_addr.s_addr == LOCALHOST) 549 | return 0; 550 | 551 | /* do not forward any traffic from proximac-cli or SOCKS5 proxy. Otherwise, traffic will be trapped in a loop */ 552 | if (proximac_cookie->pid == 0 || proximac_cookie->pidhash_value == pid_hash(MYAPPNAME) || proximac_cookie->pidhash_value == g_proxy_hash) { 553 | LOGI("Traffic from this process is not allowed to be forwarded. PID = %d", proximac_cookie->pid); 554 | return 0; 555 | } 556 | 557 | /* see if we're in forward all mode which is like VPN */ 558 | if (g_proximac_mode == PROXIMAC_MODE_ALL) { 559 | if (proximac_cookie->pid != 0 && local_tcp_flag == 0) { 560 | proximac_cookie->forward_flag = 1; 561 | LOGI("A process is now hooked"); 562 | remote_addr->sin_port = htons(8558); 563 | remote_addr->sin_addr.s_addr = LOCALHOST; 564 | LOGI("forward flag has been set to 1"); 565 | } 566 | return 0; 567 | } 568 | 569 | struct pid find_pid; 570 | find_pid.pid = proximac_cookie->pidhash_value; 571 | lck_rw_lock_exclusive(g_pidlist_lock); 572 | struct pid *exist = RB_FIND(pid_tree, &pid_list, &find_pid); 573 | LOGI("after RB_FIND pid = %d pid_num %d\n", find_pid.pid, g_pid_num); 574 | lck_rw_unlock_exclusive(g_pidlist_lock); 575 | 576 | if (exist != NULL) { 577 | proximac_cookie->forward_flag = 1; 578 | LOGI("A process is now hooked"); 579 | remote_addr->sin_port = htons(8558); 580 | remote_addr->sin_addr.s_addr = LOCALHOST; 581 | } 582 | 583 | return 0; 584 | } 585 | 586 | static errno_t 587 | proximac_tcp_attach_cb(void ** cookie, socket_t so) 588 | { 589 | // Check proximac mode 590 | lck_rw_lock_shared(g_mode_lock); 591 | if (g_proximac_mode == PROXIMAC_MODE_OFF) 592 | { 593 | lck_rw_unlock_shared(g_mode_lock); 594 | return -1; 595 | } 596 | lck_rw_unlock_shared(g_mode_lock); 597 | 598 | // Allocate cookie for this socket 599 | *cookie = _MALLOC(sizeof(proximac_cookie_t), M_TEMP, M_WAITOK | M_ZERO); 600 | if (NULL == *cookie) 601 | { 602 | LOGI("_MALLOC() error"); 603 | return ENOMEM; 604 | } 605 | 606 | proximac_cookie_t * proximac_cookie = (proximac_cookie_t *)(*cookie); 607 | proximac_cookie->forward_flag = 0; 608 | 609 | char proc_name[64] = {0}; 610 | proc_selfname(proc_name, 63); 611 | proximac_cookie->pid = proc_selfpid(); 612 | proximac_cookie->pidhash_value = pid_hash(proc_name); 613 | LOGI("pid hash value = %d proc_name = %s\n", proximac_cookie->pidhash_value, proc_name); 614 | LOGI("Proximac TCP filter has been attached to a socket"); 615 | return 0; 616 | } 617 | 618 | static void 619 | proximac_tcp_notify_cb(void *cookie, socket_t so, sflt_event_t event, void *param) { 620 | proximac_cookie_t * proximac_cookie = (proximac_cookie_t *)cookie; 621 | switch (event) { 622 | case sock_evt_connected: 623 | { 624 | unsigned char addrString[256]; 625 | void *remoteAddr; 626 | in_port_t port; 627 | remoteAddr = &(proximac_cookie->remote_addr.addr4.sin_addr); 628 | port = proximac_cookie->remote_addr.addr4.sin_port; 629 | inet_ntop(AF_INET, remoteAddr, (char*) addrString, sizeof(addrString)); 630 | 631 | // added prepend proximac_hdr for proximac 632 | 633 | if (proximac_cookie->forward_flag == 1) { 634 | LOGI("notify_cb -- do hook operations to pid"); 635 | mbuf_t proximac_hdr_data = NULL; 636 | mbuf_t proximac_hdr_control = NULL; 637 | errno_t retval; 638 | 639 | char addrlen = strlen((char*) addrString); 640 | LOGI("getsockopt addrString %s\n", addrString); 641 | int hdr_len = 1 + addrlen + sizeof(port); 642 | 643 | char* proximac_hdr = _MALLOC(hdr_len, M_TEMP, M_WAITOK| M_ZERO); 644 | proximac_hdr[0] = addrlen; 645 | memcpy(proximac_hdr + 1, addrString, addrlen); 646 | memcpy(proximac_hdr + 1 + addrlen, &port, sizeof(port)); 647 | 648 | // Allocate a mbuf chain for adding proximac header. 649 | // Note: default type and flags are fine; don't do further modification. 650 | retval = mbuf_allocpacket(MBUF_WAITOK, hdr_len, 0, &proximac_hdr_data); 651 | retval = mbuf_copyback(proximac_hdr_data, 0, hdr_len, proximac_hdr, MBUF_WAITOK); 652 | _FREE(proximac_hdr, M_TEMP); 653 | retval = sock_inject_data_out(so, NULL, proximac_hdr_data, proximac_hdr_control, 0); 654 | } 655 | break; 656 | } 657 | default: 658 | break; 659 | } 660 | } 661 | 662 | static void 663 | proximac_tcp_unregistered_cb(sflt_handle handle) 664 | { 665 | assert(PROXIMAC_TCP_FILTER_HANDLE == handle); 666 | g_proximac_tcp_unreg_completed = true; 667 | g_proximac_tcp_filter_registered = false; 668 | LOGI("Proximac TCP filter has been unregistered."); 669 | } 670 | 671 | static errno_t 672 | install_proximac_tcp_filter() { 673 | errno_t retval = 0; 674 | if (g_proximac_tcp_filter_registered) 675 | { 676 | LOGI("Proximac TCP filter is already installed."); 677 | return 0; 678 | } 679 | 680 | if (g_proximac_tcp_unreg_started && !g_proximac_tcp_unreg_completed) 681 | { 682 | LOGI("Proximac TCP filter is being uninstalled, try again!"); 683 | return EAGAIN; 684 | } 685 | 686 | if (!g_proximac_tcp_filter_registered) 687 | { 688 | // register the filter with PF_INET domain, SOCK_STREAM type, TCP protocol 689 | retval = sflt_register(&proximac_tcp_filter, PF_INET, SOCK_STREAM, IPPROTO_TCP); 690 | if (retval == 0) 691 | { 692 | LOGI("Proximac TCP filter has been registered"); 693 | g_proximac_tcp_filter_registered = true; 694 | g_proximac_tcp_unreg_started = false; 695 | g_proximac_tcp_unreg_completed = false; 696 | } 697 | else 698 | { 699 | LOGI("sflt_register failed errorno = %d", retval); 700 | return retval; 701 | } 702 | } 703 | return retval; 704 | } 705 | 706 | static errno_t 707 | uninstall_proximac_tcp_filter(void) 708 | { 709 | errno_t retval; 710 | 711 | if (!g_proximac_tcp_filter_registered) 712 | { 713 | LOGI("Proximac TCP filter has not been installed."); 714 | return 0; 715 | } 716 | 717 | if (!g_proximac_tcp_unreg_started) 718 | { 719 | // start the unregistration process 720 | retval = sflt_unregister(PROXIMAC_TCP_FILTER_HANDLE); 721 | if (retval) 722 | { 723 | LOGI("sflt_unregister(PROXIMAC_TCP_FILTER_HANDLE) error errorno = %d", retval); 724 | return retval; 725 | } 726 | else 727 | { 728 | // Indicate that we've started the unreg process. 729 | g_proximac_tcp_unreg_started = true; 730 | } 731 | } 732 | 733 | if (!g_proximac_tcp_unreg_completed) 734 | { 735 | LOGI("Proximac TCP filter is being unregistered."); 736 | return EINPROGRESS; 737 | } 738 | 739 | return 0; 740 | } 741 | 742 | #pragma mark Kernel-related functions 743 | kern_return_t proximac_start(kmod_info_t * ki, void *data) 744 | { 745 | errno_t retval = 0; 746 | retval = init_locks(); 747 | 748 | // initialize pid freelist and pidlist for proximac 749 | SLIST_INIT(&pid_freelist); 750 | RB_INIT(&pid_list); 751 | 752 | if (retval) { 753 | LOGI("locks init failed at module_start errorno = %d", retval); 754 | return KERN_RESOURCE_SHORTAGE; 755 | } 756 | 757 | retval = install_proximac_controller(); 758 | if (retval) { 759 | LOGI("controller install error"); 760 | goto fail; 761 | } 762 | return KERN_SUCCESS; 763 | 764 | fail: 765 | release_locks(); 766 | return KERN_FAILURE; 767 | } 768 | 769 | kern_return_t proximac_stop(kmod_info_t *ki, void *data) 770 | { 771 | errno_t retval; 772 | lck_rw_lock_exclusive(g_mode_lock); 773 | g_proximac_mode = PROXIMAC_MODE_OFF; 774 | lck_rw_unlock_exclusive(g_mode_lock); 775 | 776 | retval = uninstall_proximac_tcp_filter(); 777 | if (retval) { 778 | LOGI("uninstall Proximac TCP filters error errorno = %d", retval); 779 | return KERN_FAILURE; 780 | } 781 | 782 | retval = uninstall_proximac_controller(); 783 | if (retval) { 784 | LOGI("uninstall Proximac controller error errorno = %d", retval); 785 | return KERN_FAILURE; 786 | } 787 | 788 | 789 | release_locks(); 790 | LOGI("Proximac kext is now removed"); 791 | return KERN_SUCCESS; 792 | } 793 | -------------------------------------------------------------------------------- /proximac/tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2010 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | 29 | /* $NetBSD: tree.h,v 1.13 2006/08/27 22:32:38 christos Exp $ */ 30 | /* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ 31 | /* 32 | * Copyright 2002 Niels Provos 33 | * All rights reserved. 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | */ 55 | 56 | #ifndef _LIBKERN_TREE_H_ 57 | #define _LIBKERN_TREE_H_ 58 | 59 | /* 60 | * This file defines data structures for different types of trees: 61 | * splay trees and red-black trees. 62 | * 63 | * A splay tree is a self-organizing data structure. Every operation 64 | * on the tree causes a splay to happen. The splay moves the requested 65 | * node to the root of the tree and partly rebalances it. 66 | * 67 | * This has the benefit that request locality causes faster lookups as 68 | * the requested nodes move to the top of the tree. On the other hand, 69 | * every lookup causes memory writes. 70 | * 71 | * The Balance Theorem bounds the total access time for m operations 72 | * and n inserts on an initially empty tree as O((m + n)lg n). The 73 | * amortized cost for a sequence of m accesses to a splay tree is O(lg n); 74 | * 75 | * A red-black tree is a binary search tree with the node color as an 76 | * extra attribute. It fulfills a set of conditions: 77 | * - every search path from the root to a leaf consists of the 78 | * same number of black nodes, 79 | * - each red node (except for the root) has a black parent, 80 | * - each leaf node is black. 81 | * 82 | * Every operation on a red-black tree is bounded as O(lg n). 83 | * The maximum height of a red-black tree is 2lg (n+1). 84 | */ 85 | 86 | #define SPLAY_HEAD(name, type) \ 87 | struct name { \ 88 | struct type *sph_root; /* root of the tree */ \ 89 | } 90 | 91 | #define SPLAY_INITIALIZER(root) \ 92 | { NULL } 93 | 94 | #define SPLAY_INIT(root) do { \ 95 | (root)->sph_root = NULL; \ 96 | } while (/*CONSTCOND*/ 0) 97 | 98 | #define SPLAY_ENTRY(type) \ 99 | struct { \ 100 | struct type *spe_left; /* left element */ \ 101 | struct type *spe_right; /* right element */ \ 102 | } 103 | 104 | #define SPLAY_LEFT(elm, field) (elm)->field.spe_left 105 | #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right 106 | #define SPLAY_ROOT(head) (head)->sph_root 107 | #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) 108 | 109 | /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ 110 | #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ 111 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ 112 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 113 | (head)->sph_root = tmp; \ 114 | } while (/*CONSTCOND*/ 0) 115 | 116 | #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ 117 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ 118 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 119 | (head)->sph_root = tmp; \ 120 | } while (/*CONSTCOND*/ 0) 121 | 122 | #define SPLAY_LINKLEFT(head, tmp, field) do { \ 123 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 124 | tmp = (head)->sph_root; \ 125 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ 126 | } while (/*CONSTCOND*/ 0) 127 | 128 | #define SPLAY_LINKRIGHT(head, tmp, field) do { \ 129 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 130 | tmp = (head)->sph_root; \ 131 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ 132 | } while (/*CONSTCOND*/ 0) 133 | 134 | #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ 135 | SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ 136 | SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ 137 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ 138 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ 139 | } while (/*CONSTCOND*/ 0) 140 | 141 | /* Generates prototypes and inline functions */ 142 | 143 | #define SPLAY_PROTOTYPE(name, type, field, cmp) \ 144 | void name##_SPLAY(struct name *, struct type *); \ 145 | void name##_SPLAY_MINMAX(struct name *, int); \ 146 | struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ 147 | struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ 148 | \ 149 | /* Finds the node with the same key as elm */ \ 150 | static __inline struct type * \ 151 | name##_SPLAY_FIND(struct name *head, struct type *elm) \ 152 | { \ 153 | if (SPLAY_EMPTY(head)) \ 154 | return(NULL); \ 155 | name##_SPLAY(head, elm); \ 156 | if ((cmp)(elm, (head)->sph_root) == 0) \ 157 | return (head->sph_root); \ 158 | return (NULL); \ 159 | } \ 160 | \ 161 | static __inline struct type * \ 162 | name##_SPLAY_NEXT(struct name *head, struct type *elm) \ 163 | { \ 164 | name##_SPLAY(head, elm); \ 165 | if (SPLAY_RIGHT(elm, field) != NULL) { \ 166 | elm = SPLAY_RIGHT(elm, field); \ 167 | while (SPLAY_LEFT(elm, field) != NULL) { \ 168 | elm = SPLAY_LEFT(elm, field); \ 169 | } \ 170 | } else \ 171 | elm = NULL; \ 172 | return (elm); \ 173 | } \ 174 | \ 175 | static __inline struct type * \ 176 | name##_SPLAY_MIN_MAX(struct name *head, int val) \ 177 | { \ 178 | name##_SPLAY_MINMAX(head, val); \ 179 | return (SPLAY_ROOT(head)); \ 180 | } 181 | 182 | /* Main splay operation. 183 | * Moves node close to the key of elm to top 184 | */ 185 | #define SPLAY_GENERATE(name, type, field, cmp) \ 186 | struct type * \ 187 | name##_SPLAY_INSERT(struct name *head, struct type *elm) \ 188 | { \ 189 | if (SPLAY_EMPTY(head)) { \ 190 | SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ 191 | } else { \ 192 | int __comp; \ 193 | name##_SPLAY(head, elm); \ 194 | __comp = (cmp)(elm, (head)->sph_root); \ 195 | if(__comp < 0) { \ 196 | SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ 197 | SPLAY_RIGHT(elm, field) = (head)->sph_root; \ 198 | SPLAY_LEFT((head)->sph_root, field) = NULL; \ 199 | } else if (__comp > 0) { \ 200 | SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ 201 | SPLAY_LEFT(elm, field) = (head)->sph_root; \ 202 | SPLAY_RIGHT((head)->sph_root, field) = NULL; \ 203 | } else \ 204 | return ((head)->sph_root); \ 205 | } \ 206 | (head)->sph_root = (elm); \ 207 | return (NULL); \ 208 | } \ 209 | \ 210 | struct type * \ 211 | name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ 212 | { \ 213 | struct type *__tmp; \ 214 | if (SPLAY_EMPTY(head)) \ 215 | return (NULL); \ 216 | name##_SPLAY(head, elm); \ 217 | if ((cmp)(elm, (head)->sph_root) == 0) { \ 218 | if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ 219 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ 220 | } else { \ 221 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 222 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ 223 | name##_SPLAY(head, elm); \ 224 | SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ 225 | } \ 226 | return (elm); \ 227 | } \ 228 | return (NULL); \ 229 | } \ 230 | \ 231 | void \ 232 | name##_SPLAY(struct name *head, struct type *elm) \ 233 | { \ 234 | struct type __node, *__left, *__right, *__tmp; \ 235 | int __comp; \ 236 | \ 237 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 238 | __left = __right = &__node; \ 239 | \ 240 | while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ 241 | if (__comp < 0) { \ 242 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ 243 | if (__tmp == NULL) \ 244 | break; \ 245 | if ((cmp)(elm, __tmp) < 0){ \ 246 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 247 | if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 248 | break; \ 249 | } \ 250 | SPLAY_LINKLEFT(head, __right, field); \ 251 | } else if (__comp > 0) { \ 252 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 253 | if (__tmp == NULL) \ 254 | break; \ 255 | if ((cmp)(elm, __tmp) > 0){ \ 256 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ 257 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 258 | break; \ 259 | } \ 260 | SPLAY_LINKRIGHT(head, __left, field); \ 261 | } \ 262 | } \ 263 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 264 | } \ 265 | \ 266 | /* Splay with either the minimum or the maximum element \ 267 | * Used to find minimum or maximum element in tree. \ 268 | */ \ 269 | void name##_SPLAY_MINMAX(struct name *head, int __comp) \ 270 | { \ 271 | struct type __node, *__left, *__right, *__tmp; \ 272 | \ 273 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 274 | __left = __right = &__node; \ 275 | \ 276 | while (1) { \ 277 | if (__comp < 0) { \ 278 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ 279 | if (__tmp == NULL) \ 280 | break; \ 281 | if (__comp < 0){ \ 282 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 283 | if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 284 | break; \ 285 | } \ 286 | SPLAY_LINKLEFT(head, __right, field); \ 287 | } else if (__comp > 0) { \ 288 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 289 | if (__tmp == NULL) \ 290 | break; \ 291 | if (__comp > 0) { \ 292 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ 293 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 294 | break; \ 295 | } \ 296 | SPLAY_LINKRIGHT(head, __left, field); \ 297 | } \ 298 | } \ 299 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 300 | } 301 | 302 | #define SPLAY_NEGINF -1 303 | #define SPLAY_INF 1 304 | 305 | #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) 306 | #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) 307 | #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) 308 | #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) 309 | #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ 310 | : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) 311 | #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ 312 | : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) 313 | 314 | #define SPLAY_FOREACH(x, name, head) \ 315 | for ((x) = SPLAY_MIN(name, head); \ 316 | (x) != NULL; \ 317 | (x) = SPLAY_NEXT(name, head, x)) 318 | 319 | /* Macros that define a red-black tree */ 320 | #define RB_HEAD(name, type) \ 321 | struct name { \ 322 | struct type *rbh_root; /* root of the tree */ \ 323 | } 324 | 325 | #define RB_INITIALIZER(root) \ 326 | { NULL } 327 | 328 | #define RB_INIT(root) do { \ 329 | (root)->rbh_root = NULL; \ 330 | } while (/*CONSTCOND*/ 0) 331 | 332 | #define RB_BLACK 0 333 | #define RB_RED 1 334 | #define RB_PLACEHOLDER NULL 335 | #define RB_ENTRY(type) \ 336 | struct { \ 337 | struct type *rbe_parent; /* parent element */ \ 338 | struct type *rbe_left; /* left element */ \ 339 | struct type *rbe_right; /* right element */ \ 340 | } 341 | 342 | #define RB_COLOR_MASK (uintptr_t)0x1 343 | #define RB_LEFT(elm, field) (elm)->field.rbe_left 344 | #define RB_RIGHT(elm, field) (elm)->field.rbe_right 345 | #define _RB_PARENT(elm, field) (elm)->field.rbe_parent 346 | #define RB_ROOT(head) (head)->rbh_root 347 | #define RB_EMPTY(head) (RB_ROOT(head) == NULL) 348 | 349 | #define RB_SET(name, elm, parent, field) do { \ 350 | name##_RB_SETPARENT(elm, parent); \ 351 | RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ 352 | name##_RB_SETCOLOR(elm, RB_RED); \ 353 | } while (/*CONSTCOND*/ 0) 354 | 355 | #define RB_SET_BLACKRED(name, black, red, field) do { \ 356 | name##_RB_SETCOLOR(black, RB_BLACK); \ 357 | name##_RB_SETCOLOR(red, RB_RED); \ 358 | } while (/*CONSTCOND*/ 0) 359 | 360 | #ifndef RB_AUGMENT 361 | #define RB_AUGMENT(x) (void)(x) 362 | #endif 363 | 364 | #define RB_ROTATE_LEFT(name, head, elm, tmp, field) do { \ 365 | (tmp) = RB_RIGHT(elm, field); \ 366 | if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ 367 | name##_RB_SETPARENT(RB_LEFT(tmp, field),(elm)); \ 368 | } \ 369 | RB_AUGMENT(elm); \ 370 | if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \ 371 | if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \ 372 | RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \ 373 | else \ 374 | RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \ 375 | } else \ 376 | (head)->rbh_root = (tmp); \ 377 | RB_LEFT(tmp, field) = (elm); \ 378 | name##_RB_SETPARENT(elm, (tmp)); \ 379 | RB_AUGMENT(tmp); \ 380 | if ((name##_RB_GETPARENT(tmp))) \ 381 | RB_AUGMENT(name##_RB_GETPARENT(tmp)); \ 382 | } while (/*CONSTCOND*/ 0) 383 | 384 | #define RB_ROTATE_RIGHT(name, head, elm, tmp, field) do { \ 385 | (tmp) = RB_LEFT(elm, field); \ 386 | if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ 387 | name##_RB_SETPARENT(RB_RIGHT(tmp, field), (elm)); \ 388 | } \ 389 | RB_AUGMENT(elm); \ 390 | if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \ 391 | if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \ 392 | RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \ 393 | else \ 394 | RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \ 395 | } else \ 396 | (head)->rbh_root = (tmp); \ 397 | RB_RIGHT(tmp, field) = (elm); \ 398 | name##_RB_SETPARENT(elm, tmp); \ 399 | RB_AUGMENT(tmp); \ 400 | if ((name##_RB_GETPARENT(tmp))) \ 401 | RB_AUGMENT(name##_RB_GETPARENT(tmp)); \ 402 | } while (/*CONSTCOND*/ 0) 403 | 404 | /* Generates prototypes and inline functions */ 405 | #define RB_PROTOTYPE(name, type, field, cmp) \ 406 | void name##_RB_INSERT_COLOR(struct name *, struct type *); \ 407 | void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ 408 | struct type *name##_RB_REMOVE(struct name *, struct type *); \ 409 | struct type *name##_RB_INSERT(struct name *, struct type *); \ 410 | struct type *name##_RB_FIND(struct name *, struct type *); \ 411 | struct type *name##_RB_NEXT(struct type *); \ 412 | struct type *name##_RB_MINMAX(struct name *, int); \ 413 | struct type *name##_RB_GETPARENT(struct type*); \ 414 | struct type *name##_RB_SETPARENT(struct type*, struct type*); \ 415 | int name##_RB_GETCOLOR(struct type*); \ 416 | void name##_RB_SETCOLOR(struct type*,int); 417 | 418 | /* Generates prototypes (with storage class) and inline functions */ 419 | #define RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \ 420 | _sc_ void name##_RB_INSERT_COLOR(struct name *, struct type *); \ 421 | _sc_ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *); \ 422 | _sc_ struct type *name##_RB_REMOVE(struct name *, struct type *); \ 423 | _sc_ struct type *name##_RB_INSERT(struct name *, struct type *); \ 424 | _sc_ struct type *name##_RB_FIND(struct name *, struct type *); \ 425 | _sc_ struct type *name##_RB_NEXT(struct type *); \ 426 | _sc_ struct type *name##_RB_MINMAX(struct name *, int); \ 427 | _sc_ struct type *name##_RB_GETPARENT(struct type*); \ 428 | _sc_ struct type *name##_RB_SETPARENT(struct type*, struct type*); \ 429 | _sc_ int name##_RB_GETCOLOR(struct type*); \ 430 | _sc_ void name##_RB_SETCOLOR(struct type*,int); 431 | 432 | 433 | /* Main rb operation. 434 | * Moves node close to the key of elm to top 435 | */ 436 | #define RB_GENERATE(name, type, field, cmp) \ 437 | struct type *name##_RB_GETPARENT(struct type *elm) { \ 438 | struct type *parent = _RB_PARENT(elm, field); \ 439 | if( parent != NULL) { \ 440 | parent = (struct type*)((uintptr_t)parent & ~RB_COLOR_MASK);\ 441 | return( (struct type*) ( (parent == (struct type*) RB_PLACEHOLDER) ? NULL: parent));\ 442 | } \ 443 | return((struct type*)NULL); \ 444 | } \ 445 | int name##_RB_GETCOLOR(struct type *elm) { \ 446 | int color = 0; \ 447 | color = (int)((uintptr_t)_RB_PARENT(elm,field) & RB_COLOR_MASK);\ 448 | return(color); \ 449 | } \ 450 | void name##_RB_SETCOLOR(struct type *elm,int color) { \ 451 | struct type *parent = name##_RB_GETPARENT(elm); \ 452 | if(parent == (struct type*)NULL) \ 453 | parent = (struct type*) RB_PLACEHOLDER; \ 454 | _RB_PARENT(elm, field) = (struct type*)((uintptr_t)parent | (unsigned int)color);\ 455 | } \ 456 | struct type *name##_RB_SETPARENT(struct type *elm, struct type *parent) { \ 457 | int color = name##_RB_GETCOLOR(elm); \ 458 | _RB_PARENT(elm, field) = parent; \ 459 | if(color) name##_RB_SETCOLOR(elm, color); \ 460 | return(name##_RB_GETPARENT(elm)); \ 461 | } \ 462 | \ 463 | void \ 464 | name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ 465 | { \ 466 | struct type *parent, *gparent, *tmp; \ 467 | while ((parent = name##_RB_GETPARENT(elm)) != NULL && \ 468 | name##_RB_GETCOLOR(parent) == RB_RED) { \ 469 | gparent = name##_RB_GETPARENT(parent); \ 470 | if (parent == RB_LEFT(gparent, field)) { \ 471 | tmp = RB_RIGHT(gparent, field); \ 472 | if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \ 473 | name##_RB_SETCOLOR(tmp, RB_BLACK); \ 474 | RB_SET_BLACKRED(name, parent, gparent, field);\ 475 | elm = gparent; \ 476 | continue; \ 477 | } \ 478 | if (RB_RIGHT(parent, field) == elm) { \ 479 | RB_ROTATE_LEFT(name, head, parent, tmp, field);\ 480 | tmp = parent; \ 481 | parent = elm; \ 482 | elm = tmp; \ 483 | } \ 484 | RB_SET_BLACKRED(name, parent, gparent, field); \ 485 | RB_ROTATE_RIGHT(name,head, gparent, tmp, field); \ 486 | } else { \ 487 | tmp = RB_LEFT(gparent, field); \ 488 | if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \ 489 | name##_RB_SETCOLOR(tmp, RB_BLACK); \ 490 | RB_SET_BLACKRED(name, parent, gparent, field);\ 491 | elm = gparent; \ 492 | continue; \ 493 | } \ 494 | if (RB_LEFT(parent, field) == elm) { \ 495 | RB_ROTATE_RIGHT(name, head, parent, tmp, field);\ 496 | tmp = parent; \ 497 | parent = elm; \ 498 | elm = tmp; \ 499 | } \ 500 | RB_SET_BLACKRED(name, parent, gparent, field); \ 501 | RB_ROTATE_LEFT(name, head, gparent, tmp, field); \ 502 | } \ 503 | } \ 504 | name##_RB_SETCOLOR(head->rbh_root, RB_BLACK); \ 505 | } \ 506 | \ 507 | void \ 508 | name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ 509 | { \ 510 | struct type *tmp; \ 511 | while ((elm == NULL || name##_RB_GETCOLOR(elm) == RB_BLACK) && \ 512 | elm != RB_ROOT(head)) { \ 513 | if (RB_LEFT(parent, field) == elm) { \ 514 | tmp = RB_RIGHT(parent, field); \ 515 | if (name##_RB_GETCOLOR(tmp) == RB_RED) { \ 516 | RB_SET_BLACKRED(name, tmp, parent, field); \ 517 | RB_ROTATE_LEFT(name, head, parent, tmp, field);\ 518 | tmp = RB_RIGHT(parent, field); \ 519 | } \ 520 | if ((RB_LEFT(tmp, field) == NULL || \ 521 | name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\ 522 | (RB_RIGHT(tmp, field) == NULL || \ 523 | name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\ 524 | name##_RB_SETCOLOR(tmp, RB_RED); \ 525 | elm = parent; \ 526 | parent = name##_RB_GETPARENT(elm); \ 527 | } else { \ 528 | if (RB_RIGHT(tmp, field) == NULL || \ 529 | name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK) {\ 530 | struct type *oleft; \ 531 | if ((oleft = RB_LEFT(tmp, field)) \ 532 | != NULL) \ 533 | name##_RB_SETCOLOR(oleft, RB_BLACK);\ 534 | name##_RB_SETCOLOR(tmp, RB_RED); \ 535 | RB_ROTATE_RIGHT(name, head, tmp, oleft, field);\ 536 | tmp = RB_RIGHT(parent, field); \ 537 | } \ 538 | name##_RB_SETCOLOR(tmp, (name##_RB_GETCOLOR(parent)));\ 539 | name##_RB_SETCOLOR(parent, RB_BLACK); \ 540 | if (RB_RIGHT(tmp, field)) \ 541 | name##_RB_SETCOLOR(RB_RIGHT(tmp, field),RB_BLACK);\ 542 | RB_ROTATE_LEFT(name, head, parent, tmp, field);\ 543 | elm = RB_ROOT(head); \ 544 | break; \ 545 | } \ 546 | } else { \ 547 | tmp = RB_LEFT(parent, field); \ 548 | if (name##_RB_GETCOLOR(tmp) == RB_RED) { \ 549 | RB_SET_BLACKRED(name, tmp, parent, field); \ 550 | RB_ROTATE_RIGHT(name, head, parent, tmp, field);\ 551 | tmp = RB_LEFT(parent, field); \ 552 | } \ 553 | if ((RB_LEFT(tmp, field) == NULL || \ 554 | name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\ 555 | (RB_RIGHT(tmp, field) == NULL || \ 556 | name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\ 557 | name##_RB_SETCOLOR(tmp, RB_RED); \ 558 | elm = parent; \ 559 | parent = name##_RB_GETPARENT(elm); \ 560 | } else { \ 561 | if (RB_LEFT(tmp, field) == NULL || \ 562 | name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) {\ 563 | struct type *oright; \ 564 | if ((oright = RB_RIGHT(tmp, field)) \ 565 | != NULL) \ 566 | name##_RB_SETCOLOR(oright, RB_BLACK);\ 567 | name##_RB_SETCOLOR(tmp, RB_RED); \ 568 | RB_ROTATE_LEFT(name, head, tmp, oright, field);\ 569 | tmp = RB_LEFT(parent, field); \ 570 | } \ 571 | name##_RB_SETCOLOR(tmp,(name##_RB_GETCOLOR(parent)));\ 572 | name##_RB_SETCOLOR(parent, RB_BLACK); \ 573 | if (RB_LEFT(tmp, field)) \ 574 | name##_RB_SETCOLOR(RB_LEFT(tmp, field), RB_BLACK);\ 575 | RB_ROTATE_RIGHT(name, head, parent, tmp, field);\ 576 | elm = RB_ROOT(head); \ 577 | break; \ 578 | } \ 579 | } \ 580 | } \ 581 | if (elm) \ 582 | name##_RB_SETCOLOR(elm, RB_BLACK); \ 583 | } \ 584 | \ 585 | struct type * \ 586 | name##_RB_REMOVE(struct name *head, struct type *elm) \ 587 | { \ 588 | struct type *child, *parent, *old = elm; \ 589 | int color; \ 590 | if (RB_LEFT(elm, field) == NULL) \ 591 | child = RB_RIGHT(elm, field); \ 592 | else if (RB_RIGHT(elm, field) == NULL) \ 593 | child = RB_LEFT(elm, field); \ 594 | else { \ 595 | struct type *left; \ 596 | elm = RB_RIGHT(elm, field); \ 597 | while ((left = RB_LEFT(elm, field)) != NULL) \ 598 | elm = left; \ 599 | child = RB_RIGHT(elm, field); \ 600 | parent = name##_RB_GETPARENT(elm); \ 601 | color = name##_RB_GETCOLOR(elm); \ 602 | if (child) \ 603 | name##_RB_SETPARENT(child, parent); \ 604 | if (parent) { \ 605 | if (RB_LEFT(parent, field) == elm) \ 606 | RB_LEFT(parent, field) = child; \ 607 | else \ 608 | RB_RIGHT(parent, field) = child; \ 609 | RB_AUGMENT(parent); \ 610 | } else \ 611 | RB_ROOT(head) = child; \ 612 | if (name##_RB_GETPARENT(elm) == old) \ 613 | parent = elm; \ 614 | (elm)->field = (old)->field; \ 615 | if (name##_RB_GETPARENT(old)) { \ 616 | if (RB_LEFT(name##_RB_GETPARENT(old), field) == old)\ 617 | RB_LEFT(name##_RB_GETPARENT(old), field) = elm;\ 618 | else \ 619 | RB_RIGHT(name##_RB_GETPARENT(old), field) = elm;\ 620 | RB_AUGMENT(name##_RB_GETPARENT(old)); \ 621 | } else \ 622 | RB_ROOT(head) = elm; \ 623 | name##_RB_SETPARENT(RB_LEFT(old, field), elm); \ 624 | if (RB_RIGHT(old, field)) \ 625 | name##_RB_SETPARENT(RB_RIGHT(old, field), elm); \ 626 | if (parent) { \ 627 | left = parent; \ 628 | do { \ 629 | RB_AUGMENT(left); \ 630 | } while ((left = name##_RB_GETPARENT(left)) != NULL); \ 631 | } \ 632 | goto color; \ 633 | } \ 634 | parent = name##_RB_GETPARENT(elm); \ 635 | color = name##_RB_GETCOLOR(elm); \ 636 | if (child) \ 637 | name##_RB_SETPARENT(child, parent); \ 638 | if (parent) { \ 639 | if (RB_LEFT(parent, field) == elm) \ 640 | RB_LEFT(parent, field) = child; \ 641 | else \ 642 | RB_RIGHT(parent, field) = child; \ 643 | RB_AUGMENT(parent); \ 644 | } else \ 645 | RB_ROOT(head) = child; \ 646 | color: \ 647 | if (color == RB_BLACK) \ 648 | name##_RB_REMOVE_COLOR(head, parent, child); \ 649 | return (old); \ 650 | } \ 651 | \ 652 | /* Inserts a node into the RB tree */ \ 653 | struct type * \ 654 | name##_RB_INSERT(struct name *head, struct type *elm) \ 655 | { \ 656 | struct type *tmp; \ 657 | struct type *parent = NULL; \ 658 | int comp = 0; \ 659 | tmp = RB_ROOT(head); \ 660 | while (tmp) { \ 661 | parent = tmp; \ 662 | comp = (cmp)(elm, parent); \ 663 | if (comp < 0) \ 664 | tmp = RB_LEFT(tmp, field); \ 665 | else if (comp > 0) \ 666 | tmp = RB_RIGHT(tmp, field); \ 667 | else \ 668 | return (tmp); \ 669 | } \ 670 | RB_SET(name, elm, parent, field); \ 671 | if (parent != NULL) { \ 672 | if (comp < 0) \ 673 | RB_LEFT(parent, field) = elm; \ 674 | else \ 675 | RB_RIGHT(parent, field) = elm; \ 676 | RB_AUGMENT(parent); \ 677 | } else \ 678 | RB_ROOT(head) = elm; \ 679 | name##_RB_INSERT_COLOR(head, elm); \ 680 | return (NULL); \ 681 | } \ 682 | \ 683 | /* Finds the node with the same key as elm */ \ 684 | struct type * \ 685 | name##_RB_FIND(struct name *head, struct type *elm) \ 686 | { \ 687 | struct type *tmp = RB_ROOT(head); \ 688 | int comp; \ 689 | while (tmp) { \ 690 | comp = cmp(elm, tmp); \ 691 | if (comp < 0) \ 692 | tmp = RB_LEFT(tmp, field); \ 693 | else if (comp > 0) \ 694 | tmp = RB_RIGHT(tmp, field); \ 695 | else \ 696 | return (tmp); \ 697 | } \ 698 | return (NULL); \ 699 | } \ 700 | \ 701 | /* ARGSUSED */ \ 702 | struct type * \ 703 | name##_RB_NEXT(struct type *elm) \ 704 | { \ 705 | if (RB_RIGHT(elm, field)) { \ 706 | elm = RB_RIGHT(elm, field); \ 707 | while (RB_LEFT(elm, field)) \ 708 | elm = RB_LEFT(elm, field); \ 709 | } else { \ 710 | if (name##_RB_GETPARENT(elm) && \ 711 | (elm == RB_LEFT(name##_RB_GETPARENT(elm), field))) \ 712 | elm = name##_RB_GETPARENT(elm); \ 713 | else { \ 714 | while (name##_RB_GETPARENT(elm) && \ 715 | (elm == RB_RIGHT(name##_RB_GETPARENT(elm), field)))\ 716 | elm = name##_RB_GETPARENT(elm); \ 717 | elm = name##_RB_GETPARENT(elm); \ 718 | } \ 719 | } \ 720 | return (elm); \ 721 | } \ 722 | \ 723 | struct type * \ 724 | name##_RB_MINMAX(struct name *head, int val) \ 725 | { \ 726 | struct type *tmp = RB_ROOT(head); \ 727 | struct type *parent = NULL; \ 728 | while (tmp) { \ 729 | parent = tmp; \ 730 | if (val < 0) \ 731 | tmp = RB_LEFT(tmp, field); \ 732 | else \ 733 | tmp = RB_RIGHT(tmp, field); \ 734 | } \ 735 | return (parent); \ 736 | } 737 | 738 | 739 | #define RB_PROTOTYPE_PREV(name, type, field, cmp) \ 740 | RB_PROTOTYPE(name, type, field, cmp) \ 741 | struct type *name##_RB_PREV(struct type *); 742 | 743 | 744 | #define RB_PROTOTYPE_SC_PREV(_sc_, name, type, field, cmp) \ 745 | RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \ 746 | _sc_ struct type *name##_RB_PREV(struct type *); 747 | 748 | #define RB_GENERATE_PREV(name, type, field, cmp) \ 749 | RB_GENERATE(name, type, field, cmp) \ 750 | struct type * \ 751 | name##_RB_PREV(struct type *elm) \ 752 | { \ 753 | if (RB_LEFT(elm, field)) { \ 754 | elm = RB_LEFT(elm, field); \ 755 | while (RB_RIGHT(elm, field)) \ 756 | elm = RB_RIGHT(elm, field); \ 757 | } else { \ 758 | if (name##_RB_GETPARENT(elm) && \ 759 | (elm == RB_RIGHT(name##_RB_GETPARENT(elm), field))) \ 760 | elm = name##_RB_GETPARENT(elm); \ 761 | else { \ 762 | while (name##_RB_GETPARENT(elm) && \ 763 | (elm == RB_LEFT(name##_RB_GETPARENT(elm), field)))\ 764 | elm = name##_RB_GETPARENT(elm); \ 765 | elm = name##_RB_GETPARENT(elm); \ 766 | } \ 767 | } \ 768 | return (elm); \ 769 | } \ 770 | 771 | #define RB_NEGINF -1 772 | #define RB_INF 1 773 | 774 | #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) 775 | #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) 776 | #define RB_FIND(name, x, y) name##_RB_FIND(x, y) 777 | #define RB_NEXT(name, x, y) name##_RB_NEXT(y) 778 | #define RB_PREV(name, x, y) name##_RB_PREV(y) 779 | #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) 780 | #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) 781 | 782 | #define RB_FOREACH(x, name, head) \ 783 | for ((x) = RB_MIN(name, head); \ 784 | (x) != NULL; \ 785 | (x) = name##_RB_NEXT(x)) 786 | 787 | #define RB_FOREACH_FROM(x, name, y) \ 788 | for ((x) = (y); \ 789 | ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 790 | (x) = (y)) 791 | 792 | #define RB_FOREACH_REVERSE_FROM(x, name, y) \ 793 | for ((x) = (y); \ 794 | ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ 795 | (x) = (y)) 796 | 797 | #define RB_FOREACH_SAFE(x, name, head, y) \ 798 | for ((x) = RB_MIN(name, head); \ 799 | ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 800 | (x) = (y)) 801 | 802 | #endif /* _LIBKERN_TREE_H_ */ 803 | -------------------------------------------------------------------------------- /proximac-cli/tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2010 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | 29 | /* $NetBSD: tree.h,v 1.13 2006/08/27 22:32:38 christos Exp $ */ 30 | /* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ 31 | /* 32 | * Copyright 2002 Niels Provos 33 | * All rights reserved. 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions 37 | * are met: 38 | * 1. Redistributions of source code must retain the above copyright 39 | * notice, this list of conditions and the following disclaimer. 40 | * 2. Redistributions in binary form must reproduce the above copyright 41 | * notice, this list of conditions and the following disclaimer in the 42 | * documentation and/or other materials provided with the distribution. 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 | */ 55 | 56 | #ifndef _LIBKERN_TREE_H_ 57 | #define _LIBKERN_TREE_H_ 58 | 59 | /* 60 | * This file defines data structures for different types of trees: 61 | * splay trees and red-black trees. 62 | * 63 | * A splay tree is a self-organizing data structure. Every operation 64 | * on the tree causes a splay to happen. The splay moves the requested 65 | * node to the root of the tree and partly rebalances it. 66 | * 67 | * This has the benefit that request locality causes faster lookups as 68 | * the requested nodes move to the top of the tree. On the other hand, 69 | * every lookup causes memory writes. 70 | * 71 | * The Balance Theorem bounds the total access time for m operations 72 | * and n inserts on an initially empty tree as O((m + n)lg n). The 73 | * amortized cost for a sequence of m accesses to a splay tree is O(lg n); 74 | * 75 | * A red-black tree is a binary search tree with the node color as an 76 | * extra attribute. It fulfills a set of conditions: 77 | * - every search path from the root to a leaf consists of the 78 | * same number of black nodes, 79 | * - each red node (except for the root) has a black parent, 80 | * - each leaf node is black. 81 | * 82 | * Every operation on a red-black tree is bounded as O(lg n). 83 | * The maximum height of a red-black tree is 2lg (n+1). 84 | */ 85 | 86 | #define SPLAY_HEAD(name, type) \ 87 | struct name { \ 88 | struct type *sph_root; /* root of the tree */ \ 89 | } 90 | 91 | #define SPLAY_INITIALIZER(root) \ 92 | { NULL } 93 | 94 | #define SPLAY_INIT(root) do { \ 95 | (root)->sph_root = NULL; \ 96 | } while (/*CONSTCOND*/ 0) 97 | 98 | #define SPLAY_ENTRY(type) \ 99 | struct { \ 100 | struct type *spe_left; /* left element */ \ 101 | struct type *spe_right; /* right element */ \ 102 | } 103 | 104 | #define SPLAY_LEFT(elm, field) (elm)->field.spe_left 105 | #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right 106 | #define SPLAY_ROOT(head) (head)->sph_root 107 | #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) 108 | 109 | /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ 110 | #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ 111 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ 112 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 113 | (head)->sph_root = tmp; \ 114 | } while (/*CONSTCOND*/ 0) 115 | 116 | #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ 117 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ 118 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 119 | (head)->sph_root = tmp; \ 120 | } while (/*CONSTCOND*/ 0) 121 | 122 | #define SPLAY_LINKLEFT(head, tmp, field) do { \ 123 | SPLAY_LEFT(tmp, field) = (head)->sph_root; \ 124 | tmp = (head)->sph_root; \ 125 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ 126 | } while (/*CONSTCOND*/ 0) 127 | 128 | #define SPLAY_LINKRIGHT(head, tmp, field) do { \ 129 | SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ 130 | tmp = (head)->sph_root; \ 131 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ 132 | } while (/*CONSTCOND*/ 0) 133 | 134 | #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ 135 | SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ 136 | SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ 137 | SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ 138 | SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ 139 | } while (/*CONSTCOND*/ 0) 140 | 141 | /* Generates prototypes and inline functions */ 142 | 143 | #define SPLAY_PROTOTYPE(name, type, field, cmp) \ 144 | void name##_SPLAY(struct name *, struct type *); \ 145 | void name##_SPLAY_MINMAX(struct name *, int); \ 146 | struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ 147 | struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ 148 | \ 149 | /* Finds the node with the same key as elm */ \ 150 | static __inline struct type * \ 151 | name##_SPLAY_FIND(struct name *head, struct type *elm) \ 152 | { \ 153 | if (SPLAY_EMPTY(head)) \ 154 | return(NULL); \ 155 | name##_SPLAY(head, elm); \ 156 | if ((cmp)(elm, (head)->sph_root) == 0) \ 157 | return (head->sph_root); \ 158 | return (NULL); \ 159 | } \ 160 | \ 161 | static __inline struct type * \ 162 | name##_SPLAY_NEXT(struct name *head, struct type *elm) \ 163 | { \ 164 | name##_SPLAY(head, elm); \ 165 | if (SPLAY_RIGHT(elm, field) != NULL) { \ 166 | elm = SPLAY_RIGHT(elm, field); \ 167 | while (SPLAY_LEFT(elm, field) != NULL) { \ 168 | elm = SPLAY_LEFT(elm, field); \ 169 | } \ 170 | } else \ 171 | elm = NULL; \ 172 | return (elm); \ 173 | } \ 174 | \ 175 | static __inline struct type * \ 176 | name##_SPLAY_MIN_MAX(struct name *head, int val) \ 177 | { \ 178 | name##_SPLAY_MINMAX(head, val); \ 179 | return (SPLAY_ROOT(head)); \ 180 | } 181 | 182 | /* Main splay operation. 183 | * Moves node close to the key of elm to top 184 | */ 185 | #define SPLAY_GENERATE(name, type, field, cmp) \ 186 | struct type * \ 187 | name##_SPLAY_INSERT(struct name *head, struct type *elm) \ 188 | { \ 189 | if (SPLAY_EMPTY(head)) { \ 190 | SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ 191 | } else { \ 192 | int __comp; \ 193 | name##_SPLAY(head, elm); \ 194 | __comp = (cmp)(elm, (head)->sph_root); \ 195 | if(__comp < 0) { \ 196 | SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ 197 | SPLAY_RIGHT(elm, field) = (head)->sph_root; \ 198 | SPLAY_LEFT((head)->sph_root, field) = NULL; \ 199 | } else if (__comp > 0) { \ 200 | SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ 201 | SPLAY_LEFT(elm, field) = (head)->sph_root; \ 202 | SPLAY_RIGHT((head)->sph_root, field) = NULL; \ 203 | } else \ 204 | return ((head)->sph_root); \ 205 | } \ 206 | (head)->sph_root = (elm); \ 207 | return (NULL); \ 208 | } \ 209 | \ 210 | struct type * \ 211 | name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ 212 | { \ 213 | struct type *__tmp; \ 214 | if (SPLAY_EMPTY(head)) \ 215 | return (NULL); \ 216 | name##_SPLAY(head, elm); \ 217 | if ((cmp)(elm, (head)->sph_root) == 0) { \ 218 | if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ 219 | (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ 220 | } else { \ 221 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 222 | (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ 223 | name##_SPLAY(head, elm); \ 224 | SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ 225 | } \ 226 | return (elm); \ 227 | } \ 228 | return (NULL); \ 229 | } \ 230 | \ 231 | void \ 232 | name##_SPLAY(struct name *head, struct type *elm) \ 233 | { \ 234 | struct type __node, *__left, *__right, *__tmp; \ 235 | int __comp; \ 236 | \ 237 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 238 | __left = __right = &__node; \ 239 | \ 240 | while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ 241 | if (__comp < 0) { \ 242 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ 243 | if (__tmp == NULL) \ 244 | break; \ 245 | if ((cmp)(elm, __tmp) < 0){ \ 246 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 247 | if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 248 | break; \ 249 | } \ 250 | SPLAY_LINKLEFT(head, __right, field); \ 251 | } else if (__comp > 0) { \ 252 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 253 | if (__tmp == NULL) \ 254 | break; \ 255 | if ((cmp)(elm, __tmp) > 0){ \ 256 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ 257 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 258 | break; \ 259 | } \ 260 | SPLAY_LINKRIGHT(head, __left, field); \ 261 | } \ 262 | } \ 263 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 264 | } \ 265 | \ 266 | /* Splay with either the minimum or the maximum element \ 267 | * Used to find minimum or maximum element in tree. \ 268 | */ \ 269 | void name##_SPLAY_MINMAX(struct name *head, int __comp) \ 270 | { \ 271 | struct type __node, *__left, *__right, *__tmp; \ 272 | \ 273 | SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ 274 | __left = __right = &__node; \ 275 | \ 276 | while (1) { \ 277 | if (__comp < 0) { \ 278 | __tmp = SPLAY_LEFT((head)->sph_root, field); \ 279 | if (__tmp == NULL) \ 280 | break; \ 281 | if (__comp < 0){ \ 282 | SPLAY_ROTATE_RIGHT(head, __tmp, field); \ 283 | if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ 284 | break; \ 285 | } \ 286 | SPLAY_LINKLEFT(head, __right, field); \ 287 | } else if (__comp > 0) { \ 288 | __tmp = SPLAY_RIGHT((head)->sph_root, field); \ 289 | if (__tmp == NULL) \ 290 | break; \ 291 | if (__comp > 0) { \ 292 | SPLAY_ROTATE_LEFT(head, __tmp, field); \ 293 | if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ 294 | break; \ 295 | } \ 296 | SPLAY_LINKRIGHT(head, __left, field); \ 297 | } \ 298 | } \ 299 | SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ 300 | } 301 | 302 | #define SPLAY_NEGINF -1 303 | #define SPLAY_INF 1 304 | 305 | #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) 306 | #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) 307 | #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) 308 | #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) 309 | #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ 310 | : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) 311 | #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ 312 | : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) 313 | 314 | #define SPLAY_FOREACH(x, name, head) \ 315 | for ((x) = SPLAY_MIN(name, head); \ 316 | (x) != NULL; \ 317 | (x) = SPLAY_NEXT(name, head, x)) 318 | 319 | /* Macros that define a red-black tree */ 320 | #define RB_HEAD(name, type) \ 321 | struct name { \ 322 | struct type *rbh_root; /* root of the tree */ \ 323 | } 324 | 325 | #define RB_INITIALIZER(root) \ 326 | { NULL } 327 | 328 | #define RB_INIT(root) do { \ 329 | (root)->rbh_root = NULL; \ 330 | } while (/*CONSTCOND*/ 0) 331 | 332 | #define RB_BLACK 0 333 | #define RB_RED 1 334 | #define RB_PLACEHOLDER NULL 335 | #define RB_ENTRY(type) \ 336 | struct { \ 337 | struct type *rbe_parent; /* parent element */ \ 338 | struct type *rbe_left; /* left element */ \ 339 | struct type *rbe_right; /* right element */ \ 340 | } 341 | 342 | #define RB_COLOR_MASK (uintptr_t)0x1 343 | #define RB_LEFT(elm, field) (elm)->field.rbe_left 344 | #define RB_RIGHT(elm, field) (elm)->field.rbe_right 345 | #define _RB_PARENT(elm, field) (elm)->field.rbe_parent 346 | #define RB_ROOT(head) (head)->rbh_root 347 | #define RB_EMPTY(head) (RB_ROOT(head) == NULL) 348 | 349 | #define RB_SET(name, elm, parent, field) do { \ 350 | name##_RB_SETPARENT(elm, parent); \ 351 | RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ 352 | name##_RB_SETCOLOR(elm, RB_RED); \ 353 | } while (/*CONSTCOND*/ 0) 354 | 355 | #define RB_SET_BLACKRED(name, black, red, field) do { \ 356 | name##_RB_SETCOLOR(black, RB_BLACK); \ 357 | name##_RB_SETCOLOR(red, RB_RED); \ 358 | } while (/*CONSTCOND*/ 0) 359 | 360 | #ifndef RB_AUGMENT 361 | #define RB_AUGMENT(x) (void)(x) 362 | #endif 363 | 364 | #define RB_ROTATE_LEFT(name, head, elm, tmp, field) do { \ 365 | (tmp) = RB_RIGHT(elm, field); \ 366 | if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ 367 | name##_RB_SETPARENT(RB_LEFT(tmp, field),(elm)); \ 368 | } \ 369 | RB_AUGMENT(elm); \ 370 | if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \ 371 | if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \ 372 | RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \ 373 | else \ 374 | RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \ 375 | } else \ 376 | (head)->rbh_root = (tmp); \ 377 | RB_LEFT(tmp, field) = (elm); \ 378 | name##_RB_SETPARENT(elm, (tmp)); \ 379 | RB_AUGMENT(tmp); \ 380 | if ((name##_RB_GETPARENT(tmp))) \ 381 | RB_AUGMENT(name##_RB_GETPARENT(tmp)); \ 382 | } while (/*CONSTCOND*/ 0) 383 | 384 | #define RB_ROTATE_RIGHT(name, head, elm, tmp, field) do { \ 385 | (tmp) = RB_LEFT(elm, field); \ 386 | if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ 387 | name##_RB_SETPARENT(RB_RIGHT(tmp, field), (elm)); \ 388 | } \ 389 | RB_AUGMENT(elm); \ 390 | if (name##_RB_SETPARENT(tmp, name##_RB_GETPARENT(elm)) != NULL) { \ 391 | if ((elm) == RB_LEFT(name##_RB_GETPARENT(elm), field)) \ 392 | RB_LEFT(name##_RB_GETPARENT(elm), field) = (tmp); \ 393 | else \ 394 | RB_RIGHT(name##_RB_GETPARENT(elm), field) = (tmp); \ 395 | } else \ 396 | (head)->rbh_root = (tmp); \ 397 | RB_RIGHT(tmp, field) = (elm); \ 398 | name##_RB_SETPARENT(elm, tmp); \ 399 | RB_AUGMENT(tmp); \ 400 | if ((name##_RB_GETPARENT(tmp))) \ 401 | RB_AUGMENT(name##_RB_GETPARENT(tmp)); \ 402 | } while (/*CONSTCOND*/ 0) 403 | 404 | /* Generates prototypes and inline functions */ 405 | #define RB_PROTOTYPE(name, type, field, cmp) \ 406 | void name##_RB_INSERT_COLOR(struct name *, struct type *); \ 407 | void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ 408 | struct type *name##_RB_REMOVE(struct name *, struct type *); \ 409 | struct type *name##_RB_INSERT(struct name *, struct type *); \ 410 | struct type *name##_RB_FIND(struct name *, struct type *); \ 411 | struct type *name##_RB_NEXT(struct type *); \ 412 | struct type *name##_RB_MINMAX(struct name *, int); \ 413 | struct type *name##_RB_GETPARENT(struct type*); \ 414 | struct type *name##_RB_SETPARENT(struct type*, struct type*); \ 415 | int name##_RB_GETCOLOR(struct type*); \ 416 | void name##_RB_SETCOLOR(struct type*,int); 417 | 418 | /* Generates prototypes (with storage class) and inline functions */ 419 | #define RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \ 420 | _sc_ void name##_RB_INSERT_COLOR(struct name *, struct type *); \ 421 | _sc_ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *); \ 422 | _sc_ struct type *name##_RB_REMOVE(struct name *, struct type *); \ 423 | _sc_ struct type *name##_RB_INSERT(struct name *, struct type *); \ 424 | _sc_ struct type *name##_RB_FIND(struct name *, struct type *); \ 425 | _sc_ struct type *name##_RB_NEXT(struct type *); \ 426 | _sc_ struct type *name##_RB_MINMAX(struct name *, int); \ 427 | _sc_ struct type *name##_RB_GETPARENT(struct type*); \ 428 | _sc_ struct type *name##_RB_SETPARENT(struct type*, struct type*); \ 429 | _sc_ int name##_RB_GETCOLOR(struct type*); \ 430 | _sc_ void name##_RB_SETCOLOR(struct type*,int); 431 | 432 | 433 | /* Main rb operation. 434 | * Moves node close to the key of elm to top 435 | */ 436 | #define RB_GENERATE(name, type, field, cmp) \ 437 | struct type *name##_RB_GETPARENT(struct type *elm) { \ 438 | struct type *parent = _RB_PARENT(elm, field); \ 439 | if( parent != NULL) { \ 440 | parent = (struct type*)((uintptr_t)parent & ~RB_COLOR_MASK);\ 441 | return( (struct type*) ( (parent == (struct type*) RB_PLACEHOLDER) ? NULL: parent));\ 442 | } \ 443 | return((struct type*)NULL); \ 444 | } \ 445 | int name##_RB_GETCOLOR(struct type *elm) { \ 446 | int color = 0; \ 447 | color = (int)((uintptr_t)_RB_PARENT(elm,field) & RB_COLOR_MASK);\ 448 | return(color); \ 449 | } \ 450 | void name##_RB_SETCOLOR(struct type *elm,int color) { \ 451 | struct type *parent = name##_RB_GETPARENT(elm); \ 452 | if(parent == (struct type*)NULL) \ 453 | parent = (struct type*) RB_PLACEHOLDER; \ 454 | _RB_PARENT(elm, field) = (struct type*)((uintptr_t)parent | (unsigned int)color);\ 455 | } \ 456 | struct type *name##_RB_SETPARENT(struct type *elm, struct type *parent) { \ 457 | int color = name##_RB_GETCOLOR(elm); \ 458 | _RB_PARENT(elm, field) = parent; \ 459 | if(color) name##_RB_SETCOLOR(elm, color); \ 460 | return(name##_RB_GETPARENT(elm)); \ 461 | } \ 462 | \ 463 | void \ 464 | name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ 465 | { \ 466 | struct type *parent, *gparent, *tmp; \ 467 | while ((parent = name##_RB_GETPARENT(elm)) != NULL && \ 468 | name##_RB_GETCOLOR(parent) == RB_RED) { \ 469 | gparent = name##_RB_GETPARENT(parent); \ 470 | if (parent == RB_LEFT(gparent, field)) { \ 471 | tmp = RB_RIGHT(gparent, field); \ 472 | if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \ 473 | name##_RB_SETCOLOR(tmp, RB_BLACK); \ 474 | RB_SET_BLACKRED(name, parent, gparent, field);\ 475 | elm = gparent; \ 476 | continue; \ 477 | } \ 478 | if (RB_RIGHT(parent, field) == elm) { \ 479 | RB_ROTATE_LEFT(name, head, parent, tmp, field);\ 480 | tmp = parent; \ 481 | parent = elm; \ 482 | elm = tmp; \ 483 | } \ 484 | RB_SET_BLACKRED(name, parent, gparent, field); \ 485 | RB_ROTATE_RIGHT(name,head, gparent, tmp, field); \ 486 | } else { \ 487 | tmp = RB_LEFT(gparent, field); \ 488 | if (tmp && name##_RB_GETCOLOR(tmp) == RB_RED) { \ 489 | name##_RB_SETCOLOR(tmp, RB_BLACK); \ 490 | RB_SET_BLACKRED(name, parent, gparent, field);\ 491 | elm = gparent; \ 492 | continue; \ 493 | } \ 494 | if (RB_LEFT(parent, field) == elm) { \ 495 | RB_ROTATE_RIGHT(name, head, parent, tmp, field);\ 496 | tmp = parent; \ 497 | parent = elm; \ 498 | elm = tmp; \ 499 | } \ 500 | RB_SET_BLACKRED(name, parent, gparent, field); \ 501 | RB_ROTATE_LEFT(name, head, gparent, tmp, field); \ 502 | } \ 503 | } \ 504 | name##_RB_SETCOLOR(head->rbh_root, RB_BLACK); \ 505 | } \ 506 | \ 507 | void \ 508 | name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ 509 | { \ 510 | struct type *tmp; \ 511 | while ((elm == NULL || name##_RB_GETCOLOR(elm) == RB_BLACK) && \ 512 | elm != RB_ROOT(head)) { \ 513 | if (RB_LEFT(parent, field) == elm) { \ 514 | tmp = RB_RIGHT(parent, field); \ 515 | if (name##_RB_GETCOLOR(tmp) == RB_RED) { \ 516 | RB_SET_BLACKRED(name, tmp, parent, field); \ 517 | RB_ROTATE_LEFT(name, head, parent, tmp, field);\ 518 | tmp = RB_RIGHT(parent, field); \ 519 | } \ 520 | if ((RB_LEFT(tmp, field) == NULL || \ 521 | name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\ 522 | (RB_RIGHT(tmp, field) == NULL || \ 523 | name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\ 524 | name##_RB_SETCOLOR(tmp, RB_RED); \ 525 | elm = parent; \ 526 | parent = name##_RB_GETPARENT(elm); \ 527 | } else { \ 528 | if (RB_RIGHT(tmp, field) == NULL || \ 529 | name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK) {\ 530 | struct type *oleft; \ 531 | if ((oleft = RB_LEFT(tmp, field)) \ 532 | != NULL) \ 533 | name##_RB_SETCOLOR(oleft, RB_BLACK);\ 534 | name##_RB_SETCOLOR(tmp, RB_RED); \ 535 | RB_ROTATE_RIGHT(name, head, tmp, oleft, field);\ 536 | tmp = RB_RIGHT(parent, field); \ 537 | } \ 538 | name##_RB_SETCOLOR(tmp, (name##_RB_GETCOLOR(parent)));\ 539 | name##_RB_SETCOLOR(parent, RB_BLACK); \ 540 | if (RB_RIGHT(tmp, field)) \ 541 | name##_RB_SETCOLOR(RB_RIGHT(tmp, field),RB_BLACK);\ 542 | RB_ROTATE_LEFT(name, head, parent, tmp, field);\ 543 | elm = RB_ROOT(head); \ 544 | break; \ 545 | } \ 546 | } else { \ 547 | tmp = RB_LEFT(parent, field); \ 548 | if (name##_RB_GETCOLOR(tmp) == RB_RED) { \ 549 | RB_SET_BLACKRED(name, tmp, parent, field); \ 550 | RB_ROTATE_RIGHT(name, head, parent, tmp, field);\ 551 | tmp = RB_LEFT(parent, field); \ 552 | } \ 553 | if ((RB_LEFT(tmp, field) == NULL || \ 554 | name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) &&\ 555 | (RB_RIGHT(tmp, field) == NULL || \ 556 | name##_RB_GETCOLOR(RB_RIGHT(tmp, field)) == RB_BLACK)) {\ 557 | name##_RB_SETCOLOR(tmp, RB_RED); \ 558 | elm = parent; \ 559 | parent = name##_RB_GETPARENT(elm); \ 560 | } else { \ 561 | if (RB_LEFT(tmp, field) == NULL || \ 562 | name##_RB_GETCOLOR(RB_LEFT(tmp, field)) == RB_BLACK) {\ 563 | struct type *oright; \ 564 | if ((oright = RB_RIGHT(tmp, field)) \ 565 | != NULL) \ 566 | name##_RB_SETCOLOR(oright, RB_BLACK);\ 567 | name##_RB_SETCOLOR(tmp, RB_RED); \ 568 | RB_ROTATE_LEFT(name, head, tmp, oright, field);\ 569 | tmp = RB_LEFT(parent, field); \ 570 | } \ 571 | name##_RB_SETCOLOR(tmp,(name##_RB_GETCOLOR(parent)));\ 572 | name##_RB_SETCOLOR(parent, RB_BLACK); \ 573 | if (RB_LEFT(tmp, field)) \ 574 | name##_RB_SETCOLOR(RB_LEFT(tmp, field), RB_BLACK);\ 575 | RB_ROTATE_RIGHT(name, head, parent, tmp, field);\ 576 | elm = RB_ROOT(head); \ 577 | break; \ 578 | } \ 579 | } \ 580 | } \ 581 | if (elm) \ 582 | name##_RB_SETCOLOR(elm, RB_BLACK); \ 583 | } \ 584 | \ 585 | struct type * \ 586 | name##_RB_REMOVE(struct name *head, struct type *elm) \ 587 | { \ 588 | struct type *child, *parent, *old = elm; \ 589 | int color; \ 590 | if (RB_LEFT(elm, field) == NULL) \ 591 | child = RB_RIGHT(elm, field); \ 592 | else if (RB_RIGHT(elm, field) == NULL) \ 593 | child = RB_LEFT(elm, field); \ 594 | else { \ 595 | struct type *left; \ 596 | elm = RB_RIGHT(elm, field); \ 597 | while ((left = RB_LEFT(elm, field)) != NULL) \ 598 | elm = left; \ 599 | child = RB_RIGHT(elm, field); \ 600 | parent = name##_RB_GETPARENT(elm); \ 601 | color = name##_RB_GETCOLOR(elm); \ 602 | if (child) \ 603 | name##_RB_SETPARENT(child, parent); \ 604 | if (parent) { \ 605 | if (RB_LEFT(parent, field) == elm) \ 606 | RB_LEFT(parent, field) = child; \ 607 | else \ 608 | RB_RIGHT(parent, field) = child; \ 609 | RB_AUGMENT(parent); \ 610 | } else \ 611 | RB_ROOT(head) = child; \ 612 | if (name##_RB_GETPARENT(elm) == old) \ 613 | parent = elm; \ 614 | (elm)->field = (old)->field; \ 615 | if (name##_RB_GETPARENT(old)) { \ 616 | if (RB_LEFT(name##_RB_GETPARENT(old), field) == old)\ 617 | RB_LEFT(name##_RB_GETPARENT(old), field) = elm;\ 618 | else \ 619 | RB_RIGHT(name##_RB_GETPARENT(old), field) = elm;\ 620 | RB_AUGMENT(name##_RB_GETPARENT(old)); \ 621 | } else \ 622 | RB_ROOT(head) = elm; \ 623 | name##_RB_SETPARENT(RB_LEFT(old, field), elm); \ 624 | if (RB_RIGHT(old, field)) \ 625 | name##_RB_SETPARENT(RB_RIGHT(old, field), elm); \ 626 | if (parent) { \ 627 | left = parent; \ 628 | do { \ 629 | RB_AUGMENT(left); \ 630 | } while ((left = name##_RB_GETPARENT(left)) != NULL); \ 631 | } \ 632 | goto color; \ 633 | } \ 634 | parent = name##_RB_GETPARENT(elm); \ 635 | color = name##_RB_GETCOLOR(elm); \ 636 | if (child) \ 637 | name##_RB_SETPARENT(child, parent); \ 638 | if (parent) { \ 639 | if (RB_LEFT(parent, field) == elm) \ 640 | RB_LEFT(parent, field) = child; \ 641 | else \ 642 | RB_RIGHT(parent, field) = child; \ 643 | RB_AUGMENT(parent); \ 644 | } else \ 645 | RB_ROOT(head) = child; \ 646 | color: \ 647 | if (color == RB_BLACK) \ 648 | name##_RB_REMOVE_COLOR(head, parent, child); \ 649 | return (old); \ 650 | } \ 651 | \ 652 | /* Inserts a node into the RB tree */ \ 653 | struct type * \ 654 | name##_RB_INSERT(struct name *head, struct type *elm) \ 655 | { \ 656 | struct type *tmp; \ 657 | struct type *parent = NULL; \ 658 | int comp = 0; \ 659 | tmp = RB_ROOT(head); \ 660 | while (tmp) { \ 661 | parent = tmp; \ 662 | comp = (cmp)(elm, parent); \ 663 | if (comp < 0) \ 664 | tmp = RB_LEFT(tmp, field); \ 665 | else if (comp > 0) \ 666 | tmp = RB_RIGHT(tmp, field); \ 667 | else \ 668 | return (tmp); \ 669 | } \ 670 | RB_SET(name, elm, parent, field); \ 671 | if (parent != NULL) { \ 672 | if (comp < 0) \ 673 | RB_LEFT(parent, field) = elm; \ 674 | else \ 675 | RB_RIGHT(parent, field) = elm; \ 676 | RB_AUGMENT(parent); \ 677 | } else \ 678 | RB_ROOT(head) = elm; \ 679 | name##_RB_INSERT_COLOR(head, elm); \ 680 | return (NULL); \ 681 | } \ 682 | \ 683 | /* Finds the node with the same key as elm */ \ 684 | struct type * \ 685 | name##_RB_FIND(struct name *head, struct type *elm) \ 686 | { \ 687 | struct type *tmp = RB_ROOT(head); \ 688 | int comp; \ 689 | while (tmp) { \ 690 | comp = cmp(elm, tmp); \ 691 | if (comp < 0) \ 692 | tmp = RB_LEFT(tmp, field); \ 693 | else if (comp > 0) \ 694 | tmp = RB_RIGHT(tmp, field); \ 695 | else \ 696 | return (tmp); \ 697 | } \ 698 | return (NULL); \ 699 | } \ 700 | \ 701 | /* ARGSUSED */ \ 702 | struct type * \ 703 | name##_RB_NEXT(struct type *elm) \ 704 | { \ 705 | if (RB_RIGHT(elm, field)) { \ 706 | elm = RB_RIGHT(elm, field); \ 707 | while (RB_LEFT(elm, field)) \ 708 | elm = RB_LEFT(elm, field); \ 709 | } else { \ 710 | if (name##_RB_GETPARENT(elm) && \ 711 | (elm == RB_LEFT(name##_RB_GETPARENT(elm), field))) \ 712 | elm = name##_RB_GETPARENT(elm); \ 713 | else { \ 714 | while (name##_RB_GETPARENT(elm) && \ 715 | (elm == RB_RIGHT(name##_RB_GETPARENT(elm), field)))\ 716 | elm = name##_RB_GETPARENT(elm); \ 717 | elm = name##_RB_GETPARENT(elm); \ 718 | } \ 719 | } \ 720 | return (elm); \ 721 | } \ 722 | \ 723 | struct type * \ 724 | name##_RB_MINMAX(struct name *head, int val) \ 725 | { \ 726 | struct type *tmp = RB_ROOT(head); \ 727 | struct type *parent = NULL; \ 728 | while (tmp) { \ 729 | parent = tmp; \ 730 | if (val < 0) \ 731 | tmp = RB_LEFT(tmp, field); \ 732 | else \ 733 | tmp = RB_RIGHT(tmp, field); \ 734 | } \ 735 | return (parent); \ 736 | } 737 | 738 | 739 | #define RB_PROTOTYPE_PREV(name, type, field, cmp) \ 740 | RB_PROTOTYPE(name, type, field, cmp) \ 741 | struct type *name##_RB_PREV(struct type *); 742 | 743 | 744 | #define RB_PROTOTYPE_SC_PREV(_sc_, name, type, field, cmp) \ 745 | RB_PROTOTYPE_SC(_sc_, name, type, field, cmp) \ 746 | _sc_ struct type *name##_RB_PREV(struct type *); 747 | 748 | #define RB_GENERATE_PREV(name, type, field, cmp) \ 749 | RB_GENERATE(name, type, field, cmp) \ 750 | struct type * \ 751 | name##_RB_PREV(struct type *elm) \ 752 | { \ 753 | if (RB_LEFT(elm, field)) { \ 754 | elm = RB_LEFT(elm, field); \ 755 | while (RB_RIGHT(elm, field)) \ 756 | elm = RB_RIGHT(elm, field); \ 757 | } else { \ 758 | if (name##_RB_GETPARENT(elm) && \ 759 | (elm == RB_RIGHT(name##_RB_GETPARENT(elm), field))) \ 760 | elm = name##_RB_GETPARENT(elm); \ 761 | else { \ 762 | while (name##_RB_GETPARENT(elm) && \ 763 | (elm == RB_LEFT(name##_RB_GETPARENT(elm), field)))\ 764 | elm = name##_RB_GETPARENT(elm); \ 765 | elm = name##_RB_GETPARENT(elm); \ 766 | } \ 767 | } \ 768 | return (elm); \ 769 | } \ 770 | 771 | #define RB_NEGINF -1 772 | #define RB_INF 1 773 | 774 | #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) 775 | #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) 776 | #define RB_FIND(name, x, y) name##_RB_FIND(x, y) 777 | #define RB_NEXT(name, x, y) name##_RB_NEXT(y) 778 | #define RB_PREV(name, x, y) name##_RB_PREV(y) 779 | #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) 780 | #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) 781 | 782 | #define RB_FOREACH(x, name, head) \ 783 | for ((x) = RB_MIN(name, head); \ 784 | (x) != NULL; \ 785 | (x) = name##_RB_NEXT(x)) 786 | 787 | #define RB_FOREACH_FROM(x, name, y) \ 788 | for ((x) = (y); \ 789 | ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 790 | (x) = (y)) 791 | 792 | #define RB_FOREACH_REVERSE_FROM(x, name, y) \ 793 | for ((x) = (y); \ 794 | ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ 795 | (x) = (y)) 796 | 797 | #define RB_FOREACH_SAFE(x, name, head, y) \ 798 | for ((x) = RB_MIN(name, head); \ 799 | ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ 800 | (x) = (y)) 801 | 802 | #endif /* _LIBKERN_TREE_H_ */ 803 | --------------------------------------------------------------------------------