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