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