]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libevent/sample/le-proxy.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / contrib / libevent / sample / le-proxy.c
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 }