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"
64 #include "lq_plugin.h"
65 #include "common/autobuf.h"
67 #include "olsrd_httpinfo.h"
68 #include "admin_interface.h"
76 #define close(x) closesocket(x)
80 #define OS "GNU/Linux"
82 #if defined __FreeBSD__ || defined __FreeBSD_kernel__
87 #define OS "Undefined"
90 static char copyright_string[] __attribute__ ((unused)) =
91 "olsr.org HTTPINFO plugin Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
95 #define MAX_HTTPREQ_SIZE (1024 * 10)
97 #define DEFAULT_TCP_PORT 1978
99 #define HTML_BUFSIZE (1024 * 4000)
101 #define FRAMEWIDTH (resolve_ip_addresses ? 900 : 800)
103 #define FILENREQ_MATCH(req, filename) \
104 !strcmp(req, filename) || \
105 (strlen(req) && !strcmp(&req[1], filename))
107 static const char httpinfo_css[] =
108 "#A {text-decoration: none}\n" "TH{text-align: left}\n" "H1, H3, TD, TH {font-family: Helvetica; font-size: 80%}\n"
109 "h2\n {\nfont-family: Helvetica;\n font-size: 14px;text-align: center;\n"
110 "line-height: 16px;\ntext-decoration: none;\nborder: 1px solid #ccc;\n" "margin: 5px;\nbackground: #ececec;\n}\n"
111 "hr\n{\nborder: none;\npadding: 1px;\nbackground: url(grayline.gif) repeat-x bottom;\n}\n"
112 "#maintable\n{\nmargin: 0px;\npadding: 5px;\nborder-left: 1px solid #ccc;\n"
113 "border-right: 1px solid #ccc;\nborder-bottom: 1px solid #ccc;\n}\n"
114 "#footer\n{\nfont-size: 10px;\nline-height: 14px;\ntext-decoration: none;\ncolor: #666;\n}\n"
115 "#hdr\n{\nfont-size: 14px;\ntext-align: center;\nline-height: 16px;\n" "text-decoration: none;\nborder: 1px solid #ccc;\n"
116 "margin: 5px;\nbackground: #ececec;\n}\n"
117 "#container\n{\nwidth: 1000px;\npadding: 30px;\nborder: 1px solid #ccc;\nbackground: #fff;\n}\n"
118 "#tabnav\n{\nheight: 20px;\nmargin: 0;\npadding-left: 10px;\n" "background: url(grayline.gif) repeat-x bottom;\n}\n"
119 "#tabnav li\n{\nmargin: 0;\npadding: 0;\ndisplay: inline;\nlist-style-type: none;\n}\n"
120 "#tabnav a:link, #tabnav a:visited\n{\nfloat: left;\nbackground: #ececec;\n"
121 "font-size: 12px;\nline-height: 14px;\nfont-weight: bold;\npadding: 2px 10px 2px 10px;\n"
122 "margin-right: 4px;\nborder: 1px solid #ccc;\ntext-decoration: none;\ncolor: #777;\n}\n"
123 "#tabnav a:link.active, #tabnav a:visited.active\n{\nborder-bottom: 1px solid #fff;\n" "background: #ffffff;\ncolor: #000;\n}\n"
124 "#tabnav a:hover\n{\nbackground: #777777;\ncolor: #ffffff;\n}\n"
125 ".input_text\n{\nbackground: #E5E5E5;\nmargin-left: 5px; margin-top: 0px;\n"
126 "text-align: left;\n\nwidth: 100px;\npadding: 0px;\ncolor: #000000;\n"
127 "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #ccc;\n}\n"
128 ".input_button\n{\nbackground: #B5D1EE;\nmargin-left: 5px;\nmargin-top: 0px;\n"
129 "text-align: center;\nwidth: 120px;\npadding: 0px;\ncolor: #000000;\n"
130 "text-decoration: none;\nfont-family: verdana;\nfont-size: 12px;\n" "border: 1px solid #000;\n}\n";
132 typedef void (*build_body_callback) (struct autobuf *);
135 const char *tab_label;
136 const char *filename;
137 build_body_callback build_body_cb;
141 struct static_bin_file_entry {
142 const char *filename;
144 unsigned int data_size;
147 struct static_txt_file_entry {
148 const char *filename;
152 struct dynamic_file_entry {
153 const char *filename;
154 int (*process_data_cb) (char *, uint32_t, char *, uint32_t);
157 static int get_http_socket(int);
159 static void build_tabs(struct autobuf *, int);
161 static void parse_http_request(int fd, void *, unsigned int);
163 static int build_http_header(http_header_type, bool, uint32_t, char *, uint32_t);
165 static void build_frame(struct autobuf *, const char *, const char *, int, build_body_callback frame_body_cb);
167 static void build_routes_body(struct autobuf *);
169 static void build_config_body(struct autobuf *);
171 static void build_neigh_body(struct autobuf *);
173 static void build_topo_body(struct autobuf *);
175 static void build_mid_body(struct autobuf *);
177 static void build_nodes_body(struct autobuf *);
179 static void build_all_body(struct autobuf *);
181 static void build_about_body(struct autobuf *);
183 static void build_cfgfile_body(struct autobuf *);
185 static int check_allowed_ip(const struct allowed_net *const /*allowed_nets*/, const union olsr_ip_addr *const /*addr*/);
187 static void build_ip_txt(struct autobuf *, const bool want_link, const char *const ipaddrstr, const int prefix_len);
189 static void build_ipaddr_link(struct autobuf *, const bool want_link, const union olsr_ip_addr *const ipaddr,
190 const int prefix_len);
191 static void section_title(struct autobuf *, const char *title);
193 static void httpinfo_write_data(void *foo);
195 static struct timeval start_time;
196 static struct http_stats stats;
197 static int http_socket;
199 static char *outbuffer[MAX_CLIENTS];
200 static size_t outbuffer_size[MAX_CLIENTS];
201 static size_t outbuffer_written[MAX_CLIENTS];
202 static int outbuffer_socket[MAX_CLIENTS];
203 static int outbuffer_count;
205 static struct timer_entry *writetimer_entry;
208 int netsprintf(char *str, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
209 static int netsprintf_direct = 0;
210 static int netsprintf_error = 0;
211 #define sprintf netsprintf
215 static const struct tab_entry tab_entries[] = {
216 {"Configuration", "config", build_config_body, true},
217 {"Routes", "routes", build_routes_body, true},
218 {"Links/Topology", "nodes", build_nodes_body, true},
219 {"All", "all", build_all_body, true},
220 #ifdef ADMIN_INTERFACE
221 {"Admin", "admin", build_admin_body, true},
223 {"About", "about", build_about_body, true},
224 {"FOO", "cfgfile", build_cfgfile_body, false},
225 {NULL, NULL, NULL, false}
228 static const struct static_bin_file_entry static_bin_files[] = {
229 {"favicon.ico", favicon_ico, sizeof(favicon_ico)}
231 {"logo.gif", logo_gif, sizeof(logo_gif)}
233 {"grayline.gif", grayline_gif, sizeof(grayline_gif)}
238 static const struct static_txt_file_entry static_txt_files[] = {
239 {"httpinfo.css", httpinfo_css},
243 static const struct dynamic_file_entry dynamic_files[] = {
244 #ifdef ADMIN_INTERFACE
245 {"set_values", process_set_values},
251 get_http_socket(int port)
253 struct sockaddr_in sock_in;
256 /* Init ipc socket */
257 int s = socket(AF_INET, SOCK_STREAM, 0);
259 olsr_printf(1, "(HTTPINFO)socket %s\n", strerror(errno));
263 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
264 olsr_printf(1, "(HTTPINFO)SO_REUSEADDR failed %s\n", strerror(errno));
269 /* Bind the socket */
271 /* complete the socket structure */
272 memset(&sock_in, 0, sizeof(sock_in));
273 sock_in.sin_family = AF_INET;
274 sock_in.sin_addr.s_addr = httpinfo_listen_ip.v4.s_addr;
275 sock_in.sin_port = htons(port);
277 /* bind the socket to the port number */
278 if (bind(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) == -1) {
279 olsr_printf(1, "(HTTPINFO) bind failed %s\n", strerror(errno));
284 /* show that we are willing to listen */
285 if (listen(s, 1) == -1) {
286 olsr_printf(1, "(HTTPINFO) listen failed %s\n", strerror(errno));
295 *Do initialization here
297 *This function is called by the my_init
298 *function in uolsrd_plugin.c
301 olsrd_plugin_init(void)
304 gettimeofday(&start_time, NULL);
306 /* set up HTTP socket */
307 http_socket = get_http_socket(http_port != 0 ? http_port : DEFAULT_TCP_PORT);
309 if (http_socket < 0) {
310 fprintf(stderr, "(HTTPINFO) could not initialize HTTP socket\n");
314 /* Register socket */
315 add_olsr_socket(http_socket, &parse_http_request, NULL, NULL, SP_PR_READ);
320 /* Non reentrant - but we are not multithreaded anyway */
322 parse_http_request(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
324 struct sockaddr_in pin;
325 struct autobuf body_abuf = { 0, 0, NULL };
328 char header_buf[MAX_HTTPREQ_SIZE];
331 char http_version[11];
333 size_t header_length = 0;
337 struct timeval timeout = { 0, 200 };
340 if (outbuffer_count >= MAX_CLIENTS) {
341 olsr_printf(1, "(HTTPINFO) maximum number of connection reached\n");
345 addrlen = sizeof(struct sockaddr_in);
346 client_socket = accept(fd, (struct sockaddr *)&pin, &addrlen);
347 if (client_socket == -1) {
348 olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
349 goto close_connection;
353 if (setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
354 olsr_printf(1, "(HTTPINFO)SO_RCVTIMEO failed %s\n", strerror(errno));
355 goto close_connection;
358 if (setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
359 olsr_printf(1, "(HTTPINFO)SO_SNDTIMEO failed %s\n", strerror(errno));
360 goto close_connection;
363 if (!check_allowed_ip(allowed_nets, (union olsr_ip_addr *)&pin.sin_addr.s_addr)) {
364 struct ipaddr_str strbuf;
365 olsr_printf(0, "HTTP request from non-allowed host %s!\n",
366 olsr_ip_to_string(&strbuf, (union olsr_ip_addr *)&pin.sin_addr.s_addr));
367 goto close_connection;
370 addr = inet_ntoa(pin.sin_addr);
372 memset(header_buf, 0, sizeof(header_buf));
374 while ((r = recv(client_socket, &header_buf[c], 1, 0)) > 0 && (c < sizeof(header_buf) - 1)) {
377 if ((c > 3 && !strcmp(&header_buf[c - 4], "\r\n\r\n")) || (c > 1 && !strcmp(&header_buf[c - 2], "\n\n")))
382 olsr_printf(1, "(HTTPINFO) Failed to recieve data from client!\n");
384 goto close_connection;
387 /* Get the request */
388 if (sscanf(header_buf, "%10s %250s %10s\n", req_type, filename, http_version) != 3) {
389 /* Try without HTTP version */
390 if (sscanf(header_buf, "%10s %250s\n", req_type, filename) != 2) {
391 olsr_printf(1, "(HTTPINFO) Error parsing request %s!\n", header_buf);
393 goto close_connection;
397 olsr_printf(1, "Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
398 abuf_init(&body_abuf, 102400);
400 if (!strcmp(req_type, "POST")) {
401 #ifdef ADMIN_INTERFACE
403 while (dynamic_files[i].filename) {
404 printf("POST checking %s\n", dynamic_files[i].filename);
405 if (FILENREQ_MATCH(filename, dynamic_files[i].filename)) {
410 param_size = recv(client_sockets[curr_clients], header_buf, sizeof(header_buf) - 1, 0);
412 header_buf[param_size] = '\0';
413 printf("Dynamic read %d bytes\n", param_size);
415 //memcpy(body, dynamic_files[i].data, static_bin_files[i].data_size);
416 body_length += dynamic_files[i].process_data_cb(header_buf, param_size, &body_buf[body_length], sizeof(body_buf) - body_length);
417 header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
423 /* We only support GET */
424 abuf_puts(&body_abuf, HTTP_400_MSG);
426 header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
427 } else if (!strcmp(req_type, "GET")) {
430 for (i = 0; static_bin_files[i].filename; i++) {
431 if (FILENREQ_MATCH(filename, static_bin_files[i].filename)) {
436 if (static_bin_files[i].filename) {
438 abuf_memcpy(&body_abuf, static_bin_files[i].data, static_bin_files[i].data_size);
439 header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
444 while (static_txt_files[i].filename) {
445 if (FILENREQ_MATCH(filename, static_txt_files[i].filename)) {
451 if (static_txt_files[i].filename) {
453 abuf_puts(&body_abuf, static_txt_files[i].data);
454 header_length = build_http_header(HTTP_OK, false, body_abuf.len, header_buf, sizeof(header_buf));
459 if (strlen(filename) > 1) {
460 while (tab_entries[i].filename) {
461 if (FILENREQ_MATCH(filename, tab_entries[i].filename)) {
468 if (tab_entries[i].filename) {
470 header_length = build_http_header(HTTP_OK, true, body_length, header_buf, sizeof(header_buf));
471 r = send(client_sockets[curr_clients], header_buf, header_length, 0);
473 olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
474 goto close_connection;
476 netsprintf_error = 0;
477 netsprintf_direct = 1;
479 abuf_appendf(&body_abuf,
480 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n" "<head>\n"
481 "<meta http-equiv=\"Content-type\" content=\"text/html; charset=ISO-8859-1\">\n"
482 "<title>olsr.org httpinfo plugin</title>\n" "<link rel=\"icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
483 "<link rel=\"shortcut icon\" href=\"favicon.ico\" type=\"image/x-icon\">\n"
484 "<link rel=\"stylesheet\" type=\"text/css\" href=\"httpinfo.css\">\n" "</head>\n"
485 "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
486 "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"%d\">\n"
487 "<tbody><tr bgcolor=\"#ffffff\">\n" "<td align=\"left\" height=\"69\" valign=\"middle\" width=\"80%%\">\n"
488 "<font color=\"black\" face=\"timesroman\" size=\"6\"> <a href=\"http://www.olsr.org/\">olsr.org OLSR daemon</a></font></td>\n"
489 "<td height=\"69\" valign=\"middle\" width=\"20%%\">\n"
490 "<a href=\"http://www.olsr.org/\"><img border=\"0\" src=\"/logo.gif\" alt=\"olsrd logo\"></a></td>\n" "</tr>\n"
491 "</tbody>\n" "</table>\n", FRAMEWIDTH);
493 build_tabs(&body_abuf, i);
494 build_frame(&body_abuf, "Current Routes", "routes", FRAMEWIDTH, tab_entries[i].build_body_cb);
498 abuf_appendf(&body_abuf,
499 "</table>\n" "<div id=\"footer\">\n" "<center>\n" "(C)2005 Andreas Tønnesen<br/>\n"
500 "<a href=\"http://www.olsr.org/\">http://www.olsr.org</a>\n" "</center>\n" "</div>\n" "</body>\n" "</html>\n");
503 netsprintf_direct = 1;
504 goto close_connection;
506 header_length = build_http_header(HTTP_OK, true, body_abuf.len, header_buf, sizeof(header_buf));
512 abuf_puts(&body_abuf, HTTP_404_MSG);
513 header_length = build_http_header(HTTP_BAD_FILE, true, body_abuf.len, header_buf, sizeof(header_buf));
515 /* We only support GET */
516 abuf_puts(&body_abuf, HTTP_404_MSG);
518 header_length = build_http_header(HTTP_BAD_REQ, true, body_abuf.len, header_buf, sizeof(header_buf));
522 if (header_length + body_abuf.len > 0) {
523 outbuffer[outbuffer_count] = olsr_malloc(header_length + body_abuf.len, "http output buffer");
524 outbuffer_size[outbuffer_count] = header_length + body_abuf.len;
525 outbuffer_written[outbuffer_count] = 0;
526 outbuffer_socket[outbuffer_count] = client_socket;
528 memcpy(outbuffer[outbuffer_count], header_buf, header_length);
529 if (body_abuf.len > 0) {
530 memcpy((outbuffer[outbuffer_count]) + header_length, body_abuf.buf, body_abuf.len);
534 if (outbuffer_count == 1) {
535 writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &httpinfo_write_data, NULL, 0);
538 abuf_free(&body_abuf);
542 abuf_free(&body_abuf);
543 close(client_socket);
547 httpinfo_write_data(void *foo __attribute__ ((unused))) {
549 int result, i, j, max;
554 for (i=0; i<outbuffer_count; i++) {
555 /* prevent warning in win32 */
556 FD_SET((unsigned int)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 struct allowed_net *a, *next;
677 if (http_socket >= 0) {
681 for (a = allowed_nets; a != NULL; a = next) {
689 section_title(struct autobuf *abuf, const char *title)
692 "<h2>%s</h2>\n" "<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" align=\"center\">\n",
697 build_frame(struct autobuf *abuf, const char *title __attribute__ ((unused)), const char *the_link
698 __attribute__ ((unused)), int width __attribute__ ((unused)), build_body_callback frame_body_cb)
700 abuf_puts(abuf, "<div id=\"maintable\">\n");
702 abuf_puts(abuf, "</div>\n");
706 fmt_href(struct autobuf *abuf, const char *const ipaddr)
708 abuf_appendf(abuf, "<a href=\"http://%s:%d/all\">", ipaddr, http_port);
712 build_ip_txt(struct autobuf *abuf, const bool print_link, const char *const ipaddrstr, const int prefix_len)
715 fmt_href(abuf, ipaddrstr);
718 abuf_puts(abuf, ipaddrstr);
719 /* print ip address or ip prefix ? */
720 if (prefix_len != -1 && prefix_len != olsr_cnf->maxplen) {
721 abuf_appendf(abuf, "/%d", prefix_len);
724 if (print_link) { /* Print the link only if there is no prefix_len */
725 abuf_puts(abuf, "</a>");
730 build_ipaddr_link(struct autobuf *abuf, const bool want_link, const union olsr_ip_addr *const ipaddr,
731 const int prefix_len)
733 struct ipaddr_str ipaddrstr;
734 const struct hostent *const hp =
736 resolve_ip_addresses ? gethostbyaddr(ipaddr, olsr_cnf->ipsize,
737 olsr_cnf->ip_version) :
740 /* Print the link only if there is no prefix_len and ip_version is AF_INET */
741 const int print_link = want_link && (prefix_len == -1 || prefix_len == olsr_cnf->maxplen) && (olsr_cnf->ip_version == AF_INET);
742 olsr_ip_to_string(&ipaddrstr, ipaddr);
744 abuf_puts(abuf, "<td>");
745 build_ip_txt(abuf, print_link, ipaddrstr.buf, prefix_len);
746 abuf_puts(abuf, "</td>");
748 if (resolve_ip_addresses) {
750 abuf_puts(abuf, "<td>(");
752 fmt_href(abuf, ipaddrstr.buf);
754 abuf_puts(abuf, hp->h_name);
756 abuf_puts(abuf, "</a>");
758 abuf_puts(abuf, ")</td>");
760 abuf_puts(abuf, "<td/>");
765 #define build_ipaddr_with_link(buf, ipaddr, plen) \
766 build_ipaddr_link((buf), true, (ipaddr), (plen))
767 #define build_ipaddr_no_link(buf, ipaddr, plen) \
768 build_ipaddr_link((buf), false, (ipaddr), (plen))
771 build_route(struct autobuf *abuf, const struct rt_entry *rt)
773 struct lqtextbuffer lqbuffer;
775 abuf_puts(abuf, "<tr>");
776 build_ipaddr_with_link(abuf, &rt->rt_dst.prefix, rt->rt_dst.prefix_len);
777 build_ipaddr_with_link(abuf, &rt->rt_best->rtp_nexthop.gateway, -1);
779 abuf_appendf(abuf, "<td>%d</td>", rt->rt_best->rtp_metric.hops);
780 abuf_appendf(abuf, "<td>%s</td>",
781 get_linkcost_text(rt->rt_best->rtp_metric.cost, true, &lqbuffer));
782 abuf_appendf(abuf, "<td>%s</td></tr>\n",
783 if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
787 build_routes_body(struct autobuf *abuf)
790 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
791 section_title(abuf, "OLSR Routes in Kernel");
793 "<tr><th%s>Destination</th><th%s>Gateway</th><th>Metric</th><th>ETX</th><th>Interface</th></tr>\n",
796 /* Walk the route table */
797 OLSR_FOR_ALL_RT_ENTRIES(rt) {
798 build_route(abuf, rt);
799 } OLSR_FOR_ALL_RT_ENTRIES_END(rt);
801 abuf_puts(abuf, "</table>\n");
805 build_config_body(struct autobuf *abuf)
807 const struct olsr_if *ifs;
808 const struct plugin_entry *pentry;
809 const struct plugin_param *pparam;
810 struct ipaddr_str mainaddrbuf;
812 abuf_appendf(abuf, "Version: %s (built on %s on %s)\n<br>", olsrd_version, build_date, build_host);
813 abuf_appendf(abuf, "OS: %s\n<br>", OS);
816 const time_t currtime = time(NULL);
818 abuf_strftime(abuf, "System time: <em>%a, %d %b %Y %H:%M:%S</em><br>",
819 localtime(&currtime));
823 struct timeval now, uptime;
824 int hours, mins, days;
825 gettimeofday(&now, NULL);
826 timersub(&now, &start_time, &uptime);
828 days = uptime.tv_sec / 86400;
829 uptime.tv_sec %= 86400;
830 hours = uptime.tv_sec / 3600;
831 uptime.tv_sec %= 3600;
832 mins = uptime.tv_sec / 60;
835 abuf_puts(abuf, "Olsrd uptime: <em>");
837 abuf_appendf(abuf, "%d day(s) ", days);
839 abuf_appendf(abuf, "%02d hours %02d minutes %02d seconds</em><br/>\n", hours, mins, (int)uptime.tv_sec);
842 abuf_appendf(abuf, "HTTP stats(ok/dyn/error/illegal): <em>%d/%d/%d/%d</em><br>\n", stats.ok_hits,
843 stats.dyn_hits, stats.err_hits, stats.ill_hits);
846 "Click <a href=\"/cfgfile\">here</a> to <em>generate a configuration file for this node</em>.\n");
848 abuf_puts(abuf, "<h2>Variables</h2>\n");
850 abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n<tr>");
852 abuf_appendf(abuf, "<td>Main address: <strong>%s</strong></td>\n",
853 olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
854 abuf_appendf(abuf, "<td>IP version: %d</td>\n", olsr_cnf->ip_version == AF_INET ? 4 : 6);
855 abuf_appendf(abuf, "<td>Debug level: %d</td>\n", olsr_cnf->debug_level);
856 abuf_appendf(abuf, "<td>FIB Metrics: %s</td>\n", FIB_METRIC_TXT[olsr_cnf->fib_metric]);
858 abuf_puts(abuf, "</tr>\n<tr>\n");
860 abuf_appendf(abuf, "<td>Pollrate: %0.2f</td>\n", olsr_cnf->pollrate);
861 abuf_appendf(abuf, "<td>TC redundancy: %d</td>\n", olsr_cnf->tc_redundancy);
862 abuf_appendf(abuf, "<td>MPR coverage: %d</td>\n", olsr_cnf->mpr_coverage);
863 abuf_appendf(abuf, "<td>NAT threshold: %f</td>\n", olsr_cnf->lq_nat_thresh);
865 abuf_puts(abuf, "</tr>\n<tr>\n");
867 abuf_appendf(abuf, "<td>Fisheye: %s</td>\n", olsr_cnf->lq_fish ? "Enabled" : "Disabled");
868 abuf_appendf(abuf, "<td>TOS: 0x%04x</td>\n", olsr_cnf->tos);
869 abuf_appendf(abuf, "<td>RtTable: 0x%04x/%d</td>\n", olsr_cnf->rt_table, olsr_cnf->rt_table);
870 abuf_appendf(abuf, "<td>RtTableDefault: 0x%04x/%d</td>\n", olsr_cnf->rt_table_default,
871 olsr_cnf->rt_table_default);
872 abuf_appendf(abuf, "<td>RtTableTunnel: 0x%04x/%d</td>\n", olsr_cnf->rt_table_tunnel,
873 olsr_cnf->rt_table_tunnel);
874 abuf_appendf(abuf, "<td>Willingness: %d %s</td>\n", olsr_cnf->willingness,
875 olsr_cnf->willingness_auto ? "(auto)" : "");
877 if (olsr_cnf->lq_level == 0) {
878 abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>Hysteresis: %s</td>\n",
879 olsr_cnf->use_hysteresis ? "Enabled" : "Disabled");
880 if (olsr_cnf->use_hysteresis) {
881 abuf_appendf(abuf, "<td>Hyst scaling: %0.2f</td>\n", olsr_cnf->hysteresis_param.scaling);
882 abuf_appendf(abuf, "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", olsr_cnf->hysteresis_param.thr_low,
883 olsr_cnf->hysteresis_param.thr_high);
887 abuf_appendf(abuf, "</tr>\n<tr>\n" "<td>LQ extension: %s</td>\n",
888 olsr_cnf->lq_level ? "Enabled" : "Disabled");
889 if (olsr_cnf->lq_level) {
890 abuf_appendf(abuf, "<td>LQ level: %d</td>\n" "<td>LQ aging: %f</td>\n", olsr_cnf->lq_level,
893 abuf_puts(abuf, "</tr></table>\n");
895 abuf_puts(abuf, "<h2>Interfaces</h2>\n");
896 abuf_puts(abuf, "<table width=\"100%%\" border=\"0\">\n");
897 for (ifs = olsr_cnf->interfaces; ifs != NULL; ifs = ifs->next) {
898 const struct interface *const rifs = ifs->interf;
899 abuf_appendf(abuf, "<tr><th colspan=\"3\">%s</th>\n", ifs->name);
901 abuf_puts(abuf, "<tr><td colspan=\"3\">Status: DOWN</td></tr>\n");
905 if (olsr_cnf->ip_version == AF_INET) {
906 struct ipaddr_str addrbuf, maskbuf, bcastbuf;
907 abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MASK: %s</td>\n" "<td>BCAST: %s</td>\n" "</tr>\n",
908 ip4_to_string(&addrbuf, rifs->int_addr.sin_addr), ip4_to_string(&maskbuf, rifs->int_netmask.sin_addr),
909 ip4_to_string(&bcastbuf, rifs->int_broadaddr.sin_addr));
911 struct ipaddr_str addrbuf, maskbuf;
912 abuf_appendf(abuf, "<tr>\n" "<td>IP: %s</td>\n" "<td>MCAST: %s</td>\n" "<td></td>\n" "</tr>\n",
913 ip6_to_string(&addrbuf, &rifs->int6_addr.sin6_addr), ip6_to_string(&maskbuf, &rifs->int6_multaddr.sin6_addr));
915 abuf_appendf(abuf, "<tr>\n" "<td>MTU: %d</td>\n" "<td>WLAN: %s</td>\n" "<td>STATUS: UP</td>\n" "</tr>\n",
916 rifs->int_mtu, rifs->is_wireless ? "Yes" : "No");
918 abuf_puts(abuf, "</table>\n");
920 abuf_appendf(abuf, "<em>Olsrd is configured to %s if no interfaces are available</em><br>\n",
921 olsr_cnf->allow_no_interfaces ? "run even" : "halt");
923 abuf_puts(abuf, "<h2>Plugins</h2>\n");
924 abuf_puts(abuf, "<table width=\"100%%\" border=\"0\"><tr><th>Name</th><th>Parameters</th></tr>\n");
925 for (pentry = olsr_cnf->plugins; pentry; pentry = pentry->next) {
926 abuf_appendf(abuf, "<tr><td>%s</td>\n" "<td><select>\n" "<option>KEY, VALUE</option>\n", pentry->name);
928 for (pparam = pentry->params; pparam; pparam = pparam->next) {
929 abuf_appendf(abuf, "<option>\"%s\", \"%s\"</option>\n", pparam->key, pparam->value);
931 abuf_puts(abuf, "</select></td></tr>\n");
934 abuf_puts(abuf, "</table>\n");
936 section_title(abuf, "Announced HNA entries");
937 if (olsr_cnf->hna_entries) {
938 struct ip_prefix_list *hna;
939 abuf_puts(abuf, "<tr><th>Network</th></tr>\n");
940 for (hna = olsr_cnf->hna_entries; hna; hna = hna->next) {
941 struct ipaddr_str netbuf;
942 abuf_appendf(abuf, "<tr><td>%s/%d</td></tr>\n", olsr_ip_to_string(&netbuf, &hna->net.prefix),
943 hna->net.prefix_len);
946 abuf_puts(abuf, "<tr><td></td></tr>\n");
948 abuf_puts(abuf, "</table>\n");
952 build_neigh_body(struct autobuf *abuf)
954 struct neighbor_entry *neigh;
955 struct link_entry *the_link = NULL;
956 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
958 section_title(abuf, "Links");
961 "<tr><th%s>Local IP</th><th%s>Remote IP</th><th>Hysteresis</th>",
963 if (olsr_cnf->lq_level > 0) {
964 abuf_puts(abuf, "<th>LinkCost</th>");
966 abuf_puts(abuf, "</tr>\n");
969 OLSR_FOR_ALL_LINK_ENTRIES(the_link) {
970 abuf_puts(abuf, "<tr>");
971 build_ipaddr_with_link(abuf, &the_link->local_iface_addr, -1);
972 build_ipaddr_with_link(abuf, &the_link->neighbor_iface_addr, -1);
973 abuf_appendf(abuf, "<td>%0.2f</td>", the_link->L_link_quality);
974 if (olsr_cnf->lq_level > 0) {
975 struct lqtextbuffer lqbuffer1, lqbuffer2;
976 abuf_appendf(abuf, "<td>(%s) %s</td>", get_link_entry_text(the_link, '/', &lqbuffer1),
977 get_linkcost_text(the_link->linkcost, false, &lqbuffer2));
979 abuf_puts(abuf, "</tr>\n");
980 } OLSR_FOR_ALL_LINK_ENTRIES_END(the_link);
982 abuf_puts(abuf, "</table>\n");
984 section_title(abuf, "Neighbors");
986 "<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",
989 OLSR_FOR_ALL_NBR_ENTRIES(neigh) {
991 struct neighbor_2_list_entry *list_2;
993 abuf_puts(abuf, "<tr>");
994 build_ipaddr_with_link(abuf, &neigh->neighbor_main_addr, -1);
996 "<td>%s</td>" "<td>%s</td>" "<td>%s</td>"
997 "<td>%d</td>", (neigh->status == SYM) ? "YES" : "NO", neigh->is_mpr ? "YES" : "NO",
998 olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO", neigh->willingness);
1000 abuf_puts(abuf, "<td><select>\n" "<option>IP ADDRESS</option>\n");
1002 for (list_2 = neigh->neighbor_2_list.next, thop_cnt = 0; list_2 != &neigh->neighbor_2_list; list_2 = list_2->next, thop_cnt++) {
1003 struct ipaddr_str strbuf;
1004 abuf_appendf(abuf, "<option>%s</option>\n",
1005 olsr_ip_to_string(&strbuf, &list_2->neighbor_2->neighbor_2_addr));
1007 abuf_appendf(abuf, "</select> (%d)</td></tr>\n", thop_cnt);
1008 } OLSR_FOR_ALL_NBR_ENTRIES_END(neigh);
1010 abuf_puts(abuf, "</table>\n");
1014 build_topo_body(struct autobuf *abuf)
1016 struct tc_entry *tc;
1017 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1019 section_title(abuf, "Topology Entries");
1020 abuf_appendf(abuf, "<tr><th%s>Destination IP</th><th%s>Last Hop IP</th>",
1022 if (olsr_cnf->lq_level > 0) {
1023 abuf_puts(abuf, "<th>Linkcost</th>");
1025 abuf_puts(abuf, "</tr>\n");
1027 OLSR_FOR_ALL_TC_ENTRIES(tc) {
1028 struct tc_edge_entry *tc_edge;
1029 OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
1030 if (tc_edge->edge_inv) {
1031 abuf_puts(abuf, "<tr>");
1032 build_ipaddr_with_link(abuf, &tc_edge->T_dest_addr, -1);
1033 build_ipaddr_with_link(abuf, &tc->addr, -1);
1034 if (olsr_cnf->lq_level > 0) {
1035 struct lqtextbuffer lqbuffer1, lqbuffer2;
1036 abuf_appendf(abuf, "<td>(%s) %s</td>\n",
1037 get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1), get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
1039 abuf_puts(abuf, "</tr>\n");
1041 } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
1042 } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
1044 abuf_puts(abuf, "</table>\n");
1048 build_mid_body(struct autobuf *abuf)
1051 const char *colspan = resolve_ip_addresses ? " colspan=\"2\"" : "";
1053 section_title(abuf, "MID Entries");
1054 abuf_appendf(abuf, "<tr><th%s>Main Address</th><th>Aliases</th></tr>\n", colspan);
1057 for (idx = 0; idx < HASHSIZE; idx++) {
1058 struct mid_entry *entry;
1059 for (entry = mid_set[idx].next; entry != &mid_set[idx]; entry = entry->next) {
1061 struct mid_address *alias;
1062 abuf_puts(abuf, "<tr>");
1063 build_ipaddr_with_link(abuf, &entry->main_addr, -1);
1064 abuf_puts(abuf, "<td><select>\n<option>IP ADDRESS</option>\n");
1066 for (mid_cnt = 0, alias = entry->aliases; alias != NULL; alias = alias->next_alias, mid_cnt++) {
1067 struct ipaddr_str strbuf;
1068 abuf_appendf(abuf, "<option>%s</option>\n", olsr_ip_to_string(&strbuf, &alias->alias));
1070 abuf_appendf(abuf, "</select> (%d)</td></tr>\n", mid_cnt);
1074 abuf_puts(abuf, "</table>\n");
1078 build_nodes_body(struct autobuf *abuf)
1080 build_neigh_body(abuf);
1081 build_topo_body(abuf);
1082 build_mid_body(abuf);
1086 build_all_body(struct autobuf *abuf)
1088 build_config_body(abuf);
1089 build_routes_body(abuf);
1090 build_neigh_body(abuf);
1091 build_topo_body(abuf);
1092 build_mid_body(abuf);
1096 build_about_body(struct autobuf *abuf)
1099 "<strong>" PLUGIN_NAME " version " PLUGIN_VERSION "</strong><br/>\n" "by Andreas Tønnesen (C)2005.<br/>\n"
1101 #ifdef ADMIN_INTERFACE
1102 "<em>with experimental admin interface</em> "
1104 "%s at %s<hr/>\n" "This plugin implements a HTTP server that supplies\n"
1105 "the client with various dynamic web pages representing\n"
1106 "the current olsrd status.<br/>The different pages include:\n"
1107 "<ul>\n<li><strong>Configuration</strong> - This page displays information\n"
1108 "about the current olsrd configuration. This includes various\n"
1109 "olsr settings such as IP version, MID/TC redundancy, hysteresis\n"
1110 "etc. Information about the current status of the interfaces on\n"
1111 "which olsrd is configured to run is also displayed. Loaded olsrd\n"
1112 "plugins are shown with their plugin parameters. Finally all local\n"
1113 "HNA entries are shown. These are the networks that the local host\n"
1114 "will anounce itself as a gateway to.</li>\n"
1115 "<li><strong>Routes</strong> - This page displays all routes currently set in\n"
1116 "the kernel <em>by olsrd</em>. The type of route is also displayed(host\n" "or HNA).</li>\n"
1117 "<li><strong>Links/Topology</strong> - This page displays all information about\n"
1118 "links, neighbors, topology, MID and HNA entries.</li>\n"
1119 "<li><strong>All</strong> - Here all the previous pages are displayed as one.\n"
1120 "This is to make all information available as easy as possible(for example\n"
1121 "for a script) and using as few resources as possible.</li>\n"
1122 #ifdef ADMIN_INTERFACE
1123 "<li><strong>Admin</strong> - This page is highly experimental(and unsecure)!\n"
1124 "As of now it is not working at all but it provides a impression of\n"
1125 "the future possibilities of httpinfo. This is to be a interface to\n"
1126 "changing olsrd settings in realtime. These settings include various\n"
1127 "\"basic\" settings and local HNA settings.</li>\n"
1129 "<li><strong>About</strong> - this help page.</li>\n</ul>" "<hr/>\n" "Send questions or comments to\n"
1130 "<a href=\"mailto:olsr-users@olsr.org\">olsr-users@olsr.org</a> or\n"
1131 "<a href=\"mailto:andreto-at-olsr.org\">andreto-at-olsr.org</a><br/>\n"
1132 "Official olsrd homepage: <a href=\"http://www.olsr.org/\">http://www.olsr.org</a><br/>\n", build_date,
1137 build_cfgfile_body(struct autobuf *abuf)
1140 "\n\n" "<strong>This is a automatically generated configuration\n"
1141 "file based on the current olsrd configuration of this node.<br/>\n" "<hr/>\n" "<pre>\n");
1142 olsrd_write_cnf_autobuf(abuf, olsr_cnf);
1144 abuf_puts(abuf, "</pre>\n<hr/>\n");
1147 printf("RETURNING %d\n", size);
1152 check_allowed_ip(const struct allowed_net *const my_allowed_nets, const union olsr_ip_addr *const addr)
1154 const struct allowed_net *alln;
1155 for (alln = my_allowed_nets; alln != NULL; alln = alln->next) {
1156 if (ip_in_net(addr, &alln->prefix)) {
1166 * In a bigger mesh, there are probs with the fixed
1167 * bufsize. Because the Content-Length header is
1168 * optional, the sprintf() is changed to a more
1169 * scalable solution here.
1173 netsprintf(char *str, const char *format, ...)
1177 va_start(arg, format);
1178 rv = vsprintf(str, format, arg);
1180 if (0 != netsprintf_direct) {
1181 if (0 == netsprintf_error) {
1182 if (0 > send(client_sockets[curr_clients], str, rv, 0)) {
1183 olsr_printf(1, "(HTTPINFO) Failed sending data to client!\n");
1184 netsprintf_error = 1;
1196 * indent-tabs-mode: nil