root/src/noit_listener.c

Revision c6a5f6843e8c4487fe86123f4f910a49ebe29558, 16.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

dead assignments, refs #283

  • 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_hash_table listener_commands = NOIT_HASH_EMPTY;
50 noit_hash_table *
51 noit_listener_commands() {
52   return &listener_commands;
53 }
54
55 void
56 acceptor_closure_free(acceptor_closure_t *ac) {
57   if(ac->remote_cn) free(ac->remote_cn);
58   if(ac->service_ctx_free && ac->service_ctx)
59     ac->service_ctx_free(ac->service_ctx);
60   free(ac);
61 }
62
63 static int
64 noit_listener_accept_ssl(eventer_t e, int mask,
65                          void *closure, struct timeval *tv) {
66   int rv;
67   listener_closure_t listener_closure = (listener_closure_t)closure;
68   acceptor_closure_t *ac = NULL;
69   if(!closure) goto socketfail;
70   ac = listener_closure->dispatch_closure;
71
72   rv = eventer_SSL_accept(e, &mask);
73   if(rv > 0) {
74     eventer_ssl_ctx_t *sslctx;
75     e->callback = listener_closure->dispatch_callback;
76     /* We must make a copy of the acceptor_closure_t for each new
77      * connection.
78      */
79     if((sslctx = eventer_get_eventer_ssl_ctx(e)) != NULL) {
80       const char *cn, *end;
81       cn = eventer_ssl_get_peer_subject(sslctx);
82       if(cn && (cn = strstr(cn, "CN=")) != NULL) {
83         cn += 3;
84         end = cn;
85         while(*end && *end != '/') end++;
86         ac->remote_cn = malloc(end - cn + 1);
87         memcpy(ac->remote_cn, cn, end - cn);
88         ac->remote_cn[end-cn] = '\0';
89       }
90     }
91     e->closure = ac;
92     return e->callback(e, mask, e->closure, tv);
93   }
94   if(errno == EAGAIN) return mask|EVENTER_EXCEPTION;
95
96  socketfail:
97   if(listener_closure) free(listener_closure);
98   if(ac) acceptor_closure_free(ac);
99   eventer_remove_fd(e->fd);
100   e->opset->close(e->fd, &mask, e);
101   return 0;
102 }
103
104 static int
105 noit_listener_acceptor(eventer_t e, int mask,
106                        void *closure, struct timeval *tv) {
107   int conn, newmask = EVENTER_READ;
108   socklen_t salen;
109   listener_closure_t listener_closure = (listener_closure_t)closure;
110   acceptor_closure_t *ac = NULL;
111
112   if(mask & EVENTER_EXCEPTION) {
113  socketfail:
114     if(ac) acceptor_closure_free(ac);
115     /* We don't shut down the socket, it's out listener! */
116     return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
117   }
118
119   do {
120     ac = malloc(sizeof(*ac));
121     memcpy(ac, listener_closure->dispatch_closure, sizeof(*ac));
122     salen = sizeof(ac->remote);
123     conn = e->opset->accept(e->fd, &ac->remote.remote_addr, &salen, &newmask, e);
124     if(conn >= 0) {
125       eventer_t newe;
126       if(eventer_set_fd_nonblocking(conn)) {
127         close(conn);
128         free(ac);
129         goto accept_bail;
130       }
131       newe = eventer_alloc();
132       newe->fd = conn;
133       newe->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
134  
135       if(listener_closure->sslconfig->size) {
136         const char *cert, *key, *ca, *ciphers, *crl;
137         eventer_ssl_ctx_t *ctx;
138         /* We have an SSL configuration.  While our socket accept is
139          * complete, we now have to SSL_accept, which could require
140          * several reads and writes and needs its own event callback.
141          */
142   #define SSLCONFGET(var,name) do { \
143     if(!noit_hash_retr_str(listener_closure->sslconfig, name, strlen(name), \
144                            &var)) var = NULL; } while(0)
145         SSLCONFGET(cert, "certificate_file");
146         SSLCONFGET(key, "key_file");
147         SSLCONFGET(ca, "ca_chain");
148         SSLCONFGET(ciphers, "ciphers");
149         ctx = eventer_ssl_ctx_new(SSL_SERVER, cert, key, ca, ciphers);
150         if(!ctx) {
151           newe->opset->close(newe->fd, &newmask, e);
152           eventer_free(newe);
153           goto socketfail;
154         }
155         SSLCONFGET(crl, "crl");
156         if(crl) {
157           if(!eventer_ssl_use_crl(ctx, crl)) {
158             noitL(noit_error, "Failed to load CRL from %s\n", crl);
159             eventer_ssl_ctx_free(ctx);
160             newe->opset->close(newe->fd, &newmask, e);
161             eventer_free(newe);
162             goto socketfail;
163           }
164         }
165
166         eventer_ssl_ctx_set_verify(ctx, eventer_ssl_verify_cert,
167                                    listener_closure->sslconfig);
168         EVENTER_ATTACH_SSL(newe, ctx);
169         newe->callback = noit_listener_accept_ssl;
170         newe->closure = malloc(sizeof(*listener_closure));
171         memcpy(newe->closure, listener_closure, sizeof(*listener_closure));
172         ((listener_closure_t)newe->closure)->dispatch_closure = ac;
173       }
174       else {
175         newe->callback = listener_closure->dispatch_callback;
176         /* We must make a copy of the acceptor_closure_t for each new
177          * connection.
178          */
179         newe->closure = ac;
180       }
181       eventer_add(newe);
182     }
183     else {
184       if(errno == EAGAIN) {
185         if(ac) acceptor_closure_free(ac);
186       }
187       else if(errno != EINTR) {
188         noitL(noit_error, "accept socket error: %s\n", strerror(errno));
189         goto socketfail;
190       }
191     }
192   } while(conn >= 0);
193  accept_bail:
194   return newmask | EVENTER_EXCEPTION;
195 }
196
197 int
198 noit_listener(char *host, unsigned short port, int type,
199               int backlog, noit_hash_table *sslconfig,
200               noit_hash_table *config,
201               eventer_func_t handler, void *service_ctx) {
202   int rv, fd;
203   int8_t family;
204   int sockaddr_len;
205   socklen_t reuse;
206   listener_closure_t listener_closure;
207   eventer_t event;
208   union {
209     struct in_addr addr4;
210     struct in6_addr addr6;
211   } a;
212   union {
213     struct sockaddr_in addr4;
214     struct sockaddr_in6 addr6;
215     struct sockaddr_un addru;
216   } s;
217   const char *event_name;
218
219   noitL(noit_debug, "noit_listener(%s, %d, %d, %d, %s, %p)\n",
220         host, port, type, backlog,
221         (event_name = eventer_name_for_callback(handler))?event_name:"??",
222         service_ctx);
223   if(host[0] == '/') {
224     family = AF_UNIX;
225   }
226   else {
227     family = AF_INET;
228     rv = inet_pton(family, host, &a);
229     if(rv != 1) {
230       family = AF_INET6;
231       rv = inet_pton(family, host, &a);
232       if(rv != 1) {
233         if(!strcmp(host, "*")) {
234           family = AF_INET;
235           a.addr4.s_addr = INADDR_ANY;
236         } else {
237           noitL(noit_stderr, "Cannot translate '%s' to IP\n", host);
238           return -1;
239         }
240       }
241     }
242   }
243
244   fd = socket(family, type, 0);
245   if(fd < 0) {
246     noitL(noit_stderr, "Cannot create socket: %s\n", strerror(errno));
247     return -1;
248   }
249
250   if(eventer_set_fd_nonblocking(fd)) {
251     close(fd);
252     noitL(noit_stderr, "Cannot make socket non-blocking: %s\n",
253           strerror(errno));
254     return -1;
255   }
256
257   reuse = 1;
258   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
259                  (void*)&reuse, sizeof(reuse)) != 0) {
260     close(fd);
261     noitL(noit_stderr, "Cannot set SO_REUSEADDR: %s\n", strerror(errno));
262     return -1;
263   }
264
265   memset(&s, 0, sizeof(s));
266   if(family == AF_UNIX) {
267     struct stat sb;
268     /* unlink the path if it is a socket */
269     if(stat(host, &sb) == -1) {
270       if(errno != ENOENT) {
271         noitL(noit_stderr, "%s: %s\n", host, strerror(errno));
272         close(fd);
273         return -1;
274       }
275     }
276     else {
277       if(sb.st_mode & S_IFSOCK)
278         unlink(host);
279       else {
280         noitL(noit_stderr, "unlink %s failed: %s\n", host, strerror(errno));
281         close(fd);
282         return -1;
283       }
284     }
285     s.addru.sun_family = AF_UNIX;
286     strncpy(s.addru.sun_path, host, sizeof(s.addru.sun_path)-1);
287     sockaddr_len = sizeof(s.addru);
288   }
289   else {
290     if(family == AF_INET6) {
291       s.addr6.sin6_family = family;
292       s.addr6.sin6_port = htons(port);
293       memcpy(&s.addr6.sin6_addr, &a.addr6, sizeof(a.addr6));
294     }
295     else {
296       s.addr4.sin_family = family;
297       s.addr4.sin_port = htons(port);
298       memcpy(&s.addr4.sin_addr, &a.addr4, sizeof(a.addr4));
299     }
300     sockaddr_len = (family == AF_INET) ?  sizeof(s.addr4) : sizeof(s.addr6);
301   }
302   if(bind(fd, (struct sockaddr *)&s, sockaddr_len) < 0) {
303     noitL(noit_stderr, "bind failed[%s]: %s\n", host, strerror(errno));
304     close(fd);
305     return -1;
306   }
307
308   if(type == SOCK_STREAM) {
309     if(listen(fd, backlog) < 0) {
310       close(fd);
311       return -1;
312     }
313   }
314
315   listener_closure = calloc(1, sizeof(*listener_closure));
316   listener_closure->family = family;
317   listener_closure->port = htons(port);
318   listener_closure->sslconfig = calloc(1, sizeof(noit_hash_table));
319   noit_hash_merge_as_dict(listener_closure->sslconfig, sslconfig);
320   listener_closure->dispatch_callback = handler;
321
322   listener_closure->dispatch_closure =
323     calloc(1, sizeof(*listener_closure->dispatch_closure));
324   listener_closure->dispatch_closure->config = config;
325   listener_closure->dispatch_closure->dispatch = handler;
326   listener_closure->dispatch_closure->service_ctx = service_ctx;
327
328   event = eventer_alloc();
329   event->fd = fd;
330   event->mask = EVENTER_READ | EVENTER_EXCEPTION;
331   event->callback = noit_listener_acceptor;
332   event->closure = listener_closure;
333
334   eventer_add(event);
335   return 0;
336 }
337
338 void
339 noit_listener_reconfig(const char *toplevel) {
340   int i, cnt = 0;
341   noit_conf_section_t *listener_configs;
342   char path[256];
343
344   snprintf(path, sizeof(path), "/%s/listeners//listener",
345            toplevel ? toplevel : "*");
346   listener_configs = noit_conf_get_sections(NULL, path, &cnt);
347   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
348   for(i=0; i<cnt; i++) {
349     char address[256];
350     char type[256];
351     unsigned short port;
352     int portint;
353     int backlog;
354     eventer_func_t f;
355     noit_boolean ssl;
356     noit_hash_table *sslconfig, *config;
357
358     if(!noit_conf_get_stringbuf(listener_configs[i],
359                                 "ancestor-or-self::node()/@type",
360                                 type, sizeof(type))) {
361       noitL(noit_stderr, "No type specified in listener stanza %d\n", i+1);
362       continue;
363     }
364     f = eventer_callback_for_name(type);
365     if(!f) {
366       noitL(noit_stderr,
367             "Cannot find handler for listener type: '%s'\n", type);
368       continue;
369     }
370     if(!noit_conf_get_stringbuf(listener_configs[i],
371                                 "ancestor-or-self::node()/@address",
372                                 address, sizeof(address))) {
373       address[0] = '*';
374       address[1] = '\0';
375     }
376     if(!noit_conf_get_int(listener_configs[i],
377                           "ancestor-or-self::node()/@port", &portint))
378       portint = 0;
379     port = (unsigned short) portint;
380     if(address[0] != '/' && (portint == 0 || (port != portint))) {
381       /* UNIX sockets don't require a port (they'll ignore it if specified */
382       noitL(noit_stderr,
383             "Invalid port [%d] specified in stanza %d\n", port, i+1);
384       continue;
385     }
386     if(!noit_conf_get_int(listener_configs[i],
387                           "ancestor-or-self::node()/@backlog", &backlog))
388       backlog = 5;
389
390     if(!noit_conf_get_boolean(listener_configs[i],
391                               "ancestor-or-self::node()/@ssl", &ssl))
392      ssl = noit_false;
393
394     sslconfig = ssl ?
395                   noit_conf_get_hash(listener_configs[i], "sslconfig") :
396                   NULL;
397     config = noit_conf_get_hash(listener_configs[i], "config");
398
399     if(noit_listener(address, port, SOCK_STREAM, backlog,
400                      sslconfig, config, f, NULL) != 0) {
401       noit_hash_destroy(config,free,free);
402       free(config);
403     }
404     if(sslconfig) {
405       /* A copy of this is made within noit_listener */
406       noit_hash_destroy(sslconfig,free,free);
407       free(sslconfig);
408     }
409   }
410   free(listener_configs);
411 }
412 int
413 noit_control_dispatch(eventer_t e, int mask, void *closure,
414                       struct timeval *now) {
415   u_int32_t cmd;
416   int len;
417   void *vdelegation_table;
418   noit_hash_table *delegation_table = NULL;
419   acceptor_closure_t *ac = closure;
420
421   len = e->opset->read(e->fd, &cmd, sizeof(cmd), &mask, e);
422
423   if(len == -1 && errno == EAGAIN)
424     return EVENTER_READ | EVENTER_EXCEPTION;
425
426   if(mask & EVENTER_EXCEPTION || len != sizeof(cmd)) {
427     int newmask;
428 socket_error:
429     /* Exceptions cause us to simply snip the connection */
430     eventer_remove_fd(e->fd);
431     e->opset->close(e->fd, &newmask, e);
432     if(ac) acceptor_closure_free(ac);
433     return 0;
434   }
435
436   ac->cmd = ntohl(cmd);
437   /* Lookup cmd and dispatch */
438   if(noit_hash_retrieve(&listener_commands,
439                         (char *)&ac->dispatch, sizeof(ac->dispatch),
440                         (void **)&vdelegation_table)) {
441     void *vfunc;
442     delegation_table = (noit_hash_table *)vdelegation_table;
443     if(noit_hash_retrieve(delegation_table,
444                           (char *)&ac->cmd, sizeof(ac->cmd), &vfunc)) {
445       e->callback = *((eventer_func_t *)vfunc);
446       return e->callback(e, mask, closure, now);
447     }
448     else {
449     const char *event_name;
450       noitL(noit_error, "listener (%s %p) has no command: 0x%8x\n",
451             (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
452             delegation_table, cmd);
453     }
454   }
455   else {
456     const char *event_name;
457     noitL(noit_error, "No delegation table for listener (%s %p)\n",
458           (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
459           delegation_table);
460   }
461   goto socket_error;
462 }
463 void
464 noit_control_dispatch_delegate(eventer_func_t listener_dispatch,
465                                u_int32_t cmd,
466                                eventer_func_t delegate_dispatch) {
467   u_int32_t *cmd_copy;
468   eventer_func_t *handler_copy;
469   void *vdelegation_table;
470   noit_hash_table *delegation_table;
471   if(!noit_hash_retrieve(&listener_commands,
472                          (char *)&listener_dispatch, sizeof(listener_dispatch),
473                          &vdelegation_table)) {
474     delegation_table = calloc(1, sizeof(*delegation_table));
475     handler_copy = malloc(sizeof(*handler_copy));
476     *handler_copy = listener_dispatch;
477     noit_hash_store(&listener_commands,
478                     (char *)handler_copy, sizeof(*handler_copy),
479                     delegation_table);
480   }
481   else
482     delegation_table = (noit_hash_table *)vdelegation_table;
483
484   cmd_copy = malloc(sizeof(*cmd_copy));
485   *cmd_copy = cmd;
486   handler_copy = malloc(sizeof(*handler_copy));
487   *handler_copy = delegate_dispatch;
488   noit_hash_replace(delegation_table,
489                     (char *)cmd_copy, sizeof(*cmd_copy),
490                     handler_copy,
491                     free, free);
492 }
493
494 int
495 noit_convert_sockaddr_to_buff(char *buff, int blen, struct sockaddr *remote) {
496   char name[128] = "";
497   buff[0] = '\0';
498   if(remote) {
499     int len = 0;
500     switch(remote->sa_family) {
501       case AF_INET:
502         len = sizeof(struct sockaddr_in);
503         inet_ntop(remote->sa_family, &((struct sockaddr_in *)remote)->sin_addr,
504                   name, len);
505         break;
506       case AF_INET6:
507        len = sizeof(struct sockaddr_in6);
508         inet_ntop(remote->sa_family, &((struct sockaddr_in6 *)remote)->sin6_addr,
509                   name, len);
510        break;
511       case AF_UNIX:
512         snprintf(name, sizeof(name), "%s", ((struct sockaddr_un *)remote)->sun_path);
513         break;
514       default: return 0;
515     }
516   }
517   strlcpy(buff, name, blen);
518   return strlen(buff);
519 }
520
521 void
522 noit_listener_init(const char *toplevel) {
523   eventer_name_callback("noit_listener_acceptor", noit_listener_acceptor);
524   eventer_name_callback("noit_listener_accept_ssl", noit_listener_accept_ssl);
525   eventer_name_callback("control_dispatch", noit_control_dispatch);
526   noit_listener_reconfig(toplevel);
527 }
528
Note: See TracBrowser for help on using the browser.