├── .gitignore ├── .gitmodules ├── .travis.yml ├── Makefile ├── README.md ├── config.h ├── encrypt.c ├── encrypt.h ├── md5.c ├── md5.h ├── pytest ├── config.json ├── local.py └── test.py ├── rc4.c ├── rc4.h ├── server.c ├── server.h ├── tests.c ├── utils.c └── utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libuv"] 2 | path = libuv 3 | url = https://github.com/joyent/libuv.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | - clang 5 | script: sudo apt-get install libssl-dev && make && make test -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | UNAME := $(shell uname) 2 | 3 | RTFLAGS=-lrt 4 | ifeq ($(UNAME), Darwin) 5 | RTFLAGS=-framework CoreServices 6 | endif 7 | OLEVEL=-O2 -DNDEBUG 8 | CFLAGS=-Wall $(OLEVEL) -I libuv/include -std=gnu99 9 | FILES=server.c utils.c encrypt.c md5.c rc4.c 10 | APP=server 11 | 12 | all: $(FILES) libuv/libuv.a 13 | $(CC) $(CFLAGS) -o \ 14 | $(APP) $(FILES) \ 15 | libuv/libuv.a -lpthread -lcrypto -lm $(RTFLAGS) 16 | 17 | libuv/libuv.a: 18 | $(MAKE) -C libuv 19 | 20 | valgrind: OLEVEL=-O0 -g 21 | valgrind: all 22 | valgrind --leak-check=full ./server 23 | 24 | debug: OLEVEL=-O0 -g 25 | debug: all 26 | 27 | gprof: OLEVEL=-O0 -g -pg 28 | gprof: all 29 | 30 | test: OLEVEL=-O0 -g 31 | test: FILES=tests.c encrypt.c md5.c rc4.c 32 | test: APP=test 33 | test: all 34 | ./test 35 | cd pytest; python test.py 36 | 37 | clean: 38 | $(MAKE) -C libuv clean 39 | rm -f server 40 | rm -rf *.dSYM 41 | rm -rf test 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | shadowsocks-libuv 2 | ================= 3 | [![Build Status](https://travis-ci.org/dndx/shadowsocks-libuv.png?branch=master)](https://travis-ci.org/dndx/shadowsocks-libuv) 4 | 5 | Shadowsocks is a lightweight tunnel proxy to help you get through firewalls. 6 | 7 | Protocol made by [clowwindy](https://raw.github.com/clowwindy/), libuv port by [dndx](https://github.com/dndx) 8 | 9 | This is only a **server**, it should work with any shadowsocks client. 10 | 11 | Current version: 0.2 12 | 13 | This is an [Open Source](http://opensource.org/licenses/MIT) project and released under [The MIT License](http://opensource.org/licenses/MIT) 14 | 15 | ## Features 16 | * Super fast and low resource consumption (thanks to [libuv](https://github.com/joyent/libuv)), it runs smoothly on almost any VPS. 17 | * Fully compatible with other ports of shadowsocks. 18 | * Supports the latest RC4 encryption method. 19 | * Fully IPv6 Ready 20 | 21 | ## About IPv6 Support 22 | Instead of creating two separate file descriptors for IPv4 and IPv6, shadowsocks-libuv only creates one. It works because it uses the Linux kernel 2.4.21 and 2.6, and we can use `IN6ADDR_ANY` (aka. `::0`) to accept connections from both the IPv4 and IPv6 stacks. Those connections come from the IPv4 stack will be mapped to [IPv4-mapped IPv6 addresses](https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses) automatically. For example, IPv4 address `192.168.1.2` will be mapped to `::ffff:192:168:1:2` and will work whether your machine has an IPv6 link or not. 23 | 24 | If you want your shadowsocks to listen on a specific IPv4 address, listen using `::ffff:192:168:1:2`. 25 | 26 | When connecting to a remote server, shadowsocks prefers to use an IPv6 address if both your server and remote supports IPv6. This will work even if your connection to the server is using IPv4. Thus you can use shadowsocks as an IPv4 to IPv6 or IPv6 to IPv4 tunnel. 27 | 28 | ### Diagram 29 | 30 | +------+ IPv4 +------+ IPv4 +------+ 31 | |Client| <---OR---> |Server| <---OR---> |Remote| 32 | +------+ IPv6 +------+ IPv6 +------+ 33 | 34 | Client is any compatible shadowsocks client 35 | 36 | Server is shadowsocks-libuv or other compatible server 37 | 38 | Remote is the service you are trying to access 39 | 40 | ## Attention 41 | Please open an issue if you encounter any bugs. Be sure to attach the error message so I can identify it. 42 | 43 | ## How to Build 44 | $ yum install openssl-devel 45 | $ git clone --recursive https://github.com/dndx/shadowsocks-libuv.git 46 | $ cd shadowsocks-libuv/ 47 | $ vim config.h 48 | $ make 49 | 50 | Note that you need to rebuild it every time you modify config.h, just run `make` again and it will do rest of the work. 51 | 52 | Tested and confirmed to work on: 53 | 54 | * Mac OS X 10.8.2 x64 using Clang 4.1 55 | * CentOS 5.8 x86 using GCC 4.1.2 56 | * CentOS 6.3 x64 using GCC 4.4.6 57 | * Ubuntu Linux 12.04 using GCC 4.6.x and Clang 3.1.x (Travis Environment) 58 | 59 | ## How to Use 60 | After you build shadowsocks successfully, you can rename the file `server` and move it to anywhere you want. 61 | 62 | Also there are command line options that can be used to override settings in config.h: 63 | 64 | $ ./server -? 65 | ./server: invalid option -- ? 66 | Shadowsocks Version:0.2 libuv(0.9) Written by Dndx(idndx.com) 67 | Usage: ./server [-l listen] [-p port] [-k keyfile] [-f pidfile] [-m rc4|shadow] 68 | 69 | Options: 70 | -l : Override the listening IP 71 | -p : Override the listening port 72 | -k : Override the listening password 73 | -f : Override the pidfile path 74 | -m : Override the encryption method 75 | If you want to run server in background, you can: 76 | 77 | $ nohup /path/to/server & 78 | 79 | Note this will redirect all logs generated by program to `nohup.out`. If you do not want logs to be saved, you can run: 80 | 81 | $ nohup /path/to/server > /dev/null 2>&1 & 82 | 83 | This will delete all messages. 84 | 85 | If your program does not run as expected, log files will help identify the bug. 86 | 87 | ## Known Issues 88 | ### Build Failed 89 | src/unix/linux/syscalls.h:74: error: expected specifier-qualifier-list before ‘__u64’ 90 | 1. First, make sure you have the latest kernel-headers by running `yum install kernel-headers` 91 | 2. Try make again, if it still complains, see next 92 | 3. `cd` to shadowsocks-libuv and `$ vim libuv/config-unix.mk` 93 | 4. At about line 22, you will see `CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter` 94 | 5. Change it to `CSTDFLAG=--std=gnu99 -pedantic -Wall -Wextra -Wno-unused-parameter` 95 | 6. Save the file and run `make` again 96 | 97 | ### Can not using static link 98 | Thanks to [@cyfdecy](https://github.com/cyfdecyf) 99 | 100 | Do not use `-static` to compile this project. The problem is that `libuv` is using `pthread` and `getaddrinfo(3)` for async DNS resolve. But this will cause `getaddrinfo(3)` Segment Fault. 101 | 102 | More information can be found at [issue #3](https://github.com/dndx/shadowsocks-libuv/issues/3) 103 | 104 | ### CPU 100% 105 | There is a possibility that the process will sometimes consume 100% of CPU and can not be restored. The cause of problem is not clear but I am working for a solution. Including re-design the way connection is handled, please stay tuned. 106 | 107 | 108 | ## Performance 109 | I did not fully benchmark it yet, but according to my use on [TinyVZ](http://tinyvz.com/) (OpenVZ 128M RAM and CentOS 5.8 x86). When streaming YouTube 1080p vedio at about 20Mbit/s bandwidth, it use at most 3% of RAM (RSS about 7500) and almost no CPU time. While browsing it uses less than 0.7% RAM (RSS about 1164). 110 | 111 | ##Contributors 112 | * [@messense](https://github.com/messense) Logger Color 113 | * [@clowwindy](https://github.com/clowwindy) 114 | * Test Case and Protol Maker of shadowsocks 115 | * [getopt(3) issue](https://github.com/dndx/shadowsocks-libuv/pull/4) 116 | * [@cyfdecyf](https://github.com/cyfdecyf) Warning about static link in [issue #3](https://github.com/dndx/shadowsocks-libuv/issues/3) 117 | * [@madeye](https://github.com/madeye) [IPv6 Support](https://github.com/dndx/shadowsocks-libuv/pull/8) 118 | 119 | I appreciate all the people who have made this project better. Contribution is always welcome! 120 | 121 | ## TODO List 122 | * ~~Fully IPv6 Support~~ (accomplished) 123 | * ~~RC4 Crypto Support~~ (accomplished) 124 | * Multi Port Support 125 | * Client Implement 126 | * …to be continued… -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H_ 2 | #define CONFIG_H_ 3 | #include "utils.h" 4 | #include "encrypt.h" 5 | 6 | // This is the IP address server will be used to accept new connection 7 | // By default, "::0" will listen on both IPv4 and IPv6 stack if your system have a kernel later than Linux 2.4.21 and 2.6 8 | // This have to be an IPv6 address or IPv4-mapped IPv6 address. If you want it listen only on specified IPv4 address, use the format "::ffff:192:168:1:2" 9 | #define SERVER_LISTEN "::0" 10 | 11 | // This is the port server will be used to accept new connection 12 | #define SERVER_PORT 8888 13 | 14 | // This is the password used for encrypt/decrypt, should be the same as your client 15 | #define PASSWORD "foobar!" 16 | 17 | // This is the method used for encrypt/decrypt, should be the same as your client 18 | // Available methods: 19 | // METHOD_SHADOWCRYPT : Original Substitute Encryption Method Made By clowwindy 20 | // METHOD_RC4 : RC4 Encryption 21 | #define CRYPTO_METHOD METHOD_SHADOWCRYPT 22 | 23 | // This is the path shadowsocks will write it's pid to 24 | #define PID_FILE "/tmp/shadowsocks.pid" 25 | 26 | // This is the time format for log, see strftime(3) for more information 27 | #define TIME_FORMAT "%F %T" 28 | 29 | // This is the buffer size (in byte) used during handshake, generally you DO NOT need to change this unless you have a good reason to do so 30 | // This buffer will be freed right after handshake is complete 31 | #define HANDSHAKE_BUFFER_SIZE 512 32 | 33 | // This is the buffer size (in byte) that will be used during receive data, if you are not sure, just leave it 34 | #define BUFFER_LIMIT 65536 35 | 36 | // This is the number of max allowed pending write to client request, if you are running out of memory (which is very unlikely), you may want to decrease this a little 37 | // The max possible memory usage of this program is BUFFER_LIMIT * MAX_PENDING_PER_CONN * Concurrent connection number, but this is kind of situation almost impossible to happen 38 | // In most case, increase this value will better your performance 39 | #define MAX_PENDING_PER_CONN 100 40 | 41 | // This is the interval (in seconds) the operation system will be used to check whether the connection is still alive 42 | // If you think you do not need it, you can comment next line to turn it off 43 | #define KEEPALIVE_TIMEOUT 120 44 | 45 | #endif /* !CONFIG_H_ */ 46 | -------------------------------------------------------------------------------- /encrypt.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 dndx (idndx.com) 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "config.h" 22 | #include 23 | #include 24 | #include 25 | #include "md5.h" 26 | #include "encrypt.h" 27 | #include "utils.h" 28 | 29 | #ifdef HIGHFIRST 30 | uint64_t swap_uint64( uint64_t val ) 31 | { 32 | val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL ); 33 | val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL ); 34 | return (val << 32) | (val >> 32); 35 | } 36 | #endif /* BIG ENDIAN */ 37 | 38 | /* 39 | * message must be uint8_t[16] 40 | */ 41 | void md5(const uint8_t *text, uint8_t *message) 42 | { 43 | struct MD5Context context; 44 | MD5Init(&context); 45 | MD5Update(&context, text, strlen((const char*)text)); 46 | MD5Final(message, &context); 47 | } 48 | 49 | static void merge(uint8_t *arr, int start, int end, int mid, int ei, uint64_t keynum) 50 | { 51 | int asize = mid - start + 1; 52 | uint8_t a[asize]; 53 | memcpy(a, arr + start, asize); 54 | uint8_t *b = arr; 55 | uint8_t *result = arr; 56 | 57 | int i = 0; 58 | int j = mid + 1; 59 | int imax = asize; 60 | int jmax = end + 1; 61 | int k = start; 62 | 63 | while (i < imax && j < jmax) { 64 | if (keynum % (a[i] + ei) <= keynum % (b[j] + ei)) { 65 | result[k] = a[i]; 66 | i++; 67 | k++; 68 | } else { 69 | result[k] = b[j]; 70 | j++; 71 | k++; 72 | } 73 | } 74 | 75 | while (i < imax) { 76 | result[k] = a[i]; 77 | i++; 78 | k++; 79 | } 80 | while (j < jmax) { 81 | result[k] = b[j]; 82 | j++; 83 | k++; 84 | } 85 | } 86 | 87 | static void merge_sort(uint8_t *arr, int start, int end, int ei, uint64_t keynum) 88 | { 89 | if (end - start <= 0) { 90 | return; 91 | } 92 | 93 | int mid = (start + end) / 2; 94 | 95 | merge_sort(arr, start, mid, ei, keynum); 96 | merge_sort(arr, mid + 1, end, ei, keynum); 97 | merge(arr, start, end, mid, ei, keynum); 98 | } 99 | 100 | static void mergesrt(uint8_t *arr, int length, int ei, uint64_t keynum) 101 | { 102 | merge_sort(arr, 0, length - 1, ei, keynum); 103 | } 104 | 105 | /* 106 | * encrypt_table and decrypt_table must be uint8_t[TABLE_SIZE] 107 | */ 108 | void make_tables(const uint8_t *key, uint8_t *encrypt_table, uint8_t *decrypt_table) 109 | { 110 | uint8_t digest[16]; 111 | int ei; 112 | uint64_t keynum; 113 | 114 | md5(key, digest); 115 | memcpy(&keynum, digest, 8); 116 | #ifdef HIGHFIRST 117 | keynum = swap_uint64(keynum); 118 | #endif /* BIG ENDIAN */ 119 | uint8_t temp_table[TABLE_SIZE]; 120 | for (ei=0; eiencrypt_table) { 135 | while (length--) { 136 | data[length] = enc->encrypt_table[data[length]]; 137 | } 138 | } else if (enc->rc4_en) { 139 | rc4_crypt(enc->rc4_en, data, data, length); 140 | } else { 141 | FATAL("Crypto unknown!"); 142 | } 143 | 144 | } 145 | 146 | void shadow_decrypt(uint8_t *data, struct encryptor *enc, register unsigned int length) 147 | { 148 | if (enc->encrypt_table) { 149 | while (length--) { 150 | data[length] = enc->decrypt_table[data[length]]; 151 | } 152 | } else if (enc->rc4_de) { 153 | rc4_crypt(enc->rc4_de, data, data, length); 154 | } else { 155 | FATAL("Crypto unknown!"); 156 | } 157 | } 158 | 159 | static int init_rc4_key(struct encryptor *enc) 160 | { 161 | unsigned char *key = calloc(1, EVP_MAX_IV_LENGTH); 162 | if (!key) 163 | FATAL("RC4 Cliper Init Failed"); 164 | unsigned char iv[EVP_MAX_IV_LENGTH]; 165 | int key_len = EVP_BytesToKey(EVP_rc4(), EVP_md5(), NULL, (uint8_t*) enc->key, strlen((char *)enc->key), 1, key, iv); 166 | if (!key_len) 167 | FATAL("RC4 Cliper Init Failed"); 168 | 169 | enc->key = key; 170 | 171 | return key_len; 172 | } 173 | 174 | // key should end with \0 175 | void make_encryptor(struct encryptor *tpl, struct encryptor *enc, uint8_t method, uint8_t *key) 176 | { 177 | memset(enc, 0, sizeof(struct encryptor)); 178 | 179 | if (!tpl) { 180 | if (method == METHOD_SHADOWCRYPT) { 181 | assert(key); 182 | enc->key = key; 183 | enc->encrypt_table = (uint8_t *)calloc(TABLE_SIZE, sizeof(uint8_t)); 184 | enc->decrypt_table = (uint8_t *)calloc(TABLE_SIZE, sizeof(uint8_t)); 185 | if (!(enc->encrypt_table && enc->decrypt_table)) 186 | FATAL("malloc() failed!"); 187 | make_tables(key, enc->encrypt_table, enc->decrypt_table); 188 | } else if (method == METHOD_RC4) { 189 | assert(key); 190 | enc->key = key; 191 | init_rc4_key(enc); 192 | } 193 | } else { 194 | assert(!method); 195 | if (tpl->encrypt_table) { 196 | assert(!key); 197 | enc->encrypt_table = tpl->encrypt_table; 198 | enc->decrypt_table = tpl->decrypt_table; 199 | } else { 200 | assert(!key); 201 | assert(tpl->key); 202 | enc->key = tpl->key; 203 | enc->rc4_en = (struct rc4_state *)malloc(sizeof(struct rc4_state)); 204 | enc->rc4_de = (struct rc4_state *)malloc(sizeof(struct rc4_state)); 205 | if (!(enc->rc4_en && enc->rc4_de)) 206 | FATAL("malloc() failed!"); 207 | rc4_init(enc->rc4_en, enc->key, MD5_LEN); 208 | rc4_init(enc->rc4_de, enc->key, MD5_LEN); 209 | } 210 | } 211 | } 212 | 213 | void destroy_encryptor(struct encryptor *enc) 214 | { 215 | if (enc->rc4_en) { 216 | free(enc->rc4_en); 217 | free(enc->rc4_de); 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /encrypt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 dndx (idndx.com) 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef ENCRYPT_H_ 22 | #define ENCRYPT_H_ 23 | #include 24 | #include "rc4.h" 25 | 26 | #define TABLE_SIZE 256 27 | #define METHOD_SHADOWCRYPT 0x1 28 | #define METHOD_RC4 0x2 29 | #define MD5_LEN 16 30 | 31 | struct encryptor { 32 | uint8_t *key; 33 | uint8_t *encrypt_table; 34 | uint8_t *decrypt_table; 35 | struct rc4_state *rc4_en; 36 | struct rc4_state *rc4_de; 37 | }; 38 | 39 | void md5(const uint8_t *text, uint8_t *message); 40 | void make_tables(const uint8_t *key, uint8_t *encrypt_table, uint8_t *decrypt_table); 41 | void shadow_encrypt(uint8_t *data, struct encryptor *enc, register unsigned int length); 42 | void shadow_decrypt(uint8_t *data, struct encryptor *enc, register unsigned int length); 43 | void make_encryptor(struct encryptor *tpl, struct encryptor *enc, uint8_t method, uint8_t *key); 44 | void destroy_encryptor(struct encryptor *enc); 45 | 46 | #endif /* !ENCRYPT_H_ */ 47 | -------------------------------------------------------------------------------- /md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This code implements the MD5 message-digest algorithm. 3 | * The algorithm is due to Ron Rivest. This code was 4 | * written by Colin Plumb in 1993, no copyright is claimed. 5 | * This code is in the public domain; do with it what you wish. 6 | * 7 | * Equivalent code is available from RSA Data Security, Inc. 8 | * This code has been tested against that, and is equivalent, 9 | * except that you don't need to include two pages of legalese 10 | * with every copy. 11 | * 12 | * To compute the message digest of a chunk of bytes, declare an 13 | * MD5Context structure, pass it to MD5Init, call MD5Update as 14 | * needed on buffers full of bytes, and then call MD5Final, which 15 | * will fill a supplied 16-byte array with the digest. 16 | */ 17 | 18 | /* Brutally hacked by John Walker back from ANSI C to K&R (no 19 | prototypes) to maintain the tradition that Netfone will compile 20 | with Sun's original "cc". */ 21 | 22 | #include /* for memcpy() */ 23 | #include "md5.h" 24 | 25 | #ifndef HIGHFIRST 26 | #define byteReverse(buf, len) /* Nothing */ 27 | #else 28 | /* 29 | * Note: this code is harmless on little-endian machines. 30 | */ 31 | void byteReverse(buf, longs) 32 | unsigned char *buf; unsigned longs; 33 | { 34 | uint32 t; 35 | do { 36 | t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | 37 | ((unsigned) buf[1] << 8 | buf[0]); 38 | *(uint32 *) buf = t; 39 | buf += 4; 40 | } while (--longs); 41 | } 42 | #endif 43 | 44 | /* 45 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious 46 | * initialization constants. 47 | */ 48 | void MD5Init(ctx) 49 | struct MD5Context *ctx; 50 | { 51 | ctx->buf[0] = 0x67452301; 52 | ctx->buf[1] = 0xefcdab89; 53 | ctx->buf[2] = 0x98badcfe; 54 | ctx->buf[3] = 0x10325476; 55 | 56 | ctx->bits[0] = 0; 57 | ctx->bits[1] = 0; 58 | } 59 | 60 | /* 61 | * Update context to reflect the concatenation of another buffer full 62 | * of bytes. 63 | */ 64 | void MD5Update(ctx, buf, len) 65 | struct MD5Context *ctx; unsigned char *buf; unsigned len; 66 | { 67 | uint32 t; 68 | 69 | /* Update bitcount */ 70 | 71 | t = ctx->bits[0]; 72 | if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) 73 | ctx->bits[1]++; /* Carry from low to high */ 74 | ctx->bits[1] += len >> 29; 75 | 76 | t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ 77 | 78 | /* Handle any leading odd-sized chunks */ 79 | 80 | if (t) { 81 | unsigned char *p = (unsigned char *) ctx->in + t; 82 | 83 | t = 64 - t; 84 | if (len < t) { 85 | memcpy(p, buf, len); 86 | return; 87 | } 88 | memcpy(p, buf, t); 89 | byteReverse(ctx->in, 16); 90 | MD5Transform(ctx->buf, (uint32 *) ctx->in); 91 | buf += t; 92 | len -= t; 93 | } 94 | /* Process data in 64-byte chunks */ 95 | 96 | while (len >= 64) { 97 | memcpy(ctx->in, buf, 64); 98 | byteReverse(ctx->in, 16); 99 | MD5Transform(ctx->buf, (uint32 *) ctx->in); 100 | buf += 64; 101 | len -= 64; 102 | } 103 | 104 | /* Handle any remaining bytes of data. */ 105 | 106 | memcpy(ctx->in, buf, len); 107 | } 108 | 109 | /* 110 | * Final wrapup - pad to 64-byte boundary with the bit pattern 111 | * 1 0* (64-bit count of bits processed, MSB-first) 112 | */ 113 | void MD5Final(digest, ctx) 114 | unsigned char digest[16]; struct MD5Context *ctx; 115 | { 116 | unsigned count; 117 | unsigned char *p; 118 | 119 | /* Compute number of bytes mod 64 */ 120 | count = (ctx->bits[0] >> 3) & 0x3F; 121 | 122 | /* Set the first char of padding to 0x80. This is safe since there is 123 | always at least one byte free */ 124 | p = ctx->in + count; 125 | *p++ = 0x80; 126 | 127 | /* Bytes of padding needed to make 64 bytes */ 128 | count = 64 - 1 - count; 129 | 130 | /* Pad out to 56 mod 64 */ 131 | if (count < 8) { 132 | /* Two lots of padding: Pad the first block to 64 bytes */ 133 | memset(p, 0, count); 134 | byteReverse(ctx->in, 16); 135 | MD5Transform(ctx->buf, (uint32 *) ctx->in); 136 | 137 | /* Now fill the next block with 56 bytes */ 138 | memset(ctx->in, 0, 56); 139 | } else { 140 | /* Pad block to 56 bytes */ 141 | memset(p, 0, count - 8); 142 | } 143 | byteReverse(ctx->in, 14); 144 | 145 | /* Append length in bits and transform */ 146 | // ((uint32 *) ctx->in)[14] = ctx->bits[0]; 147 | // ((uint32 *) ctx->in)[15] = ctx->bits[1]; 148 | memcpy(ctx->in + 56, ctx->bits, 8); 149 | 150 | MD5Transform(ctx->buf, (uint32 *) ctx->in); 151 | byteReverse((unsigned char *) ctx->buf, 4); 152 | memcpy(digest, ctx->buf, 16); 153 | // memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ 154 | memset(ctx, 0, sizeof(*ctx)); // Fix by dndx to let gcc happy 155 | } 156 | 157 | 158 | /* The four core functions - F1 is optimized somewhat */ 159 | 160 | /* #define F1(x, y, z) (x & y | ~x & z) */ 161 | #define F1(x, y, z) (z ^ (x & (y ^ z))) 162 | #define F2(x, y, z) F1(z, x, y) 163 | #define F3(x, y, z) (x ^ y ^ z) 164 | #define F4(x, y, z) (y ^ (x | ~z)) 165 | 166 | /* This is the central step in the MD5 algorithm. */ 167 | #define MD5STEP(f, w, x, y, z, data, s) \ 168 | ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) 169 | 170 | /* 171 | * The core of the MD5 algorithm, this alters an existing MD5 hash to 172 | * reflect the addition of 16 longwords of new data. MD5Update blocks 173 | * the data and converts bytes into longwords for this routine. 174 | */ 175 | void MD5Transform(buf, in) 176 | uint32 buf[4]; uint32 in[16]; 177 | { 178 | register uint32 a, b, c, d; 179 | 180 | a = buf[0]; 181 | b = buf[1]; 182 | c = buf[2]; 183 | d = buf[3]; 184 | 185 | MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); 186 | MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); 187 | MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); 188 | MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); 189 | MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); 190 | MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); 191 | MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); 192 | MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); 193 | MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); 194 | MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); 195 | MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); 196 | MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); 197 | MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); 198 | MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); 199 | MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); 200 | MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); 201 | 202 | MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); 203 | MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); 204 | MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); 205 | MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); 206 | MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); 207 | MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); 208 | MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); 209 | MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); 210 | MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); 211 | MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); 212 | MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); 213 | MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); 214 | MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); 215 | MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); 216 | MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); 217 | MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); 218 | 219 | MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); 220 | MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); 221 | MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); 222 | MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); 223 | MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); 224 | MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); 225 | MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); 226 | MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); 227 | MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); 228 | MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); 229 | MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); 230 | MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); 231 | MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); 232 | MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); 233 | MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); 234 | MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); 235 | 236 | MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); 237 | MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); 238 | MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); 239 | MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); 240 | MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); 241 | MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); 242 | MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); 243 | MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); 244 | MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); 245 | MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); 246 | MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); 247 | MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); 248 | MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); 249 | MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); 250 | MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); 251 | MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); 252 | 253 | buf[0] += a; 254 | buf[1] += b; 255 | buf[2] += c; 256 | buf[3] += d; 257 | } 258 | -------------------------------------------------------------------------------- /md5.h: -------------------------------------------------------------------------------- 1 | #ifndef MD5_H 2 | #define MD5_H 3 | 4 | #include 5 | 6 | /* The following tests optimise behaviour on little-endian 7 | machines, where there is no need to reverse the byte order 8 | of 32 bit words in the MD5 computation. By default, 9 | HIGHFIRST is defined, which indicates we're running on a 10 | big-endian (most significant byte first) machine, on which 11 | the byteReverse function in md5.c must be invoked. However, 12 | byteReverse is coded in such a way that it is an identity 13 | function when run on a little-endian machine, so calling it 14 | on such a platform causes no harm apart from wasting time. 15 | If the platform is known to be little-endian, we speed 16 | things up by undefining HIGHFIRST, which defines 17 | byteReverse as a null macro. Doing things in this manner 18 | insures we work on new platforms regardless of their byte 19 | order. */ 20 | 21 | #define HIGHFIRST 22 | 23 | #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) 24 | #undef HIGHFIRST 25 | #endif 26 | 27 | /* On machines where "long" is 64 bits, we need to declare 28 | uint32 as something guaranteed to be 32 bits. */ 29 | 30 | typedef uint32_t uint32; 31 | 32 | struct MD5Context { 33 | uint32 buf[4]; 34 | uint32 bits[2]; 35 | unsigned char in[64]; 36 | }; 37 | 38 | extern void MD5Init(); 39 | extern void MD5Update(); 40 | extern void MD5Final(); 41 | extern void MD5Transform(); 42 | 43 | /* 44 | * This is needed to make RSAREF happy on some MS-DOS compilers. 45 | */ 46 | typedef struct MD5Context MD5_CTX; 47 | 48 | /* Define CHECK_HARDWARE_PROPERTIES to have main.c verify 49 | byte order and uint32 settings. */ 50 | #define CHECK_HARDWARE_PROPERTIES 51 | 52 | #endif /* !MD5_H */ 53 | -------------------------------------------------------------------------------- /pytest/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server":"localhost", 3 | "server_port":8888, 4 | "local_port":1080, 5 | "password":"foobar!", 6 | "timeout":60 7 | } 8 | -------------------------------------------------------------------------------- /pytest/local.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2012 clowwindy 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | import sys 24 | 25 | try: 26 | import gevent, gevent.monkey 27 | gevent.monkey.patch_all(dns=gevent.version_info[0]>=1) 28 | except ImportError: 29 | gevent = None 30 | print >>sys.stderr, 'warning: gevent not found, using threading instead' 31 | 32 | import socket 33 | import select 34 | import SocketServer 35 | import struct 36 | import string 37 | import hashlib 38 | import os 39 | import json 40 | import logging 41 | import getopt 42 | 43 | def get_table(key): 44 | m = hashlib.md5() 45 | m.update(key) 46 | s = m.digest() 47 | (a, b) = struct.unpack('H', addr_port) 128 | try: 129 | reply = "\x05\x00\x00\x01" 130 | reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 2222) 131 | self.wfile.write(reply) 132 | # reply immediately 133 | if '-6' in sys.argv[1:]: 134 | remote = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) 135 | else: 136 | remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 137 | remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 138 | remote.connect((SERVER, REMOTE_PORT)) 139 | self.send_encrypt(remote, addr_to_send) 140 | logging.info('connecting %s:%d' % (addr, port[0])) 141 | except socket.error, e: 142 | logging.warn(e) 143 | return 144 | self.handle_tcp(sock, remote) 145 | except socket.error, e: 146 | logging.warn(e) 147 | 148 | 149 | if __name__ == '__main__': 150 | os.chdir(os.path.dirname(__file__) or '.') 151 | print 'shadowsocks v0.9' 152 | 153 | with open('config.json', 'rb') as f: 154 | config = json.load(f) 155 | SERVER = config['server'] 156 | REMOTE_PORT = config['server_port'] 157 | PORT = config['local_port'] 158 | KEY = config['password'] 159 | 160 | optlist, args = getopt.getopt(sys.argv[1:], 's:p:k:l:') 161 | for key, value in optlist: 162 | if key == '-p': 163 | REMOTE_PORT = int(value) 164 | elif key == '-k': 165 | KEY = value 166 | elif key == '-l': 167 | PORT = int(value) 168 | elif key == '-s': 169 | SERVER = value 170 | 171 | logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s', 172 | datefmt='%Y-%m-%d %H:%M:%S', filemode='a+') 173 | 174 | encrypt_table = ''.join(get_table(KEY)) 175 | decrypt_table = string.maketrans(encrypt_table, string.maketrans('', '')) 176 | try: 177 | server = ThreadingTCPServer(('', PORT), Socks5Server) 178 | logging.info("starting server at port %d ..." % PORT) 179 | server.serve_forever() 180 | except socket.error, e: 181 | logging.error(e) 182 | 183 | -------------------------------------------------------------------------------- /pytest/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import sys 5 | import select 6 | import struct 7 | import hashlib 8 | import string 9 | from subprocess import Popen, PIPE 10 | 11 | p1 = Popen(['../server'], shell=False, bufsize=0, stdin=PIPE, 12 | stdout=PIPE, stderr=PIPE, close_fds=True) 13 | p2 = Popen(['python', 'local.py'], shell=False, bufsize=0, stdin=PIPE, 14 | stdout=PIPE, stderr=PIPE, close_fds=True) 15 | p3 = None 16 | 17 | try: 18 | ready_count = 0 19 | fdset = [p1.stdout, p2.stdout, p1.stderr, p2.stderr] 20 | while True: 21 | r, w, e = select.select(fdset, [], fdset) 22 | if e: 23 | break 24 | 25 | for fd in r: 26 | line = fd.readline() 27 | sys.stderr.write(line) 28 | if line.find('at port') >= 0 or line.find('Listening') >= 0: 29 | ready_count += 1 30 | 31 | if ready_count == 2 and p3 is None: 32 | p3 = Popen(['curl', 'http://www.google.com/', '-v', '-L', 33 | '--socks5-hostname', '127.0.0.1:1080'], shell=False, 34 | bufsize=0, close_fds=True) 35 | break 36 | 37 | if p3 is not None: 38 | r = p3.wait() 39 | if r == 0: 40 | print 'test passed' 41 | sys.exit(r) 42 | 43 | finally: 44 | for p in [p1, p2]: 45 | try: 46 | p.kill() 47 | except OSError: 48 | pass 49 | 50 | sys.exit(-1) 51 | -------------------------------------------------------------------------------- /rc4.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * rc4.c 4 | * 5 | * Copyright (c) 1996-2000 Whistle Communications, Inc. 6 | * All rights reserved. 7 | * 8 | * Subject to the following obligations and disclaimer of warranty, use and 9 | * redistribution of this software, in source or object code forms, with or 10 | * without modifications are expressly permitted by Whistle Communications; 11 | * provided, however, that: 12 | * 1. Any and all reproductions of the source or object code must include the 13 | * copyright notice above and the following disclaimer of warranties; and 14 | * 2. No rights are granted, in any manner or form, to use Whistle 15 | * Communications, Inc. trademarks, including the mark "WHISTLE 16 | * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 | * such appears in the above copyright notice or in the software. 18 | * 19 | * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 | * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 | * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 | * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 | * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 | * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 | * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 | * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 | * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 | * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 | * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 | * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 | * OF SUCH DAMAGE. 36 | * 37 | * $FreeBSD: src/sys/crypto/rc4/rc4.c,v 1.2.2.1 2000/04/18 04:48:31 archie Exp $ 38 | */ 39 | #include 40 | #include "rc4.h" 41 | 42 | static inline void 43 | swap_bytes(u_char *a, u_char *b) 44 | { 45 | u_char temp; 46 | 47 | temp = *a; 48 | *a = *b; 49 | *b = temp; 50 | } 51 | 52 | /* 53 | * Initialize an RC4 state buffer using the supplied key, 54 | * which can have arbitrary length. 55 | */ 56 | void 57 | rc4_init(struct rc4_state *const state, const u_char *key, int keylen) 58 | { 59 | u_char j; 60 | int i; 61 | 62 | /* Initialize state with identity permutation */ 63 | for (i = 0; i < 256; i++) 64 | state->perm[i] = (u_char)i; 65 | state->index1 = 0; 66 | state->index2 = 0; 67 | 68 | /* Randomize the permutation using key data */ 69 | for (j = i = 0; i < 256; i++) { 70 | j += state->perm[i] + key[i % keylen]; 71 | swap_bytes(&state->perm[i], &state->perm[j]); 72 | } 73 | } 74 | 75 | /* 76 | * Encrypt some data using the supplied RC4 state buffer. 77 | * The input and output buffers may be the same buffer. 78 | * Since RC4 is a stream cypher, this function is used 79 | * for both encryption and decryption. 80 | */ 81 | void 82 | rc4_crypt(struct rc4_state *const state, 83 | const u_char *inbuf, u_char *outbuf, int buflen) 84 | { 85 | int i; 86 | u_char j; 87 | 88 | for (i = 0; i < buflen; i++) { 89 | 90 | /* Update modification indicies */ 91 | state->index1++; 92 | state->index2 += state->perm[state->index1]; 93 | 94 | /* Modify permutation */ 95 | swap_bytes(&state->perm[state->index1], 96 | &state->perm[state->index2]); 97 | 98 | /* Encrypt/decrypt next byte */ 99 | j = state->perm[state->index1] + state->perm[state->index2]; 100 | outbuf[i] = inbuf[i] ^ state->perm[j]; 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /rc4.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * rc4.h 4 | * 5 | * Copyright (c) 1996-2000 Whistle Communications, Inc. 6 | * All rights reserved. 7 | * 8 | * Subject to the following obligations and disclaimer of warranty, use and 9 | * redistribution of this software, in source or object code forms, with or 10 | * without modifications are expressly permitted by Whistle Communications; 11 | * provided, however, that: 12 | * 1. Any and all reproductions of the source or object code must include the 13 | * copyright notice above and the following disclaimer of warranties; and 14 | * 2. No rights are granted, in any manner or form, to use Whistle 15 | * Communications, Inc. trademarks, including the mark "WHISTLE 16 | * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 | * such appears in the above copyright notice or in the software. 18 | * 19 | * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 | * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 | * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 | * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 | * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 | * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 | * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 | * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 | * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 | * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 | * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 | * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 | * OF SUCH DAMAGE. 36 | * 37 | * $FreeBSD: src/sys/crypto/rc4/rc4.h,v 1.2.2.1 2000/04/18 04:48:32 archie Exp $ 38 | */ 39 | 40 | #ifndef RC4_H_ 41 | #define RC4_H_ 42 | 43 | typedef uint8_t u_char; 44 | 45 | struct rc4_state { 46 | u_char perm[256]; 47 | u_char index1; 48 | u_char index2; 49 | }; 50 | 51 | void rc4_init(struct rc4_state *state, const u_char *key, int keylen); 52 | void rc4_crypt(struct rc4_state *state, 53 | const u_char *inbuf, u_char *outbuf, int buflen); 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /server.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 dndx (idndx.com) 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "config.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "encrypt.h" 30 | #include "utils.h" 31 | #include "server.h" 32 | 33 | struct encryptor crypto; 34 | 35 | static void established_free_cb(uv_handle_t* handle) 36 | { 37 | server_ctx *ctx = (server_ctx *)handle->data; 38 | if (!ctx->encoder.encrypt_table) 39 | destroy_encryptor(&ctx->encoder); 40 | free(ctx); 41 | } 42 | 43 | // Close remote and free ctx 44 | static void client_established_shutdown_complete(uv_shutdown_t* req, int status) 45 | { 46 | server_ctx *ctx = (server_ctx *)req->data; 47 | uv_close((uv_handle_t*)(void *)&ctx->client, established_free_cb); 48 | free(req); 49 | } 50 | 51 | // Close client and free ctx 52 | static void remote_established_shutdown_complete(uv_shutdown_t* req, int status) 53 | { 54 | server_ctx *ctx = (server_ctx *)req->data; 55 | uv_close((uv_handle_t*)(void *)&ctx->remote, established_free_cb); 56 | free(req); 57 | } 58 | 59 | // Shutdown client 60 | static void remote_established_close_cb(uv_handle_t* handle) 61 | { 62 | server_ctx *ctx = (server_ctx *)handle->data; 63 | uv_read_stop((uv_stream_t *)(void *)&ctx->client); 64 | uv_shutdown_t *req = malloc(sizeof(uv_shutdown_t)); 65 | req->data = ctx; 66 | 67 | int n = uv_shutdown(req, (uv_stream_t *)(void *)&ctx->client, client_established_shutdown_complete); 68 | if (n) { 69 | LOGE("Shutdown client side write stream failed!"); 70 | uv_close((uv_handle_t*)(void *)&ctx->client, established_free_cb); 71 | free(req); 72 | } 73 | } 74 | 75 | // Close client then close remote 76 | static void client_established_close_cb(uv_handle_t* handle) 77 | { 78 | server_ctx *ctx = (server_ctx *)handle->data; 79 | uv_read_stop((uv_stream_t *)(void *)&ctx->remote); 80 | uv_shutdown_t *req = malloc(sizeof(uv_shutdown_t)); 81 | req->data = ctx; 82 | 83 | int n = uv_shutdown(req, (uv_stream_t *)(void *)&ctx->remote, remote_established_shutdown_complete); 84 | if (n) { 85 | LOGE("Shutdown remote side write stream failed!"); 86 | uv_close((uv_handle_t*)(void *)&ctx->remote, established_free_cb); 87 | free(req); 88 | } 89 | } 90 | 91 | static void remote_established_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) 92 | { 93 | int n; 94 | server_ctx *ctx = (server_ctx *)stream->data; 95 | 96 | if (nread < 0) { // EOF 97 | if (buf.len) // If buf is set, we need to free it 98 | free(buf.base); 99 | LOGCONN(&ctx->remote, "Remote %s EOF, closing"); 100 | HANDLE_CLOSE((uv_handle_t*)stream, remote_established_close_cb); // Then close the connection 101 | return; 102 | } else if (!nread) { 103 | free(buf.base); 104 | return; 105 | } 106 | 107 | shadow_encrypt((uint8_t *)buf.base, &ctx->encoder, nread); 108 | 109 | uv_write_t *req = (uv_write_t *)malloc(sizeof(uv_write_t)); 110 | if (!req) { 111 | HANDLE_CLOSE((uv_handle_t*)stream, remote_established_close_cb); 112 | FATAL("malloc() failed!"); 113 | } 114 | req->data = buf.base; 115 | buf.len = nread; 116 | n = uv_write(req, (uv_stream_t *)(void *)&ctx->client, &buf, 1, after_write_cb); 117 | if (n) { 118 | LOGE("Write to client failed!"); 119 | free(req); 120 | free(buf.base); 121 | HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); 122 | return; 123 | } 124 | if (ctx->buffer_len == MAX_PENDING_PER_CONN - 1) { // buffer_len used as pending write request counter 125 | uv_read_stop(stream); 126 | } 127 | ctx->buffer_len++; 128 | } 129 | 130 | static void after_write_cb(uv_write_t* req, int status) 131 | { 132 | server_ctx *ctx = (server_ctx *)req->handle->data; 133 | if (status) { 134 | if (uv_last_error(req->handle->loop).code != UV_ECANCELED) { 135 | if ((uv_tcp_t *)req->handle == &ctx->client) { 136 | HANDLE_CLOSE((uv_handle_t *)req->handle, client_established_close_cb); 137 | } else { 138 | HANDLE_CLOSE((uv_handle_t *)req->handle, remote_established_close_cb); 139 | } 140 | } 141 | free(req->data); // Free buffer 142 | free(req); 143 | return; 144 | } 145 | 146 | if ((uv_tcp_t *)req->handle == &ctx->client && !uv_is_closing((uv_handle_t *)(void *)&ctx->remote)) { 147 | if (ctx->buffer_len <= MAX_PENDING_PER_CONN) { 148 | int n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); 149 | if (n) { 150 | SHOW_UV_ERROR(ctx->client.loop); 151 | HANDLE_CLOSE((uv_handle_t *)(void *)&ctx->remote, remote_established_close_cb); 152 | free(req->data); // Free buffer 153 | free(req); 154 | return; 155 | } 156 | } 157 | ctx->buffer_len--; 158 | } 159 | 160 | free(req->data); // Free buffer 161 | free(req); 162 | } 163 | 164 | static void client_established_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) 165 | { 166 | int n; 167 | server_ctx *ctx = (server_ctx *)stream->data; 168 | 169 | if (nread < 0) { // EOF 170 | if (buf.len) // If buf is set, we need to free it 171 | free(buf.base); 172 | LOGCONN(&ctx->client, "Client %s EOF, closing"); 173 | HANDLE_CLOSE((uv_handle_t*)stream, client_established_close_cb); // Then close the connection 174 | return; 175 | } else if (!nread) { 176 | free(buf.base); 177 | return; 178 | } 179 | 180 | shadow_decrypt((uint8_t *)buf.base, &ctx->encoder, nread); 181 | 182 | uv_write_t *req = (uv_write_t *)malloc(sizeof(uv_write_t)); 183 | if (!req) { 184 | HANDLE_CLOSE((uv_handle_t*)stream, client_established_close_cb); 185 | FATAL("malloc() failed!"); 186 | } 187 | req->data = buf.base; 188 | buf.len = nread; 189 | n = uv_write(req, (uv_stream_t *)(void *)&ctx->remote, &buf, 1, after_write_cb); 190 | if (n) { 191 | LOGE("Write to remote failed!"); 192 | free(req); 193 | free(buf.base); 194 | HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); 195 | return; 196 | } 197 | 198 | // LOGI("Writed to remote"); 199 | } 200 | 201 | static uv_buf_t established_alloc_cb(uv_handle_t* handle, size_t suggested_size) 202 | { 203 | #ifdef BUFFER_LIMIT 204 | void *buf = malloc(BUFFER_LIMIT); 205 | #else 206 | void *buf = malloc(suggested_size); 207 | #endif /* BUFFER_LIMIT */ 208 | if (!buf) { 209 | FATAL("malloc() failed!"); 210 | } 211 | #ifdef BUFFER_LIMIT 212 | return uv_buf_init(buf, BUFFER_LIMIT); 213 | #else 214 | return uv_buf_init(buf, suggested_size); 215 | #endif /* BUFFER_LIMIT */ 216 | } 217 | 218 | // Failed during handshake 219 | static void handshake_client_close_cb(uv_handle_t* handle) 220 | { 221 | server_ctx *ctx = (server_ctx *)handle->data; 222 | if (ctx->handshake_buffer) { 223 | free(ctx->handshake_buffer); 224 | ctx->handshake_buffer = NULL; 225 | } 226 | if (!ctx->encoder.encrypt_table) 227 | destroy_encryptor(&ctx->encoder); 228 | free(ctx); 229 | } 230 | 231 | static void connect_to_remote_cb(uv_connect_t* req, int status) 232 | { 233 | server_ctx *ctx = (server_ctx *)req->data; 234 | if (status) { 235 | if (uv_last_error(req->handle->loop).code != UV_ECANCELED) { 236 | SHOW_UV_ERROR(ctx->client.loop); 237 | uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); 238 | free(ctx->handshake_buffer); 239 | free(req); 240 | } 241 | return; 242 | } 243 | 244 | free(req); 245 | 246 | LOGCONN(&ctx->remote, "Connected to %s"); 247 | 248 | uv_buf_t buf; 249 | buf.base = (char *)ctx->handshake_buffer; 250 | buf.len = HANDSHAKE_BUFFER_SIZE; 251 | 252 | if (!ctx->buffer_len) { 253 | free(ctx->handshake_buffer); 254 | } else { 255 | uv_write_t *wreq = (uv_write_t *)malloc(sizeof(uv_write_t)); 256 | if (!wreq) { 257 | uv_close((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); 258 | FATAL("malloc() failed!"); 259 | } 260 | wreq->data = buf.base; 261 | buf.len = ctx->buffer_len; 262 | int n = uv_write(wreq, (uv_stream_t *)(void *)&ctx->remote, &buf, 1, after_write_cb); 263 | if (n) { 264 | LOGE("Write to remote failed!"); 265 | free(wreq); 266 | uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); 267 | return; 268 | } 269 | } 270 | 271 | ctx->handshake_buffer = NULL; 272 | ctx->buffer_len = 0; 273 | 274 | int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, established_alloc_cb, client_established_read_cb); 275 | if (n) { 276 | SHOW_UV_ERROR(ctx->client.loop); 277 | uv_close((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); 278 | return; 279 | } 280 | n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); 281 | if (n) { 282 | SHOW_UV_ERROR(ctx->client.loop); 283 | uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); 284 | return; 285 | } 286 | } 287 | 288 | static int do_handshake(uv_stream_t *stream) 289 | { 290 | server_ctx *ctx = (server_ctx *)stream->data; 291 | int n; 292 | 293 | if (!ctx->remote_ip_type) { 294 | if (ctx->buffer_len < 2) // Not interpretable 295 | return 1; 296 | uint8_t addrtype = ctx->handshake_buffer[0]; 297 | if (addrtype == ADDRTYPE_IPV4) { 298 | if (ctx->buffer_len < 5) 299 | return 1; 300 | memcpy(ctx->remote_ip, ctx->handshake_buffer + 1, 4); 301 | ctx->remote_ip_type = ADDRTYPE_IPV4; 302 | SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 5, HANDSHAKE_BUFFER_SIZE); 303 | ctx->buffer_len -= 5; 304 | // TODO: Print out 305 | } else if (addrtype == ADDRTYPE_DOMAIN) { 306 | uint8_t domain_len = ctx->handshake_buffer[1]; 307 | if (!domain_len) { // Domain length is zero 308 | LOGE("Domain length is zero"); 309 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); 310 | return -1; 311 | } 312 | if (ctx->buffer_len < domain_len + 2) 313 | return 1; 314 | char domain[domain_len+1]; 315 | domain[domain_len] = 0; 316 | memcpy(domain, ctx->handshake_buffer+2, domain_len); 317 | 318 | uv_getaddrinfo_t *resolver = (uv_getaddrinfo_t *)malloc(sizeof(uv_getaddrinfo_t)); 319 | if (!resolver) { 320 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); 321 | FATAL("malloc() failed!"); 322 | } 323 | resolver->data = ctx; // We need to locate back the stream 324 | LOGI("Domain is: %s", domain); 325 | n = uv_getaddrinfo(stream->loop, resolver, client_handshake_domain_resolved, domain, NULL, NULL); 326 | if (n) { 327 | SHOW_UV_ERROR(stream->loop); 328 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); 329 | free(resolver); 330 | return -1; 331 | } 332 | SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 2+domain_len, HANDSHAKE_BUFFER_SIZE); 333 | ctx->buffer_len -= 2 + domain_len; 334 | uv_read_stop(stream); // Pause the reading process, wait for resolve result 335 | return 1; 336 | } else { // Unsupported addrtype 337 | LOGI("addrtype unknown, closing"); 338 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); 339 | return -1; 340 | } 341 | } // !ctx->remote_ip 342 | 343 | if (!ctx->remote_port) { 344 | if (ctx->buffer_len < 2) // Not interpretable 345 | return 1; 346 | ctx->remote_port = *((uint16_t *)ctx->handshake_buffer); 347 | if (!ctx->remote_port) { 348 | LOGE("Remote port is zero"); 349 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); 350 | return -1; 351 | } 352 | SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 2, HANDSHAKE_BUFFER_SIZE); 353 | ctx->buffer_len -= 2; 354 | // Try connect now 355 | n = uv_tcp_init(stream->loop, &ctx->remote); 356 | if (n) 357 | SHOW_UV_ERROR_AND_EXIT(stream->loop); 358 | uv_connect_t *req = (uv_connect_t *)malloc(sizeof(uv_connect_t)); 359 | if (!req) { 360 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); 361 | FATAL("malloc() failed!"); 362 | } 363 | req->data = ctx; 364 | 365 | if (ctx->remote_ip_type == ADDRTYPE_IPV4) { 366 | struct sockaddr_in remote; 367 | memset(&remote, 0, sizeof(remote)); 368 | remote.sin_family = AF_INET; 369 | memcpy(&remote.sin_addr.s_addr, ctx->remote_ip, 4); 370 | remote.sin_port = ctx->remote_port; 371 | 372 | n = uv_tcp_connect(req, &ctx->remote, remote, connect_to_remote_cb); 373 | } else if (ctx->remote_ip_type == ADDRTYPE_IPV6) { 374 | struct sockaddr_in6 remote; 375 | memset(&remote, 0, sizeof(remote)); 376 | remote.sin6_family = AF_INET6; 377 | memcpy(&remote.sin6_addr.s6_addr, ctx->remote_ip, 16); 378 | remote.sin6_port = ctx->remote_port; 379 | 380 | n = uv_tcp_connect6(req, &ctx->remote, remote, connect_to_remote_cb); 381 | } else { 382 | FATAL("addrtype unknown!"); 383 | } 384 | 385 | if (n) { 386 | SHOW_UV_ERROR(stream->loop); 387 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); 388 | free(req); 389 | return -1; 390 | } 391 | } 392 | 393 | uv_read_stop(stream); 394 | return 0; 395 | } 396 | 397 | static void client_handshake_domain_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) 398 | { 399 | server_ctx *ctx = (server_ctx *)resolver->data; 400 | if (status) { 401 | if (uv_last_error(ctx->client.loop).code == UV_ENOENT) { 402 | LOGI("Resolve error, NXDOMAIN"); 403 | } else { 404 | SHOW_UV_ERROR(ctx->client.loop); 405 | } 406 | uv_close((uv_handle_t*)(void *)&ctx->client, handshake_client_close_cb); 407 | uv_freeaddrinfo(res); 408 | free(resolver); 409 | return; 410 | } 411 | 412 | if (res->ai_family == AF_INET) { // IPv4 413 | memcpy(ctx->remote_ip, &((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr, 4); 414 | ctx->remote_ip_type = ADDRTYPE_IPV4; 415 | } else if (res->ai_family == AF_INET6) { 416 | memcpy(ctx->remote_ip, &((struct sockaddr_in6*)(res->ai_addr))->sin6_addr.s6_addr, 16); 417 | ctx->remote_ip_type = ADDRTYPE_IPV6; 418 | } else { 419 | FATAL("dns resolve failed!"); 420 | } 421 | 422 | if (do_handshake((uv_stream_t *)(void *)&ctx->client) == 1) { 423 | int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, client_handshake_alloc_cb, client_handshake_read_cb); 424 | if (n) { 425 | uv_close((uv_handle_t*)(void *)&ctx->client, handshake_client_close_cb); 426 | SHOW_UV_ERROR(ctx->client.loop); 427 | } 428 | } 429 | 430 | uv_freeaddrinfo(res); 431 | free(resolver); 432 | } 433 | 434 | static void client_handshake_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) 435 | { 436 | server_ctx *ctx = (server_ctx *)stream->data; 437 | 438 | if (nread < 0) { 439 | if (buf.len) // If buf is set, we need to free it 440 | free(buf.base); 441 | uv_close((uv_handle_t*)stream, handshake_client_close_cb); // Then close the connection 442 | return; 443 | } else if (!nread) { 444 | free(buf.base); 445 | return; 446 | } 447 | 448 | memcpy(ctx->handshake_buffer + ctx->buffer_len, buf.base, nread); 449 | shadow_decrypt(ctx->handshake_buffer + ctx->buffer_len, &ctx->encoder, nread); 450 | 451 | ctx->buffer_len += nread; 452 | 453 | if (!ctx->handshake_buffer) { 454 | FATAL("Should not call this anymore"); 455 | } 456 | free(buf.base); 457 | 458 | do_handshake(stream); 459 | } 460 | 461 | static uv_buf_t client_handshake_alloc_cb(uv_handle_t* handle, size_t suggested_size) 462 | { 463 | server_ctx *ctx = (server_ctx *)handle->data; 464 | void *buf = malloc(HANDSHAKE_BUFFER_SIZE - ctx->buffer_len); 465 | if (!buf) { 466 | HANDLE_CLOSE(handle, handshake_client_close_cb); 467 | FATAL("malloc() failed!"); 468 | } 469 | return uv_buf_init(buf, HANDSHAKE_BUFFER_SIZE - ctx->buffer_len); 470 | } 471 | 472 | static void connect_cb(uv_stream_t* listener, int status) 473 | { 474 | int n; 475 | 476 | if (status) { 477 | SHOW_UV_ERROR(listener->loop); 478 | return; 479 | } 480 | 481 | server_ctx *ctx = calloc(1, sizeof(server_ctx)); 482 | ctx->handshake_buffer = calloc(1, HANDSHAKE_BUFFER_SIZE); 483 | 484 | if (!ctx || !ctx->handshake_buffer) 485 | FATAL("malloc() failed!"); 486 | 487 | ctx->client.data = ctx; 488 | ctx->remote.data = ctx; 489 | 490 | make_encryptor(&crypto, &ctx->encoder, 0, NULL); 491 | 492 | n = uv_tcp_init(listener->loop, &ctx->client); 493 | if (n) 494 | SHOW_UV_ERROR_AND_EXIT(listener->loop); 495 | 496 | n = uv_accept(listener, (uv_stream_t *)(void *)&ctx->client); 497 | if (n) 498 | SHOW_UV_ERROR_AND_EXIT(listener->loop); 499 | 500 | n = uv_tcp_nodelay(&ctx->client, 1); 501 | if (n) 502 | SHOW_UV_ERROR_AND_EXIT(listener->loop); 503 | 504 | #ifdef KEEPALIVE_TIMEOUT 505 | n = uv_tcp_keepalive(&ctx->client, 1, KEEPALIVE_TIMEOUT); 506 | if (n) 507 | SHOW_UV_ERROR_AND_EXIT(listener->loop); 508 | #endif /* KEEPALIVE_TIMEOUT */ 509 | 510 | n = uv_read_start((uv_stream_t *)(void *)&ctx->client, client_handshake_alloc_cb, client_handshake_read_cb); 511 | if (n) 512 | SHOW_UV_ERROR_AND_EXIT(listener->loop); 513 | 514 | LOGCONN(&ctx->client, "Accepted connection from %s"); 515 | } 516 | 517 | int main(int argc, char *argv[]) 518 | { 519 | char **newargv = uv_setup_args(argc, argv); 520 | char *server_listen = SERVER_LISTEN; 521 | int server_port = SERVER_PORT; 522 | uint8_t *password = (uint8_t *)PASSWORD; 523 | uint8_t crypt_method = CRYPTO_METHOD; 524 | char *pid_path = PID_FILE; 525 | 526 | char opt; 527 | while((opt = getopt(argc, newargv, "l:p:k:f:m:")) != -1) { // not portable to windows 528 | switch(opt) { 529 | case 'l': 530 | server_listen = optarg; 531 | break; 532 | case 'p': 533 | server_port = atoi(optarg); 534 | break; 535 | case 'k': 536 | password = (uint8_t *)optarg; 537 | break; 538 | case 'f': 539 | pid_path = optarg; 540 | break; 541 | case 'm': 542 | if (!strcmp("rc4", optarg)) 543 | crypt_method = METHOD_RC4; 544 | else if (!strcmp("shadow", optarg)) 545 | crypt_method = METHOD_SHADOWCRYPT; 546 | break; 547 | default: 548 | fprintf(stderr, USAGE, newargv[0]); 549 | abort(); 550 | } 551 | } 552 | 553 | FILE *pid_file = fopen(pid_path, "wb"); 554 | if (!pid_file) 555 | FATAL("fopen failed, %s", strerror(errno)); 556 | fprintf(pid_file, "%d", getpid()); 557 | fclose(pid_file); 558 | 559 | char *process_title = malloc(PROCESS_TITLE_LENGTH); // we do not like waste memory 560 | if (!process_title) 561 | FATAL("malloc() failed!"); 562 | snprintf(process_title, PROCESS_TITLE_LENGTH, PROCESS_TITLE, server_port); 563 | uv_set_process_title(process_title); 564 | free(process_title); 565 | 566 | LOGI(WELCOME_MESSAGE); 567 | 568 | if (crypt_method == METHOD_SHADOWCRYPT) 569 | LOGI("Using shadowcrypt crypto"); 570 | else if (crypt_method == METHOD_RC4) 571 | LOGI("Using RC4 crypto"); 572 | else 573 | FATAL("Crypto unknown!"); 574 | 575 | make_encryptor(NULL, &crypto, crypt_method, password); 576 | 577 | LOGI("Crypto ready"); 578 | 579 | int n; 580 | uv_loop_t *loop = uv_default_loop(); 581 | uv_tcp_t listener; 582 | 583 | struct sockaddr_in6 addr = uv_ip6_addr(server_listen, server_port); 584 | 585 | n = uv_tcp_init(loop, &listener); 586 | if (n) 587 | SHOW_UV_ERROR_AND_EXIT(loop); 588 | 589 | n = uv_tcp_bind6(&listener, addr); 590 | if (n) 591 | SHOW_UV_ERROR_AND_EXIT(loop); 592 | 593 | n = uv_listen((uv_stream_t*)(void *)&listener, 5, connect_cb); 594 | if (n) 595 | SHOW_UV_ERROR_AND_EXIT(loop); 596 | LOGI("Listening on %s:%d", server_listen, server_port); 597 | 598 | #ifndef NDEBUG 599 | setup_signal_handler(loop); 600 | #endif /* !NDEBUG */ 601 | 602 | return uv_run(loop, UV_RUN_DEFAULT); 603 | } 604 | -------------------------------------------------------------------------------- /server.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 dndx (idndx.com) 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef SERVER_H_ 22 | #define SERVER_H_ 23 | 24 | #include 25 | 26 | #define SHADOW_MAJOR_VERSION 0 27 | #define SHADOW_MINOR_VERSION 2 28 | #define WELCOME_MESSAGE "Shadowsocks Version:" TOSTR(SHADOW_MAJOR_VERSION) "." TOSTR(SHADOW_MINOR_VERSION) \ 29 | " libuv(" TOSTR(UV_VERSION_MAJOR) "." TOSTR(UV_VERSION_MINOR) ")"\ 30 | " Written by Dndx(idndx.com)" 31 | #define USAGE "Shadowsocks Version:" TOSTR(SHADOW_MAJOR_VERSION) "." TOSTR(SHADOW_MINOR_VERSION) \ 32 | " libuv(" TOSTR(UV_VERSION_MAJOR) "." TOSTR(UV_VERSION_MINOR) ")"\ 33 | " Written by Dndx(idndx.com)\n"\ 34 | "Usage: %s [-l listen] [-p port] [-k keyfile] [-f pidfile] [-m rc4|shadow]\n\n"\ 35 | "Options:\n"\ 36 | " -l : Override the listening IP\n"\ 37 | " -p : Override the listening port\n"\ 38 | " -k : Override the listening password\n"\ 39 | " -f : Override the pidfile path\n"\ 40 | " -m : Override the encryption method\n\n" 41 | #define PROCESS_TITLE "shadowsocks on port:%d" 42 | #define PROCESS_TITLE_LENGTH 26 43 | #define ADDRTYPE_IPV4 1 44 | #define ADDRTYPE_DOMAIN 3 45 | #define ADDRTYPE_IPV6 4 46 | 47 | typedef struct 48 | { 49 | uv_tcp_t client; 50 | uv_tcp_t remote; 51 | uint8_t remote_ip[16]; // Network order 52 | uint8_t remote_ip_type; 53 | uint16_t remote_port; // Network order 54 | struct encryptor encoder; // En/decoder 55 | unsigned char *handshake_buffer; 56 | size_t buffer_len; // Also use as pending cound after handshake 57 | } server_ctx; 58 | 59 | static void client_handshake_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); 60 | static uv_buf_t client_handshake_alloc_cb(uv_handle_t* handle, size_t suggested_size); 61 | static void after_write_cb(uv_write_t* req, int status); 62 | static uv_buf_t established_alloc_cb(uv_handle_t* handle, size_t suggested_size); 63 | static void client_handshake_domain_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res); 64 | 65 | #endif /* !SERVER_H_ */ 66 | -------------------------------------------------------------------------------- /tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "encrypt.h" 5 | #include "utils.h" 6 | 7 | void encrypt_test() 8 | { 9 | struct encryptor enc; 10 | 11 | uint8_t target1[2][256] = { 12 | {60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, 143, 83, 247, 162, 16, 31, 209, 190, 13 | 171, 115, 65, 38, 41, 21, 245, 236, 46, 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, 14 | 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, 149, 239, 192, 195, 24, 155, 170, 183, 11 15 | , 254, 213, 37, 137, 226, 75, 203, 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, 2, 16 | 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, 150, 196, 133, 5, 253, 130, 8, 184, 14, 17 | 152, 231, 3, 186, 159, 76, 89, 228, 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, 235, 18 | 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 19 | 174, 92, 52, 120, 240, 15, 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, 45, 6, 25, 4 20 | , 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 21 | 118, 135, 148, 47, 238, 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, 160, 187, 246, 234 22 | , 161, 188, 193, 249, 252}, 23 | {151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, 21, 191, 138, 83, 217, 30, 86, 7, 70, 24 | 200, 56, 62, 218, 47, 168, 22, 107, 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, 25 | 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, 212, 209, 235, 93, 84, 169, 166, 80, 130 26 | , 94, 164, 165, 142, 184, 111, 18, 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, 238 27 | , 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, 206, 100, 227, 49, 178, 34, 234, 108, 28 | 207, 245, 204, 150, 44, 87, 121, 54, 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, 229, 29 | 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 30 | 175, 89, 145, 113, 90, 159, 190, 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, 57, 92, 31 | 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 32 | 185, 241, 79, 224, 132, 51, 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, 19, 85, 33 | 254, 156, 115, 255, 120, 75, 16}}; 34 | 35 | uint8_t target2[2][256] = { 36 | {124, 30, 170, 247, 27, 127, 224, 59, 13, 22, 196, 76, 72, 154, 32, 209, 4, 2, 131, 62, 101, 51, 230, 9, 166, 11, 99 37 | , 80, 208, 112, 36, 248, 81, 102, 130, 88, 218, 38, 168, 15, 241, 228, 167, 117, 158, 41, 10, 180, 194, 50, 204, 38 | 243, 246, 251, 29, 198, 219, 210, 195, 21, 54, 91, 203, 221, 70, 57, 183, 17, 147, 49, 133, 65, 77, 55, 202, 122, 39 | 162, 169, 188, 200, 190, 125, 63, 244, 96, 31, 107, 106, 74, 143, 116, 148, 78, 46, 1, 137, 150, 110, 181, 56, 95, 40 | 139, 58, 3, 231, 66, 165, 142, 242, 43, 192, 157, 89, 175, 109, 220, 128, 0, 178, 42, 255, 20, 214, 185, 83, 160, 41 | 253, 7, 23, 92, 111, 153, 26, 226, 33, 176, 144, 18, 216, 212, 28, 151, 71, 206, 222, 182, 8, 174, 205, 201, 152, 42 | 240, 155, 108, 223, 104, 239, 98, 164, 211, 184, 34, 193, 14, 114, 187, 40, 254, 12, 67, 93, 217, 6, 94, 16, 19, 82 43 | , 86, 245, 24, 197, 134, 132, 138, 229, 121, 5, 235, 238, 85, 47, 103, 113, 179, 69, 250, 45, 135, 156, 25, 61, 44 | 75, 44, 146, 189, 84, 207, 172, 119, 53, 123, 186, 120, 171, 68, 227, 145, 136, 100, 90, 48, 79, 159, 149, 39, 213, 45 | 236, 126, 52, 60, 225, 199, 105, 73, 233, 252, 118, 215, 35, 115, 64, 37, 97, 129, 161, 177, 87, 237, 141, 173, 191 46 | , 163, 140, 234, 232, 249}, 47 | {117, 94, 17, 103, 16, 186, 172, 127, 146, 23, 46, 25, 168, 8, 163, 39, 174, 67, 137, 175, 121, 59, 9, 128, 179, 199 48 | , 132, 4, 140, 54, 1, 85, 14, 134, 161, 238, 30, 241, 37, 224, 166, 45, 119, 109, 202, 196, 93, 190, 220, 69, 49 49 | , 21, 228, 209, 60, 73, 99, 65, 102, 7, 229, 200, 19, 82, 240, 71, 105, 169, 214, 194, 64, 142, 12, 233, 88, 201 50 | , 11, 72, 92, 221, 27, 32, 176, 124, 205, 189, 177, 246, 35, 112, 219, 61, 129, 170, 173, 100, 84, 242, 157, 26, 51 | 218, 20, 33, 191, 155, 232, 87, 86, 153, 114, 97, 130, 29, 192, 164, 239, 90, 43, 236, 208, 212, 185, 75, 210, 0, 52 | 81, 227, 5, 116, 243, 34, 18, 182, 70, 181, 197, 217, 95, 183, 101, 252, 248, 107, 89, 136, 216, 203, 68, 91, 223, 53 | 96, 141, 150, 131, 13, 152, 198, 111, 44, 222, 125, 244, 76, 251, 158, 106, 24, 42, 38, 77, 2, 213, 207, 249, 147, 54 | 113, 135, 245, 118, 193, 47, 98, 145, 66, 160, 123, 211, 165, 78, 204, 80, 250, 110, 162, 48, 58, 10, 180, 55, 231, 55 | 79, 149, 74, 62, 50, 148, 143, 206, 28, 15, 57, 159, 139, 225, 122, 237, 138, 171, 36, 56, 115, 63, 144, 154, 6, 56 | 230, 133, 215, 41, 184, 22, 104, 254, 234, 253, 187, 226, 247, 188, 156, 151, 40, 108, 51, 83, 178, 52, 3, 31, 255, 57 | 195, 53, 235, 126, 167, 120}}; 58 | 59 | make_encryptor(NULL, &enc, METHOD_SHADOWCRYPT, (uint8_t *)"foobar!"); 60 | 61 | for (int i=0; i<256; i++) { 62 | assert(target1[0][i] == enc.encrypt_table[i]); 63 | assert(target1[1][i] == enc.decrypt_table[i]); 64 | } 65 | 66 | free(enc.encrypt_table); 67 | free(enc.decrypt_table); 68 | 69 | make_encryptor(NULL, &enc, METHOD_SHADOWCRYPT, (uint8_t *)"barfoo!"); 70 | 71 | for (int i=0; i<256; i++) { 72 | assert(target2[0][i] == enc.encrypt_table[i]); 73 | assert(target2[1][i] == enc.decrypt_table[i]); 74 | } 75 | 76 | free(enc.encrypt_table); 77 | free(enc.decrypt_table); 78 | 79 | puts("Encryption/Decryption test passed!"); 80 | 81 | } 82 | 83 | 84 | int main(void) 85 | { 86 | encrypt_test(); 87 | } 88 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "utils.h" 3 | #include 4 | #include 5 | 6 | // Convert IPv4 or IPv6 sockaddr to string, DO NOT forget to free the buffer after use! 7 | char *sockaddr_to_str(struct sockaddr_storage *addr) 8 | { 9 | char *result; 10 | if (addr->ss_family == AF_INET) { // IPv4 11 | result = (char *)malloc(INET_ADDRSTRLEN); 12 | if (!result) 13 | FATAL("malloc() failed!"); 14 | int n = uv_ip4_name((struct sockaddr_in*)addr, result, INET_ADDRSTRLEN); 15 | if (n) { 16 | free(result); 17 | result = NULL; 18 | } 19 | } else if (addr->ss_family == AF_INET6) { // IPv4 20 | result = (char *)malloc(INET6_ADDRSTRLEN); 21 | if (!result) 22 | FATAL("malloc() failed!"); 23 | int n = uv_ip6_name((struct sockaddr_in6*)addr, result, INET6_ADDRSTRLEN); 24 | if (n) { 25 | free(result); 26 | result = NULL; 27 | } 28 | } else { 29 | result = NULL; 30 | } 31 | return result; 32 | } 33 | 34 | void signal_cb(uv_signal_t* handle, int signum) 35 | { 36 | extern struct encryptor crypto; 37 | 38 | if (uv_signal_stop(handle)) 39 | SHOW_UV_ERROR_AND_EXIT(handle->loop); 40 | free(handle); 41 | LOGI("Ctrl+C Pressed"); 42 | 43 | if (crypto.encrypt_table) { 44 | free(crypto.encrypt_table); 45 | free(crypto.decrypt_table); 46 | } else { 47 | free(crypto.key); 48 | } 49 | 50 | uv_loop_delete(uv_default_loop()); // Make Valgrind Happy 51 | 52 | exit(0); 53 | } 54 | 55 | void setup_signal_handler(uv_loop_t *loop) 56 | { 57 | signal(SIGPIPE, SIG_IGN); 58 | 59 | uv_signal_t *hup = (uv_signal_t *)malloc(sizeof(uv_signal_t)); 60 | if (!hup) 61 | FATAL("malloc() failed!"); 62 | 63 | int n = uv_signal_init(loop, hup); 64 | if (n) 65 | SHOW_UV_ERROR_AND_EXIT(loop); 66 | 67 | n = uv_signal_start(hup, signal_cb, SIGINT); 68 | if (n) 69 | SHOW_UV_ERROR_AND_EXIT(loop); 70 | } 71 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 dndx (idndx.com) 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef UTILS_H_ 22 | #define UTILS_H_ 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define STR(x) #x 31 | #define TOSTR(x) STR(x) 32 | 33 | #define LOGI(format, ...) do {\ 34 | time_t now = time(NULL);\ 35 | char timestr[20];\ 36 | strftime(timestr, 20, TIME_FORMAT, localtime(&now));\ 37 | fprintf(stderr, "\e[01;32m %s INFO: \e[0m" format "\n", timestr, ##__VA_ARGS__);}\ 38 | while(0) 39 | #define LOGE(format, ...) do {\ 40 | time_t now = time(NULL);\ 41 | char timestr[20];\ 42 | strftime(timestr, 20, TIME_FORMAT, localtime(&now));\ 43 | fprintf(stderr, "\e[01;35m %s ERROR: \e[0m" format " on File: %s Line: %s\n", timestr, ##__VA_ARGS__, __FILE__, TOSTR(__LINE__));}\ 44 | while(0) 45 | #define LOGCONN(stream, message) do {\ 46 | struct sockaddr_storage remote_addr;\ 47 | memset(&remote_addr, 0, sizeof(remote_addr));\ 48 | int namelen = sizeof(remote_addr);\ 49 | if (uv_tcp_getpeername((stream), (struct sockaddr *)&remote_addr, &namelen))\ 50 | break;\ 51 | char *ip_str = sockaddr_to_str(&remote_addr);\ 52 | if (!ip_str)\ 53 | FATAL("unknown address type");\ 54 | LOGI(message, ip_str);\ 55 | free(ip_str);\ 56 | } while (0) 57 | #define FATAL(format, ...) do {\ 58 | time_t now = time(NULL);\ 59 | char timestr[20];\ 60 | strftime(timestr, 20, TIME_FORMAT, localtime(&now));\ 61 | fprintf(stderr, "\e[01;31m %s FATAL: \e[0m" format " on File: %s Line: %s\n", timestr, ##__VA_ARGS__, __FILE__, TOSTR(__LINE__));exit(1);}\ 62 | while(0) 63 | #define SHOW_UV_ERROR(loop) do {LOGE("libuv error: %s", uv_strerror(uv_last_error(loop)));} while (0) 64 | #define SHOW_UV_ERROR_AND_EXIT(loop) do {SHOW_UV_ERROR(loop);LOGE("Fatal error, terminating... ");exit(1);} while (0) 65 | //#define POINT_TO_STRUCT(field_ptr, field_name, struct_name) ((struct_name *)((char *)(field_ptr) - offsetof(struct_name, field_name))) 66 | #define SHIFT_BYTE_ARRAY_TO_LEFT(arr, offset, array_size) memmove((arr), (arr) + (offset), (array_size) - (offset)) 67 | #define SHOW_BUFFER(buf, len) do {\ 68 | for (int i=0; iremote) || uv_is_closing((uv_handle_t *)(void *)&ctx->client)))\ 73 | uv_close((uv_handle_t *)handle, callback);\ 74 | } while (0) 75 | 76 | char *sockaddr_to_str(struct sockaddr_storage *addr); 77 | void setup_signal_handler(uv_loop_t *loop); 78 | 79 | #endif /* !UTILS_H_ */ 80 | --------------------------------------------------------------------------------