1d60a1bd5SNick Mathewson /* 2d60a1bd5SNick Mathewson This example code shows how to write an (optionally encrypting) SSL proxy 3d60a1bd5SNick Mathewson with Libevent's bufferevent layer. 4d60a1bd5SNick Mathewson 5d60a1bd5SNick Mathewson XXX It's a little ugly and should probably be cleaned up. 6d60a1bd5SNick Mathewson */ 7709c21c4SNick Mathewson 869c3516bSJoakim Söderberg // Get rid of OSX 10.7 and greater deprecation warnings. 98b40a5b0SJoakim Söderberg #if defined(__APPLE__) && defined(__clang__) 1069c3516bSJoakim Söderberg #pragma clang diagnostic ignored "-Wdeprecated-declarations" 110ef1d04eSJoakim Soderberg #endif 1269c3516bSJoakim Söderberg 13709c21c4SNick Mathewson #include <stdio.h> 14709c21c4SNick Mathewson #include <assert.h> 15709c21c4SNick Mathewson #include <stdlib.h> 16709c21c4SNick Mathewson #include <string.h> 17709c21c4SNick Mathewson #include <errno.h> 18709c21c4SNick Mathewson 199f560bfaSNick Mathewson #ifdef _WIN32 2013b912e4STrond Norbye #include <winsock2.h> 2113b912e4STrond Norbye #include <ws2tcpip.h> 2213b912e4STrond Norbye #else 23709c21c4SNick Mathewson #include <sys/socket.h> 24709c21c4SNick Mathewson #include <netinet/in.h> 2513b912e4STrond Norbye #endif 26709c21c4SNick Mathewson 27709c21c4SNick Mathewson #include <event2/bufferevent_ssl.h> 28709c21c4SNick Mathewson #include <event2/bufferevent.h> 29709c21c4SNick Mathewson #include <event2/buffer.h> 30709c21c4SNick Mathewson #include <event2/listener.h> 31709c21c4SNick Mathewson #include <event2/util.h> 32709c21c4SNick Mathewson 33*449f5a57SAzat Khuzhin #include "util-internal.h" 34*449f5a57SAzat Khuzhin #include <openssl/bio.h> 35709c21c4SNick Mathewson #include <openssl/ssl.h> 36709c21c4SNick Mathewson #include <openssl/err.h> 37709c21c4SNick Mathewson #include <openssl/rand.h> 38fa58cb1dSAzat Khuzhin #include "openssl-compat.h" 39709c21c4SNick Mathewson 40709c21c4SNick Mathewson static struct event_base *base; 41709c21c4SNick Mathewson static struct sockaddr_storage listen_on_addr; 42709c21c4SNick Mathewson static struct sockaddr_storage connect_to_addr; 43709c21c4SNick Mathewson static int connect_to_addrlen; 44709c21c4SNick Mathewson static int use_wrapper = 1; 45709c21c4SNick Mathewson 46709c21c4SNick Mathewson static SSL_CTX *ssl_ctx = NULL; 47709c21c4SNick Mathewson 48c119e4a1SNick Mathewson #define MAX_OUTPUT (512*1024) 49c119e4a1SNick Mathewson 50c119e4a1SNick Mathewson static void drained_writecb(struct bufferevent *bev, void *ctx); 51c119e4a1SNick Mathewson static void eventcb(struct bufferevent *bev, short what, void *ctx); 52c119e4a1SNick Mathewson 53709c21c4SNick Mathewson static void 54709c21c4SNick Mathewson readcb(struct bufferevent *bev, void *ctx) 55709c21c4SNick Mathewson { 56709c21c4SNick Mathewson struct bufferevent *partner = ctx; 57709c21c4SNick Mathewson struct evbuffer *src, *dst; 58c119e4a1SNick Mathewson size_t len; 59709c21c4SNick Mathewson src = bufferevent_get_input(bev); 60c119e4a1SNick Mathewson len = evbuffer_get_length(src); 61709c21c4SNick Mathewson if (!partner) { 62c119e4a1SNick Mathewson evbuffer_drain(src, len); 63709c21c4SNick Mathewson return; 64709c21c4SNick Mathewson } 65709c21c4SNick Mathewson dst = bufferevent_get_output(partner); 66709c21c4SNick Mathewson evbuffer_add_buffer(dst, src); 67c119e4a1SNick Mathewson 68c119e4a1SNick Mathewson if (evbuffer_get_length(dst) >= MAX_OUTPUT) { 69c119e4a1SNick Mathewson /* We're giving the other side data faster than it can 70c119e4a1SNick Mathewson * pass it on. Stop reading here until we have drained the 71c119e4a1SNick Mathewson * other side to MAX_OUTPUT/2 bytes. */ 72c119e4a1SNick Mathewson bufferevent_setcb(partner, readcb, drained_writecb, 73c119e4a1SNick Mathewson eventcb, bev); 74c119e4a1SNick Mathewson bufferevent_setwatermark(partner, EV_WRITE, MAX_OUTPUT/2, 75c119e4a1SNick Mathewson MAX_OUTPUT); 76c119e4a1SNick Mathewson bufferevent_disable(bev, EV_READ); 77c119e4a1SNick Mathewson } 78c119e4a1SNick Mathewson } 79c119e4a1SNick Mathewson 80c119e4a1SNick Mathewson static void 81c119e4a1SNick Mathewson drained_writecb(struct bufferevent *bev, void *ctx) 82c119e4a1SNick Mathewson { 83c119e4a1SNick Mathewson struct bufferevent *partner = ctx; 84c119e4a1SNick Mathewson 85c119e4a1SNick Mathewson /* We were choking the other side until we drained our outbuf a bit. 86c119e4a1SNick Mathewson * Now it seems drained. */ 87c119e4a1SNick Mathewson bufferevent_setcb(bev, readcb, NULL, eventcb, partner); 88c119e4a1SNick Mathewson bufferevent_setwatermark(bev, EV_WRITE, 0, 0); 89c119e4a1SNick Mathewson if (partner) 90c119e4a1SNick Mathewson bufferevent_enable(partner, EV_READ); 91709c21c4SNick Mathewson } 92709c21c4SNick Mathewson 93709c21c4SNick Mathewson static void 94709c21c4SNick Mathewson close_on_finished_writecb(struct bufferevent *bev, void *ctx) 95709c21c4SNick Mathewson { 96709c21c4SNick Mathewson struct evbuffer *b = bufferevent_get_output(bev); 97c119e4a1SNick Mathewson 98709c21c4SNick Mathewson if (evbuffer_get_length(b) == 0) { 99709c21c4SNick Mathewson bufferevent_free(bev); 100709c21c4SNick Mathewson } 101709c21c4SNick Mathewson } 102709c21c4SNick Mathewson 103709c21c4SNick Mathewson static void 104709c21c4SNick Mathewson eventcb(struct bufferevent *bev, short what, void *ctx) 105709c21c4SNick Mathewson { 106709c21c4SNick Mathewson struct bufferevent *partner = ctx; 107709c21c4SNick Mathewson 108709c21c4SNick Mathewson if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { 109516452b7SNick Mathewson if (what & BEV_EVENT_ERROR) { 110516452b7SNick Mathewson unsigned long err; 111516452b7SNick Mathewson while ((err = (bufferevent_get_openssl_error(bev)))) { 112516452b7SNick Mathewson const char *msg = (const char*) 113516452b7SNick Mathewson ERR_reason_error_string(err); 114516452b7SNick Mathewson const char *lib = (const char*) 115516452b7SNick Mathewson ERR_lib_error_string(err); 116516452b7SNick Mathewson const char *func = (const char*) 117516452b7SNick Mathewson ERR_func_error_string(err); 118516452b7SNick Mathewson fprintf(stderr, 119516452b7SNick Mathewson "%s in %s %s\n", msg, lib, func); 120516452b7SNick Mathewson } 121516452b7SNick Mathewson if (errno) 122516452b7SNick Mathewson perror("connection error"); 123516452b7SNick Mathewson } 124709c21c4SNick Mathewson 125709c21c4SNick Mathewson if (partner) { 126709c21c4SNick Mathewson /* Flush all pending data */ 127709c21c4SNick Mathewson readcb(bev, ctx); 128709c21c4SNick Mathewson 129c119e4a1SNick Mathewson if (evbuffer_get_length( 130c119e4a1SNick Mathewson bufferevent_get_output(partner))) { 131c119e4a1SNick Mathewson /* We still have to flush data from the other 132c119e4a1SNick Mathewson * side, but when that's done, close the other 133c119e4a1SNick Mathewson * side. */ 134709c21c4SNick Mathewson bufferevent_setcb(partner, 135709c21c4SNick Mathewson NULL, close_on_finished_writecb, 136709c21c4SNick Mathewson eventcb, NULL); 137c119e4a1SNick Mathewson bufferevent_disable(partner, EV_READ); 138c119e4a1SNick Mathewson } else { 139c119e4a1SNick Mathewson /* We have nothing left to say to the other 140c119e4a1SNick Mathewson * side; close it. */ 141c119e4a1SNick Mathewson bufferevent_free(partner); 142c119e4a1SNick Mathewson } 143709c21c4SNick Mathewson } 144709c21c4SNick Mathewson bufferevent_free(bev); 145709c21c4SNick Mathewson } 146709c21c4SNick Mathewson } 147709c21c4SNick Mathewson 148709c21c4SNick Mathewson static void 149709c21c4SNick Mathewson syntax(void) 150709c21c4SNick Mathewson { 151709c21c4SNick Mathewson fputs("Syntax:\n", stderr); 152709c21c4SNick Mathewson fputs(" le-proxy [-s] [-W] <listen-on-addr> <connect-to-addr>\n", stderr); 153709c21c4SNick Mathewson fputs("Example:\n", stderr); 154709c21c4SNick Mathewson fputs(" le-proxy 127.0.0.1:8888 1.2.3.4:80\n", stderr); 155709c21c4SNick Mathewson 156709c21c4SNick Mathewson exit(1); 157709c21c4SNick Mathewson } 158709c21c4SNick Mathewson 159709c21c4SNick Mathewson static void 160709c21c4SNick Mathewson accept_cb(struct evconnlistener *listener, evutil_socket_t fd, 161709c21c4SNick Mathewson struct sockaddr *a, int slen, void *p) 162709c21c4SNick Mathewson { 163709c21c4SNick Mathewson struct bufferevent *b_out, *b_in; 164709c21c4SNick Mathewson /* Create two linked bufferevent objects: one to connect, one for the 165709c21c4SNick Mathewson * new connection */ 166709c21c4SNick Mathewson b_in = bufferevent_socket_new(base, fd, 167709c21c4SNick Mathewson BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 168709c21c4SNick Mathewson 169709c21c4SNick Mathewson if (!ssl_ctx || use_wrapper) 170709c21c4SNick Mathewson b_out = bufferevent_socket_new(base, -1, 171709c21c4SNick Mathewson BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 172709c21c4SNick Mathewson else { 173709c21c4SNick Mathewson SSL *ssl = SSL_new(ssl_ctx); 174709c21c4SNick Mathewson b_out = bufferevent_openssl_socket_new(base, -1, ssl, 175709c21c4SNick Mathewson BUFFEREVENT_SSL_CONNECTING, 176709c21c4SNick Mathewson BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 177709c21c4SNick Mathewson } 178709c21c4SNick Mathewson 179709c21c4SNick Mathewson assert(b_in && b_out); 180709c21c4SNick Mathewson 181709c21c4SNick Mathewson if (bufferevent_socket_connect(b_out, 182709c21c4SNick Mathewson (struct sockaddr*)&connect_to_addr, connect_to_addrlen)<0) { 183709c21c4SNick Mathewson perror("bufferevent_socket_connect"); 184709c21c4SNick Mathewson bufferevent_free(b_out); 185709c21c4SNick Mathewson bufferevent_free(b_in); 186709c21c4SNick Mathewson return; 187709c21c4SNick Mathewson } 188709c21c4SNick Mathewson 189709c21c4SNick Mathewson if (ssl_ctx && use_wrapper) { 190709c21c4SNick Mathewson struct bufferevent *b_ssl; 191709c21c4SNick Mathewson SSL *ssl = SSL_new(ssl_ctx); 192709c21c4SNick Mathewson b_ssl = bufferevent_openssl_filter_new(base, 193709c21c4SNick Mathewson b_out, ssl, BUFFEREVENT_SSL_CONNECTING, 194709c21c4SNick Mathewson BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS); 195709c21c4SNick Mathewson if (!b_ssl) { 196709c21c4SNick Mathewson perror("Bufferevent_openssl_new"); 197709c21c4SNick Mathewson bufferevent_free(b_out); 198709c21c4SNick Mathewson bufferevent_free(b_in); 19956a52003SMaximilian Brunner return; 200709c21c4SNick Mathewson } 201709c21c4SNick Mathewson b_out = b_ssl; 202709c21c4SNick Mathewson } 203709c21c4SNick Mathewson 204709c21c4SNick Mathewson bufferevent_setcb(b_in, readcb, NULL, eventcb, b_out); 205709c21c4SNick Mathewson bufferevent_setcb(b_out, readcb, NULL, eventcb, b_in); 206709c21c4SNick Mathewson 207709c21c4SNick Mathewson bufferevent_enable(b_in, EV_READ|EV_WRITE); 208709c21c4SNick Mathewson bufferevent_enable(b_out, EV_READ|EV_WRITE); 209709c21c4SNick Mathewson } 210709c21c4SNick Mathewson 211709c21c4SNick Mathewson int 212709c21c4SNick Mathewson main(int argc, char **argv) 213709c21c4SNick Mathewson { 214709c21c4SNick Mathewson int i; 215709c21c4SNick Mathewson int socklen; 216709c21c4SNick Mathewson 217709c21c4SNick Mathewson int use_ssl = 0; 218709c21c4SNick Mathewson struct evconnlistener *listener; 219709c21c4SNick Mathewson 220709c21c4SNick Mathewson if (argc < 3) 221709c21c4SNick Mathewson syntax(); 222709c21c4SNick Mathewson 223709c21c4SNick Mathewson for (i=1; i < argc; ++i) { 224709c21c4SNick Mathewson if (!strcmp(argv[i], "-s")) { 225709c21c4SNick Mathewson use_ssl = 1; 226709c21c4SNick Mathewson } else if (!strcmp(argv[i], "-W")) { 227709c21c4SNick Mathewson use_wrapper = 0; 228709c21c4SNick Mathewson } else if (argv[i][0] == '-') { 229709c21c4SNick Mathewson syntax(); 230709c21c4SNick Mathewson } else 231709c21c4SNick Mathewson break; 232709c21c4SNick Mathewson } 233709c21c4SNick Mathewson 234709c21c4SNick Mathewson if (i+2 != argc) 235709c21c4SNick Mathewson syntax(); 236709c21c4SNick Mathewson 237709c21c4SNick Mathewson memset(&listen_on_addr, 0, sizeof(listen_on_addr)); 238709c21c4SNick Mathewson socklen = sizeof(listen_on_addr); 239709c21c4SNick Mathewson if (evutil_parse_sockaddr_port(argv[i], 240709c21c4SNick Mathewson (struct sockaddr*)&listen_on_addr, &socklen)<0) { 241709c21c4SNick Mathewson int p = atoi(argv[i]); 242709c21c4SNick Mathewson struct sockaddr_in *sin = (struct sockaddr_in*)&listen_on_addr; 243709c21c4SNick Mathewson if (p < 1 || p > 65535) 244709c21c4SNick Mathewson syntax(); 245709c21c4SNick Mathewson sin->sin_port = htons(p); 246709c21c4SNick Mathewson sin->sin_addr.s_addr = htonl(0x7f000001); 247709c21c4SNick Mathewson sin->sin_family = AF_INET; 248709c21c4SNick Mathewson socklen = sizeof(struct sockaddr_in); 249709c21c4SNick Mathewson } 250709c21c4SNick Mathewson 251709c21c4SNick Mathewson memset(&connect_to_addr, 0, sizeof(connect_to_addr)); 252709c21c4SNick Mathewson connect_to_addrlen = sizeof(connect_to_addr); 253709c21c4SNick Mathewson if (evutil_parse_sockaddr_port(argv[i+1], 254709c21c4SNick Mathewson (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) 255709c21c4SNick Mathewson syntax(); 256709c21c4SNick Mathewson 257709c21c4SNick Mathewson base = event_base_new(); 258709c21c4SNick Mathewson if (!base) { 259709c21c4SNick Mathewson perror("event_base_new()"); 260709c21c4SNick Mathewson return 1; 261709c21c4SNick Mathewson } 262709c21c4SNick Mathewson 263709c21c4SNick Mathewson if (use_ssl) { 264709c21c4SNick Mathewson int r; 265230af9f0SJan Beich #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) 266709c21c4SNick Mathewson SSL_library_init(); 267709c21c4SNick Mathewson ERR_load_crypto_strings(); 268709c21c4SNick Mathewson SSL_load_error_strings(); 269709c21c4SNick Mathewson OpenSSL_add_all_algorithms(); 270122bf144SAzat Khuzhin #endif 271709c21c4SNick Mathewson r = RAND_poll(); 272709c21c4SNick Mathewson if (r == 0) { 273709c21c4SNick Mathewson fprintf(stderr, "RAND_poll() failed.\n"); 274709c21c4SNick Mathewson return 1; 275709c21c4SNick Mathewson } 276fa58cb1dSAzat Khuzhin ssl_ctx = SSL_CTX_new(TLS_method()); 277709c21c4SNick Mathewson } 278709c21c4SNick Mathewson 279709c21c4SNick Mathewson listener = evconnlistener_new_bind(base, accept_cb, NULL, 280709c21c4SNick Mathewson LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE, 281709c21c4SNick Mathewson -1, (struct sockaddr*)&listen_on_addr, socklen); 282709c21c4SNick Mathewson 28344b2491bSNick Mathewson if (! listener) { 28444b2491bSNick Mathewson fprintf(stderr, "Couldn't open listener.\n"); 28544b2491bSNick Mathewson event_base_free(base); 28644b2491bSNick Mathewson return 1; 28744b2491bSNick Mathewson } 288709c21c4SNick Mathewson event_base_dispatch(base); 289709c21c4SNick Mathewson 2907bcace2dSNick Mathewson evconnlistener_free(listener); 2917bcace2dSNick Mathewson event_base_free(base); 2927bcace2dSNick Mathewson 293709c21c4SNick Mathewson return 0; 294709c21c4SNick Mathewson } 295