root/src/noit_listener.c

Revision 06f58e662d9dcb103af43ff53f3bd7e72248cea4, 9.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

prep for jlog transit over SSL

  • 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/socket.h>
12 #include <sys/ioctl.h>
13 #include <netinet/in.h>
14 #include <sys/un.h>
15 #include <arpa/inet.h>
16
17 #include "eventer/eventer.h"
18 #include "utils/noit_log.h"
19 #include "noit_listener.h"
20 #include "noit_conf.h"
21
22 void
23 acceptor_closure_free(acceptor_closure_t *ac) {
24   if(ac->remote_cn) free(ac->remote_cn);
25   free(ac);
26 }
27
28 static int
29 noit_listener_accept_ssl(eventer_t e, int mask,
30                          void *closure, struct timeval *tv) {
31   int rv;
32   listener_closure_t listener_closure = (listener_closure_t)closure;
33   acceptor_closure_t *ac = NULL;
34   if(!closure) goto socketfail;
35   ac = listener_closure->dispatch_closure;
36
37   rv = eventer_SSL_accept(e, &mask);
38   if(rv > 0) {
39     eventer_ssl_ctx_t *sslctx;
40     e->callback = listener_closure->dispatch_callback;
41     /* We must make a copy of the acceptor_closure_t for each new
42      * connection.
43      */
44     if((sslctx = eventer_get_eventer_ssl_ctx(e)) != NULL) {
45       char *cn, *end;
46       cn = eventer_ssl_get_peer_subject(sslctx);
47       if(cn && (cn = strstr(cn, "CN=")) != NULL) {
48         cn += 3;
49         end = cn;
50         while(*end && *end != '/') end++;
51         ac->remote_cn = malloc(end - cn + 1);
52         memcpy(ac->remote_cn, cn, end - cn);
53         ac->remote_cn[end-cn] = '\0';
54       }
55     }
56     e->closure = ac;
57     return e->callback(e, mask, e->closure, tv);
58   }
59   if(errno == EAGAIN) return mask|EVENTER_EXCEPTION;
60
61  socketfail:
62   if(listener_closure) free(listener_closure);
63   if(ac) acceptor_closure_free(ac);
64   eventer_remove_fd(e->fd);
65   e->opset->close(e->fd, &mask, e);
66   return 0;
67 }
68
69 static int
70 noit_listener_acceptor(eventer_t e, int mask,
71                        void *closure, struct timeval *tv) {
72   int conn, newmask = EVENTER_READ;
73   socklen_t salen;
74   listener_closure_t listener_closure = (listener_closure_t)closure;
75   acceptor_closure_t *ac = NULL;
76
77   if(mask & EVENTER_EXCEPTION) {
78  socketfail:
79     if(ac) acceptor_closure_free(ac);
80     eventer_remove_fd(e->fd);
81     e->opset->close(e->fd, &mask, e);
82     return 0;
83   }
84
85   ac = malloc(sizeof(*ac));
86   memcpy(ac, listener_closure->dispatch_closure, sizeof(*ac));
87   conn = e->opset->accept(e->fd, &ac->remote_addr, &salen, &newmask, e);
88   if(conn >= 0) {
89     socklen_t on = 1;
90     eventer_t newe;
91     if(ioctl(conn, FIONBIO, &on)) {
92       close(conn);
93       goto accept_bail;
94     }
95     newe = eventer_alloc();
96     newe->fd = conn;
97     newe->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
98
99     if(listener_closure->sslconfig->size) {
100       char *cert, *key, *ca, *ciphers;
101       eventer_ssl_ctx_t *ctx;
102       /* We have an SSL configuration.  While our socket accept is
103        * complete, we now have to SSL_accept, which could require
104        * several reads and writes and needs its own event callback.
105        */
106 #define SSLCONFGET(var,name) do { \
107   if(!noit_hash_retrieve(listener_closure->sslconfig, name, strlen(name), \
108                          (void **)&var)) var = NULL; } while(0)
109       SSLCONFGET(cert, "certificate_file");
110       SSLCONFGET(key, "key_file");
111       SSLCONFGET(ca, "ca_chain");
112       SSLCONFGET(ciphers, "ciphers");
113       ctx = eventer_ssl_ctx_new(SSL_SERVER, cert, key, ca, ciphers);
114       if(!ctx) {
115         eventer_free(newe);
116         goto socketfail;
117       }
118       eventer_ssl_ctx_set_verify(ctx, eventer_ssl_verify_cert,
119                                  listener_closure->sslconfig);
120       EVENTER_ATTACH_SSL(newe, ctx);
121       newe->callback = noit_listener_accept_ssl;
122       newe->closure = malloc(sizeof(*listener_closure));
123       memcpy(newe->closure, listener_closure, sizeof(*listener_closure));
124       ((listener_closure_t)newe->closure)->dispatch_closure = ac;
125     }
126     else {
127       newe->callback = listener_closure->dispatch_callback;
128       /* We must make a copy of the acceptor_closure_t for each new
129        * connection.
130        */
131       newe->closure = ac;
132     }
133     eventer_add(newe);
134   }
135  accept_bail:
136   return newmask | EVENTER_EXCEPTION;
137 }
138
139 int
140 noit_listener(char *host, unsigned short port, int type,
141               int backlog, noit_hash_table *sslconfig,
142               noit_hash_table *config,
143               eventer_func_t handler, void *service_ctx) {
144   int rv, fd;
145   int8_t family;
146   int sockaddr_len;
147   socklen_t on;
148   long reuse;
149   listener_closure_t listener_closure;
150   eventer_t event;
151   union {
152     struct in_addr addr4;
153     struct in6_addr addr6;
154   } a;
155   union {
156     struct sockaddr_in addr4;
157     struct sockaddr_in6 addr6;
158     struct sockaddr_un unix;
159   } s;
160   const char *event_name;
161
162   noitL(noit_debug, "noit_listener(%s, %d, %d, %d, %s, %p)\n",
163         host, port, type, backlog,
164         (event_name = eventer_name_for_callback(handler))?event_name:"??",
165         service_ctx);
166   if(host[0] == '/') {
167     family = AF_UNIX;
168   }
169   else {
170     family = AF_INET;
171     rv = inet_pton(family, host, &a);
172     if(rv != 1) {
173       family = AF_INET6;
174       rv = inet_pton(family, host, &a);
175       if(rv != 1) {
176         if(!strcmp(host, "*")) {
177           family = AF_INET;
178           a.addr4.s_addr = INADDR_ANY;
179         } else {
180           noitL(noit_stderr, "Cannot translate '%s' to IP\n", host);
181           return -1;
182         }
183       }
184     }
185   }
186
187   fd = socket(family, type, 0);
188   if(fd < 0) return -1;
189
190   on = 1;
191   if(ioctl(fd, FIONBIO, &on)) {
192     close(fd);
193     return -1;
194   }
195
196   reuse = 1;
197   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
198                  (void*)&reuse, sizeof(reuse)) != 0) {
199     close(fd);
200     return -1;
201   }
202
203   memset(&s, 0, sizeof(s));
204   if(family == AF_UNIX) {
205     struct stat sb;
206     /* unlink the path iff it is a socket */
207     if(stat(host, &sb) == -1) {
208       if(errno != ENOENT) {
209         noitL(noit_stderr, "%s: %s\n", host, strerror(errno));
210         close(fd);
211         return -1;
212       }
213     }
214     else {
215       if(sb.st_mode & S_IFSOCK)
216         unlink(host);
217       else {
218         noitL(noit_stderr, "unlink %s failed: %s\n", host, strerror(errno));
219         close(fd);
220         return -1;
221       }
222     }
223     strncpy(s.unix.sun_path, host, sizeof(s.unix.sun_path)-1);
224     sockaddr_len = sizeof(s.unix);
225   }
226   else {
227     s.addr6.sin6_family = family;
228     s.addr6.sin6_port = htons(port);
229     memcpy(&s.addr6.sin6_addr, &a, sizeof(a));
230     sockaddr_len = (family == AF_INET) ?  sizeof(s.addr4) : sizeof(s.addr6);
231   }
232   if(bind(fd, (struct sockaddr *)&s, sockaddr_len) < 0) {
233     noitL(noit_stderr, "bind failed[%s]: %s\n", host, strerror(errno));
234     close(fd);
235     return -1;
236   }
237
238   if(type == SOCK_STREAM) {
239     if(listen(fd, backlog) < 0) {
240       close(fd);
241       return -1;
242     }
243   }
244
245   listener_closure = calloc(1, sizeof(*listener_closure));
246   listener_closure->family = family;
247   listener_closure->port = htons(port);
248   listener_closure->sslconfig = calloc(1, sizeof(noit_hash_table));
249   noit_hash_merge_as_dict(listener_closure->sslconfig, sslconfig);
250   listener_closure->dispatch_callback = handler;
251
252   listener_closure->dispatch_closure =
253     calloc(1, sizeof(*listener_closure->dispatch_closure));
254   listener_closure->dispatch_closure->config = config;
255   listener_closure->dispatch_closure->service_ctx = service_ctx;
256
257   event = eventer_alloc();
258   event->fd = fd;
259   event->mask = EVENTER_READ | EVENTER_EXCEPTION;
260   event->callback = noit_listener_acceptor;
261   event->closure = listener_closure;
262
263   eventer_add(event);
264   return 0;
265 }
266
267 void
268 noit_listener_reconfig(const char *toplevel) {
269   int i, cnt = 0;
270   noit_conf_section_t *listener_configs;
271   char path[256];
272
273   snprintf(path, sizeof(path), "/%s/listeners//listener",
274            toplevel ? toplevel : "*");
275   listener_configs = noit_conf_get_sections(NULL, path, &cnt);
276   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
277   for(i=0; i<cnt; i++) {
278     char address[256];
279     char type[256];
280     unsigned short port;
281     int portint;
282     int backlog;
283     eventer_func_t f;
284     noit_hash_table *sslconfig, *config;
285
286     if(!noit_conf_get_stringbuf(listener_configs[i],
287                                 "ancestor-or-self::node()/@type",
288                                 type, sizeof(type))) {
289       noitL(noit_stderr, "No type specified in listener stanza %d\n", i+1);
290       continue;
291     }
292     f = eventer_callback_for_name(type);
293     if(!f) {
294       noitL(noit_stderr,
295             "Cannot find handler for listener type: '%s'\n", type);
296       continue;
297     }
298     if(!noit_conf_get_stringbuf(listener_configs[i],
299                                 "ancestor-or-self::node()/@address",
300                                 address, sizeof(address))) {
301       address[0] = '*';
302       address[1] = '\0';
303     }
304     if(!noit_conf_get_int(listener_configs[i],
305                           "ancestor-or-self::node()/@port", &portint))
306       portint = 0;
307     port = (unsigned short) portint;
308     if(address[0] != '/' && (portint == 0 || (port != portint))) {
309       /* UNIX sockets don't require a port (they'll ignore it if specified */
310       noitL(noit_stderr,
311             "Invalid port [%d] specified in stanza %d\n", port, i+1);
312       continue;
313     }
314     if(!noit_conf_get_int(listener_configs[i],
315                           "ancestor-or-self::node()/@backlog", &backlog))
316       backlog = 5;
317
318     sslconfig = noit_conf_get_hash(listener_configs[i], "sslconfig");
319     config = noit_conf_get_hash(listener_configs[i], "config");
320
321     noit_listener(address, port, SOCK_STREAM, backlog,
322                   sslconfig, config, f, NULL);
323   }
324 }
325 void
326 noit_listener_init(const char *toplevel) {
327   eventer_name_callback("noit_listener_acceptor", noit_listener_acceptor);
328   eventer_name_callback("noit_listener_accept_ssl", noit_listener_accept_ssl);
329   noit_listener_reconfig(toplevel);
330 }
331
Note: See TracBrowser for help on using the browser.