"Fossies" - the Fresh Open Source Software Archive 
Member "stud-0.3/stud.c" (2 Nov 2011, 38430 Bytes) of package /linux/privat/old/stud-0.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "stud.c" see the
Fossies "Dox" file reference documentation.
1 /**
2 * Copyright 2011 Bump Technologies, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY BUMP TECHNOLOGIES, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BUMP TECHNOLOGIES, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of Bump Technologies, Inc.
27 *
28 **/
29
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <netdb.h>
34 #include <sys/wait.h>
35 #include <netinet/in.h>
36 #include <netinet/tcp.h>
37 #include <arpa/inet.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <assert.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <getopt.h>
46 #include <pwd.h>
47 #include <limits.h>
48 #include <syslog.h>
49
50 #include <sched.h>
51 #include <signal.h>
52
53 #include <openssl/x509.h>
54 #include <openssl/ssl.h>
55 #include <openssl/err.h>
56 #include <openssl/engine.h>
57 #include <ev.h>
58
59 #include "ringbuffer.h"
60 #include "shctx.h"
61
62 #ifndef MSG_NOSIGNAL
63 # define MSG_NOSIGNAL 0
64 #endif
65 #ifndef AI_ADDRCONFIG
66 # define AI_ADDRCONFIG 0
67 #endif
68
69 /* Globals */
70 static struct ev_loop *loop;
71 static struct addrinfo *backaddr;
72 static pid_t master_pid;
73 static ev_io listener;
74 static int listener_socket;
75 static int child_num;
76 static pid_t *child_pids;
77 static SSL_CTX *ssl_ctx;
78
79 /* Command line Options */
80 typedef enum {
81 ENC_TLS,
82 ENC_SSL
83 } ENC_TYPE;
84
85 typedef struct stud_options {
86 ENC_TYPE ETYPE;
87 int WRITE_IP_OCTET;
88 int WRITE_PROXY_LINE;
89 const char* CHROOT;
90 uid_t UID;
91 gid_t GID;
92 const char *FRONT_IP;
93 const char *FRONT_PORT;
94 const char *BACK_IP;
95 const char *BACK_PORT;
96 long NCORES;
97 const char *CERT_FILE;
98 const char *CIPHER_SUITE;
99 const char *ENGINE;
100 int BACKLOG;
101 #ifdef USE_SHARED_CACHE
102 int SHARED_CACHE;
103 #endif
104 int QUIET;
105 int SYSLOG;
106 int TCP_KEEPALIVE;
107 } stud_options;
108
109 static stud_options OPTIONS = {
110 ENC_TLS, // ETYPE
111 0, // WRITE_IP_OCTET
112 0, // WRITE_PROXY_LINE
113 NULL, // CHROOT
114 0, // UID
115 0, // GID
116 NULL, // FRONT_IP
117 "8443", // FRONT_PORT
118 "127.0.0.1", // BACK_IP
119 "8000", // BACK_PORT
120 1, // NCORES
121 NULL, // CERT_FILE
122 NULL, // CIPHER_SUITE
123 NULL, // ENGINE
124 100, // BACKLOG
125 #ifdef USE_SHARED_CACHE
126 0, // SHARED_CACHE
127 #endif
128 0, // QUIET
129 0, // SYSLOG
130 3600 // TCP_KEEPALIVE
131 };
132
133
134
135 static char tcp_proxy_line[128] = "";
136
137 /* What agent/state requests the shutdown--for proper half-closed
138 * handling */
139 typedef enum _SHUTDOWN_REQUESTOR {
140 SHUTDOWN_HARD,
141 SHUTDOWN_DOWN,
142 SHUTDOWN_UP
143 } SHUTDOWN_REQUESTOR;
144
145 /*
146 * Proxied State
147 *
148 * All state associated with one proxied connection
149 */
150 typedef struct proxystate {
151 ringbuffer ring_down; /* pushing bytes from client to backend */
152 ringbuffer ring_up; /* pushing bytes from backend to client */
153
154 ev_io ev_r_up; /* Upstream write event */
155 ev_io ev_w_up; /* Upstream read event */
156
157 ev_io ev_r_handshake; /* Downstream write event */
158 ev_io ev_w_handshake; /* Downstream read event */
159
160 ev_io ev_r_down; /* Downstream write event */
161 ev_io ev_w_down; /* Downstream read event */
162
163 int fd_up; /* Upstream (client) socket */
164 int fd_down; /* Downstream (backend) socket */
165
166 int want_shutdown:1; /* Connection is half-shutdown */
167 int handshaked:1; /* Initial handshake happened */
168 int renegotiation:1; /* Renegotation is occuring */
169
170 SSL *ssl; /* OpenSSL SSL state */
171
172 struct sockaddr_storage remote_ip; /* Remote ip returned from `accept` */
173 } proxystate;
174
175 #define LOG(...) \
176 do { \
177 if (!OPTIONS.QUIET) fprintf(stdout, __VA_ARGS__); \
178 if (OPTIONS.SYSLOG) syslog(LOG_INFO, __VA_ARGS__); \
179 } while(0)
180
181 #define ERR(...) \
182 do { \
183 fprintf(stderr, __VA_ARGS__); \
184 if (OPTIONS.SYSLOG) syslog(LOG_ERR, __VA_ARGS__); \
185 } while(0)
186
187
188 /* set a file descriptor (socket) to non-blocking mode */
189 static void setnonblocking(int fd) {
190 int flag = 1;
191
192 assert (ioctl(fd, FIONBIO, &flag) == 0);
193 }
194
195 /* set a tcp socket to use TCP Keepalive */
196 static void settcpkeepalive(int fd) {
197 int optval = 1;
198 socklen_t optlen = sizeof(optval);
199
200 if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
201 ERR("Error activating SO_KEEPALIVE on client socket: %s", strerror(errno));
202 }
203
204 optval = OPTIONS.TCP_KEEPALIVE;
205 optlen = sizeof(optval);
206 if(setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) {
207 ERR("Error setting TCP_KEEPIDLE on client socket: %s", strerror(errno));
208 }
209 }
210
211 static void fail(const char* s) {
212 perror(s);
213 exit(1);
214 }
215
216 #ifndef OPENSSL_NO_DH
217 static int init_dh(SSL_CTX *ctx, const char *cert) {
218 DH *dh;
219 BIO *bio;
220
221 assert(cert);
222
223 bio = BIO_new_file(cert, "r");
224 if (!bio) {
225 ERR_print_errors_fp(stderr);
226 return -1;
227 }
228
229 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
230 BIO_free(bio);
231 if (!dh) {
232 ERR("{core} Note: no DH parameters found in %s\n", cert);
233 return -1;
234 }
235
236 LOG("{core} Using DH parameters from %s\n", cert);
237 SSL_CTX_set_tmp_dh(ctx, dh);
238 LOG("{core} DH initialized with %d bit key\n", 8*DH_size(dh));
239 DH_free(dh);
240
241 return 0;
242 }
243 #endif /* OPENSSL_NO_DH */
244
245 /* This callback function is executed while OpenSSL processes the SSL
246 * handshake and does SSL record layer stuff. It's used to trap
247 * client-initiated renegotiations.
248 */
249 static void info_callback(const SSL *ssl, int where, int ret) {
250 (void)ret;
251 if (where & SSL_CB_HANDSHAKE_START) {
252 proxystate *ps = (proxystate *)SSL_get_app_data(ssl);
253 if (ps->handshaked) {
254 ps->renegotiation = 1;
255 LOG("{core} SSL renegotiation asked by client\n");
256 }
257 }
258 }
259
260 /* Init library and load specified certificate.
261 * Establishes a SSL_ctx, to act as a template for
262 * each connection */
263 static SSL_CTX * init_openssl() {
264 SSL_library_init();
265 SSL_load_error_strings();
266 SSL_CTX *ctx = NULL;
267 long ssloptions = SSL_OP_NO_SSLv2 | SSL_OP_ALL |
268 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
269
270 if (OPTIONS.ETYPE == ENC_TLS)
271 ctx = SSL_CTX_new(TLSv1_server_method());
272 else if (OPTIONS.ETYPE == ENC_SSL)
273 ctx = SSL_CTX_new(SSLv23_server_method());
274 else
275 assert(OPTIONS.ETYPE == ENC_TLS || OPTIONS.ETYPE == ENC_SSL);
276
277 #ifdef SSL_OP_NO_COMPRESSION
278 ssloptions |= SSL_OP_NO_COMPRESSION;
279 #endif
280
281 SSL_CTX_set_options(ctx, ssloptions);
282 SSL_CTX_set_info_callback(ctx, info_callback);
283
284 if (SSL_CTX_use_certificate_chain_file(ctx, OPTIONS.CERT_FILE) <= 0) {
285 ERR_print_errors_fp(stderr);
286 exit(1);
287 }
288 if (SSL_CTX_use_RSAPrivateKey_file(ctx, OPTIONS.CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
289 ERR_print_errors_fp(stderr);
290 exit(1);
291 }
292
293 #ifndef OPENSSL_NO_DH
294 init_dh(ctx, OPTIONS.CERT_FILE);
295 #endif /* OPENSSL_NO_DH */
296
297 if (OPTIONS.ENGINE) {
298 ENGINE *e = NULL;
299 ENGINE_load_builtin_engines();
300 if (!strcmp(OPTIONS.ENGINE, "auto"))
301 ENGINE_register_all_complete();
302 else {
303 if ((e = ENGINE_by_id(OPTIONS.ENGINE)) == NULL ||
304 !ENGINE_init(e) ||
305 !ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
306 ERR_print_errors_fp(stderr);
307 exit(1);
308 }
309 LOG("{core} will use OpenSSL engine %s.\n", ENGINE_get_id(e));
310 ENGINE_finish(e);
311 ENGINE_free(e);
312 }
313 }
314
315 if (OPTIONS.CIPHER_SUITE)
316 if (SSL_CTX_set_cipher_list(ctx, OPTIONS.CIPHER_SUITE) != 1)
317 ERR_print_errors_fp(stderr);
318
319 #ifdef USE_SHARED_CACHE
320 if (OPTIONS.SHARED_CACHE) {
321 if (shared_context_init(ctx, OPTIONS.SHARED_CACHE) < 0) {
322 ERR("Unable to alloc memory for shared cache.\n");
323 exit(1);
324 }
325 }
326 #endif
327
328 return ctx;
329 }
330
331 static void prepare_proxy_line(struct sockaddr* ai_addr) {
332 tcp_proxy_line[0] = 0;
333 char tcp6_address_string[INET6_ADDRSTRLEN];
334
335 if (ai_addr->sa_family == AF_INET) {
336 struct sockaddr_in* addr = (struct sockaddr_in*)ai_addr;
337 size_t res = snprintf(tcp_proxy_line,
338 sizeof(tcp_proxy_line),
339 "PROXY %%s %%s %s %%hu %hu\r\n",
340 inet_ntoa(addr->sin_addr),
341 ntohs(addr->sin_port));
342 assert(res < sizeof(tcp_proxy_line));
343 }
344 else if (ai_addr->sa_family == AF_INET6 ) {
345 struct sockaddr_in6* addr = (struct sockaddr_in6*)ai_addr;
346 inet_ntop(AF_INET6,&(addr->sin6_addr),tcp6_address_string,INET6_ADDRSTRLEN);
347 size_t res = snprintf(tcp_proxy_line,
348 sizeof(tcp_proxy_line),
349 "PROXY %%s %%s %s %%hu %hu\r\n",
350 tcp6_address_string,
351 ntohs(addr->sin6_port));
352 assert(res < sizeof(tcp_proxy_line));
353 }
354 else {
355 ERR("The --write-proxy mode is not implemented for this address family.\n");
356 exit(1);
357 }
358 }
359
360 /* Create the bound socket in the parent process */
361 static int create_main_socket() {
362 struct addrinfo *ai, hints;
363 memset(&hints, 0, sizeof hints);
364 hints.ai_family = AF_UNSPEC;
365 hints.ai_socktype = SOCK_STREAM;
366 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
367 const int gai_err = getaddrinfo(OPTIONS.FRONT_IP, OPTIONS.FRONT_PORT,
368 &hints, &ai);
369 if (gai_err != 0) {
370 ERR("{getaddrinfo}: [%s]\n", gai_strerror(gai_err));
371 exit(1);
372 }
373
374 int s = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
375
376 if (s == -1)
377 fail("{socket: main}");
378
379 int t = 1;
380 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int));
381 #ifdef SO_REUSEPORT
382 setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &t, sizeof(int));
383 #endif
384 setnonblocking(s);
385
386 if (bind(s, ai->ai_addr, ai->ai_addrlen)) {
387 fail("{bind-socket}");
388 }
389
390 #if TCP_DEFER_ACCEPT
391 int timeout = 1;
392 setsockopt(s, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(int) );
393 #endif /* TCP_DEFER_ACCEPT */
394
395 prepare_proxy_line(ai->ai_addr);
396
397 freeaddrinfo(ai);
398 listen(s, OPTIONS.BACKLOG);
399
400 return s;
401 }
402
403 /* Initiate a clear-text nonblocking connect() to the backend IP on behalf
404 * of a newly connected upstream (encrypted) client*/
405 static int create_back_socket() {
406 int s = socket(backaddr->ai_family, SOCK_STREAM, IPPROTO_TCP);
407
408 if (s == -1)
409 return -1;
410
411 int flag = 1;
412 int ret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
413 if (ret == -1) {
414 perror("Couldn't setsockopt to backend (TCP_NODELAY)\n");
415 }
416
417 int t = 1;
418 setnonblocking(s);
419 t = connect(s, backaddr->ai_addr, backaddr->ai_addrlen);
420 if (t == 0 || errno == EINPROGRESS || errno == EINTR)
421 return s;
422
423 perror("{backend-connect}");
424
425 return -1;
426 }
427
428 /* Only enable a libev ev_io event if the proxied connection still
429 * has both up and down connected */
430 static void safe_enable_io(proxystate *ps, ev_io *w) {
431 if (!ps->want_shutdown)
432 ev_io_start(loop, w);
433 }
434
435 /* Only enable a libev ev_io event if the proxied connection still
436 * has both up and down connected */
437 static void shutdown_proxy(proxystate *ps, SHUTDOWN_REQUESTOR req) {
438 if (ps->want_shutdown || req == SHUTDOWN_HARD) {
439 ev_io_stop(loop, &ps->ev_w_up);
440 ev_io_stop(loop, &ps->ev_r_up);
441 ev_io_stop(loop, &ps->ev_w_handshake);
442 ev_io_stop(loop, &ps->ev_r_handshake);
443 ev_io_stop(loop, &ps->ev_w_down);
444 ev_io_stop(loop, &ps->ev_r_down);
445
446 close(ps->fd_up);
447 close(ps->fd_down);
448
449 SSL_set_shutdown(ps->ssl, SSL_SENT_SHUTDOWN);
450 SSL_free(ps->ssl);
451
452 free(ps);
453 }
454 else {
455 ps->want_shutdown = 1;
456 if (req == SHUTDOWN_DOWN && ringbuffer_is_empty(&ps->ring_up))
457 shutdown_proxy(ps, SHUTDOWN_HARD);
458 else if (req == SHUTDOWN_UP && ringbuffer_is_empty(&ps->ring_down))
459 shutdown_proxy(ps, SHUTDOWN_HARD);
460 }
461 }
462
463 /* Handle various socket errors */
464 static void handle_socket_errno(proxystate *ps) {
465 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
466 return;
467
468 if (errno == ECONNRESET)
469 ERR("{backend} Connection reset by peer\n");
470 else if (errno == ETIMEDOUT)
471 ERR("{backend} Connection to backend timed out\n");
472 else if (errno == EPIPE)
473 ERR("{backend} Broken pipe to backend (EPIPE)\n");
474 else
475 perror("{backend} [errno]");
476 shutdown_proxy(ps, SHUTDOWN_DOWN);
477 }
478
479 /* Read some data from the backend when libev says data is available--
480 * write it into the upstream buffer and make sure the write event is
481 * enabled for the upstream socket */
482 static void back_read(struct ev_loop *loop, ev_io *w, int revents) {
483 (void) revents;
484 int t;
485 proxystate *ps = (proxystate *)w->data;
486 if (ps->want_shutdown) {
487 ev_io_stop(loop, &ps->ev_r_down);
488 return;
489 }
490 int fd = w->fd;
491 char * buf = ringbuffer_write_ptr(&ps->ring_up);
492 t = recv(fd, buf, RING_DATA_LEN, 0);
493
494 if (t > 0) {
495 ringbuffer_write_append(&ps->ring_up, t);
496 if (ringbuffer_is_full(&ps->ring_up))
497 ev_io_stop(loop, &ps->ev_r_down);
498 safe_enable_io(ps, &ps->ev_w_up);
499 }
500 else if (t == 0) {
501 LOG("{backend} Connection closed\n");
502 shutdown_proxy(ps, SHUTDOWN_DOWN);
503 }
504 else {
505 assert(t == -1);
506 handle_socket_errno(ps);
507 }
508 }
509 /* Write some data, previously received on the secure upstream socket,
510 * out of the downstream buffer and onto the backend socket */
511 static void back_write(struct ev_loop *loop, ev_io *w, int revents) {
512 (void) revents;
513 int t;
514 proxystate *ps = (proxystate *)w->data;
515 int fd = w->fd;
516 int sz;
517
518 assert(!ringbuffer_is_empty(&ps->ring_down));
519
520 char *next = ringbuffer_read_next(&ps->ring_down, &sz);
521 t = send(fd, next, sz, MSG_NOSIGNAL);
522
523 if (t > 0) {
524 if (t == sz) {
525 ringbuffer_read_pop(&ps->ring_down);
526 safe_enable_io(ps, &ps->ev_r_up);
527 if (ringbuffer_is_empty(&ps->ring_down)) {
528 if (ps->want_shutdown) {
529 shutdown_proxy(ps, SHUTDOWN_HARD);
530 return; // dealloc'd
531 }
532 ev_io_stop(loop, &ps->ev_w_down);
533 }
534 }
535 else {
536 ringbuffer_read_skip(&ps->ring_down, t);
537 }
538 }
539 else {
540 assert(t == -1);
541 handle_socket_errno(ps);
542 }
543 }
544
545 static void start_handshake(proxystate *ps, int err);
546
547 /* Continue/complete the asynchronous connect() before starting data transmission
548 * between front/backend */
549 static void handle_connect(struct ev_loop *loop, ev_io *w, int revents) {
550 (void) revents;
551 int t;
552 proxystate *ps = (proxystate *)w->data;
553 char tcp6_address_string[INET6_ADDRSTRLEN];
554 size_t written = 0;
555 t = connect(ps->fd_down, backaddr->ai_addr, backaddr->ai_addrlen);
556 if (!t || errno == EISCONN || !errno) {
557 /* INIT */
558 ev_io_stop(loop, &ps->ev_w_down);
559 ev_io_init(&ps->ev_r_down, back_read, ps->fd_down, EV_READ);
560 ev_io_init(&ps->ev_w_down, back_write, ps->fd_down, EV_WRITE);
561 start_handshake(ps, SSL_ERROR_WANT_READ); /* for client-first handshake */
562 ev_io_start(loop, &ps->ev_r_down);
563 if (OPTIONS.WRITE_PROXY_LINE) {
564 char *ring_pnt = ringbuffer_write_ptr(&ps->ring_down);
565 assert(ps->remote_ip.ss_family == AF_INET ||
566 ps->remote_ip.ss_family == AF_INET6);
567 if(ps->remote_ip.ss_family == AF_INET) {
568 struct sockaddr_in* addr = (struct sockaddr_in*)&ps->remote_ip;
569 written = snprintf(ring_pnt,
570 RING_DATA_LEN,
571 tcp_proxy_line,
572 "TCP4",
573 inet_ntoa(addr->sin_addr),
574 ntohs(addr->sin_port));
575 }
576 else if (ps->remote_ip.ss_family == AF_INET6) {
577 struct sockaddr_in6* addr = (struct sockaddr_in6*)&ps->remote_ip;
578 inet_ntop(AF_INET6,&(addr->sin6_addr),tcp6_address_string,INET6_ADDRSTRLEN);
579 written = snprintf(ring_pnt,
580 RING_DATA_LEN,
581 tcp_proxy_line,
582 "TCP6",
583 tcp6_address_string,
584 ntohs(addr->sin6_port));
585 }
586 ringbuffer_write_append(&ps->ring_down, written);
587 ev_io_start(loop, &ps->ev_w_down);
588 }
589 else if (OPTIONS.WRITE_IP_OCTET) {
590 char *ring_pnt = ringbuffer_write_ptr(&ps->ring_down);
591 assert(ps->remote_ip.ss_family == AF_INET ||
592 ps->remote_ip.ss_family == AF_INET6);
593 *ring_pnt++ = (unsigned char) ps->remote_ip.ss_family;
594 if (ps->remote_ip.ss_family == AF_INET6) {
595 memcpy(ring_pnt, &((struct sockaddr_in6 *) &ps->remote_ip)
596 ->sin6_addr.s6_addr, 16U);
597 ringbuffer_write_append(&ps->ring_down, 1U + 16U);
598 } else {
599 memcpy(ring_pnt, &((struct sockaddr_in *) &ps->remote_ip)
600 ->sin_addr.s_addr, 4U);
601 ringbuffer_write_append(&ps->ring_down, 1U + 4U);
602 }
603 ev_io_start(loop, &ps->ev_w_down);
604 }
605 }
606 else if (errno == EINPROGRESS || errno == EINTR || errno == EALREADY) {
607 /* do nothing, we'll get phoned home again... */
608 }
609 else {
610 perror("{backend-connect}");
611 shutdown_proxy(ps, SHUTDOWN_HARD);
612 }
613 }
614
615 /* Upon receiving a signal from OpenSSL that a handshake is required, re-wire
616 * the read/write events to hook up to the handshake handlers */
617 static void start_handshake(proxystate *ps, int err) {
618 ev_io_stop(loop, &ps->ev_r_up);
619 ev_io_stop(loop, &ps->ev_w_up);
620 if (err == SSL_ERROR_WANT_READ)
621 ev_io_start(loop, &ps->ev_r_handshake);
622 else if (err == SSL_ERROR_WANT_WRITE)
623 ev_io_start(loop, &ps->ev_w_handshake);
624 }
625
626 /* After OpenSSL is done with a handshake, re-wire standard read/write handlers
627 * for data transmission */
628 static void end_handshake(proxystate *ps) {
629 ev_io_stop(loop, &ps->ev_r_handshake);
630 ev_io_stop(loop, &ps->ev_w_handshake);
631
632 /* Disable renegotiation (CVE-2009-3555) */
633 if (ps->ssl->s3) {
634 ps->ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
635 }
636 ps->handshaked = 1;
637
638 /* if incoming buffer is not full */
639 if (!ringbuffer_is_full(&ps->ring_down))
640 safe_enable_io(ps, &ps->ev_r_up);
641
642 /* if outgoing buffer is not empty */
643 if (!ringbuffer_is_empty(&ps->ring_up))
644 // not safe.. we want to resume stream even during half-closed
645 ev_io_start(loop, &ps->ev_w_up);
646 }
647
648 /* The libev I/O handler during the OpenSSL handshake phase. Basically, just
649 * let OpenSSL do what it likes with the socket and obey its requests for reads
650 * or writes */
651 static void client_handshake(struct ev_loop *loop, ev_io *w, int revents) {
652 (void) revents;
653 int t;
654 proxystate *ps = (proxystate *)w->data;
655
656 t = SSL_do_handshake(ps->ssl);
657 if (t == 1) {
658 end_handshake(ps);
659 }
660 else {
661 int err = SSL_get_error(ps->ssl, t);
662 if (err == SSL_ERROR_WANT_READ) {
663 ev_io_stop(loop, &ps->ev_w_handshake);
664 ev_io_start(loop, &ps->ev_r_handshake);
665 }
666 else if (err == SSL_ERROR_WANT_WRITE) {
667 ev_io_stop(loop, &ps->ev_r_handshake);
668 ev_io_start(loop, &ps->ev_w_handshake);
669 }
670 else if (err == SSL_ERROR_ZERO_RETURN) {
671 LOG("{client} Connection closed (in handshake)\n");
672 shutdown_proxy(ps, SHUTDOWN_UP);
673 }
674 else {
675 LOG("{client} Unexpected SSL error (in handshake): %d\n", err);
676 shutdown_proxy(ps, SHUTDOWN_UP);
677 }
678 }
679 }
680
681 /* Handle a socket error condition passed to us from OpenSSL */
682 static void handle_fatal_ssl_error(proxystate *ps, int err) {
683 if (err == SSL_ERROR_ZERO_RETURN)
684 ERR("{client} Connection closed (in data)\n");
685 else if (err == SSL_ERROR_SYSCALL)
686 if (errno == 0)
687 ERR("{client} Connection closed (in data)\n");
688 else
689 perror("{client} [errno] ");
690 else
691 ERR("{client} Unexpected SSL_read error: %d\n", err);
692 shutdown_proxy(ps, SHUTDOWN_UP);
693 }
694
695 /* Read some data from the upstream secure socket via OpenSSL,
696 * and buffer anything we get for writing to the backend */
697 static void client_read(struct ev_loop *loop, ev_io *w, int revents) {
698 (void) revents;
699 int t;
700 proxystate *ps = (proxystate *)w->data;
701 if (ps->want_shutdown) {
702 ev_io_stop(loop, &ps->ev_r_up);
703 return;
704 }
705 char * buf = ringbuffer_write_ptr(&ps->ring_down);
706 t = SSL_read(ps->ssl, buf, RING_DATA_LEN);
707
708 /* Fix CVE-2009-3555. Disable reneg if started by client. */
709 if (ps->renegotiation) {
710 shutdown_proxy(ps, SHUTDOWN_UP);
711 return;
712 }
713
714 if (t > 0) {
715 ringbuffer_write_append(&ps->ring_down, t);
716 if (ringbuffer_is_full(&ps->ring_down))
717 ev_io_stop(loop, &ps->ev_r_up);
718 safe_enable_io(ps, &ps->ev_w_down);
719 }
720 else {
721 int err = SSL_get_error(ps->ssl, t);
722 if (err == SSL_ERROR_WANT_WRITE) {
723 start_handshake(ps, err);
724 }
725 else if (err == SSL_ERROR_WANT_READ) { } /* incomplete SSL data */
726 else
727 handle_fatal_ssl_error(ps, err);
728 }
729 }
730
731 /* Write some previously-buffered backend data upstream on the
732 * secure socket using OpenSSL */
733 static void client_write(struct ev_loop *loop, ev_io *w, int revents) {
734 (void) revents;
735 int t;
736 int sz;
737 proxystate *ps = (proxystate *)w->data;
738 assert(!ringbuffer_is_empty(&ps->ring_up));
739 char * next = ringbuffer_read_next(&ps->ring_up, &sz);
740 t = SSL_write(ps->ssl, next, sz);
741 if (t > 0) {
742 if (t == sz) {
743 ringbuffer_read_pop(&ps->ring_up);
744 safe_enable_io(ps, &ps->ev_r_down); // can be re-enabled b/c we've popped
745 if (ringbuffer_is_empty(&ps->ring_up)) {
746 if (ps->want_shutdown) {
747 shutdown_proxy(ps, SHUTDOWN_HARD);
748 return;
749 }
750 ev_io_stop(loop, &ps->ev_w_up);
751 }
752 }
753 else {
754 ringbuffer_read_skip(&ps->ring_up, t);
755 }
756 }
757 else {
758 int err = SSL_get_error(ps->ssl, t);
759 if (err == SSL_ERROR_WANT_READ) {
760 start_handshake(ps, err);
761 }
762 else if (err == SSL_ERROR_WANT_WRITE) {} /* incomplete SSL data */
763 else
764 handle_fatal_ssl_error(ps, err);
765 }
766 }
767
768 /* libev read handler for the bound socket. Socket is accepted,
769 * the proxystate is allocated and initalized, and we're off the races
770 * connecting to the backend */
771 static void handle_accept(struct ev_loop *loop, ev_io *w, int revents) {
772 (void) revents;
773 struct sockaddr_storage addr;
774 socklen_t sl = sizeof(addr);
775 int client = accept(w->fd, (struct sockaddr *) &addr, &sl);
776 if (client == -1) {
777 switch (errno) {
778 case EMFILE:
779 ERR("{client} accept() failed; too many open files for this process\n");
780 break;
781
782 case ENFILE:
783 ERR("{client} accept() failed; too many open files for this system\n");
784 break;
785
786 case 'k':
787 OPTIONS.TCP_KEEPALIVE = atoi(optarg);
788 break;
789
790 default:
791 assert(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN);
792 break;
793 }
794 return;
795 }
796
797 int flag = 1;
798 int ret = setsockopt(client, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) );
799 if (ret == -1) {
800 perror("Couldn't setsockopt on client (TCP_NODELAY)\n");
801 }
802 #ifdef TCP_CWND
803 int cwnd = 10;
804 ret = setsockopt(client, IPPROTO_TCP, TCP_CWND, &cwnd, sizeof(cwnd));
805 if (ret == -1) {
806 perror("Couldn't setsockopt on client (TCP_CWND)\n");
807 }
808 #endif
809
810 setnonblocking(client);
811 settcpkeepalive(client);
812
813 int back = create_back_socket();
814
815 if (back == -1) {
816 close(client);
817 perror("{backend-connect}");
818 return;
819 }
820
821 SSL_CTX * ctx = (SSL_CTX *)w->data;
822 SSL *ssl = SSL_new(ctx);
823 long mode = SSL_MODE_ENABLE_PARTIAL_WRITE;
824 #ifdef SSL_MODE_RELEASE_BUFFERS
825 mode |= SSL_MODE_RELEASE_BUFFERS;
826 #endif
827 SSL_set_mode(ssl, mode);
828 SSL_set_accept_state(ssl);
829 SSL_set_fd(ssl, client);
830
831 proxystate *ps = (proxystate *)malloc(sizeof(proxystate));
832
833 ps->fd_up = client;
834 ps->fd_down = back;
835 ps->ssl = ssl;
836 ps->want_shutdown = 0;
837 ps->handshaked = 0;
838 ps->renegotiation = 0;
839 ps->remote_ip = addr;
840 ringbuffer_init(&ps->ring_up);
841 ringbuffer_init(&ps->ring_down);
842
843 /* set up events */
844 ev_io_init(&ps->ev_r_up, client_read, client, EV_READ);
845 ev_io_init(&ps->ev_w_up, client_write, client, EV_WRITE);
846
847 ev_io_init(&ps->ev_r_handshake, client_handshake, client, EV_READ);
848 ev_io_init(&ps->ev_w_handshake, client_handshake, client, EV_WRITE);
849
850 ev_io_init(&ps->ev_w_down, handle_connect, back, EV_WRITE);
851 ev_io_init(&ps->ev_r_down, back_read, back, EV_READ);
852
853 ev_io_start(loop, &ps->ev_w_down);
854
855 ps->ev_r_up.data = ps;
856 ps->ev_w_up.data = ps;
857 ps->ev_r_down.data = ps;
858 ps->ev_w_down.data = ps;
859 ps->ev_r_handshake.data = ps;
860 ps->ev_w_handshake.data = ps;
861
862 /* Link back proxystate to SSL state */
863 SSL_set_app_data(ssl, ps);
864 }
865
866
867 static void check_ppid(struct ev_loop *loop, ev_timer *w, int revents) {
868 (void) revents;
869 pid_t ppid = getppid();
870 if (ppid != master_pid) {
871 ERR("{core} Process %d detected parent death, closing listener socket.\n", child_num);
872 ev_timer_stop(loop, w);
873 ev_io_stop(loop, &listener);
874 close(listener_socket);
875 }
876
877 }
878
879
880 /* Set up the child (worker) process including libev event loop, read event
881 * on the bound socket, etc */
882 static void handle_connections() {
883 LOG("{core} Process %d online\n", child_num);
884 #if defined(CPU_ZERO) && defined(CPU_SET)
885 cpu_set_t cpus;
886
887 CPU_ZERO(&cpus);
888 CPU_SET(child_num, &cpus);
889
890 int res = sched_setaffinity(0, sizeof(cpus), &cpus);
891 if (!res)
892 LOG("{core} Successfully attached to CPU #%d\n", child_num);
893 else
894 ERR("{core-warning} Unable to attach to CPU #%d; do you have that many cores?\n", child_num);
895 #endif
896
897 loop = ev_default_loop(EVFLAG_AUTO);
898
899 ev_timer timer_ppid_check;
900 ev_timer_init(&timer_ppid_check, check_ppid, 1.0, 1.0);
901 ev_timer_start(loop, &timer_ppid_check);
902
903 ev_io_init(&listener, handle_accept, listener_socket, EV_READ);
904 listener.data = ssl_ctx;
905 ev_io_start(loop, &listener);
906
907 ev_loop(loop, 0);
908 ERR("{core} Child %d exiting.\n", child_num);
909 exit(1);
910 }
911
912
913 /* Print usage w/error message and exit failure */
914 static void usage_fail(const char *prog, const char *msg) {
915 if (msg)
916 fprintf(stderr, "%s: %s\n", prog, msg);
917 fprintf(stderr, "usage: %s [OPTION] PEM\n", prog);
918
919 fprintf(stderr,
920 "Encryption Methods:\n"
921 " --tls TLSv1 (default)\n"
922 " --ssl SSLv3 (implies no TLSv1)\n"
923 " -c CIPHER_SUITE set allowed ciphers (default is OpenSSL defaults)\n"
924 " -e ENGINE set OpenSSL engine\n"
925 "\n"
926 "Socket:\n"
927 " -b HOST,PORT backend [connect] (default is \"127.0.0.1,8000\")\n"
928 " -f HOST,PORT frontend [bind] (default is \"*,8443\")\n"
929 "\n"
930 "Performance:\n"
931 " -n CORES number of worker processes (default is 1)\n"
932 " -B BACKLOG set listen backlog size (default is 100)\n"
933 " -k SECS Change default tcp keepalive on client socket\n"
934 #ifdef USE_SHARED_CACHE
935 " -C SHARED_CACHE set shared cache size in sessions (default no shared cache)\n"
936 #endif
937 "\n"
938 "Security:\n"
939 " -r PATH chroot\n"
940 " -u USERNAME set gid/uid after binding the socket\n"
941 "\n"
942 "Logging:\n"
943 " -q be quiet; emit only error messages\n"
944 " -s send log message to syslog in addition to stderr/stdout\n"
945 "\n"
946 "Special:\n"
947 " --write-ip write 1 octet with the IP family followed by the IP\n"
948 " address in 4 (IPv4) or 16 (IPv6) octets little-endian\n"
949 " to backend before the actual data\n"
950 " --write-proxy write HaProxy's PROXY (IPv4 or IPv6) protocol line\n"
951 " before actual data\n"
952 );
953 exit(1);
954 }
955
956
957 static void parse_host_and_port(const char *prog, const char *name, char *inp, int wildcard_okay, const char **ip, const char **port) {
958 char buf[150];
959 char *sp;
960
961 if (strlen(inp) >= sizeof buf) {
962 snprintf(buf, sizeof buf, "invalid option for %s HOST,PORT\n", name);
963 usage_fail(prog, buf);
964 }
965
966 sp = strchr(inp, ',');
967 if (!sp) {
968 snprintf(buf, sizeof buf, "invalid option for %s HOST,PORT\n", name);
969 usage_fail(prog, buf);
970 }
971
972 if (!strncmp(inp, "*", sp - inp)) {
973 if (!wildcard_okay) {
974 snprintf(buf, sizeof buf, "wildcard host specification invalid for %s\n", name);
975 usage_fail(prog, buf);
976 }
977 *ip = NULL;
978 }
979 else {
980 *sp = 0;
981 *ip = inp;
982 }
983 *port = sp + 1;
984 }
985
986
987 /* Handle command line arguments modifying behavior */
988 static void parse_cli(int argc, char **argv) {
989 const char *prog = argv[0];
990
991 static int tls = 0, ssl = 0;
992 int c;
993 struct passwd* passwd;
994
995 static struct option long_options[] =
996 {
997 {"tls", 0, &tls, 1},
998 {"ssl", 0, &ssl, 1},
999 {"write-ip", 0, &OPTIONS.WRITE_IP_OCTET, 1},
1000 {"write-proxy", 0, &OPTIONS.WRITE_PROXY_LINE, 1},
1001 {0, 0, 0, 0}
1002 };
1003
1004 while (1) {
1005 int option_index = 0;
1006 c = getopt_long(argc, argv, "hf:b:n:c:e:u:r:B:C:k:qs",
1007 long_options, &option_index);
1008
1009 if (c == -1)
1010 break;
1011
1012 switch (c) {
1013
1014 case 0:
1015 break;
1016
1017 case 'n':
1018 errno = 0;
1019 OPTIONS.NCORES = strtol(optarg, NULL, 10);
1020 if ((errno == ERANGE &&
1021 (OPTIONS.NCORES == LONG_MAX || OPTIONS.NCORES == LONG_MIN)) ||
1022 OPTIONS.NCORES < 1 || OPTIONS.NCORES > 128) {
1023 usage_fail(prog, "invalid option for -n CORES; please provide an integer between 1 and 128\n");
1024 }
1025 break;
1026
1027 case 'b':
1028 parse_host_and_port(prog, "-b", optarg, 0, &(OPTIONS.BACK_IP), &(OPTIONS.BACK_PORT));
1029 break;
1030
1031 case 'f':
1032 parse_host_and_port(prog, "-f", optarg, 1, &(OPTIONS.FRONT_IP), &(OPTIONS.FRONT_PORT));
1033 break;
1034
1035 case 'c':
1036 OPTIONS.CIPHER_SUITE = optarg;
1037 break;
1038
1039 case 'e':
1040 OPTIONS.ENGINE = optarg;
1041 break;
1042
1043 case 'u':
1044 passwd = getpwnam(optarg);
1045 if (!passwd) {
1046 if (errno)
1047 fail("getpwnam failed");
1048 else
1049 ERR("user not found: %s\n", optarg);
1050 exit(1);
1051 }
1052 OPTIONS.UID = passwd->pw_uid;
1053 OPTIONS.GID = passwd->pw_gid;
1054 break;
1055
1056 case 'r':
1057 if (optarg && optarg[0] == '/')
1058 OPTIONS.CHROOT = optarg;
1059 else {
1060 ERR("chroot must be absolute path: \"%s\"\n", optarg);
1061 exit(1);
1062 }
1063 break;
1064
1065 case 'B':
1066 OPTIONS.BACKLOG = atoi(optarg);
1067 if ( OPTIONS.BACKLOG <= 0 ) {
1068 ERR("listen backlog can not be set to %d\n", OPTIONS.BACKLOG);
1069 exit(1);
1070 }
1071 break;
1072
1073 #ifdef USE_SHARED_CACHE
1074 case 'C':
1075 OPTIONS.SHARED_CACHE = atoi(optarg);
1076 if ( OPTIONS.SHARED_CACHE < 0 ) {
1077 ERR("shared cache size can not be set to %d\n", OPTIONS.SHARED_CACHE);
1078 exit(1);
1079 }
1080 break;
1081 #endif
1082
1083 case 'q':
1084 OPTIONS.QUIET = 1;
1085 break;
1086
1087 case 's':
1088 OPTIONS.SYSLOG = 1;
1089 break;
1090
1091 default:
1092 usage_fail(prog, NULL);
1093 }
1094 }
1095
1096 /* Post-processing */
1097 if (tls && ssl)
1098 usage_fail(prog, "Cannot specify both --tls and --ssl");
1099
1100 if (ssl)
1101 OPTIONS.ETYPE = ENC_SSL; // implied.. else, TLS
1102
1103 if (OPTIONS.WRITE_IP_OCTET && OPTIONS.WRITE_PROXY_LINE)
1104 usage_fail(prog, "Cannot specify both --write-ip and --write-proxy; pick one!");
1105
1106 argc -= optind;
1107 argv += optind;
1108
1109 if (argc != 1)
1110 usage_fail(prog, "exactly one argument is required: path to PEM file with cert/key");
1111
1112 OPTIONS.CERT_FILE = argv[0];
1113 }
1114
1115
1116 void change_root() {
1117 if (chroot(OPTIONS.CHROOT) == -1)
1118 fail("chroot");
1119 if (chdir("/"))
1120 fail("chdir");
1121 }
1122
1123 void drop_privileges() {
1124 if (setgid(OPTIONS.GID))
1125 fail("setgid failed");
1126 if (setuid(OPTIONS.UID))
1127 fail("setuid failed");
1128 }
1129
1130
1131 void init_globals() {
1132 /* backaddr */
1133 struct addrinfo hints;
1134 memset(&hints, 0, sizeof hints);
1135 hints.ai_family = AF_UNSPEC;
1136 hints.ai_socktype = SOCK_STREAM;
1137 hints.ai_flags = 0;
1138 const int gai_err = getaddrinfo(OPTIONS.BACK_IP, OPTIONS.BACK_PORT,
1139 &hints, &backaddr);
1140 if (gai_err != 0) {
1141 ERR("{getaddrinfo}: [%s]", gai_strerror(gai_err));
1142 exit(1);
1143 }
1144
1145 /* child_pids */
1146 if ((child_pids = calloc(OPTIONS.NCORES, sizeof(pid_t))) == NULL)
1147 fail("calloc");
1148
1149 if (OPTIONS.SYSLOG)
1150 openlog("stud", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
1151 }
1152
1153 /* Forks COUNT children starting with START_INDEX.
1154 * Each child's index is stored in child_num and its pid is stored in child_pids[child_num]
1155 * so the parent can manage it later. */
1156 void start_children(int start_index, int count) {
1157 for (child_num = start_index; child_num < start_index + count; child_num++) {
1158 int pid = fork();
1159 if (pid == -1) {
1160 ERR("{core} fork() failed! Goodbye cruel world!\n");
1161 exit(1);
1162 }
1163 else if (pid == 0) { /* child */
1164 handle_connections();
1165 exit(0);
1166 }
1167 else { /* parent. Track new child. */
1168 child_pids[child_num] = pid;
1169 }
1170 }
1171 }
1172
1173 /* Forks a new child to replace the old, dead, one with the given PID.*/
1174 void replace_child_with_pid(pid_t pid) {
1175 int i;
1176
1177 /* find old child's slot and put a new child there */
1178 for (i = 0; i < OPTIONS.NCORES; i++) {
1179 if (child_pids[i] == pid) {
1180 start_children(i, 1);
1181 return;
1182 }
1183 }
1184
1185 ERR("Cannot find index for child pid %d", pid);
1186 }
1187
1188 /* Manage status changes in child processes */
1189 static void do_wait(int __attribute__ ((unused)) signo) {
1190
1191 int status;
1192 int pid = wait(&status);
1193
1194 if (pid == -1) {
1195 if (errno == ECHILD) {
1196 ERR("{core} All children have exited! Restarting...\n");
1197 start_children(0, OPTIONS.NCORES);
1198 }
1199 else if (errno == EINTR) {
1200 ERR("{core} Interrupted wait\n");
1201 }
1202 else {
1203 fail("wait");
1204 }
1205 }
1206 else {
1207 if (WIFEXITED(status)) {
1208 ERR("{core} Child %d exited with status %d. Replacing...\n", pid, WEXITSTATUS(status));
1209 replace_child_with_pid(pid);
1210 }
1211 else if (WIFSIGNALED(status)) {
1212 ERR("{core} Child %d was terminated by signal %d. Replacing...\n", pid, WTERMSIG(status));
1213 replace_child_with_pid(pid);
1214 }
1215 }
1216 }
1217
1218 void init_signals() {
1219 struct sigaction act;
1220
1221 sigemptyset(&act.sa_mask);
1222 act.sa_flags = 0;
1223 act.sa_handler = SIG_IGN;
1224
1225 /* Avoid getting PIPE signal when writing to a closed file descriptor */
1226 if (sigaction(SIGPIPE, &act, NULL) < 0)
1227 fail("sigaction - sigpipe");
1228
1229 /* We don't care if someone stops and starts a child process with kill (1) */
1230 act.sa_flags = SA_NOCLDSTOP;
1231
1232 act.sa_handler = do_wait;
1233
1234 /* We do care when child processes change status */
1235 if (sigaction(SIGCHLD, &act, NULL) < 0)
1236 fail("sigaction - sigchld");
1237 }
1238
1239 /* Process command line args, create the bound socket,
1240 * spawn child (worker) processes, and respawn if any die */
1241 int main(int argc, char **argv) {
1242 parse_cli(argc, argv);
1243
1244 init_signals();
1245
1246 init_globals();
1247
1248 listener_socket = create_main_socket();
1249
1250 /* load certificate, pass to handle_connections */
1251 ssl_ctx = init_openssl();
1252
1253 master_pid = getpid();
1254
1255 if (OPTIONS.CHROOT && OPTIONS.CHROOT[0])
1256 change_root();
1257
1258 if (OPTIONS.UID || OPTIONS.GID)
1259 drop_privileges();
1260
1261 start_children(0, OPTIONS.NCORES);
1262
1263 for (;;) {
1264 /* Sleep and let the children work.
1265 * Parent will be woken up if a signal arrives */
1266 pause();
1267 }
1268
1269 exit(0); /* just a formality; we never get here */
1270 }