1 /* 2 This example code shows how to write an (optionally encrypting) SSL proxy 3 with Libevent's bufferevent layer. 4 5 XXX It's a little ugly and should probably be cleaned up. 6 */ 7 8 // Get rid of OSX 10.7 and greater deprecation warnings. 9 #if defined(__APPLE__) && defined(__clang__) 10 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 11 #endif 12 13 #include <stdio.h> 14 #include <assert.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <errno.h> 18 19 #ifdef _WIN32 20 #include <winsock2.h> 21 #include <ws2tcpip.h> 22 #else 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #endif 26 27 #include <event2/bufferevent_ssl.h> 28 #include <event2/bufferevent.h> 29 #include <event2/buffer.h> 30 #include <event2/listener.h> 31 #include <event2/util.h> 32 33 #include <openssl/ssl.h> 34 #include <openssl/err.h> 35 #include <openssl/rand.h> 36 37 static struct event_base *base; 38 static struct sockaddr_storage listen_on_addr; 39 static struct sockaddr_storage connect_to_addr; 40 static int connect_to_addrlen; 41 static int use_wrapper = 1; 42 43 static SSL_CTX *ssl_ctx = NULL; 44 45 #define MAX_OUTPUT (512*1024) 46 47 static void drained_writecb(struct bufferevent *bev, void *ctx); 48 static void eventcb(struct bufferevent *bev, short what, void *ctx); 49 50 static void 51 readcb(struct bufferevent *bev, void *ctx) 52 { 53 struct bufferevent *partner = ctx; 54 struct evbuffer *src, *dst; 55 size_t len; 56 src = bufferevent_get_input(bev); 57 len = evbuffer_get_length(src); 58 if (!partner) { 59 evbuffer_drain(src, len); 60 return; 61 } 62 dst = bufferevent_get_output(partner); 63 evbuffer_add_buffer(dst, src); 64 65 if (evbuffer_get_length(dst) >= MAX_OUTPUT) { 66 /* We're giving the other side data faster than it can 67 * pass it on. Stop reading here until we have drained the 68 * other side to MAX_OUTPUT/2 bytes. */ 69 bufferevent_setcb(partner, readcb, drained_writecb, 70 eventcb, bev); 71 bufferevent_setwatermark(partner, EV_WRITE, MAX_OUTPUT/2, 72 MAX_OUTPUT); 73 bufferevent_disable(bev, EV_READ); 74 } 75 } 76 77 static void 78 drained_writecb(struct bufferevent *bev, void *ctx) 79 { 80 struct bufferevent *partner = ctx; 81 82 /* We were choking the other side until we drained our outbuf a bit. 83 * Now it seems drained. */ 84 bufferevent_setcb(bev, readcb, NULL, eventcb, partner); 85 bufferevent_setwatermark(bev, EV_WRITE, 0, 0); 86 if (partner) 87 bufferevent_enable(partner, EV_READ); 88 } 89 90 static void 91 close_on_finished_writecb(struct bufferevent *bev, void *ctx) 92 { 93 struct evbuffer *b = bufferevent_get_output(bev); 94 95 if (evbuffer_get_length(b) == 0) { 96 bufferevent_free(bev); 97 } 98 } 99 100 static void 101 eventcb(struct bufferevent *bev, short what, void *ctx) 102 { 103 struct bufferevent *partner = ctx; 104 105 if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { 106 if (what & BEV_EVENT_ERROR) { 107 unsigned long err; 108 while ((err = (bufferevent_get_openssl_error(bev)))) { 109 const char *msg = (const char*) 110 ERR_reason_error_string(err); 111 const char *lib = (const char*) 112 ERR_lib_error_string(err); 113 const char *func = (const char*) 114 ERR_func_error_string(err); 115 fprintf(stderr, 116 "%s in %s %s\n", msg, lib, func); 117 } 118 if (errno) 119 perror("connection error"); 120 } 121 122 if (partner) { 123 /* Flush all pending data */ 124 readcb(bev, ctx); 125 126 if (evbuffer_get_length( 127 bufferevent_get_output(partner))) { 128 /* We still have to flush data from the other 129 * side, but when that's done, close the other 130 * side. */ 131 bufferevent_setcb(partner, 132 NULL, close_on_finished_writecb, 133 eventcb, NULL); 134 bufferevent_disable(partner, EV_READ); 135 } else { 136 /* We have nothing left to say to the other 137 * side; close it. */ 138 bufferevent_free(partner); 139 } 140 } 141 bufferevent_free(bev); 142 } 143 } 144 145 static void 146 syntax(void) 147 { 148 fputs("Syntax:\n", stderr); 149 fputs(" le-proxy [-s] [-W] <listen-on-addr> <connect-to-addr>\n", stderr); 150 fputs("Example:\n", stderr); 151 fputs(" le-proxy 127.0.0.1:8888 1.2.3.4:80\n", stderr); 152 153 exit(1); 154 } 155 156 static void 157 accept_cb(struct evconnlistener *listener, evutil_socket_t fd, 158 struct sockaddr *a, int slen, void *p) 159 { 160 struct bufferevent *b_out, *b_in; 161 /* Create two linked bufferevent objects: one to connect, one for the 162 * new connection */ 163 b_in = bufferevent_socket_new(base, fd, 164 BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 165 166 if (!ssl_ctx || use_wrapper) 167 b_out = bufferevent_socket_new(base, -1, 168 BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 169 else { 170 SSL *ssl = SSL_new(ssl_ctx); 171 b_out = bufferevent_openssl_socket_new(base, -1, ssl, 172 BUFFEREVENT_SSL_CONNECTING, 173 BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 174 } 175 176 assert(b_in && b_out); 177 178 if (bufferevent_socket_connect(b_out, 179 (struct sockaddr*)&connect_to_addr, connect_to_addrlen)<0) { 180 perror("bufferevent_socket_connect"); 181 bufferevent_free(b_out); 182 bufferevent_free(b_in); 183 return; 184 } 185 186 if (ssl_ctx && use_wrapper) { 187 struct bufferevent *b_ssl; 188 SSL *ssl = SSL_new(ssl_ctx); 189 b_ssl = bufferevent_openssl_filter_new(base, 190 b_out, ssl, BUFFEREVENT_SSL_CONNECTING, 191 BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 192 if (!b_ssl) { 193 perror("Bufferevent_openssl_new"); 194 bufferevent_free(b_out); 195 bufferevent_free(b_in); 196 } 197 b_out = b_ssl; 198 } 199 200 bufferevent_setcb(b_in, readcb, NULL, eventcb, b_out); 201 bufferevent_setcb(b_out, readcb, NULL, eventcb, b_in); 202 203 bufferevent_enable(b_in, EV_READ|EV_WRITE); 204 bufferevent_enable(b_out, EV_READ|EV_WRITE); 205 } 206 207 int 208 main(int argc, char **argv) 209 { 210 int i; 211 int socklen; 212 213 int use_ssl = 0; 214 struct evconnlistener *listener; 215 216 if (argc < 3) 217 syntax(); 218 219 for (i=1; i < argc; ++i) { 220 if (!strcmp(argv[i], "-s")) { 221 use_ssl = 1; 222 } else if (!strcmp(argv[i], "-W")) { 223 use_wrapper = 0; 224 } else if (argv[i][0] == '-') { 225 syntax(); 226 } else 227 break; 228 } 229 230 if (i+2 != argc) 231 syntax(); 232 233 memset(&listen_on_addr, 0, sizeof(listen_on_addr)); 234 socklen = sizeof(listen_on_addr); 235 if (evutil_parse_sockaddr_port(argv[i], 236 (struct sockaddr*)&listen_on_addr, &socklen)<0) { 237 int p = atoi(argv[i]); 238 struct sockaddr_in *sin = (struct sockaddr_in*)&listen_on_addr; 239 if (p < 1 || p > 65535) 240 syntax(); 241 sin->sin_port = htons(p); 242 sin->sin_addr.s_addr = htonl(0x7f000001); 243 sin->sin_family = AF_INET; 244 socklen = sizeof(struct sockaddr_in); 245 } 246 247 memset(&connect_to_addr, 0, sizeof(connect_to_addr)); 248 connect_to_addrlen = sizeof(connect_to_addr); 249 if (evutil_parse_sockaddr_port(argv[i+1], 250 (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) 251 syntax(); 252 253 base = event_base_new(); 254 if (!base) { 255 perror("event_base_new()"); 256 return 1; 257 } 258 259 if (use_ssl) { 260 int r; 261 SSL_library_init(); 262 ERR_load_crypto_strings(); 263 SSL_load_error_strings(); 264 OpenSSL_add_all_algorithms(); 265 r = RAND_poll(); 266 if (r == 0) { 267 fprintf(stderr, "RAND_poll() failed.\n"); 268 return 1; 269 } 270 ssl_ctx = SSL_CTX_new(SSLv23_method()); 271 } 272 273 listener = evconnlistener_new_bind(base, accept_cb, NULL, 274 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE, 275 -1, (struct sockaddr*)&listen_on_addr, socklen); 276 277 if (! listener) { 278 fprintf(stderr, "Couldn't open listener.\n"); 279 event_base_free(base); 280 return 1; 281 } 282 event_base_dispatch(base); 283 284 evconnlistener_free(listener); 285 event_base_free(base); 286 287 return 0; 288 } 289