root/src/noit_listener.c

Revision bf43de9fc6e2ee0e927bcb143110685e1af80450, 15.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 4 years ago)

fixes #251

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