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