1 /*
2  * Pound - the reverse-proxy load-balancer
3  * Copyright (C) 2002-2010 Apsis GmbH
4  *
5  * This file is part of Pound.
6  *
7  * Pound is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Pound is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  * Contact information:
21  * Apsis GmbH
22  * P.O.Box
23  * 8707 Uetikon am See
24  * Switzerland
25  * EMail: roseg@apsis.ch
26  */
27 
28 #include    "pound.h"
29 
30 /* common variables */
31 char        *user,              /* user to run as */
32             *group,             /* group to run as */
33             *root_jail,         /* directory to chroot to */
34             *pid_name,          /* file to record pid in */
35             *ctrl_name;         /* control socket name */
36 
37 int         alive_to,           /* check interval for resurrection */
38             anonymise,          /* anonymise client address */
39             daemonize,          /* run as daemon */
40             log_facility,       /* log facility to use */
41             print_log,          /* print log messages to stdout/stderr */
42             grace,              /* grace period before shutdown */
43             control_sock;       /* control socket */
44 
45 SERVICE     *services;          /* global services (if any) */
46 
47 LISTENER    *listeners;         /* all available listeners */
48 
49 regex_t HEADER,             /* Allowed header */
50         CONN_UPGRD,         /* upgrade in connection header */
51         CHUNK_HEAD,         /* chunk header line */
52         RESP_SKIP,          /* responses for which we skip response */
53         RESP_IGN,           /* responses for which we ignore content */
54         LOCATION,           /* the host we are redirected to */
55         AUTHORIZATION;      /* the Authorisation header */
56 
57 static int  shut_down = 0;
58 
59 #ifndef  SOL_TCP
60 /* for systems without the definition */
61 int     SOL_TCP;
62 #endif
63 
64 /* worker pid */
65 static  pid_t               son = 0;
66 
67 /*
68  * OpenSSL thread support stuff
69  */
70 static pthread_mutex_t  *l_array;
71 
72 static void
l_init(void)73 l_init(void)
74 {
75     int i, n_locks;
76 
77     n_locks = CRYPTO_num_locks();
78     if((l_array = (pthread_mutex_t *)calloc(n_locks, sizeof(pthread_mutex_t))) == NULL) {
79         logmsg(LOG_ERR, "lock init: out of memory - aborted...");
80         exit(1);
81     }
82     for(i = 0; i < n_locks; i++)
83         /* pthread_mutex_init() always returns 0 */
84         pthread_mutex_init(&l_array[i], NULL);
85     return;
86 }
87 
88 static void
l_lock(const int mode,const int n,const char * file,int line)89 l_lock(const int mode, const int n, /* unused */ const char *file, /* unused */ int line)
90 {
91     int ret_val;
92 
93     if(mode & CRYPTO_LOCK) {
94         if(ret_val = pthread_mutex_lock(&l_array[n]))
95             logmsg(LOG_ERR, "l_lock lock(): %s", strerror(ret_val));
96     } else {
97         if(ret_val = pthread_mutex_unlock(&l_array[n]))
98             logmsg(LOG_ERR, "l_lock unlock(): %s", strerror(ret_val));
99     }
100     return;
101 }
102 
103 static unsigned long
l_id(void)104 l_id(void)
105 {
106     return (unsigned long)pthread_self();
107 }
108 
109 /*
110  * work queue stuff
111  */
112 static thr_arg          *first = NULL, *last = NULL;
113 static pthread_cond_t   arg_cond;
114 static pthread_mutex_t  arg_mut;
115 int                     numthreads;
116 
117 static void
init_thr_arg(void)118 init_thr_arg(void)
119 {
120     pthread_cond_init(&arg_cond, NULL);
121     pthread_mutex_init(&arg_mut, NULL);
122     return;
123 }
124 
125 /*
126  * add a request to the queue
127  */
128 int
put_thr_arg(thr_arg * arg)129 put_thr_arg(thr_arg *arg)
130 {
131     thr_arg *res;
132 
133     if((res = malloc(sizeof(thr_arg))) == NULL) {
134         logmsg(LOG_WARNING, "thr_arg malloc");
135         return -1;
136     }
137     memcpy(res, arg, sizeof(thr_arg));
138     res->next = NULL;
139     (void)pthread_mutex_lock(&arg_mut);
140     if(last == NULL)
141         first = last = res;
142     else {
143         last->next = res;
144         last = last->next;
145     }
146     (void)pthread_mutex_unlock(&arg_mut);
147     pthread_cond_signal(&arg_cond);
148     return 0;
149 }
150 
151 /*
152  * get a request from the queue
153  */
154 thr_arg *
get_thr_arg(void)155 get_thr_arg(void)
156 {
157     thr_arg *res;
158 
159     (void)pthread_mutex_lock(&arg_mut);
160     if(first == NULL)
161         (void)pthread_cond_wait(&arg_cond, &arg_mut);
162     if((res = first) != NULL)
163         if((first = first->next) == NULL)
164             last = NULL;
165     (void)pthread_mutex_unlock(&arg_mut);
166     if(first != NULL)
167         pthread_cond_signal(&arg_cond);
168     return res;
169 }
170 
171 /*
172  * get the current queue length
173  */
174 int
get_thr_qlen(void)175 get_thr_qlen(void)
176 {
177     int     res;
178     thr_arg *tap;
179 
180     (void)pthread_mutex_lock(&arg_mut);
181     for(res = 0, tap = first; tap != NULL; tap = tap->next, res++)
182         ;
183     (void)pthread_mutex_unlock(&arg_mut);
184     return res;
185 }
186 
187 /*
188  * handle SIGTERM/SIGQUIT - exit
189  */
190 static RETSIGTYPE
h_term(const int sig)191 h_term(const int sig)
192 {
193     logmsg(LOG_NOTICE, "received signal %d - exiting...", sig);
194     if(son > 0)
195         kill(son, sig);
196     if(ctrl_name != NULL)
197         (void)unlink(ctrl_name);
198     exit(0);
199 }
200 
201 /*
202  * handle SIGHUP/SIGINT - exit after grace period
203  */
204 static RETSIGTYPE
h_shut(const int sig)205 h_shut(const int sig)
206 {
207     int         status;
208     LISTENER    *lstn;
209 
210     logmsg(LOG_NOTICE, "received signal %d - shutting down...", sig);
211     if(son > 0) {
212         for(lstn = listeners; lstn; lstn = lstn->next)
213             close(lstn->sock);
214         kill(son, sig);
215         (void)wait(&status);
216         if(ctrl_name != NULL)
217             (void)unlink(ctrl_name);
218         exit(0);
219     } else
220         shut_down = 1;
221 }
222 
223 /*
224  * Pound: the reverse-proxy/load-balancer
225  *
226  * Arguments:
227  *  -f config_file      configuration file - exclusive of other flags
228  */
229 
230 int
main(const int argc,char ** argv)231 main(const int argc, char **argv)
232 {
233     int                 n_listeners, i, clnt_length, clnt;
234     struct pollfd       *polls;
235     LISTENER            *lstn;
236     pthread_t           thr;
237     pthread_attr_t      attr;
238     struct sched_param  sp;
239     uid_t               user_id;
240     gid_t               group_id;
241     FILE                *fpid;
242     struct sockaddr_storage clnt_addr;
243     char                tmp[MAXBUF];
244 #ifndef SOL_TCP
245     struct protoent     *pe;
246 #endif
247 
248     print_log = 0;
249     (void)umask(077);
250     control_sock = -1;
251     log_facility = -1;
252     logmsg(LOG_NOTICE, "starting...");
253 
254     signal(SIGHUP, h_shut);
255     signal(SIGINT, h_shut);
256     signal(SIGTERM, h_term);
257     signal(SIGQUIT, h_term);
258     signal(SIGPIPE, SIG_IGN);
259 
260     srandom(getpid());
261 
262     /* SSL stuff */
263     SSL_load_error_strings();
264     SSL_library_init();
265     OpenSSL_add_all_algorithms();
266     l_init();
267     init_thr_arg();
268     CRYPTO_set_id_callback(l_id);
269     CRYPTO_set_locking_callback(l_lock);
270     init_timer();
271 
272     /* Disable SSL Compression for OpenSSL pre-1.0.  1.0 is handled with an option in config.c */
273 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
274 #ifndef SSL_OP_NO_COMPRESSION
275     {
276       int i,n;
277       STACK_OF(SSL_COMP) *ssl_comp_methods;
278 
279       ssl_comp_methods = SSL_COMP_get_compression_methods();
280       n = sk_SSL_COMP_num(ssl_comp_methods);
281 
282       for(i=n-1; i>=0; i--) {
283         sk_SSL_COMP_delete(ssl_comp_methods, i);
284       }
285     }
286 #endif
287 #endif
288 
289     /* prepare regular expressions */
290     if(regcomp(&HEADER, "^([a-z0-9!#$%&'*+.^_`|~-]+):[ \t]*(.*)[ \t]*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
291     || regcomp(&CONN_UPGRD, "(^|[ \t,])upgrade([ \t,]|$)", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
292     || regcomp(&CHUNK_HEAD, "^([0-9a-f]+).*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
293     || regcomp(&RESP_SKIP, "^HTTP/1.1 100.*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
294     || regcomp(&RESP_IGN, "^HTTP/1.[01] (10[1-9]|1[1-9][0-9]|204|30[456]).*$", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
295     || regcomp(&LOCATION, "(http|https)://([^/]+)(.*)", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
296     || regcomp(&AUTHORIZATION, "Authorization:[ \t]*Basic[ \t]*\"?([^ \t]*)\"?[ \t]*", REG_ICASE | REG_NEWLINE | REG_EXTENDED)
297     ) {
298         logmsg(LOG_ERR, "bad essential Regex - aborted");
299         exit(1);
300     }
301 
302 #ifndef SOL_TCP
303     /* for systems without the definition */
304     if((pe = getprotobyname("tcp")) == NULL) {
305         logmsg(LOG_ERR, "missing TCP protocol");
306         exit(1);
307     }
308     SOL_TCP = pe->p_proto;
309 #endif
310 
311     /* read config */
312     config_parse(argc, argv);
313 
314     if(log_facility != -1)
315         openlog("pound", LOG_CONS | LOG_NDELAY, LOG_DAEMON);
316     if(ctrl_name != NULL) {
317         struct sockaddr_un  ctrl;
318 
319         memset(&ctrl, 0, sizeof(ctrl));
320         ctrl.sun_family = AF_UNIX;
321         strncpy(ctrl.sun_path, ctrl_name, sizeof(ctrl.sun_path) - 1);
322         (void)unlink(ctrl.sun_path);
323         if((control_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
324             logmsg(LOG_ERR, "Control \"%s\" create: %s", ctrl.sun_path, strerror(errno));
325             exit(1);
326         }
327         if(bind(control_sock, (struct sockaddr *)&ctrl, (socklen_t)sizeof(ctrl)) < 0) {
328             logmsg(LOG_ERR, "Control \"%s\" bind: %s", ctrl.sun_path, strerror(errno));
329             exit(1);
330         }
331         listen(control_sock, 512);
332     }
333 
334     /* open listeners */
335     for(lstn = listeners, n_listeners = 0; lstn; lstn = lstn->next, n_listeners++) {
336         int opt;
337 
338         /* prepare the socket */
339         if((lstn->sock = socket(lstn->addr.ai_family == AF_INET? PF_INET: PF_INET6, SOCK_STREAM, 0)) < 0) {
340             addr2str(tmp, MAXBUF - 1, &lstn->addr, 0);
341             logmsg(LOG_ERR, "HTTP socket %s create: %s - aborted", tmp, strerror(errno));
342             exit(1);
343         }
344         opt = 1;
345         setsockopt(lstn->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
346         if(bind(lstn->sock, lstn->addr.ai_addr, (socklen_t)lstn->addr.ai_addrlen) < 0) {
347             addr2str(tmp, MAXBUF - 1, &lstn->addr, 0);
348             logmsg(LOG_ERR, "HTTP socket bind %s: %s - aborted", tmp, strerror(errno));
349             exit(1);
350         }
351         listen(lstn->sock, 512);
352     }
353 
354     /* alloc the poll structures */
355     if((polls = (struct pollfd *)calloc(n_listeners, sizeof(struct pollfd))) == NULL) {
356         logmsg(LOG_ERR, "Out of memory for poll - aborted");
357         exit(1);
358     }
359     for(lstn = listeners, i = 0; lstn; lstn = lstn->next, i++)
360         polls[i].fd = lstn->sock;
361 
362     /* set uid if necessary */
363     if(user) {
364         struct passwd   *pw;
365 
366         if((pw = getpwnam(user)) == NULL) {
367             logmsg(LOG_ERR, "no such user %s - aborted", user);
368             exit(1);
369         }
370         user_id = pw->pw_uid;
371     }
372 
373     /* set gid if necessary */
374     if(group) {
375         struct group    *gr;
376 
377         if((gr = getgrnam(group)) == NULL) {
378             logmsg(LOG_ERR, "no such group %s - aborted", group);
379             exit(1);
380         }
381         group_id = gr->gr_gid;
382     }
383 
384     /* Turn off verbose messages (if necessary) */
385     print_log = 0;
386 
387     if(daemonize) {
388         /* daemonize - make ourselves a subprocess. */
389         switch (fork()) {
390             case 0:
391                 if(log_facility != -1) {
392                     close(0);
393                     close(1);
394                     close(2);
395                 }
396                 break;
397             case -1:
398                 logmsg(LOG_ERR, "fork: %s - aborted", strerror(errno));
399                 exit(1);
400             default:
401                 exit(0);
402         }
403 #ifdef  HAVE_SETSID
404         (void) setsid();
405 #endif
406     }
407 
408     /* record pid in file */
409     if((fpid = fopen(pid_name, "wt")) != NULL) {
410         fprintf(fpid, "%d\n", getpid());
411         fclose(fpid);
412     } else
413         logmsg(LOG_NOTICE, "Create \"%s\": %s", pid_name, strerror(errno));
414 
415     /* chroot if necessary */
416     if(root_jail) {
417         if(chroot(root_jail)) {
418             logmsg(LOG_ERR, "chroot: %s - aborted", strerror(errno));
419             exit(1);
420         }
421         if(chdir("/")) {
422             logmsg(LOG_ERR, "chroot/chdir: %s - aborted", strerror(errno));
423             exit(1);
424         }
425     }
426 
427     if(group)
428         if(setgid(group_id) || setegid(group_id)) {
429             logmsg(LOG_ERR, "setgid: %s - aborted", strerror(errno));
430             exit(1);
431         }
432     if(user)
433         if(setuid(user_id) || seteuid(user_id)) {
434             logmsg(LOG_ERR, "setuid: %s - aborted", strerror(errno));
435             exit(1);
436         }
437 
438     /* split off into monitor and working process if necessary */
439     for(;;) {
440 #ifdef  UPER
441         if((son = fork()) > 0) {
442             int status;
443 
444             (void)wait(&status);
445             if(WIFEXITED(status))
446                 logmsg(LOG_ERR, "MONITOR: worker exited normally %d, restarting...", WEXITSTATUS(status));
447             else if(WIFSIGNALED(status))
448                 logmsg(LOG_ERR, "MONITOR: worker exited on signal %d, restarting...", WTERMSIG(status));
449             else
450                 logmsg(LOG_ERR, "MONITOR: worker exited (stopped?) %d, restarting...", status);
451         } else if (son == 0) {
452 #endif
453 
454             /* thread stuff */
455             pthread_attr_init(&attr);
456             pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
457 
458 #ifdef  NEED_STACK
459             /* set new stack size - necessary for OpenBSD/FreeBSD and Linux NPTL */
460             if(pthread_attr_setstacksize(&attr, 1 << 18)) {
461                 logmsg(LOG_ERR, "can't set stack size - aborted");
462                 exit(1);
463             }
464 #endif
465             /* start timer */
466             if(pthread_create(&thr, &attr, thr_timer, NULL)) {
467                 logmsg(LOG_ERR, "create thr_resurect: %s - aborted", strerror(errno));
468                 exit(1);
469             }
470 
471             /* start the controlling thread (if needed) */
472             if(control_sock >= 0 && pthread_create(&thr, &attr, thr_control, NULL)) {
473                 logmsg(LOG_ERR, "create thr_control: %s - aborted", strerror(errno));
474                 exit(1);
475             }
476 
477             /* pause to make sure the service threads were started */
478             sleep(1);
479 
480             /* create the worker threads */
481             for(i = 0; i < numthreads; i++)
482                 if(pthread_create(&thr, &attr, thr_http, NULL)) {
483                     logmsg(LOG_ERR, "create thr_http: %s - aborted", strerror(errno));
484                     exit(1);
485                 }
486 
487             /* pause to make sure at least some of the worker threads were started */
488             sleep(1);
489 
490             /* and start working */
491             for(;;) {
492                 if(shut_down) {
493                     logmsg(LOG_NOTICE, "shutting down...");
494                     for(lstn = listeners; lstn; lstn = lstn->next)
495                         close(lstn->sock);
496                     if(grace > 0) {
497                         sleep(grace);
498                         logmsg(LOG_NOTICE, "grace period expired - exiting...");
499                     }
500                     if(ctrl_name != NULL)
501                         (void)unlink(ctrl_name);
502                     exit(0);
503                 }
504                 for(lstn = listeners, i = 0; i < n_listeners; lstn = lstn->next, i++) {
505                     polls[i].events = POLLIN | POLLPRI;
506                     polls[i].revents = 0;
507                 }
508                 if(poll(polls, n_listeners, -1) < 0) {
509                     logmsg(LOG_WARNING, "poll: %s", strerror(errno));
510                 } else {
511                     for(lstn = listeners, i = 0; lstn; lstn = lstn->next, i++) {
512                         if(polls[i].revents & (POLLIN | POLLPRI)) {
513                             memset(&clnt_addr, 0, sizeof(clnt_addr));
514                             clnt_length = sizeof(clnt_addr);
515                             if((clnt = accept(lstn->sock, (struct sockaddr *)&clnt_addr,
516                                 (socklen_t *)&clnt_length)) < 0) {
517                                 logmsg(LOG_WARNING, "HTTP accept: %s", strerror(errno));
518                             } else if(((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET
519                                    || ((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET6) {
520                                 thr_arg arg;
521 
522                                 if(lstn->disabled) {
523                                     /*
524                                     addr2str(tmp, MAXBUF - 1, &clnt_addr, 1);
525                                     logmsg(LOG_WARNING, "HTTP disabled listener from %s", tmp);
526                                     */
527                                     close(clnt);
528                                 }
529                                 arg.sock = clnt;
530                                 arg.lstn = lstn;
531                                 if((arg.from_host.ai_addr = (struct sockaddr *)malloc(clnt_length)) == NULL) {
532                                     logmsg(LOG_WARNING, "HTTP arg address: malloc");
533                                     close(clnt);
534                                     continue;
535                                 }
536                                 memcpy(arg.from_host.ai_addr, &clnt_addr, clnt_length);
537                                 arg.from_host.ai_addrlen = clnt_length;
538                                 if(((struct sockaddr_in *)&clnt_addr)->sin_family == AF_INET)
539                                     arg.from_host.ai_family = AF_INET;
540                                 else
541                                     arg.from_host.ai_family = AF_INET6;
542                                 if(put_thr_arg(&arg))
543                                     close(clnt);
544                             } else {
545                                 /* may happen on FreeBSD, I am told */
546                                 logmsg(LOG_WARNING, "HTTP connection prematurely closed by peer");
547                                 close(clnt);
548                             }
549                         }
550                     }
551                 }
552             }
553 #ifdef  UPER
554         } else {
555             /* failed to spawn son */
556             logmsg(LOG_ERR, "Can't fork worker (%s) - aborted", strerror(errno));
557             exit(1);
558         }
559 #endif
560     }
561 }
562