ipc/chromium/src/third_party/libevent/sample/le-proxy.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

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

mercurial