root/src/noit_listener.c

Revision 99b18a876a3d4ec5c15c811d87927341584e0ccc, 17.2 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 2 years ago)

assorted valgrind exposed memory leaks

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include <unistd.h>
36 #include <errno.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <sys/un.h>
42 #include <arpa/inet.h>
43
44 #include "eventer/eventer.h"
45 #include "utils/noit_log.h"
46 #include "noit_listener.h"
47 #include "noit_conf.h"
48
49 static noit_log_stream_t nlerr = NULL;
50 static noit_log_stream_t nldeb = NULL;
51 static noit_hash_table listener_commands = NOIT_HASH_EMPTY;
52 noit_hash_table *
53 noit_listener_commands() {
54   return &listener_commands;
55 }
56
57 void
58 acceptor_closure_free(acceptor_closure_t *ac) {
59   if(ac->remote_cn) free(ac->remote_cn);
60   if(ac->service_ctx_free && ac->service_ctx)
61     ac->service_ctx_free(ac->service_ctx);
62   free(ac);
63 }
64
65 static int
66 noit_listener_accept_ssl(eventer_t e, int mask,
67                          void *closure, struct timeval *tv) {
68   int rv;
69   listener_closure_t listener_closure = (listener_closure_t)closure;
70   acceptor_closure_t *ac = NULL;
71   if(!closure) goto socketfail;
72   ac = listener_closure->dispatch_closure;
73
74   rv = eventer_SSL_accept(e, &mask);
75   if(rv > 0) {
76     eventer_ssl_ctx_t *sslctx;
77     e->callback = listener_closure->dispatch_callback;
78     /* We must make a copy of the acceptor_closure_t for each new
79      * connection.
80      */
81     if((sslctx = eventer_get_eventer_ssl_ctx(e)) != NULL) {
82       const char *cn, *end;
83       cn = eventer_ssl_get_peer_subject(sslctx);
84       if(cn && (cn = strstr(cn, "CN=")) != NULL) {
85         cn += 3;
86         end = cn;
87         while(*end && *end != '/') end++;
88         ac->remote_cn = malloc(end - cn + 1);
89         memcpy(ac->remote_cn, cn, end - cn);
90         ac->remote_cn[end-cn] = '\0';
91       }
92     }
93     e->closure = ac;
94     noitL(nlerr, "noit_listener[%s] SSL_accept on fd %d [%s]\n",
95           eventer_name_for_callback(e->callback),
96           e->fd, ac->remote_cn ? ac->remote_cn : "anonymous");
97     if(listener_closure) free(listener_closure);
98     return e->callback(e, mask, e->closure, tv);
99   }
100   if(errno == EAGAIN) return mask|EVENTER_EXCEPTION;
101
102  socketfail:
103   if(listener_closure) free(listener_closure);
104   if(ac) acceptor_closure_free(ac);
105   eventer_remove_fd(e->fd);
106   e->opset->close(e->fd, &mask, e);
107   return 0;
108 }
109
110 static int
111 noit_listener_acceptor(eventer_t e, int mask,
112                        void *closure, struct timeval *tv) {
113   int conn, newmask = EVENTER_READ;
114   socklen_t salen;
115   listener_closure_t listener_closure = (listener_closure_t)closure;
116   acceptor_closure_t *ac = NULL;
117
118   if(mask & EVENTER_EXCEPTION) {
119  socketfail:
120     if(ac) acceptor_closure_free(ac);
121     /* We don't shut down the socket, it's out listener! */
122     return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
123   }
124
125   do {
126     ac = malloc(sizeof(*ac));
127     memcpy(ac, listener_closure->dispatch_closure, sizeof(*ac));
128     salen = sizeof(ac->remote);
129     conn = e->opset->accept(e->fd, &ac->remote.remote_addr, &salen, &newmask, e);
130     if(conn >= 0) {
131       eventer_t newe;
132       noitL(nldeb, "noit_listener[%s] accepted fd %d\n",
133             eventer_name_for_callback(listener_closure->dispatch_callback),
134             conn);
135       if(eventer_set_fd_nonblocking(conn)) {
136         close(conn);
137         free(ac);
138         goto accept_bail;
139       }
140       newe = eventer_alloc();
141       newe->fd = conn;
142       newe->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
143  
144       if(listener_closure->sslconfig->size) {
145         const char *cert, *key, *ca, *ciphers, *crl;
146         eventer_ssl_ctx_t *ctx;
147         /* We have an SSL configuration.  While our socket accept is
148          * complete, we now have to SSL_accept, which could require
149          * several reads and writes and needs its own event callback.
150          */
151   #define SSLCONFGET(var,name) do { \
152     if(!noit_hash_retr_str(listener_closure->sslconfig, name, strlen(name), \
153                            &var)) var = NULL; } while(0)
154         SSLCONFGET(cert, "certificate_file");
155         SSLCONFGET(key, "key_file");
156         SSLCONFGET(ca, "ca_chain");
157         SSLCONFGET(ciphers, "ciphers");
158         ctx = eventer_ssl_ctx_new(SSL_SERVER, cert, key, ca, ciphers);
159         if(!ctx) {
160           newe->opset->close(newe->fd, &newmask, e);
161           eventer_free(newe);
162           goto socketfail;
163         }
164         SSLCONFGET(crl, "crl");
165         if(crl) {
166           if(!eventer_ssl_use_crl(ctx, crl)) {
167             noitL(noit_error, "Failed to load CRL from %s\n", crl);
168             eventer_ssl_ctx_free(ctx);
169             newe->opset->close(newe->fd, &newmask, e);
170             eventer_free(newe);
171             goto socketfail;
172           }
173         }
174
175         eventer_ssl_ctx_set_verify(ctx, eventer_ssl_verify_cert,
176                                    listener_closure->sslconfig);
177         EVENTER_ATTACH_SSL(newe, ctx);
178         newe->callback = noit_listener_accept_ssl;
179         newe->closure = malloc(sizeof(*listener_closure));
180         memcpy(newe->closure, listener_closure, sizeof(*listener_closure));
181         ((listener_closure_t)newe->closure)->dispatch_closure = ac;
182       }
183       else {
184         newe->callback = listener_closure->dispatch_callback;
185         /* We must make a copy of the acceptor_closure_t for each new
186          * connection.
187          */
188         newe->closure = ac;
189       }
190       eventer_add(newe);
191     }
192     else {
193       if(errno == EAGAIN) {
194         if(ac) acceptor_closure_free(ac);
195       }
196       else if(errno != EINTR) {
197         noitL(noit_error, "accept socket error: %s\n", strerror(errno));
198         goto socketfail;
199       }
200     }
201   } while(conn >= 0);
202  accept_bail:
203   return newmask | EVENTER_EXCEPTION;
204 }
205
206 int
207 noit_listener(char *host, unsigned short port, int type,
208               int backlog, noit_hash_table *sslconfig,
209               noit_hash_table *config,
210               eventer_func_t handler, void *service_ctx) {
211   int rv, fd;
212   int8_t family;
213   int sockaddr_len;
214   socklen_t reuse;
215   listener_closure_t listener_closure;
216   eventer_t event;
217   union {
218     struct in_addr addr4;
219     struct in6_addr addr6;
220   } a;
221   union {
222     struct sockaddr_in addr4;
223     struct sockaddr_in6 addr6;
224     struct sockaddr_un addru;
225   } s;
226   const char *event_name;
227
228   noitL(nldeb, "noit_listener(%s, %d, %d, %d, %s, %p)\n",
229         host, port, type, backlog,
230         (event_name = eventer_name_for_callback(handler))?event_name:"??",
231         service_ctx);
232   if(host[0] == '/') {
233     family = AF_UNIX;
234   }
235   else {
236     family = AF_INET;
237     rv = inet_pton(family, host, &a);
238     if(rv != 1) {
239       family = AF_INET6;
240       rv = inet_pton(family, host, &a);
241       if(rv != 1) {
242         if(!strcmp(host, "*")) {
243           family = AF_INET;
244           a.addr4.s_addr = INADDR_ANY;
245         } else {
246           noitL(noit_stderr, "Cannot translate '%s' to IP\n", host);
247           return -1;
248         }
249       }
250     }
251   }
252
253   fd = socket(family, type, 0);
254   if(fd < 0) {
255     noitL(noit_stderr, "Cannot create socket: %s\n", strerror(errno));
256     return -1;
257   }
258
259   if(eventer_set_fd_nonblocking(fd)) {
260     close(fd);
261     noitL(noit_stderr, "Cannot make socket non-blocking: %s\n",
262           strerror(errno));
263     return -1;
264   }
265
266   reuse = 1;
267   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
268                  (void*)&reuse, sizeof(reuse)) != 0) {
269     close(fd);
270     noitL(noit_stderr, "Cannot set SO_REUSEADDR: %s\n", strerror(errno));
271     return -1;
272   }
273
274   memset(&s, 0, sizeof(s));
275   if(family == AF_UNIX) {
276     struct stat sb;
277     /* unlink the path if it is a socket */
278     if(stat(host, &sb) == -1) {
279       if(errno != ENOENT) {
280         noitL(noit_stderr, "%s: %s\n", host, strerror(errno));
281         close(fd);
282         return -1;
283       }
284     }
285     else {
286       if(sb.st_mode & S_IFSOCK)
287         unlink(host);
288       else {
289         noitL(noit_stderr, "unlink %s failed: %s\n", host, strerror(errno));
290         close(fd);
291         return -1;
292       }
293     }
294     s.addru.sun_family = AF_UNIX;
295     strncpy(s.addru.sun_path, host, sizeof(s.addru.sun_path)-1);
296     sockaddr_len = sizeof(s.addru);
297   }
298   else {
299     if(family == AF_INET6) {
300       s.addr6.sin6_family = family;
301       s.addr6.sin6_port = htons(port);
302       memcpy(&s.addr6.sin6_addr, &a.addr6, sizeof(a.addr6));
303     }
304     else {
305       s.addr4.sin_family = family;
306       s.addr4.sin_port = htons(port);
307       memcpy(&s.addr4.sin_addr, &a.addr4, sizeof(a.addr4));
308     }
309     sockaddr_len = (family == AF_INET) ?  sizeof(s.addr4) : sizeof(s.addr6);
310   }
311   if(bind(fd, (struct sockaddr *)&s, sockaddr_len) < 0) {
312     noitL(noit_stderr, "bind failed[%s]: %s\n", host, strerror(errno));
313     close(fd);
314     return -1;
315   }
316
317   if(type == SOCK_STREAM) {
318     if(listen(fd, backlog) < 0) {
319       close(fd);
320       return -1;
321     }
322   }
323
324   listener_closure = calloc(1, sizeof(*listener_closure));
325   listener_closure->family = family;
326   listener_closure->port = htons(port);
327   listener_closure->sslconfig = calloc(1, sizeof(noit_hash_table));
328   noit_hash_merge_as_dict(listener_closure->sslconfig, sslconfig);
329   listener_closure->dispatch_callback = handler;
330
331   listener_closure->dispatch_closure =
332     calloc(1, sizeof(*listener_closure->dispatch_closure));
333   listener_closure->dispatch_closure->config = config;
334   listener_closure->dispatch_closure->dispatch = handler;
335   listener_closure->dispatch_closure->service_ctx = service_ctx;
336
337   event = eventer_alloc();
338   event->fd = fd;
339   event->mask = EVENTER_READ | EVENTER_EXCEPTION;
340   event->callback = noit_listener_acceptor;
341   event->closure = listener_closure;
342
343   eventer_add(event);
344   return 0;
345 }
346
347 void
348 noit_listener_reconfig(const char *toplevel) {
349   int i, cnt = 0;
350   noit_conf_section_t *listener_configs;
351   char path[256];
352
353   snprintf(path, sizeof(path), "/%s/listeners//listener",
354            toplevel ? toplevel : "*");
355   listener_configs = noit_conf_get_sections(NULL, path, &cnt);
356   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
357   for(i=0; i<cnt; i++) {
358     char address[256];
359     char type[256];
360     unsigned short port;
361     int portint;
362     int backlog;
363     eventer_func_t f;
364     noit_boolean ssl;
365     noit_hash_table *sslconfig, *config;
366
367     if(!noit_conf_get_stringbuf(listener_configs[i],
368                                 "ancestor-or-self::node()/@type",
369                                 type, sizeof(type))) {
370       noitL(noit_stderr, "No type specified in listener stanza %d\n", i+1);
371       continue;
372     }
373     f = eventer_callback_for_name(type);
374     if(!f) {
375       noitL(noit_stderr,
376             "Cannot find handler for listener type: '%s'\n", type);
377       continue;
378     }
379     if(!noit_conf_get_stringbuf(listener_configs[i],
380                                 "ancestor-or-self::node()/@address",
381                                 address, sizeof(address))) {
382       address[0] = '*';
383       address[1] = '\0';
384     }
385     if(!noit_conf_get_int(listener_configs[i],
386                           "ancestor-or-self::node()/@port", &portint))
387       portint = 0;
388     port = (unsigned short) portint;
389     if(address[0] != '/' && (portint == 0 || (port != portint))) {
390       /* UNIX sockets don't require a port (they'll ignore it if specified */
391       noitL(noit_stderr,
392             "Invalid port [%d] specified in stanza %d\n", port, i+1);
393       continue;
394     }
395     if(!noit_conf_get_int(listener_configs[i],
396                           "ancestor-or-self::node()/@backlog", &backlog))
397       backlog = 5;
398
399     if(!noit_conf_get_boolean(listener_configs[i],
400                               "ancestor-or-self::node()/@ssl", &ssl))
401      ssl = noit_false;
402
403     sslconfig = ssl ?
404                   noit_conf_get_hash(listener_configs[i], "sslconfig") :
405                   NULL;
406     config = noit_conf_get_hash(listener_configs[i], "config");
407
408     if(noit_listener(address, port, SOCK_STREAM, backlog,
409                      sslconfig, config, f, NULL) != 0) {
410       noit_hash_destroy(config,free,free);
411       free(config);
412     }
413     if(sslconfig) {
414       /* A copy of this is made within noit_listener */
415       noit_hash_destroy(sslconfig,free,free);
416       free(sslconfig);
417     }
418   }
419   free(listener_configs);
420 }
421 int
422 noit_control_dispatch(eventer_t e, int mask, void *closure,
423                       struct timeval *now) {
424   u_int32_t cmd;
425   int len;
426   void *vdelegation_table;
427   noit_hash_table *delegation_table = NULL;
428   acceptor_closure_t *ac = closure;
429
430   len = e->opset->read(e->fd, &cmd, sizeof(cmd), &mask, e);
431
432   if(len == -1 && errno == EAGAIN)
433     return EVENTER_READ | EVENTER_EXCEPTION;
434
435   if(mask & EVENTER_EXCEPTION || len != sizeof(cmd)) {
436     int newmask;
437 socket_error:
438     /* Exceptions cause us to simply snip the connection */
439     eventer_remove_fd(e->fd);
440     e->opset->close(e->fd, &newmask, e);
441     if(ac) acceptor_closure_free(ac);
442     return 0;
443   }
444
445   ac->cmd = ntohl(cmd);
446   /* Lookup cmd and dispatch */
447   if(noit_hash_retrieve(&listener_commands,
448                         (char *)&ac->dispatch, sizeof(ac->dispatch),
449                         (void **)&vdelegation_table)) {
450     void *vfunc;
451     delegation_table = (noit_hash_table *)vdelegation_table;
452     if(noit_hash_retrieve(delegation_table,
453                           (char *)&ac->cmd, sizeof(ac->cmd), &vfunc)) {
454       e->callback = *((eventer_func_t *)vfunc);
455       return e->callback(e, mask, closure, now);
456     }
457     else {
458     const char *event_name;
459       noitL(noit_error, "listener (%s %p) has no command: 0x%8x\n",
460             (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
461             delegation_table, cmd);
462     }
463   }
464   else {
465     const char *event_name;
466     noitL(noit_error, "No delegation table for listener (%s %p)\n",
467           (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
468           delegation_table);
469   }
470   goto socket_error;
471 }
472 void
473 noit_control_dispatch_delegate(eventer_func_t listener_dispatch,
474                                u_int32_t cmd,
475                                eventer_func_t delegate_dispatch) {
476   u_int32_t *cmd_copy;
477   eventer_func_t *handler_copy;
478   void *vdelegation_table;
479   noit_hash_table *delegation_table;
480   if(!noit_hash_retrieve(&listener_commands,
481                          (char *)&listener_dispatch, sizeof(listener_dispatch),
482                          &vdelegation_table)) {
483     delegation_table = calloc(1, sizeof(*delegation_table));
484     handler_copy = malloc(sizeof(*handler_copy));
485     *handler_copy = listener_dispatch;
486     noit_hash_store(&listener_commands,
487                     (char *)handler_copy, sizeof(*handler_copy),
488                     delegation_table);
489   }
490   else
491     delegation_table = (noit_hash_table *)vdelegation_table;
492
493   cmd_copy = malloc(sizeof(*cmd_copy));
494   *cmd_copy = cmd;
495   handler_copy = malloc(sizeof(*handler_copy));
496   *handler_copy = delegate_dispatch;
497   noit_hash_replace(delegation_table,
498                     (char *)cmd_copy, sizeof(*cmd_copy),
499                     handler_copy,
500                     free, free);
501 }
502
503 int
504 noit_convert_sockaddr_to_buff(char *buff, int blen, struct sockaddr *remote) {
505   char name[128] = "";
506   buff[0] = '\0';
507   if(remote) {
508     int len = 0;
509     switch(remote->sa_family) {
510       case AF_INET:
511         len = sizeof(struct sockaddr_in);
512         inet_ntop(remote->sa_family, &((struct sockaddr_in *)remote)->sin_addr,
513                   name, len);
514         break;
515       case AF_INET6:
516        len = sizeof(struct sockaddr_in6);
517         inet_ntop(remote->sa_family, &((struct sockaddr_in6 *)remote)->sin6_addr,
518                   name, len);
519        break;
520       case AF_UNIX:
521         snprintf(name, sizeof(name), "%s", ((struct sockaddr_un *)remote)->sun_path);
522         break;
523       default: return 0;
524     }
525   }
526   strlcpy(buff, name, blen);
527   return strlen(buff);
528 }
529
530 void
531 noit_listener_init(const char *toplevel) {
532   nlerr = noit_log_stream_find("error/listener");
533   nldeb = noit_log_stream_find("debug/listener");
534   if(!nlerr) nlerr = noit_error;
535   if(!nldeb) nldeb = noit_debug;
536   eventer_name_callback("noit_listener_acceptor", noit_listener_acceptor);
537   eventer_name_callback("noit_listener_accept_ssl", noit_listener_accept_ssl);
538   eventer_name_callback("control_dispatch", noit_control_dispatch);
539   noit_listener_reconfig(toplevel);
540 }
541
Note: See TracBrowser for help on using the browser.