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