info: fix processing of command per HTTP request
[olsrd.git] / lib / info / olsrd_info.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2015
4  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <arpa/inet.h>
43 #include <unistd.h>
44 #include <assert.h>
45 #include <ctype.h>
46
47 #include "olsrd_info.h"
48 #include "olsr.h"
49 #include "scheduler.h"
50 #include "ipcalc.h"
51 #include "http_headers.h"
52
53 #ifdef _WIN32
54 #define close(x) closesocket(x)
55 #endif /* _WIN32 */
56
57 #define MAX_CLIENTS 3
58
59 typedef struct {
60   int socket[MAX_CLIENTS];
61   char *buffer[MAX_CLIENTS];
62   size_t size[MAX_CLIENTS];
63   size_t written[MAX_CLIENTS];
64   int count;
65 } info_plugin_outbuffer_t;
66
67 static char sink_buffer[4096];
68
69 static const char * name = NULL;
70
71 static info_plugin_functions_t *functions = NULL;
72
73 static info_plugin_config_t *config = NULL;
74
75 static int ipc_socket = -1;
76
77 static info_plugin_outbuffer_t outbuffer;
78
79 static struct timer_entry *writetimer_entry = NULL;
80
81 static unsigned int determine_action(char *requ) {
82   static unsigned int SIW_ENTRIES[] = {
83   //
84       SIW_OLSRD_CONF,//
85       SIW_ALL, //
86       //
87       // these are the two overarching categories
88       SIW_RUNTIME_ALL,//
89       SIW_STARTUP_ALL, //
90       //
91       // these are the individual sections
92       SIW_NEIGHBORS,//
93       SIW_LINKS, //
94       SIW_ROUTES, //
95       SIW_HNA, //
96       SIW_MID, //
97       SIW_TOPOLOGY, //
98       SIW_GATEWAYS, //
99       SIW_INTERFACES, //
100       SIW_2HOP, //
101       SIW_SGW, //
102       //
103       // specials
104       SIW_VERSION,//
105       SIW_CONFIG, //
106       SIW_PLUGINS, //
107       //
108       // Freifunk special
109       SIW_NEIGHBORS_FREIFUNK //
110       };
111
112   unsigned int i;
113
114   if (!functions->is_command)
115     return 0;
116
117   for (i = 0; i < (sizeof(SIW_ENTRIES) / sizeof(SIW_ENTRIES[0])); ++i) {
118     unsigned int siw = SIW_ENTRIES[i];
119     if (functions->is_command(requ, siw))
120       return siw;
121   }
122
123   return 0;
124 }
125
126 static void write_data(void *foo __attribute__ ((unused))) {
127   fd_set set;
128   int result, i, max;
129   struct timeval tv;
130
131   if (outbuffer.count <= 0) {
132     /* exit early if there is nothing to send */
133     return;
134   }
135
136   FD_ZERO(&set);
137   max = 0;
138   for (i = 0; i < outbuffer.count; i++) {
139     if (outbuffer.socket[i] < 0) {
140       continue;
141     }
142
143     /* And we cast here since we get a warning on Win32 */
144     FD_SET((unsigned int ) (outbuffer.socket[i]), &set);
145
146     if (outbuffer.socket[i] > max) {
147       max = outbuffer.socket[i];
148     }
149   }
150
151   tv.tv_sec = 0;
152   tv.tv_usec = 0;
153
154   result = select(max + 1, NULL, &set, NULL, &tv);
155   if (result <= 0) {
156     /* exit early if any of the sockets is not ready for writing */
157     return;
158   }
159
160   for (i = 0; i < MAX_CLIENTS; i++) {
161     if (outbuffer.socket[i] < 0) {
162       continue;
163     }
164
165     result = send(outbuffer.socket[i], outbuffer.buffer[i] + outbuffer.written[i], outbuffer.size[i] - outbuffer.written[i], 0);
166     if (result > 0) {
167       outbuffer.written[i] += result;
168     }
169
170     if ((result <= 0) || (outbuffer.written[i] >= outbuffer.size[i])) {
171       /* close this socket and cleanup*/
172       close(outbuffer.socket[i]);
173       outbuffer.socket[i] = -1;
174       free(outbuffer.buffer[i]);
175       outbuffer.buffer[i] = NULL;
176       outbuffer.size[i] = 0;
177       outbuffer.written[i] = 0;
178
179       outbuffer.count--;
180     }
181   }
182
183   if (!outbuffer.count) {
184     olsr_stop_timer(writetimer_entry);
185   }
186 }
187
188 static void send_info(unsigned int send_what, int the_socket) {
189   struct autobuf abuf;
190
191   const char *content_type = functions->determine_mime_type ? functions->determine_mime_type(send_what) : "text/plain; charset=utf-8";
192   int contentLengthIndex = 0;
193   int headerLength = 0;
194
195   abuf_init(&abuf, 2 * 4096);
196
197   if (config->http_headers) {
198     http_header_build(name, HTTP_200, content_type, &abuf, &contentLengthIndex);
199     headerLength = abuf.len;
200   }
201
202   // only add if normal format
203   if (send_what & SIW_ALL) {
204     if (functions->output_start)
205       functions->output_start(&abuf);
206
207     if ((send_what & SIW_NEIGHBORS) && functions->neighbors)
208       functions->neighbors(&abuf);
209     if ((send_what & SIW_LINKS) && functions->links)
210       functions->links(&abuf);
211     if ((send_what & SIW_ROUTES) && functions->routes)
212       functions->routes(&abuf);
213     if ((send_what & SIW_HNA) && functions->hna)
214       functions->hna(&abuf);
215     if ((send_what & SIW_MID) && functions->mid)
216       functions->mid(&abuf);
217     if ((send_what & SIW_TOPOLOGY) && functions->topology)
218       functions->topology(&abuf);
219     if ((send_what & SIW_GATEWAYS) && functions->gateways)
220       functions->gateways(&abuf);
221     if ((send_what & SIW_INTERFACES) && functions->interfaces)
222       functions->interfaces(&abuf);
223     if ((send_what & SIW_2HOP) && functions->twohop)
224       functions->twohop(&abuf);
225     if ((send_what & SIW_SGW) && functions->sgw)
226       functions->sgw(&abuf);
227
228     if ((send_what & SIW_VERSION) && functions->version)
229       functions->version(&abuf);
230     if ((send_what & SIW_CONFIG) && functions->config)
231       functions->config(&abuf);
232     if ((send_what & SIW_PLUGINS) && functions->plugins)
233       functions->plugins(&abuf);
234
235     if (functions->output_end)
236       functions->output_end(&abuf);
237   } else if ((send_what & SIW_OLSRD_CONF) && functions->olsrd_conf) {
238     /* this outputs the olsrd.conf text directly, not normal format */
239     functions->olsrd_conf(&abuf);
240   }
241
242   if (config->http_headers) {
243     http_header_adjust_content_length(&abuf, contentLengthIndex, abuf.len - headerLength);
244   }
245
246   /* avoid a memcpy: just move the abuf.buf pointer and clear abuf */
247   outbuffer.buffer[outbuffer.count] = abuf.buf;
248   outbuffer.size[outbuffer.count] = abuf.len;
249   outbuffer.written[outbuffer.count] = 0;
250   outbuffer.socket[outbuffer.count] = the_socket;
251   abuf.buf = NULL;
252   abuf.len = 0;
253   abuf.size = 0;
254
255   outbuffer.count++;
256
257   if (outbuffer.count == 1) {
258     writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &write_data, NULL, 0);
259   }
260
261   abuf_free(&abuf);
262 }
263
264 static char * skipLeadingWhitespace(char * requ, size_t *len) {
265   while (isspace(*requ) && (*requ != '\0')) {
266     *len = *len - 1;
267     requ++;
268   }
269   return requ;
270 }
271
272 static char * stripEOLs(char * requ, size_t *len) {
273   while (isspace(requ[*len - 1]) && (requ[*len - 1] != '\0')) {
274     *len = *len - 1;
275     requ[*len] = '\0';
276   }
277   return requ;
278 }
279
280 static char * cutAtFirstEOL(char * requ, size_t *len) {
281   char * s = requ;
282   size_t l = 0;
283   while (!((*s == '\n') || (*s == '\r')) && (*s != '\0')) {
284     s++;
285     l++;
286   }
287   if ((*s == '\n') || (*s == '\r')) {
288     *s = '\0';
289   }
290   *len = l;
291   return requ;
292 }
293
294 static char * parseRequest(char * requ, size_t *len) {
295   char * req = requ;
296
297   if (!req || !*len) {
298     return requ;
299   }
300
301   req = skipLeadingWhitespace(req, len);
302   req = stripEOLs(req, len);
303
304   /* HTTP request: GET whitespace URI whitespace HTTP/1.1 */
305   if (*len < (3 + 1 + 1 + 1 + 8)) {
306     return req;
307   }
308
309   if (strncasecmp(req, "GET", 3) || !isspace(req[3])) {
310     /* does not start with 'GET ' */
311     return req;
312   }
313
314   /* skip 'GET ' and further leading whitespace */
315   req = skipLeadingWhitespace(&req[4], len);
316   if (!*len) return req;
317
318   /* cut req at the first '\n' */
319   req = cutAtFirstEOL(req, len);
320   if (!*len) return req;
321
322   /* strip req of trailing EOL and whitespace */
323   req = stripEOLs(req, len);
324   if (*len < 9) return req;
325
326   if (!isspace(req[*len - 9]) //
327       || strncasecmp(&req[*len - 8], "HTTP/1.", 7) //
328       || ((req[*len - 1] != '1') && (req[*len - 1] != '0'))) {
329     return req;
330   }
331   *len = *len - 8;
332   req[*len] = '\0';
333   if (!*len) return req;
334
335   /* strip req of trailing EOL and whitespace */
336   req = stripEOLs(req, len);
337
338   return req;
339 }
340
341 static void ipc_action(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
342 #ifndef NODEBUG
343   char addr[INET6_ADDRSTRLEN];
344 #endif /* NODEBUG */
345
346   union olsr_sockaddr sock_addr;
347   socklen_t sock_addr_len = sizeof(sock_addr);
348   fd_set rfds;
349   struct timeval tv;
350   unsigned int send_what = 0;
351   int ipc_connection = -1;
352
353   if (outbuffer.count >= MAX_CLIENTS) {
354     return;
355   }
356
357   if ((ipc_connection = accept(fd, &sock_addr.in, &sock_addr_len)) == -1) {
358 #ifndef NODEBUG
359     olsr_printf(1, "(%s) accept()=%s\n", name, strerror(errno));
360 #endif /* NODEBUG */
361     return;
362   }
363
364 #ifndef NODEBUG
365   if (!inet_ntop( //
366       olsr_cnf->ip_version, //
367       (olsr_cnf->ip_version == AF_INET) ? (void *) &sock_addr.in4.sin_addr : (void *) &sock_addr.in6.sin6_addr, //
368       addr, //
369       sizeof(addr))) {
370     addr[0] = '\0';
371   }
372 #endif /* NODEBUG */
373
374   tv.tv_sec = tv.tv_usec = 0;
375   if (olsr_cnf->ip_version == AF_INET) {
376     if (!ip4equal(&sock_addr.in4.sin_addr, &config->accept_ip.v4) && (config->accept_ip.v4.s_addr != INADDR_ANY) //
377         && (!config->allow_localhost || (ntohl(sock_addr.in4.sin_addr.s_addr) != INADDR_LOOPBACK))) {
378 #ifndef NODEBUG
379       olsr_printf(1, "(%s) From host(%s) not allowed!\n", name, addr);
380 #endif /* NODEBUG */
381       close(ipc_connection);
382       return;
383     }
384   } else {
385     /* Use in6addr_any (::) in olsr.conf to allow anybody. */
386     if (!ip6equal(&sock_addr.in6.sin6_addr, &config->accept_ip.v6) && !ip6equal(&config->accept_ip.v6, &in6addr_any)) {
387 #ifndef NODEBUG
388       olsr_printf(1, "(%s) From host(%s) not allowed!\n", name, addr);
389 #endif /* NODEBUG */
390       close(ipc_connection);
391       return;
392     }
393   }
394
395 #ifndef NODEBUG
396   olsr_printf(2, "(%s) Connect from %s\n", name, addr);
397 #endif /* NODEBUG */
398
399   /* purge read buffer to prevent blocking on linux */
400   FD_ZERO(&rfds);
401   FD_SET((unsigned int ) ipc_connection, &rfds); /* Win32 needs the cast here */
402   if (0 <= select(ipc_connection + 1, &rfds, NULL, NULL, &tv)) {
403     char requ[1024];
404     ssize_t s = recv(ipc_connection, (void *) &requ, sizeof(requ) - 1, 0); /* Win32 needs the cast here */
405
406     if (s >= (ssize_t) (sizeof(requ) - 1)) {
407       /* input was much too long, just skip the rest */
408       while (recv(ipc_connection, (void *) &sink_buffer, sizeof(sink_buffer), 0) == sizeof(sink_buffer))
409         ;
410       s = 0;
411     }
412
413     if (0 < s) {
414       char * req = requ;
415       req[s] = '\0';
416       req = parseRequest(req, (size_t*)&s);
417       send_what = determine_action(req);
418     }
419
420     if (!send_what)
421       send_what = SIW_ALL;
422   }
423
424   send_info(send_what, ipc_connection);
425 }
426
427 static int plugin_ipc_init(void) {
428   union olsr_sockaddr sock_addr;
429   uint32_t yes = 1;
430   socklen_t sock_addr_len;
431
432   /* Init ipc socket */
433   if ((ipc_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0)) == -1) {
434 #ifndef NODEBUG
435     olsr_printf(1, "(%s) socket()=%s\n", name, strerror(errno));
436 #endif /* NODEBUG */
437     goto error_out;
438   }
439
440   if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof(yes)) < 0) {
441 #ifndef NODEBUG
442     olsr_printf(1, "(%s) setsockopt()=%s\n", name, strerror(errno));
443 #endif /* NODEBUG */
444     goto error_out;
445   }
446
447 #if (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE
448   if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *) &yes, sizeof(yes)) < 0) {
449     perror("SO_NOSIGPIPE failed");
450     goto error_out;
451   }
452 #endif /* (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE */
453
454 #if defined __linux__ && defined IPV6_V6ONLY
455   if (config->ipv6_only && (olsr_cnf->ip_version == AF_INET6) //
456       && (setsockopt(ipc_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &yes, sizeof(yes)) < 0)) {
457     perror("IPV6_V6ONLY failed");
458     goto error_out;
459   }
460 #endif /* defined __linux__ && defined IPV6_V6ONLY */
461
462   /* complete the socket structure */
463   memset(&sock_addr, 0, sizeof(sock_addr));
464   if (olsr_cnf->ip_version == AF_INET) {
465     sock_addr.in4.sin_family = AF_INET;
466     sock_addr_len = sizeof(struct sockaddr_in);
467 #ifdef SIN6_LEN
468     sock_addr.in4.sin_len = sock_addr_len;
469 #endif /* SIN6_LEN */
470     sock_addr.in4.sin_addr.s_addr = config->listen_ip.v4.s_addr;
471     sock_addr.in4.sin_port = htons(config->ipc_port);
472   } else {
473     sock_addr.in6.sin6_family = AF_INET6;
474     sock_addr_len = sizeof(struct sockaddr_in6);
475 #ifdef SIN6_LEN
476     sock_addr.in6.sin6_len = sock_addr_len;
477 #endif /* SIN6_LEN */
478     sock_addr.in6.sin6_addr = config->listen_ip.v6;
479     sock_addr.in6.sin6_port = htons(config->ipc_port);
480   }
481
482   /* bind the socket to the port number */
483   if (bind(ipc_socket, &sock_addr.in, sock_addr_len) == -1) {
484 #ifndef NODEBUG
485     olsr_printf(1, "(%s) bind()=%s\n", name, strerror(errno));
486 #endif /* NODEBUG */
487     goto error_out;
488   }
489
490   /* show that we are willing to listen */
491   if (listen(ipc_socket, 1) == -1) {
492 #ifndef NODEBUG
493     olsr_printf(1, "(%s) listen()=%s\n", name, strerror(errno));
494 #endif /* NODEBUG */
495     goto error_out;
496   }
497
498   /* Register with olsrd */
499   add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
500
501 #ifndef NODEBUG
502   olsr_printf(2, "(%s) listening on port %d\n", name, config->ipc_port);
503 #endif /* NODEBUG */
504
505   return 1;
506
507   error_out: //
508   if (ipc_socket >= 0) {
509     close(ipc_socket);
510     ipc_socket = -1;
511   }
512   return 0;
513 }
514
515 int info_plugin_init(const char * plugin_name, info_plugin_functions_t *plugin_functions, info_plugin_config_t *plugin_config) {
516   int i;
517
518   assert(plugin_name);
519   assert(plugin_functions);
520   assert(plugin_config);
521
522   name = plugin_name;
523   functions = plugin_functions;
524   config = plugin_config;
525
526   memset(&outbuffer, 0, sizeof(outbuffer));
527   for (i = 0; i < MAX_CLIENTS; ++i) {
528     outbuffer.socket[i] = -1;
529   }
530
531   ipc_socket = -1;
532
533   if (functions->init) {
534     functions->init(name);
535   }
536
537   plugin_ipc_init();
538   return 1;
539 }
540
541 void info_plugin_exit(void) {
542   int i;
543
544   if (ipc_socket != -1) {
545     close(ipc_socket);
546     ipc_socket = -1;
547   }
548   for (i = 0; i < MAX_CLIENTS; ++i) {
549     if (outbuffer.buffer[i]) {
550       free(outbuffer.buffer[i]);
551       outbuffer.buffer[i] = NULL;
552     }
553     outbuffer.size[i] = 0;
554     outbuffer.written[i] = 0;
555     if (outbuffer.socket[i]) {
556       close(outbuffer.socket[i]);
557       outbuffer.socket[i] = -1;
558     }
559   }
560   outbuffer.count = 0;
561 }