root/src/noit_listener.c

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

ouch, little bug

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <unistd.h>
9 #include <errno.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/ioctl.h>
14 #include <netinet/in.h>
15 #include <sys/un.h>
16 #include <arpa/inet.h>
17
18 #include "eventer/eventer.h"
19 #include "utils/noit_log.h"
20 #include "noit_listener.h"
21 #include "noit_conf.h"
22
23 static noit_hash_table listener_commands = NOIT_HASH_EMPTY;
24
25 void
26 acceptor_closure_free(acceptor_closure_t *ac) {
27   if(ac->remote_cn) free(ac->remote_cn);
28   free(ac);
29 }
30
31 static int
32 noit_listener_accept_ssl(eventer_t e, int mask,
33                          void *closure, struct timeval *tv) {
34   int rv;
35   listener_closure_t listener_closure = (listener_closure_t)closure;
36   acceptor_closure_t *ac = NULL;
37   if(!closure) goto socketfail;
38   ac = listener_closure->dispatch_closure;
39
40   rv = eventer_SSL_accept(e, &mask);
41   if(rv > 0) {
42     eventer_ssl_ctx_t *sslctx;
43     e->callback = listener_closure->dispatch_callback;
44     /* We must make a copy of the acceptor_closure_t for each new
45      * connection.
46      */
47     if((sslctx = eventer_get_eventer_ssl_ctx(e)) != NULL) {
48       char *cn, *end;
49       cn = eventer_ssl_get_peer_subject(sslctx);
50       if(cn && (cn = strstr(cn, "CN=")) != NULL) {
51         cn += 3;
52         end = cn;
53         while(*end && *end != '/') end++;
54         ac->remote_cn = malloc(end - cn + 1);
55         memcpy(ac->remote_cn, cn, end - cn);
56         ac->remote_cn[end-cn] = '\0';
57       }
58     }
59     e->closure = ac;
60     return e->callback(e, mask, e->closure, tv);
61   }
62   if(errno == EAGAIN) return mask|EVENTER_EXCEPTION;
63
64  socketfail:
65   if(listener_closure) free(listener_closure);
66   if(ac) acceptor_closure_free(ac);
67   eventer_remove_fd(e->fd);
68   e->opset->close(e->fd, &mask, e);
69   return 0;
70 }
71
72 static int
73 noit_listener_acceptor(eventer_t e, int mask,
74                        void *closure, struct timeval *tv) {
75   int conn, newmask = EVENTER_READ;
76   socklen_t salen;
77   listener_closure_t listener_closure = (listener_closure_t)closure;
78   acceptor_closure_t *ac = NULL;
79
80   if(mask & EVENTER_EXCEPTION) {
81  socketfail:
82     if(ac) acceptor_closure_free(ac);
83     eventer_remove_fd(e->fd);
84     e->opset->close(e->fd, &mask, e);
85     return 0;
86   }
87
88   ac = malloc(sizeof(*ac));
89   memcpy(ac, listener_closure->dispatch_closure, sizeof(*ac));
90   salen = sizeof(ac->remote);
91   conn = e->opset->accept(e->fd, &ac->remote.remote_addr, &salen, &newmask, e);
92   if(conn >= 0) {
93     socklen_t on = 1;
94     eventer_t newe;
95     if(ioctl(conn, FIONBIO, &on)) {
96       close(conn);
97       goto accept_bail;
98     }
99     newe = eventer_alloc();
100     newe->fd = conn;
101     newe->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
102
103     if(listener_closure->sslconfig->size) {
104       char *cert, *key, *ca, *ciphers;
105       eventer_ssl_ctx_t *ctx;
106       /* We have an SSL configuration.  While our socket accept is
107        * complete, we now have to SSL_accept, which could require
108        * several reads and writes and needs its own event callback.
109        */
110 #define SSLCONFGET(var,name) do { \
111   if(!noit_hash_retrieve(listener_closure->sslconfig, name, strlen(name), \
112                          (void **)&var)) var = NULL; } while(0)
113       SSLCONFGET(cert, "certificate_file");
114       SSLCONFGET(key, "key_file");
115       SSLCONFGET(ca, "ca_chain");
116       SSLCONFGET(ciphers, "ciphers");
117       ctx = eventer_ssl_ctx_new(SSL_SERVER, cert, key, ca, ciphers);
118       if(!ctx) {
119         eventer_free(newe);
120         goto socketfail;
121       }
122       eventer_ssl_ctx_set_verify(ctx, eventer_ssl_verify_cert,
123                                  listener_closure->sslconfig);
124       EVENTER_ATTACH_SSL(newe, ctx);
125       newe->callback = noit_listener_accept_ssl;
126       newe->closure = malloc(sizeof(*listener_closure));
127       memcpy(newe->closure, listener_closure, sizeof(*listener_closure));
128       ((listener_closure_t)newe->closure)->dispatch_closure = ac;
129     }
130     else {
131       newe->callback = listener_closure->dispatch_callback;
132       /* We must make a copy of the acceptor_closure_t for each new
133        * connection.
134        */
135       newe->closure = ac;
136     }
137     eventer_add(newe);
138   }
139  accept_bail:
140   return newmask | EVENTER_EXCEPTION;
141 }
142
143 int
144 noit_listener(char *host, unsigned short port, int type,
145               int backlog, noit_hash_table *sslconfig,
146               noit_hash_table *config,
147               eventer_func_t handler, void *service_ctx) {
148   int rv, fd;
149   int8_t family;
150   int sockaddr_len;
151   socklen_t on, reuse;
152   listener_closure_t listener_closure;
153   eventer_t event;
154   union {
155     struct in_addr addr4;
156     struct in6_addr addr6;
157   } a;
158   union {
159     struct sockaddr_in addr4;
160     struct sockaddr_in6 addr6;
161     struct sockaddr_un addru;
162   } s;
163   const char *event_name;
164
165   noitL(noit_debug, "noit_listener(%s, %d, %d, %d, %s, %p)\n",
166         host, port, type, backlog,
167         (event_name = eventer_name_for_callback(handler))?event_name:"??",
168         service_ctx);
169   if(host[0] == '/') {
170     family = AF_UNIX;
171   }
172   else {
173     family = AF_INET;
174     rv = inet_pton(family, host, &a);
175     if(rv != 1) {
176       family = AF_INET6;
177       rv = inet_pton(family, host, &a);
178       if(rv != 1) {
179         if(!strcmp(host, "*")) {
180           family = AF_INET;
181           a.addr4.s_addr = INADDR_ANY;
182         } else {
183           noitL(noit_stderr, "Cannot translate '%s' to IP\n", host);
184           return -1;
185         }
186       }
187     }
188   }
189
190   fd = socket(family, type, 0);
191   if(fd < 0) {
192     noitL(noit_stderr, "Cannot create socket: %s\n", strerror(errno));
193     return -1;
194   }
195
196   on = 1;
197   if(ioctl(fd, FIONBIO, &on)) {
198     close(fd);
199     noitL(noit_stderr, "Cannot make socket non-blocking: %s\n",
200           strerror(errno));
201     return -1;
202   }
203
204   reuse = 1;
205   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
206                  (void*)&reuse, sizeof(reuse)) != 0) {
207     close(fd);
208     noitL(noit_stderr, "Cannot set SO_REUSEADDR: %s\n", strerror(errno));
209     return -1;
210   }
211
212   memset(&s, 0, sizeof(s));
213   if(family == AF_UNIX) {
214     struct stat sb;
215     /* unlink the path iff it is a socket */
216     if(stat(host, &sb) == -1) {
217       if(errno != ENOENT) {
218         noitL(noit_stderr, "%s: %s\n", host, strerror(errno));
219         close(fd);
220         return -1;
221       }
222     }
223     else {
224       if(sb.st_mode & S_IFSOCK)
225         unlink(host);
226       else {
227         noitL(noit_stderr, "unlink %s failed: %s\n", host, strerror(errno));
228         close(fd);
229         return -1;
230       }
231     }
232     strncpy(s.addru.sun_path, host, sizeof(s.addru.sun_path)-1);
233     sockaddr_len = sizeof(s.addru);
234   }
235   else {
236     s.addr6.sin6_family = family;
237     s.addr6.sin6_port = htons(port);
238     memcpy(&s.addr6.sin6_addr, &a, sizeof(a));
239     sockaddr_len = (family == AF_INET) ?  sizeof(s.addr4) : sizeof(s.addr6);
240   }
241   if(bind(fd, (struct sockaddr *)&s, sockaddr_len) < 0) {
242     noitL(noit_stderr, "bind failed[%s]: %s\n", host, strerror(errno));
243     close(fd);
244     return -1;
245   }
246
247   if(type == SOCK_STREAM) {
248     if(listen(fd, backlog) < 0) {
249       close(fd);
250       return -1;
251     }
252   }
253
254   listener_closure = calloc(1, sizeof(*listener_closure));
255   listener_closure->family = family;
256   listener_closure->port = htons(port);
257   listener_closure->sslconfig = calloc(1, sizeof(noit_hash_table));
258   noit_hash_merge_as_dict(listener_closure->sslconfig, sslconfig);
259   listener_closure->dispatch_callback = handler;
260
261   listener_closure->dispatch_closure =
262     calloc(1, sizeof(*listener_closure->dispatch_closure));
263   listener_closure->dispatch_closure->config = config;
264   listener_closure->dispatch_closure->dispatch = handler;
265   listener_closure->dispatch_closure->service_ctx = service_ctx;
266
267   event = eventer_alloc();
268   event->fd = fd;
269   event->mask = EVENTER_READ | EVENTER_EXCEPTION;
270   event->callback = noit_listener_acceptor;
271   event->closure = listener_closure;
272
273   eventer_add(event);
274   return 0;
275 }
276
277 void
278 noit_listener_reconfig(const char *toplevel) {
279   int i, cnt = 0;
280   noit_conf_section_t *listener_configs;
281   char path[256];
282
283   snprintf(path, sizeof(path), "/%s/listeners//listener",
284            toplevel ? toplevel : "*");
285   listener_configs = noit_conf_get_sections(NULL, path, &cnt);
286   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
287   for(i=0; i<cnt; i++) {
288     char address[256];
289     char type[256];
290     unsigned short port;
291     int portint;
292     int backlog;
293     eventer_func_t f;
294     noit_boolean ssl;
295     noit_hash_table *sslconfig, *config;
296
297     if(!noit_conf_get_stringbuf(listener_configs[i],
298                                 "ancestor-or-self::node()/@type",
299                                 type, sizeof(type))) {
300       noitL(noit_stderr, "No type specified in listener stanza %d\n", i+1);
301       continue;
302     }
303     f = eventer_callback_for_name(type);
304     if(!f) {
305       noitL(noit_stderr,
306             "Cannot find handler for listener type: '%s'\n", type);
307       continue;
308     }
309     if(!noit_conf_get_stringbuf(listener_configs[i],
310                                 "ancestor-or-self::node()/@address",
311                                 address, sizeof(address))) {
312       address[0] = '*';
313       address[1] = '\0';
314     }
315     if(!noit_conf_get_int(listener_configs[i],
316                           "ancestor-or-self::node()/@port", &portint))
317       portint = 0;
318     port = (unsigned short) portint;
319     if(address[0] != '/' && (portint == 0 || (port != portint))) {
320       /* UNIX sockets don't require a port (they'll ignore it if specified */
321       noitL(noit_stderr,
322             "Invalid port [%d] specified in stanza %d\n", port, i+1);
323       continue;
324     }
325     if(!noit_conf_get_int(listener_configs[i],
326                           "ancestor-or-self::node()/@backlog", &backlog))
327       backlog = 5;
328
329     if(!noit_conf_get_boolean(listener_configs[i],
330                               "ancestor-or-self::node()/@ssl", &ssl))
331      ssl = noit_false;
332
333     sslconfig = ssl ?
334                   noit_conf_get_hash(listener_configs[i], "sslconfig") :
335                   NULL;
336     config = noit_conf_get_hash(listener_configs[i], "config");
337
338     noit_listener(address, port, SOCK_STREAM, backlog,
339                   sslconfig, config, f, NULL);
340   }
341 }
342 int
343 noit_control_dispatch(eventer_t e, int mask, void *closure,
344                       struct timeval *now) {
345   u_int32_t cmd;
346   int len;
347   noit_hash_table *delegation_table;
348   acceptor_closure_t *ac = closure;
349
350   len = e->opset->read(e->fd, &cmd, sizeof(cmd), &mask, e);
351
352   if(len == -1 && errno == EAGAIN)
353     return EVENTER_READ | EVENTER_EXCEPTION;
354
355   if(mask & EVENTER_EXCEPTION || len != sizeof(cmd)) {
356     int newmask;
357 socket_error:
358     /* Exceptions cause us to simply snip the connection */
359     eventer_remove_fd(e->fd);
360     e->opset->close(e->fd, &newmask, e);
361     if(ac) acceptor_closure_free(ac);
362     return 0;
363   }
364
365   cmd = ntohl(cmd);
366   /* Lookup cmd and dispatch */
367   if(noit_hash_retrieve(&listener_commands,
368                         (char *)&ac->dispatch, sizeof(ac->dispatch),
369                         (void **)&delegation_table)) {
370     eventer_func_t *eventer_func;
371     if(noit_hash_retrieve(delegation_table,
372                           (char *)&cmd, sizeof(cmd),
373                           (void **)&eventer_func)) {
374       e->callback = *eventer_func;
375       return e->callback(e, mask, closure, now);
376     }
377     else {
378     const char *event_name;
379       noitL(noit_error, "listener (%s %p) has no command: 0x%8x\n",
380             (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
381             delegation_table, cmd);
382     }
383   }
384   else {
385     const char *event_name;
386     noitL(noit_error, "No delegation table for listener (%s %p)\n",
387           (event_name = eventer_name_for_callback(ac->dispatch))?event_name:"???",
388           delegation_table);
389   }
390   goto socket_error;
391 }
392 void
393 noit_control_dispatch_delegate(eventer_func_t listener_dispatch,
394                                u_int32_t cmd,
395                                eventer_func_t delegate_dispatch) {
396   u_int32_t *cmd_copy;
397   eventer_func_t *handler_copy;
398   noit_hash_table *delegation_table;
399   if(!noit_hash_retrieve(&listener_commands,
400                          (char *)&listener_dispatch, sizeof(listener_dispatch),
401                          (void **)&delegation_table)) {
402     delegation_table = calloc(1, sizeof(*delegation_table));
403     handler_copy = malloc(sizeof(*handler_copy));
404     *handler_copy = listener_dispatch;
405     noit_hash_store(&listener_commands,
406                     (char *)handler_copy, sizeof(*handler_copy),
407                     delegation_table);
408   }
409   cmd_copy = malloc(sizeof(*cmd_copy));
410   *cmd_copy = cmd;
411   handler_copy = malloc(sizeof(*handler_copy));
412   *handler_copy = delegate_dispatch;
413   noit_hash_replace(delegation_table,
414                     (char *)cmd_copy, sizeof(*cmd_copy),
415                     handler_copy,
416                     free, free);
417 }
418
419 void
420 noit_listener_init(const char *toplevel) {
421   eventer_name_callback("noit_listener_acceptor", noit_listener_acceptor);
422   eventer_name_callback("noit_listener_accept_ssl", noit_listener_accept_ssl);
423   eventer_name_callback("control_dispatch", noit_control_dispatch);
424   noit_listener_reconfig(toplevel);
425 }
426
Note: See TracBrowser for help on using the browser.