3 * HTTP Info plugin for the olsr.org OLSR daemon
4 * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
43 * Dynamic linked library for the olsr.org olsr daemon
59 #include "interfaces.h"
60 #include "olsr_protocol.h"
63 #include "socket_parser.h"
65 #include "lq_plugin.h"
66 #include "common/autobuf.h"
68 #include "olsrd_httpinfo.h"
69 #include "admin_interface.h"
77 #define close(x) closesocket(x)
81 #define OS "GNU/Linux"
88 #define OS "Undefined"
91 static char copyright_string[] __attribute__ ((unused)) =
92 "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
96 #define MAX_HTTPREQ_SIZE (1024 * 10)
98 #define DEFAULT_TCP_PORT 1978
100 #define HTML_BUFSIZE (1024 * 4000)
102 #define FRAMEWIDTH (resolve_ip_addresses ? 900 : 800)
104 #define FILENREQ_MATCH(req, filename) \
105 !strcmp(req, filename) || \
106 (strlen(req) && !strcmp(&req[1], filename))
108 static const char httpinfo_css[] =
109 "#A {text-decoration: none}\n" "TH{text-align: left}\n" "H1, H3, TD, TH {font-family: Helvetica; font-size: 80%}\n"
110 "h2\n {\nfont-family: Helvetica;\n font-size: 14px;text-align: center;\n"
111 "line-height: 16px;\ntext-decoration: none;\nborder: 1px solid #ccc;\n" "margin: 5px;\nbackground: #ececec;\n}\n"
112 "hr\n{\nborder: none;\npadding: 1px;\nbackground: url(grayline.gif) repeat-x bottom;\n}\n"
113 "#maintable\n{\nmargin: 0px;\npadding: 5px;\nborder-left: 1px solid #ccc;\n"
114 "border-right: 1px solid #ccc;\nborder-bottom: 1px solid #ccc;\n}\n"
115 "#footer\n{\nfont-size: 10px;\nline-height: 14px;\ntext-decoration: none;\ncolor: #666;\n}\n"
116 "#hdr\n{\nfont-size: 14px;\ntext-align: center;\nline-height: 16px;\n" "text-decoration: none;\nborder: 1px solid #ccc;\n"
117 "margin: 5px;\nbackground: #ececec;\n}\n"
118 "#container\n{\nwidth: 1000px;\npadding: 30px;\nborder: 1px solid #ccc;\nbackground: #fff;\n}\n"
119 "#tabnav\n{\nheight: 20px;\nmargin: 0;\npadding-left: 10px;\n" "background: url(grayline.gif) repeat-x bottom;\n}\n"
120 "#tabnav li\n{\nmargin: 0;\npadding: 0;\ndisplay: inline;\nlist-style-type: none;\n}\n"
121 "#tabnav a:link, #tabnav a:visited\n{\nfloat: left;\nbackground: #ececec;\n"
122 "font-size: 12px;\nline-height: 14px;\nfont-weight: bold;\npadding: 2px 10px 2px 10px;\n"
123 "margin-right: 4px;\nborder: 1px solid #ccc;\ntext-decoration: none;\ncolor: #777;\n}\n"
124 "#tabnav a:link.active, #tabnav a:visited.active\n{\nborder-bottom: 1px solid #fff;\n" "background: #ffffff;\ncolor: #000;\n}\n"
125 "#tabnav a:hover\n{\nbackground: #777777;\ncolor: #ffffff;\n}\n"
126 ".input_text\n{\nbackground: #E5E5E5;\nmargin-left: 5px; margin-top: 0px;\n"
127 "text-align: left;\n\nwidth: 100px;\npadding: 0px;\ncolor: #000000;\n"
128 "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #ccc;\n}\n"
129 ".input_button\n{\nbackground: #B5D1EE;\nmargin-left: 5px;\nmargin-top: 0px;\n"
130 "text-align: center;\nwidth: 120px;\npadding: 0px;\ncolor: #000000;\n"
131 "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #000;\n}\n";
133 typedef void (*build_body_callback) (struct autobuf *);
136 const char *tab_label;
137 const char *filename;
138 build_body_callback build_body_cb;
142 struct static_bin_file_entry {
143 const char *filename;
145 unsigned int data_size;
148 struct static_txt_file_entry {
149 const char *filename;
153 struct dynamic_file_entry {
154 const char *filename;
155 int (*process_data_cb) (char *, uint32_t, char *, uint32_t);
158 static int get_http_socket(int);
160 static void build_tabs(struct autobuf *, int);
162 static void parse_http_request(int);
164 static int build_http_header(http_header_type, bool, uint32_t, char *, uint32_t);
166 static void build_frame(struct autobuf *, const char *, const char *, int, build_body_callback frame_body_cb);
168 static void build_routes_body(struct autobuf *);
170 static void build_config_body(struct autobuf *);
172 static void build_neigh_body(struct autobuf *);
174 static void build_topo_body(struct autobuf *);
176 static void build_mid_body(struct autobuf *);
178 static void build_nodes_body(struct autobuf *);
180 static void build_all_body(struct autobuf *);
182 static void build_about_body(struct autobuf *);
184 static void build_cfgfile_body(struct autobuf *);
186 static int check_allowed_ip(const struct allowed_net *const allowed_nets, const union olsr_ip_addr *const addr);
188 static void build_ip_txt(struct autobuf *, const bool want_link, const char *const ipaddrstr, const int prefix_len);
190 static void build_ipaddr_link(struct autobuf *, const bool want_link, const union olsr_ip_addr *const ipaddr,
191 const int prefix_len);
192 static void section_title(struct autobuf *, const char *title);
194 static void httpinfo_write_data(void *foo);
196 static struct timeval start_time;
197 static struct http_stats stats;
198 static int http_socket;
200 static char *outbuffer[MAX_CLIENTS];
201 static size_t outbuffer_size[MAX_CLIENTS];
202 static size_t outbuffer_written[MAX_CLIENTS];
203 static int outbuffer_socket[MAX_CLIENTS];
204 static int outbuffer_count;
206 static struct timer_entry *writetimer_entry;
209 int netsprintf(char *str, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
210 static int netsprintf_direct = 0;
211 static int netsprintf_error = 0;
212 #define sprintf netsprintf
216 static const struct tab_entry tab_entries[] = {
217 {"Configuration", "config", build_config_body, true},
218 {"Routes", "routes", build_routes_body, true},
219 {"Links/Topology", "nodes", build_nodes_body, true},
220 {"All", "all", build_all_body, true},
221 #ifdef ADMIN_INTERFACE
222 {"Admin", "admin", build_admin_body, true},
224 {"About", "about", build_about_body, true},
225 {"FOO", "cfgfile", build_cfgfile_body, false},
226 {NULL, NULL, NULL, false}
229 static const struct static_bin_file_entry static_bin_files[] = {
230 {"favicon.ico", favicon_ico, sizeof(favicon_ico)}
232 {"logo.gif", logo_gif, sizeof(logo_gif)}
234 {"grayline.gif", grayline_gif, sizeof(grayline_gif)}
239 static const struct static_txt_file_entry static_txt_files[] = {
240 {"httpinfo.css", httpinfo_css},
244 static const struct dynamic_file_entry dynamic_files[] = {
245 #ifdef ADMIN_INTERFACE
246 {"set_values", process_set_values},
252 get_http_socket(int port)
254 struct sockaddr_in sin;
257 /* Init ipc socket */
258 int s = socket(AF_INET, SOCK_STREAM, 0);
260 olsr_printf(1, "(HTTPINFO)socket %s\n", strerror(errno));
264 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
265 olsr_printf(1, "(HTTPINFO)SO_REUSEADDR failed %s\n", strerror(errno));
270 /* Bind the socket */
272 /* complete the socket structure */
273 memset(&sin, 0, sizeof(sin));
274 sin.sin_family = AF_INET;
275 sin.sin_addr.s_addr = INADDR_ANY;
276 sin.sin_port = htons(port);
278 /* bind the socket to the port number */
279 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
280 olsr_printf(1, "(HTTPINFO) bind failed %s\n", strerror(errno));
285 /* show that we are willing to listen */
286 if (listen(s, 1) == -1) {
287 olsr_printf(1, "(HTTPINFO) listen failed %s\n", strerror(errno));
296 *Do initialization here
298 *This function is called by the my_init
299 *function in uolsrd_plugin.c
302 olsrd_plugin_init(void)
305 gettimeofday(&start_time, NULL);
307 /* set up HTTP socket */
308 http_socket = get_http_socket(http_port != 0 ? http_port : DEFAULT_TCP_PORT);
310 if (http_socket < 0) {
311 fprintf(stderr, "(HTTPINFO) could not initialize HTTP socket\n");
315 /* Register socket */
316 add_olsr_socket(http_socket, &parse_http_request);
321 /* Non reentrant - but we are not multithreaded anyway */
323 parse_http_request(int fd)
325 struct sockaddr_in pin;
326 struct autobuf body_abuf = { 0, 0, NULL };
329 char header_buf[MAX_HTTPREQ_SIZE];
332 char http_version[11];
334 size_t header_length = 0;
338 struct timeval timeout = { 0, 200 };
341 if (outbuffer_count >= MAX_CLIENTS) {
342 olsr_printf(1, "(HTTPINFO) maximum number of connection reached\n");
346 addrlen = sizeof(struct sockaddr_in);
347 client_socket = accept(fd, (struct sockaddr *)&pin, &addrlen);
348 if (client_socket == -1) {
349 olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
350 goto close_connection;
354 if (setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
355 olsr_printf(1, "(HTTPINFO)SO_RCVTIMEO failed %s\n", strerror(errno));
356 goto close_connection;
359 if (setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
360 olsr_printf(1, "(HTTPINFO)SO_SNDTIMEO failed %s\n", strerror(errno));
361 goto close_connection;
364 if (!check_allowed_ip(allowed_nets, (union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
365 struct ipaddr_str strbuf;
366 olsr_printf(0, "HTTP request from non-allowed host %s!\n",
367 olsr_ip_to_string(&strbuf, (union olsr_ip_addr *)&pin.sin_addr.s_addr));
368 goto close_connection;
371 addr = inet_ntoa(pin.sin_addr);
373 memset(header_buf, 0, sizeof(header_buf));
375 while ((r = recv(client_socket, &header_buf[c], 1, 0)) > 0 && (c < sizeof(header_buf) - 1)) {
378 if ((c > 3 && !strcmp(&header_buf[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&header_buf[c - 2], "\n\n")))
383 olsr_printf(1, "(HTTPINFO) Failed to recieve data from client!\n");
385 goto close_connection;
388 /* Get the request */
389 if (sscanf(header_buf, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
390 /* Try without HTTP version */
391 if (sscanf(header_buf, "%10s %250s\n", req_type, filename) != 2) {
392 olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", header_buf);
394 goto close_connection;
398 olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
399 abuf_init(&body_abuf, 102400);
401 if (!strcmp(req_type, "POST")) {
402 #ifdef ADMIN_INTERFACE
404 while (dynamic_files[i].filename) {
405 printf("POST checking %s\n", dynamic_files[i].filename);
406 if (FILENREQ_MATCH(filename, dynamic_files[i].filename)) {
411 param_size = recv(client_sockets[curr_clients], header_buf, sizeof(header_buf) - 1, 0);
413 header_buf[param_size] = '\0';
414 printf("Dynamic read %d bytes\n", param_size);
416 //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
417 body_length += dynamic_files[i].process_data_cb(header_buf, param_size, &body_buf[body_length], sizeof(body_buf) - body_length);
418 header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
424 /* We only support GET */
425 abuf_puts(&body_abuf, HTTP_400_MSG);
427 header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
428 } else if (!strcmp(req_type, "GET")) {
431 for (i = 0; static_bin_files[i].filename; i++) {
432 if (FILENREQ_MATCH(filename, static_bin_files[i].filename)) {
437 if (static_bin_files[i].filename) {
439 abuf_memcpy(&body_abuf, static_bin_files[i].data, static_bin_files[i].data_size);
440 header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
445 while (static_txt_files[i].filename) {
446 if (FILENREQ_MATCH(filename, static_txt_files[i].filename)) {
452 if (static_txt_files[i].filename) {
454 abuf_puts(&body_abuf, static_txt_files[i].data);
455 header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
460 if (strlen(filename) > 1) {
461 while (tab_entries[i].filename) {
462 if (FILENREQ_MATCH(filename, tab_entries[i].filename)) {
469 if (tab_entries[i].filename) {
471 header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
472 r = send(client_sockets[curr_clients], header_buf, header_length, 0);
474 olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
475 goto close_connection;
477 netsprintf_error = 0;
478 netsprintf_direct = 1;
480 abuf_appendf(&body_abuf,
481 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<head>\n"
482 "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
483 "<title>olsr.org httpinfo plugin</title>\n" "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
484 "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
485 "<link rel=\"stylesheet\" type=\"text/css\" href=\"httpinfo.css\">\n" "</head>\n"
486 "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
487 "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
488 "<tbody><tr bgcolor=\"#ffffff\">\n" "<td align=\"left\" height=\"69\" valign=\"middle\" width=\"80%%\">\n"
489 "<font color=\"black\" face=\"timesroman\" size=\"6\"> <a href=\"http://www.olsr.org/\">olsr.org OLSR daemon</a></font></td>\n"
490 "<td height=\"69\" valign=\"middle\" width=\"20%%\">\n"
491 "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n" "</tr>\n"
492 "</tbody>\n" "</table>\n", FRAMEWIDTH);
494 build_tabs(&body_abuf, i);
495 build_frame(&body_abuf, "Current Routes", "routes", FRAMEWIDTH, tab_entries[i].build_body_cb);
499 abuf_appendf(&body_abuf,
500 "</table>\n" "<div id=\"footer\">\n" "<center>\n" "(C)2005 Andreas Tønnesen<br/>\n"
501 "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
504 netsprintf_direct = 1;
505 goto close_connection;
507 header_length = build_http_header(HTTP_OK, true, body_abuf.len, header_buf, sizeof(header_buf));
513 abuf_puts(&body_abuf, HTTP_404_MSG);
514 header_length = build_http_header(HTTP_BAD_FILE, true, body_abuf.len, header_buf, sizeof(header_buf));
516 /* We only support GET */
517 abuf_puts(&body_abuf, HTTP_404_MSG);
519 header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
523 if (header_length + body_abuf.len > 0) {
524 outbuffer[outbuffer_count] = olsr_malloc(header_length + body_abuf.len, "http output buffer");
525 outbuffer_size[outbuffer_count] = header_length + body_abuf.len;
526 outbuffer_written[outbuffer_count] = 0;
527 outbuffer_socket[outbuffer_count] = client_socket;
529 memcpy(outbuffer[outbuffer_count], header_buf, header_length);
530 if (body_abuf.len > 0) {
531 memcpy((outbuffer[outbuffer_count]) + header_length, body_abuf.buf, body_abuf.len);
535 if (outbuffer_count == 1) {
536 writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &httpinfo_write_data, NULL, 0);
539 abuf_free(&body_abuf);
543 abuf_free(&body_abuf);
544 close(client_socket);
548 httpinfo_write_data(void *foo __attribute__ ((unused))) {
550 int result, i, j, max;
555 for (i=0; i<outbuffer_count; i++) {
556 FD_SET(outbuffer_socket[i], &set);
557 if (outbuffer_socket[i] > max) {
558 max = outbuffer_socket[i];
565 result = select(max + 1, NULL, &set, NULL, &tv);
570 for (i=0; i<outbuffer_count; i++) {
571 if (FD_ISSET(outbuffer_socket[i], &set)) {
572 result = write(outbuffer_socket[i], outbuffer[i] + outbuffer_written[i], outbuffer_size[i] - outbuffer_written[i]);
574 outbuffer_written[i] += result;
577 if (result <= 0 || outbuffer_written[i] == outbuffer_size[i]) {
578 /* close this socket and cleanup*/
579 close(outbuffer_socket[i]);
582 for (j=i+1; j<outbuffer_count; j++) {
583 outbuffer[j-1] = outbuffer[j];
584 outbuffer_size[j-1] = outbuffer_size[j];
585 outbuffer_socket[j-1] = outbuffer_socket[j];
586 outbuffer_written[j-1] = outbuffer_written[j];
592 if (outbuffer_count == 0) {
593 olsr_stop_timer(writetimer_entry);
598 build_http_header(http_header_type type, bool is_html, uint32_t msgsize, char *buf, uint32_t bufsize)
616 size = snprintf(buf, bufsize, "%s", h);
620 size += strftime(&buf[size], bufsize - size, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", localtime(&currtime));
623 size += snprintf(&buf[size], bufsize - size, "Server: %s %s %s\r\n", PLUGIN_NAME, PLUGIN_VERSION, HTTP_VERSION);
625 /* connection-type */
626 size += snprintf(&buf[size], bufsize - size, "Connection: closed\r\n");
629 size += snprintf(&buf[size], bufsize - size, "Content-type: text/%s\r\n", is_html ? "html" : "plain");
633 size += snprintf(&buf[size], bufsize - size, "Content-length: %i\r\n", msgsize);
637 * No caching dynamic pages
639 size += snprintf(&buf[size], bufsize - size, "Cache-Control: no-cache\r\n");
642 size += snprintf(&buf[size], bufsize - size, "Accept-Ranges: bytes\r\n");
645 size += snprintf(&buf[size], bufsize - size, "\r\n");
647 olsr_printf(1, "HEADER:\n%s", buf);
653 build_tabs(struct autobuf *abuf, int active)
658 "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
659 "<tr bgcolor=\"#ffffff\"><td>\n" "<ul id=\"tabnav\">\n", FRAMEWIDTH);
660 for (tabs = 0; tab_entries[tabs].tab_label; tabs++) {
661 if (!tab_entries[tabs].display_tab) {
664 abuf_appendf(abuf, "<li><a href=\"%s\"%s>%s</a></li>\n", tab_entries[tabs].filename,
665 tabs == active ? " class=\"active\"" : "", tab_entries[tabs].tab_label);
667 abuf_appendf(abuf, "</ul>\n" "</td></tr>\n" "<tr><td>\n");
671 * destructor - called at unload
674 olsr_plugin_exit(void)
676 if (http_socket >= 0) {
682 section_title(struct autobuf *abuf, const char *title)
685 "<h2>%s</h2>\n" "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n",
690 build_frame(struct autobuf *abuf, const char *title __attribute__ ((unused)), const char *link
691 __attribute__ ((unused)), int width __attribute__ ((unused)), build_body_callback frame_body_cb)
693 abuf_puts(abuf, "<div id=\"maintable\">\n");
695 abuf_puts(abuf, "</div>\n");
699 fmt_href(struct autobuf *abuf, const char *const ipaddr)
701 abuf_appendf(abuf, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
705 build_ip_txt(struct autobuf *abuf, const bool print_link, const char *const ipaddrstr, const int prefix_len)
708 fmt_href(abuf, ipaddrstr);
711 abuf_puts(abuf, ipaddrstr);
712 /* print ip address or ip prefix ? */
713 if (prefix_len != -1 && prefix_len != olsr_cnf->maxplen) {
714 abuf_appendf(abuf, "/%d", prefix_len);
717 if (print_link) { /* Print the link only if there is no prefix_len */
718 abuf_puts(abuf, "</a>");
723 build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_ip_addr *const ipaddr,
724 const int prefix_len)
726 struct ipaddr_str ipaddrstr;
727 const struct hostent *const hp =
729 resolve_ip_addresses ? gethostbyaddr(ipaddr, olsr_cnf->ipsize,
730 olsr_cnf->ip_version) :
733 /* Print the link only if there is no prefix_len */
734 const int print_link = want_link && (prefix_len == -1 || prefix_len == olsr_cnf->maxplen);
735 olsr_ip_to_string(&ipaddrstr, ipaddr);
737 abuf_puts(abuf, "<td>");
738 build_ip_txt(abuf, print_link, ipaddrstr.buf, prefix_len);
739 abuf_puts(abuf, "</td>");
741 if (resolve_ip_addresses) {
743 abuf_puts(abuf, "<td>(");
745 fmt_href(abuf, ipaddrstr.buf);
747 abuf_puts(abuf, hp->h_name);
749 abuf_puts(abuf, "</a>");
751 abuf_puts(abuf, ")</td>");
753 abuf_puts(abuf, "<td/>");
758 #define build_ipaddr_with_link(buf, ipaddr, plen) \
759 build_ipaddr_link((buf), true, (ipaddr), (plen))
760 #define build_ipaddr_no_link(buf, ipaddr, plen) \
761 build_ipaddr_link((buf), false, (ipaddr), (plen))
764 build_route(struct autobuf *abuf, const struct rt_entry *rt)
766 struct lqtextbuffer lqbuffer;
768 abuf_puts(abuf, "<tr>");
769 build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
770 build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
772 abuf_appendf(abuf, "<td>%d</td>", rt->rt_best->rtp_metric.hops);
773 abuf_appendf(abuf, "<td>%s</td>",
774 get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer));
775 abuf_appendf(abuf, "<td>%s</td></tr>\n",
776 if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
780 build_routes_body(struct autobuf *abuf)
783 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
784 section_title(abuf, "OLSR Routes in Kernel");
786 "<tr><th%s>Destination</th><th%s>Gateway</th><th>Metric</th><th>ETX</th><th>Interface</th></tr>\n",
789 /* Walk the route table */
790 OLSR_FOR_ALL_RT_ENTRIES(rt) {
791 build_route(abuf, rt);
792 } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
794 abuf_puts(abuf, "</table>\n");
798 build_config_body(struct autobuf *abuf)
800 const struct olsr_if *ifs;
801 const struct plugin_entry *pentry;
802 const struct plugin_param *pparam;
803 struct ipaddr_str mainaddrbuf;
805 abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>", olsrd_version, build_date, build_host);
806 abuf_appendf(abuf, "OS: %s\n<br>", OS);
809 const time_t currtime = time(NULL);
811 abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>",
812 localtime(&currtime));
816 struct timeval now, uptime;
817 int hours, mins, days;
818 gettimeofday(&now, NULL);
819 timersub(&now, &start_time, &uptime);
821 days = uptime.tv_sec / 86400;
822 uptime.tv_sec %= 86400;
823 hours = uptime.tv_sec / 3600;
824 uptime.tv_sec %= 3600;
825 mins = uptime.tv_sec / 60;
828 abuf_puts(abuf, "Olsrd uptime: <em>");
830 abuf_appendf(abuf, "%d day(s) ", days);
832 abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
835 abuf_appendf(abuf, "HTTP stats(ok/dyn/error/illegal): <em>%d/%d/%d/%d</em><br>\n", stats.ok_hits,
836 stats.dyn_hits, stats.err_hits, stats.ill_hits);
839 "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
841 abuf_puts(abuf, "<h2>Variables</h2>\n");
843 abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
845 abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n",
846 olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
847 abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
848 abuf_appendf(abuf, "<td>Debug level: %d</td>\n", olsr_cnf->debug_level);
849 abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n",
850 FIBM_FLAT == olsr_cnf->fib_metric ? CFG_FIBM_FLAT : FIBM_CORRECT ==
851 olsr_cnf->fib_metric ? CFG_FIBM_CORRECT : CFG_FIBM_APPROX);
853 abuf_puts(abuf, "</tr>\n<tr>\n");
855 abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", olsr_cnf->pollrate);
856 abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
857 abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
858 abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", olsr_cnf->lq_nat_thresh);
860 abuf_puts(abuf, "</tr>\n<tr>\n");
862 abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
863 abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
864 abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rttable, olsr_cnf->rttable);
865 abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rttable_default,
866 olsr_cnf->rttable_default);
867 abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness,
868 olsr_cnf->willingness_auto ? "(auto)" : "");
870 if (olsr_cnf->lq_level == 0) {
871 abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>Hysteresis: %s</td>\n",
872 olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
873 if (olsr_cnf->use_hysteresis) {
874 abuf_appendf(abuf, "<td>Hyst scaling: %0.2f</td>\n", olsr_cnf->hysteresis_param.scaling);
875 abuf_appendf(abuf, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", olsr_cnf->hysteresis_param.thr_low,
876 olsr_cnf->hysteresis_param.thr_high);
880 abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>LQ extension: %s</td>\n",
881 olsr_cnf->lq_level ? "Enabled" : "Disabled");
882 if (olsr_cnf->lq_level) {
883 abuf_appendf(abuf, "<td>LQ level: %d</td>\n" "<td>LQ aging: %f</td>\n", olsr_cnf->lq_level,
886 abuf_puts(abuf, "</tr></table>\n");
888 abuf_puts(abuf, "<h2>Interfaces</h2>\n");
889 abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
890 for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
891 const struct interface *const rifs = ifs->interf;
892 abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
894 abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
898 if (olsr_cnf->ip_version == AF_INET) {
899 struct ipaddr_str addrbuf, maskbuf, bcastbuf;
900 abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MASK: %s</td>\n" "<td>BCAST: %s</td>\n" "</tr>\n",
901 ip4_to_string(&addrbuf, rifs->int_addr.sin_addr), ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr),
902 ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
904 struct ipaddr_str addrbuf, maskbuf;
905 abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MCAST: %s</td>\n" "<td></td>\n" "</tr>\n",
906 ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr), ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
908 abuf_appendf(abuf, "<tr>\n" "<td>MTU: %d</td>\n" "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n",
909 rifs->int_mtu, rifs->is_wireless ? "Yes" : "No");
911 abuf_puts(abuf, "</table>\n");
913 abuf_appendf(abuf, "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
914 olsr_cnf->allow_no_interfaces ? "run even" : "halt");
916 abuf_puts(abuf, "<h2>Plugins</h2>\n");
917 abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
918 for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
919 abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
921 for (pparam = pentry->params; pparam; pparam = pparam->next) {
922 abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
924 abuf_puts(abuf, "</select></td></tr>\n");
927 abuf_puts(abuf, "</table>\n");
929 section_title(abuf, "Announced HNA entries");
930 if (olsr_cnf->hna_entries) {
931 struct ip_prefix_list *hna;
932 abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
933 for (hna = olsr_cnf->hna_entries; hna; hna = hna->next) {
934 struct ipaddr_str netbuf;
935 abuf_appendf(abuf, "<tr><td>%s/%d</td></tr>\n", olsr_ip_to_string(&netbuf, &hna->net.prefix),
936 hna->net.prefix_len);
939 abuf_puts(abuf, "<tr><td></td></tr>\n");
941 abuf_puts(abuf, "</table>\n");
945 build_neigh_body(struct autobuf *abuf)
947 struct neighbor_entry *neigh;
948 struct link_entry *link = NULL;
949 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
951 section_title(abuf, "Links");
954 "<tr><th%s>Local IP</th><th%s>Remote IP</th><th>Hysteresis</th>",
956 if (olsr_cnf->lq_level > 0) {
957 abuf_puts(abuf, "<th>LinkCost</th>");
959 abuf_puts(abuf, "</tr>\n");
962 OLSR_FOR_ALL_LINK_ENTRIES(link) {
963 abuf_puts(abuf, "<tr>");
964 build_ipaddr_with_link(abuf, &link->local_iface_addr, -1);
965 build_ipaddr_with_link(abuf, &link->neighbor_iface_addr, -1);
966 abuf_appendf(abuf, "<td>%0.2f</td>", link->L_link_quality);
967 if (olsr_cnf->lq_level > 0) {
968 struct lqtextbuffer lqbuffer1, lqbuffer2;
969 abuf_appendf(abuf, "<td>(%s) %s</td>", get_link_entry_text(link, '/', &lqbuffer1),
970 get_linkcost_text(link->linkcost, false, &lqbuffer2));
972 abuf_puts(abuf, "</tr>\n");
973 } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
975 abuf_puts(abuf, "</table>\n");
977 section_title(abuf, "Neighbors");
979 "<tr><th%s>IP Address</th><th>SYM</th><th>MPR</th><th>MPRS</th><th>Willingness</th><th>2 Hop Neighbors</th></tr>\n",
982 OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
984 struct neighbor_2_list_entry *list_2;
986 abuf_puts(abuf, "<tr>");
987 build_ipaddr_with_link(abuf, &neigh->neighbor_main_addr, -1);
989 "<td>%s</td>" "<td>%s</td>" "<td>%s</td>"
990 "<td>%d</td>", (neigh->status == SYM) ? "YES" : "NO", neigh->is_mpr ? "YES" : "NO",
991 olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness);
993 abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
995 for (list_2 = neigh->neighbor_2_list.next, thop_cnt = 0; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next, thop_cnt++) {
996 struct ipaddr_str strbuf;
997 abuf_appendf(abuf, "<option>%s</option>\n",
998 olsr_ip_to_string(&strbuf, &list_2->neighbor_2->neighbor_2_addr));
1000 abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
1001 } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
1003 abuf_puts(abuf, "</table>\n");
1007 build_topo_body(struct autobuf *abuf)
1009 struct tc_entry *tc;
1010 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1012 section_title(abuf, "Topology Entries");
1013 abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>",
1015 if (olsr_cnf->lq_level > 0) {
1016 abuf_puts(abuf, "<th>Linkcost</th>");
1018 abuf_puts(abuf, "</tr>\n");
1020 OLSR_FOR_ALL_TC_ENTRIES(tc) {
1021 struct tc_edge_entry *tc_edge;
1022 OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
1023 if (tc_edge->edge_inv) {
1024 abuf_puts(abuf, "<tr>");
1025 build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
1026 build_ipaddr_with_link(abuf, &tc->addr, -1);
1027 if (olsr_cnf->lq_level > 0) {
1028 struct lqtextbuffer lqbuffer1, lqbuffer2;
1029 abuf_appendf(abuf, "<td>(%s) %s</td>\n",
1030 get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
1032 abuf_puts(abuf, "</tr>\n");
1034 } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1035 } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1037 abuf_puts(abuf, "</table>\n");
1041 build_mid_body(struct autobuf *abuf)
1044 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1046 section_title(abuf, "MID Entries");
1047 abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1050 for (idx = 0; idx < HASHSIZE; idx++) {
1051 struct mid_entry *entry;
1052 for (entry = mid_set[idx].next; entry != &mid_set[idx]; entry = entry->next) {
1054 struct mid_address *alias;
1055 abuf_puts(abuf, "<tr>");
1056 build_ipaddr_with_link(abuf, &entry->main_addr, -1);
1057 abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
1059 for (mid_cnt = 0, alias = entry->aliases; alias != NULL; alias = alias->next_alias, mid_cnt++) {
1060 struct ipaddr_str strbuf;
1061 abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
1063 abuf_appendf(abuf, "</select> (%d)</td></tr>\n", mid_cnt);
1067 abuf_puts(abuf, "</table>\n");
1071 build_nodes_body(struct autobuf *abuf)
1073 build_neigh_body(abuf);
1074 build_topo_body(abuf);
1075 build_mid_body(abuf);
1079 build_all_body(struct autobuf *abuf)
1081 build_config_body(abuf);
1082 build_routes_body(abuf);
1083 build_neigh_body(abuf);
1084 build_topo_body(abuf);
1085 build_mid_body(abuf);
1089 build_about_body(struct autobuf *abuf)
1092 "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas Tønnesen (C)2005.<br/>\n"
1094 #ifdef ADMIN_INTERFACE
1095 "<em>with experimental admin interface</em> "
1097 "%s at %s<hr/>\n" "This plugin implements a HTTP server that supplies\n"
1098 "the client with various dynamic web pages representing\n"
1099 "the current olsrd status.<br/>The different pages include:\n"
1100 "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1101 "about the current olsrd configuration. This includes various\n"
1102 "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1103 "etc. Information about the current status of the interfaces on\n"
1104 "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1105 "plugins are shown with their plugin parameters. Finally all local\n"
1106 "HNA entries are shown. These are the networks that the local host\n"
1107 "will anounce itself as a gateway to.</li>\n"
1108 "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1109 "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n" "or HNA).</li>\n"
1110 "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1111 "links, neighbors, topology, MID and HNA entries.</li>\n"
1112 "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1113 "This is to make all information available as easy as possible(for example\n"
1114 "for a script) and using as few resources as possible.</li>\n"
1115 #ifdef ADMIN_INTERFACE
1116 "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1117 "As of now it is not working at all but it provides a impression of\n"
1118 "the future possibilities of httpinfo. This is to be a interface to\n"
1119 "changing olsrd settings in realtime. These settings include various\n"
1120 "\"basic\" settings and local HNA settings.</li>\n"
1122 "<li><strong>About</strong> - this help page.</li>\n</ul>" "<hr/>\n" "Send questions or comments to\n"
1123 "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1124 "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1125 "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date,
1130 build_cfgfile_body(struct autobuf *abuf)
1133 "\n\n" "<strong>This is a automatically generated configuration\n"
1134 "file based on the current olsrd configuration of this node.<br/>\n" "<hr/>\n" "<pre>\n");
1137 /* Hack to make netdirect stuff work with
1142 size = olsrd_write_cnf_buf(olsr_cnf, tmpBuf, 10000);
1144 abuf_puts(abuf, "ERROR GENERATING CONFIGFILE!\n");
1147 abuf_puts(abuf, tmpBuf);
1151 abuf_puts(abuf, "</pre>\n<hr/>\n");
1154 printf("RETURNING %d\n", size);
1159 check_allowed_ip(const struct allowed_net *const allowed_nets, const union olsr_ip_addr *const addr)
1161 const struct allowed_net *alln;
1162 for (alln = allowed_nets; alln != NULL; alln = alln->next) {
1163 if ((addr->v4.s_addr & alln->mask.v4.s_addr) == (alln->net.v4.s_addr & alln->mask.v4.s_addr)) {
1173 * In a bigger mesh, there are probs with the fixed
1174 * bufsize. Because the Content-Length header is
1175 * optional, the sprintf() is changed to a more
1176 * scalable solution here.
1180 netsprintf(char *str, const char *format, ...)
1184 va_start(arg, format);
1185 rv = vsprintf(str, format, arg);
1187 if (0 != netsprintf_direct) {
1188 if (0 == netsprintf_error) {
1189 if (0 > send(client_sockets[curr_clients], str, rv, 0)) {
1190 olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
1191 netsprintf_error = 1;
1203 * indent-tabs-mode: nil