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