Patch ALIGN_NOWARN_ARM macro for better priority handling.
[olsrd.git] / lib / nameservice / src / nameservice.c
1
2 /*
3  * Copyright (c) 2006, Jens Nachtigall <nachtigall@web.de>
4  * Copyright (c) 2005, Bruno Randolf <bruno.randolf@4g-systems.biz>
5  * Copyright (c) 2004, Andreas Tonnesen(andreto-at-olsr.org)
6  * Copyright (c) 2007, Sven-Ola <sven-ola@gmx.de>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  * * Neither the name of the UniK olsr daemon nor the names of its contributors
19  *   may be used to endorse or promote products derived from this software
20  *   without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34
35 /*
36  * Dynamic linked library for UniK OLSRd
37  */
38
39 #define _GNU_SOURCE 1
40
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <ctype.h>
46 #include <sys/types.h>
47 #include <regex.h>
48 #include <sys/stat.h>
49 #include <signal.h>
50 #include <fcntl.h>
51
52 #include "olsr.h"
53 #include "ipcalc.h"
54 #include "net_olsr.h"
55 #include "routing_table.h"
56 #include "mantissa.h"
57 #include "scheduler.h"
58 #include "parser.h"
59 #include "duplicate_set.h"
60 #include "tc_set.h"
61 #include "hna_set.h"
62 #include "mid_set.h"
63 #include "link_set.h"
64
65 #include "plugin_util.h"
66 #include "nameservice.h"
67 #include "mapwrite.h"
68 #include "compat.h"
69
70 /* config parameters */
71 static char my_hosts_file[MAX_FILE + 1];
72 static char my_sighup_pid_file[MAX_FILE + 1];
73
74 static char my_add_hosts[MAX_FILE + 1];
75 static char my_suffix[MAX_SUFFIX];
76 static int my_interval = EMISSION_INTERVAL;
77 static double my_timeout = NAME_VALID_TIME;
78 static char my_resolv_file[MAX_FILE + 1];
79 static char my_services_file[MAX_FILE + 1];
80 static char my_macs_file[MAX_FILE + 1];
81 static char my_name_change_script[MAX_FILE + 1];
82 static char my_services_change_script[MAX_FILE + 1];
83 static char my_macs_change_script[MAX_FILE + 1];
84 static char latlon_in_file[MAX_FILE + 1];
85 static char my_latlon_file[MAX_FILE + 1];
86 float my_lat = 0.0, my_lon = 0.0;
87
88 /* the databases (using hashing)
89  * for hostnames, service_lines and dns-servers
90  *
91  * my own hostnames, service_lines and dns-servers
92  * are store in a linked list (without hashing)
93  * */
94 static struct list_node name_list[HASHSIZE];
95 struct name_entry *my_names = NULL;
96 struct timer_entry *name_table_write = NULL;
97 static bool name_table_changed = true;
98
99 static struct list_node service_list[HASHSIZE];
100 static struct name_entry *my_services = NULL;
101 static bool service_table_changed = true;
102
103 static struct list_node mac_list[HASHSIZE];
104 static struct name_entry *my_macs = NULL;
105 static bool mac_table_changed = true;
106
107 static struct list_node forwarder_list[HASHSIZE];
108 static struct name_entry *my_forwarders = NULL;
109 static bool forwarder_table_changed = true;
110
111 struct list_node latlon_list[HASHSIZE];
112 static bool latlon_table_changed = true;
113
114 /* backoff timer for writing changes into a file */
115 struct timer_entry *write_file_timer = NULL;
116
117 /* periodic message generation */
118 struct timer_entry *msg_gen_timer = NULL;
119
120 /* regular expression to be matched by valid hostnames, compiled in name_init() */
121 static regex_t regex_t_name;
122 static regmatch_t regmatch_t_name;
123
124 /* regular expression to be matched by valid service_lines, compiled in name_init() */
125 static regex_t regex_t_service;
126 static int pmatch_service = 10;
127 static regmatch_t regmatch_t_service[10];
128
129 /**
130  * do initialization
131  */
132 void
133 name_constructor(void)
134 {
135   int i;
136
137 #ifdef WIN32
138   int len;
139
140   GetWindowsDirectory(my_hosts_file, MAX_FILE - 12);
141   GetWindowsDirectory(my_services_file, MAX_FILE - 12);
142   GetWindowsDirectory(my_macs_file, MAX_FILE - 12);
143   GetWindowsDirectory(my_resolv_file, MAX_FILE - 12);
144
145   len = strlen(my_hosts_file);
146   if (my_hosts_file[len - 1] != '\\')
147     strscat(my_hosts_file, "\\", sizeof(my_host_file));
148   strscat(my_hosts_file, "hosts_olsr", sizeof(my_host_file));
149
150   len = strlen(my_services_file);
151   if (my_services_file[len - 1] != '\\')
152     strscat(my_services_file, "\\", sizeof(my_services_file));
153   strscat(my_services_file, "services_olsr", sizeof(my_services_file));
154
155   len = strlen(my_macs_file);
156   if (my_macs_file[len - 1] != '\\')
157     strscat(my_macs_file, "\\", sizeof(my_macs_file));
158   strscat(my_macs_file, "macs_olsr", sizeof(my_macs_file));
159
160   len = strlen(my_resolv_file);
161   if (my_resolv_file[len - 1] != '\\')
162     strscat(my_resolv_file, "\\", sizeof(my_resolv_file));
163   strscat(my_resolv_file, "resolvconf_olsr", sizeof(my_resolv_file));
164 #else
165   strscpy(my_hosts_file, "/var/run/hosts_olsr", sizeof(my_hosts_file));
166   strscpy(my_services_file, "/var/run/services_olsr", sizeof(my_services_file));
167   strscpy(my_macs_file, "/var/run/macs_olsr", sizeof(my_macs_file));
168   strscpy(my_resolv_file, "/var/run/resolvconf_olsr", sizeof(my_resolv_file));
169   *my_sighup_pid_file = 0;
170 #endif
171
172   my_suffix[0] = '\0';
173   my_add_hosts[0] = '\0';
174   my_latlon_file[0] = '\0';
175   latlon_in_file[0] = '\0';
176   my_name_change_script[0] = '\0';
177   my_services_change_script[0] = '\0';
178   my_macs_change_script[0] = '\0';
179
180   /* init the lists heads */
181   for (i = 0; i < HASHSIZE; i++) {
182     list_head_init(&name_list[i]);
183     list_head_init(&forwarder_list[i]);
184     list_head_init(&service_list[i]);
185     list_head_init(&mac_list[i]);
186     list_head_init(&latlon_list[i]);
187   }
188
189 }
190
191 static int
192 set_nameservice_server(const char *value, void *data, set_plugin_parameter_addon addon)
193 {
194   union olsr_ip_addr ip;
195   struct name_entry **v = data;
196   if (0 == strlen(value)) {
197     *v = add_name_to_list(*v, "", addon.ui, NULL);
198     OLSR_PRINTF(1, "%s got %s (main address)\n", "Got", value);
199     return 0;
200   } else if (0 < inet_pton(olsr_cnf->ip_version, value, &ip)) {
201     *v = add_name_to_list(*v, "", addon.ui, &ip);
202     OLSR_PRINTF(1, "%s got %s\n", "Got", value);
203     return 0;
204   } else {
205     OLSR_PRINTF(0, "Illegal IP address \"%s\"", value);
206   }
207   return 1;
208 }
209
210 static int
211 set_nameservice_name(const char *value, void *data, set_plugin_parameter_addon addon)
212 {
213   struct name_entry **v = data;
214   if (0 < strlen(value)) {
215     *v = add_name_to_list(*v, value, addon.ui, NULL);
216     OLSR_PRINTF(1, "%s got %s (main address)\n", "Got", value);
217     return 0;
218   } else {
219     OLSR_PRINTF(0, "Illegal name \"%s\"", value);
220   }
221   return 1;
222 }
223
224 static int
225 set_nameservice_host(const char *value, void *data, set_plugin_parameter_addon addon)
226 {
227   union olsr_ip_addr ip;
228   struct name_entry **v = data;
229   if (0 < inet_pton(olsr_cnf->ip_version, addon.pc, &ip)) {
230     // the IP is validated later
231     *v = add_name_to_list(*v, value, NAME_HOST, &ip);
232     OLSR_PRINTF(1, "%s: %s got %s\n", "Got", addon.pc, value);
233     return 0;
234   } else {
235     OLSR_PRINTF(0, "%s: Illegal IP address \"%s\"", addon.pc, value);
236   }
237   return 1;
238 }
239
240 static int
241 set_nameservice_float(const char *value, void *data, set_plugin_parameter_addon addon __attribute__ ((unused)))
242 {
243   if (data != NULL) {
244     sscanf(value, "%f", (float *)data);
245     OLSR_PRINTF(1, "%s float %f\n", "Got", *(float *)data);
246   } else {
247     OLSR_PRINTF(0, "%s float %s\n", "Ignored", value);
248   }
249   return 0;
250 }
251
252 /* *INDENT-OFF* */
253 static const struct olsrd_plugin_parameters plugin_parameters[] = {
254   { .name = "interval",               .set_plugin_parameter = &set_plugin_int,         .data = &my_interval },
255   { .name = "timeout",                .set_plugin_parameter = &set_nameservice_float,  .data = &my_timeout },
256   { .name = "sighup-pid-file",        .set_plugin_parameter = &set_plugin_string,      .data = &my_sighup_pid_file,        .addon = {sizeof(my_sighup_pid_file)} },
257   { .name = "hosts-file",             .set_plugin_parameter = &set_plugin_string,      .data = &my_hosts_file,             .addon = {sizeof(my_hosts_file)} },
258   { .name = "name-change-script",     .set_plugin_parameter = &set_plugin_string,      .data = &my_name_change_script,     .addon = {sizeof(my_name_change_script)} },
259   { .name = "services-change-script", .set_plugin_parameter = &set_plugin_string,      .data = &my_services_change_script, .addon = {sizeof(my_services_change_script)} },
260   { .name = "macs-change-script",     .set_plugin_parameter = &set_plugin_string,      .data = &my_macs_change_script,     .addon = {sizeof(my_macs_change_script)} },
261   { .name = "resolv-file",            .set_plugin_parameter = &set_plugin_string,      .data = &my_resolv_file,            .addon = {sizeof(my_resolv_file)} },
262   { .name = "suffix",                 .set_plugin_parameter = &set_plugin_string,      .data = &my_suffix,                 .addon = {sizeof(my_suffix)} },
263   { .name = "add-hosts",              .set_plugin_parameter = &set_plugin_string,      .data = &my_add_hosts,              .addon = {sizeof(my_add_hosts)} },
264   { .name = "services-file",          .set_plugin_parameter = &set_plugin_string,      .data = &my_services_file,          .addon = {sizeof(my_services_file)} },
265   { .name = "macs-file",              .set_plugin_parameter = &set_plugin_string,      .data = &my_macs_file,              .addon = {sizeof(my_macs_file)} },
266   { .name = "lat",                    .set_plugin_parameter = &set_nameservice_float,  .data = &my_lat },
267   { .name = "lon",                    .set_plugin_parameter = &set_nameservice_float,  .data = &my_lon },
268   { .name = "latlon-file",            .set_plugin_parameter = &set_plugin_string,      .data = &my_latlon_file,            .addon = {sizeof(my_latlon_file)} },
269   { .name = "latlon-infile",          .set_plugin_parameter = &set_plugin_string,      .data = &latlon_in_file,            .addon = {sizeof(latlon_in_file)} },
270   { .name = "dns-server",             .set_plugin_parameter = &set_nameservice_server, .data = &my_forwarders,             .addon = {NAME_FORWARDER} },
271   { .name = "name",                   .set_plugin_parameter = &set_nameservice_name,   .data = &my_names,                  .addon = {NAME_HOST} },
272   { .name = "service",                .set_plugin_parameter = &set_nameservice_name,   .data = &my_services,               .addon = {NAME_SERVICE} },
273   { .name = "mac",                    .set_plugin_parameter = &set_nameservice_name,   .data = &my_macs,                   .addon = {NAME_MACADDR} },
274   { .name = "",                       .set_plugin_parameter = &set_nameservice_host,   .data = &my_names },
275 };
276 /* *INDENT-OFF* */
277
278 void
279 olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
280 {
281   *params = plugin_parameters;
282   *size = sizeof(plugin_parameters) / sizeof(*plugin_parameters);
283 }
284
285 /**
286  * queue the name/forwarder/service given in value
287  * to the front of my_list
288  */
289 struct name_entry *
290 add_name_to_list(struct name_entry *my_list, const char *value, int type, const union olsr_ip_addr *ip)
291 {
292   struct name_entry *tmp = olsr_malloc(sizeof(struct name_entry),
293                                        "new name_entry add_name_to_list");
294   tmp->name = strndup(value, MAX_NAME);
295   tmp->len = strlen(tmp->name);
296   tmp->type = type;
297   // all IPs with value 0 will be set to main_addr later
298   if (ip == NULL)
299     memset(&tmp->ip, 0, sizeof(tmp->ip));
300   else
301     tmp->ip = *ip;
302   tmp->next = my_list;
303   return tmp;
304 }
305
306 /**
307  * last initialization
308  *
309  * we have to do this here because some things like main_addr
310  * or the dns suffix (for validation) are not known before
311  *
312  * this is beause of the order in which the plugin is initialized
313  * by the plugin loader:
314  *   - first the parameters are sent
315  *   - then register_olsr_data() from olsrd_plugin.c is called
316  *     which sets up main_addr and some other variables
317  *   - register_olsr_data() then then finally calls this function
318  */
319 int
320 name_init(void)
321 {
322   struct name_entry *name;
323   union olsr_ip_addr ipz;
324   int ret;
325
326   //regex string for validating the hostnames
327   const char *regex_name = "^[[:alnum:]_.-]+$";
328   //regex string for the service line
329   size_t regex_size = 256 * sizeof(char) + strlen(my_suffix);
330   char *regex_service = olsr_malloc(regex_size, "new *char from name_init for regex_service");
331   memset(&ipz, 0, sizeof(ipz));
332
333   //compile the regex from the string
334   if ((ret = regcomp(&regex_t_name, regex_name, REG_EXTENDED)) != 0) {
335     /* #2: call regerror() if regcomp failed
336      * commented out, because only for debuggin needed
337      *
338      int errmsgsz = regerror(ret, &regex_t_name, NULL, 0);
339      char *errmsg = malloc(errmsgsz);
340      regerror(ret, &regex_t_name, errmsg, errmsgsz);
341      fprintf(stderr, "regcomp: %s", errmsg);
342      free(errmsg);
343      regfree(&regex_t_name);
344      * */
345     OLSR_PRINTF(0, "compilation of regex \"%s\" for hostname failed", regex_name);
346   }
347   // a service line is something like prot://hostname.suffix:port|tcp|my little description about this service
348   //                  for example     http://router.olsr:80|tcp|my homepage
349   //                     prot     ://  (hostname.suffix     OR         ip)
350   //regex_service = "^[[:alnum:]]+://(([[:alnum:]_.-]+.olsr)|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}))
351   //                 :    port              /path      |(tcp OR udp) |short description
352   //                 :[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$";
353   strscpy(regex_service, "^[[:alnum:]]+://(([[:alnum:]_.-]+", regex_size);
354   strscat(regex_service, my_suffix, regex_size);
355   strscat(regex_service,
356           ")|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3})):[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$",
357           regex_size);
358
359   /* #1: call regcomp() to compile the regex */
360   if ((ret = regcomp(&regex_t_service, regex_service, REG_EXTENDED)) != 0) {
361     /* #2: call regerror() if regcomp failed
362      * commented out, because only for debuggin needed
363      *
364      int errmsgsz = regerror(ret, &regex_t_service, NULL, 0);
365      char *errmsg = malloc(errmsgsz);
366      regerror(ret, &regex_t_service, errmsg, errmsgsz);
367      fprintf(stderr, "regcomp: %s", errmsg);
368      free(errmsg);
369      regfree(&regex_t_service);
370      * */
371     OLSR_PRINTF(0, "compilation of regex \"%s\" for hostname failed", regex_name);
372   }
373   free(regex_service);
374   regex_service = NULL;
375
376   //fill in main addr for all entries with ip==0
377   //this does not matter for service, because the ip does not matter
378   //for service
379
380   for (name = my_names; name != NULL; name = name->next) {
381     if (ipequal(&name->ip, &ipz)) {
382       OLSR_PRINTF(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
383       name->ip = olsr_cnf->main_addr;
384     }
385   }
386   for (name = my_forwarders; name != NULL; name = name->next) {
387     if (name->ip.v4.s_addr == 0) {
388       OLSR_PRINTF(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
389       name->ip = olsr_cnf->main_addr;
390     }
391   }
392
393   //check if entries I want to announce myself are valid and allowed
394   my_names = remove_nonvalid_names_from_list(my_names, NAME_HOST);
395   my_forwarders = remove_nonvalid_names_from_list(my_forwarders, NAME_FORWARDER);
396   my_services = remove_nonvalid_names_from_list(my_services, NAME_SERVICE);
397   my_macs = remove_nonvalid_names_from_list(my_macs, NAME_MACADDR);
398
399   /* register functions with olsrd */
400   olsr_parser_add_function(&olsr_parser, PARSER_TYPE);
401
402   /* periodic message generation */
403   msg_gen_timer = olsr_start_timer(my_interval * MSEC_PER_SEC, EMISSION_JITTER, OLSR_TIMER_PERIODIC, &olsr_namesvc_gen, NULL, 0);
404
405   mapwrite_init(my_latlon_file);
406
407   return 1;
408 }
409
410 struct name_entry *
411 remove_nonvalid_names_from_list(struct name_entry *my_list, int type)
412 {
413   struct name_entry *next = my_list;
414   bool valid = false;
415   if (my_list == NULL) {
416     return NULL;
417   }
418
419   switch (type) {
420   case NAME_HOST:
421     valid = is_name_wellformed(my_list->name) && allowed_ip(&my_list->ip);
422     break;
423   case NAME_FORWARDER:
424     valid = allowed_ip(&my_list->ip);
425     break;
426   case NAME_SERVICE:
427     valid = allowed_service(my_list->name);
428     break;
429   case NAME_MACADDR:
430     valid = is_mac_wellformed(my_list->name);
431     break;
432   case NAME_LATLON:
433     valid = is_latlon_wellformed(my_list->name);
434     break;
435   }
436
437   if (!valid) {
438     struct ipaddr_str strbuf;
439     OLSR_PRINTF(1, "NAME PLUGIN: invalid or malformed parameter %s (%s), fix your config!\n", my_list->name,
440                 olsr_ip_to_string(&strbuf, &my_list->ip));
441     next = my_list->next;
442     free(my_list->name);
443     my_list->name = NULL;
444     free(my_list);
445     my_list = NULL;
446     return remove_nonvalid_names_from_list(next, type);
447   } else {
448     struct ipaddr_str strbuf;
449     OLSR_PRINTF(2, "NAME PLUGIN: validate parameter %s (%s) -> OK\n", my_list->name, olsr_ip_to_string(&strbuf, &my_list->ip));
450     my_list->next = remove_nonvalid_names_from_list(my_list->next, type);
451     return my_list;
452   }
453 }
454
455 /**
456  * called at unload: free everything
457  *
458  * XXX: should I delete the hosts/services/resolv.conf files on exit?
459  */
460 void
461 name_destructor(void)
462 {
463   OLSR_PRINTF(2, "NAME PLUGIN: exit. cleaning up...\n");
464
465   free_name_entry_list(&my_names);
466   free_name_entry_list(&my_services);
467   free_name_entry_list(&my_macs);
468   free_name_entry_list(&my_forwarders);
469
470   free_all_list_entries(name_list);
471   free_all_list_entries(service_list);
472   free_all_list_entries(mac_list);
473   free_all_list_entries(forwarder_list);
474   free_all_list_entries(latlon_list);
475
476   olsr_stop_timer(write_file_timer);
477   olsr_stop_timer(msg_gen_timer);
478
479   regfree(&regex_t_name);
480   regfree(&regex_t_service);
481   mapwrite_exit();
482 }
483
484 /* free all list entries */
485 void
486 free_all_list_entries(struct list_node *this_db_list)
487 {
488   struct db_entry *db;
489   struct list_node *list_head, *list_node, *list_node_next;
490
491   int i;
492
493   for (i = 0; i < HASHSIZE; i++) {
494
495     list_head = &this_db_list[i];
496
497     for (list_node = list_head->next; list_node != list_head; list_node = list_node_next) {
498
499       /* prefetch next node before loosing context */
500       list_node_next = list_node->next;
501
502       db = list2db(list_node);
503       olsr_namesvc_delete_db_entry(db);
504     }
505   }
506 }
507
508 /**
509  * The write file timer has fired.
510  */
511 void
512 olsr_expire_write_file_timer(void *context __attribute__ ((unused)))
513 {
514   write_file_timer = NULL;
515
516   write_resolv_file();             /* if forwarder_table_changed */
517   write_hosts_file();              /* if name_table_changed */
518   write_services_file(false); /* if service_table_changed */
519   write_services_file(true);  /* if mac_table_changed */
520 #ifdef WIN32
521   write_latlon_file();             /* if latlon_table_changed */
522 #endif
523 }
524
525 /*
526  * Kick a timer to write everything into a file.
527  * This also paces things a bit.
528  */
529 static void
530 olsr_start_write_file_timer(void)
531 {
532   if (write_file_timer) {
533     return;
534   }
535
536   write_file_timer = olsr_start_timer(5 * MSEC_PER_SEC, 5, OLSR_TIMER_ONESHOT, olsr_expire_write_file_timer, NULL, 0);
537 }
538
539 /*
540  * Delete and unlink db_entry.
541  */
542 void
543 olsr_namesvc_delete_db_entry(struct db_entry *db)
544 {
545   struct ipaddr_str strbuf;
546   OLSR_PRINTF(2, "NAME PLUGIN: %s timed out... deleting\n", olsr_ip_to_string(&strbuf, &db->originator));
547
548   olsr_start_write_file_timer();
549   olsr_stop_timer(db->db_timer);        /* stop timer if running */
550
551   /* Delete */
552   free_name_entry_list(&db->names);
553   list_remove(&db->db_list);
554   free(db);
555 }
556
557 /**
558  * Callback for the db validity timer.
559  */
560 static void
561 olsr_nameservice_expire_db_timer(void *context)
562 {
563   struct db_entry *db;
564
565   db = (struct db_entry *)context;
566   db->db_timer = NULL;          /* be pedandic */
567
568   olsr_namesvc_delete_db_entry(db);
569 }
570
571 /**
572  * Scheduled event: generate and send NAME packet
573  */
574 void
575 olsr_namesvc_gen(void *foo __attribute__ ((unused)))
576 {
577   /* send buffer: huge */
578   char buffer[10240];
579   union olsr_message *message = (union olsr_message *)buffer;
580   struct interface *ifn;
581   int namesize;
582
583   /* fill message */
584   if (olsr_cnf->ip_version == AF_INET) {
585     /* IPv4 */
586     message->v4.olsr_msgtype = MESSAGE_TYPE;
587     message->v4.olsr_vtime = reltime_to_me(my_timeout * MSEC_PER_SEC);
588     memcpy(&message->v4.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
589     message->v4.ttl = MAX_TTL;
590     message->v4.hopcnt = 0;
591     message->v4.seqno = htons(get_msg_seqno());
592
593     namesize = encap_namemsg((struct namemsg *)ARM_NOWARN_ALIGN(&message->v4.message));
594     namesize = namesize + sizeof(struct olsrmsg);
595
596     message->v4.olsr_msgsize = htons(namesize);
597   } else {
598     /* IPv6 */
599     message->v6.olsr_msgtype = MESSAGE_TYPE;
600     message->v6.olsr_vtime = reltime_to_me(my_timeout * MSEC_PER_SEC);
601     memcpy(&message->v6.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
602     message->v6.ttl = MAX_TTL;
603     message->v6.hopcnt = 0;
604     message->v6.seqno = htons(get_msg_seqno());
605
606     namesize = encap_namemsg((struct namemsg *)ARM_NOWARN_ALIGN(&message->v6.message));
607     namesize = namesize + sizeof(struct olsrmsg6);
608
609     message->v6.olsr_msgsize = htons(namesize);
610   }
611
612   /* looping trough interfaces */
613   for (ifn = ifnet; ifn; ifn = ifn->int_next) {
614     OLSR_PRINTF(3, "NAME PLUGIN: Generating packet - [%s]\n", ifn->int_name);
615
616     if (net_outbuffer_push(ifn, message, namesize) != namesize) {
617       /* send data and try again */
618       net_output(ifn);
619       if (net_outbuffer_push(ifn, message, namesize) != namesize) {
620         OLSR_PRINTF(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
621       }
622     }
623   }
624 }
625
626 /**
627  * Parse name olsr message of NAME type
628  */
629 bool
630 olsr_parser(union olsr_message *m, struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *ipaddr)
631 {
632   struct namemsg *namemessage;
633   union olsr_ip_addr originator;
634   olsr_reltime vtime;
635   int size;
636   uint16_t seqno;
637
638   /* Fetch the originator of the messsage */
639   if (olsr_cnf->ip_version == AF_INET) {
640     memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);
641     seqno = ntohs(m->v4.seqno);
642   } else {
643     memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);
644     seqno = ntohs(m->v6.seqno);
645   }
646
647   /* Fetch the message based on IP version */
648   if (olsr_cnf->ip_version == AF_INET) {
649     vtime = me_to_reltime(m->v4.olsr_vtime);
650     size = ntohs(m->v4.olsr_msgsize);
651     namemessage = (struct namemsg *)ARM_NOWARN_ALIGN(&m->v4.message);
652   } else {
653     vtime = me_to_reltime(m->v6.olsr_vtime);
654     size = ntohs(m->v6.olsr_msgsize);
655     namemessage = (struct namemsg *)ARM_NOWARN_ALIGN(&m->v6.message);
656   }
657
658   /* Check if message originated from this node.
659      If so - back off */
660   if (ipequal(&originator, &olsr_cnf->main_addr))
661     return false;
662
663   /* Check that the neighbor this message was received from is symmetric.
664      If not - back off */
665   if (check_neighbor_link(ipaddr) != SYM_LINK) {
666     struct ipaddr_str strbuf;
667     OLSR_PRINTF(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(&strbuf, ipaddr));
668     return false;
669   }
670
671   update_name_entry(&originator, namemessage, size, vtime);
672
673   /* Forward the message */
674   return true;
675 }
676
677 /**
678  * Encapsulate a name message into a packet.
679  *
680  * It assumed that there is enough space in the buffer to do this!
681  *
682  * Returns: the length of the message that was appended
683  */
684 int
685 encap_namemsg(struct namemsg *msg)
686 {
687   struct name_entry *my_name;
688
689   // add the hostname, service and forwarder entries after the namemsg header
690   char *pos = (char *)msg + sizeof(struct namemsg);
691   short i = 0;
692
693   // names
694   for (my_name = my_names; my_name != NULL; my_name = my_name->next) {
695     pos = create_packet((struct name *)ARM_NOWARN_ALIGN(pos), my_name);
696     i++;
697   }
698   // forwarders
699   for (my_name = my_forwarders; my_name != NULL; my_name = my_name->next) {
700     pos = create_packet((struct name *)ARM_NOWARN_ALIGN(pos), my_name);
701     i++;
702   }
703   // services
704   for (my_name = my_services; my_name != NULL; my_name = my_name->next) {
705     pos = create_packet((struct name *)ARM_NOWARN_ALIGN(pos), my_name);
706     i++;
707   }
708   // macs
709   for (my_name = my_macs; my_name != NULL; my_name = my_name->next) {
710     pos = create_packet((struct name *)ARM_NOWARN_ALIGN(pos), my_name);
711     i++;
712   }
713   // latlon
714   if ('\0' != latlon_in_file[0]) {
715     FILE *in = fopen(latlon_in_file, "r");
716     if (in != NULL) {
717       if (fscanf(in, "%f,%f", &my_lat, &my_lon)) {}
718       fclose(in);
719     } else {
720       OLSR_PRINTF(0, "NAME PLUGIN: cant read latlon in file %s\n", latlon_in_file);
721     }
722   }
723   if (0.0 != my_lat && 0.0 != my_lon) {
724     char s[64];
725     struct name_entry e;
726     memset(&e, 0, sizeof(e));
727     sprintf(s, "%f,%f,%d", my_lat, my_lon, get_isdefhna_latlon());
728     e.len = strlen(s);
729     e.type = NAME_LATLON;
730     e.name = s;
731     lookup_defhna_latlon(&e.ip);
732     pos = create_packet((struct name *)ARM_NOWARN_ALIGN(pos), &e);
733     i++;
734   }
735   // write the namemsg header with the number of announced entries and the protocol version
736   msg->nr_names = htons(i);
737   msg->version = htons(NAME_PROTOCOL_VERSION);
738
739   return pos - (char *)msg;     //length
740 }
741
742 /**
743  * convert each of my to be announced name_entries into network
744  * compatible format
745  *
746  * return the length of the name packet
747  */
748 char *
749 create_packet(struct name *to, struct name_entry *from)
750 {
751   char *pos = (char *)to;
752   int k;
753   struct ipaddr_str strbuf;
754   OLSR_PRINTF(3, "NAME PLUGIN: Announcing name %s (%s) %d\n", from->name, olsr_ip_to_string(&strbuf, &from->ip), from->len);
755   to->type = htons(from->type);
756   to->len = htons(from->len);
757   to->ip = from->ip;
758   pos += sizeof(struct name);
759   memcpy(pos, from->name, from->len);
760   pos += from->len;
761   for (k = from->len; (k & 3) != 0; k++)
762     *pos++ = '\0';
763   return pos;
764 }
765
766 /**
767  * decapsulate a received name, service or forwarder and update the corresponding hash table if necessary
768  */
769 void
770 decap_namemsg(struct name *from_packet, struct name_entry **to, bool * this_table_changed)
771 {
772   struct ipaddr_str strbuf;
773   struct name_entry *tmp;
774   struct name_entry *already_saved_name_entries;
775   char *name = (char *)from_packet + sizeof(struct name);
776   int type_of_from_packet = ntohs(from_packet->type);
777   unsigned int len_of_name = ntohs(from_packet->len);
778   OLSR_PRINTF(4, "NAME PLUGIN: decap type=%d, len=%d, name=%s\n", type_of_from_packet, len_of_name, name);
779
780   //XXX: should I check the from_packet->ip here? If so, why not also check the ip from HOST and SERVICE?
781   if ((type_of_from_packet == NAME_HOST && !is_name_wellformed(name))
782       || (type_of_from_packet == NAME_SERVICE && !is_service_wellformed(name))
783       || (type_of_from_packet == NAME_MACADDR && !is_mac_wellformed(name))
784       || (type_of_from_packet == NAME_LATLON && !is_latlon_wellformed(name))) {
785     OLSR_PRINTF(4, "NAME PLUGIN: invalid name [%s] received, skipping.\n", name);
786     return;
787   }
788   //ignore all packets with a too long name
789   //or a spoofed len of its included name string
790   if (len_of_name > MAX_NAME || strlen(name) != len_of_name || NULL != strchr(name, '\\') || NULL != strchr(name, '\'')) {
791     OLSR_PRINTF(4, "NAME PLUGIN: from_packet->len %d > MAX_NAME %d or from_packet->len %d !0 strlen(name [%s] in packet)\n",
792                 len_of_name, MAX_NAME, len_of_name, name);
793     return;
794   }
795   // don't insert the received entry again, if it has already been inserted in the hash table.
796   // Instead only the validity time is set in insert_new_name_in_list function, which calls this one
797   for (already_saved_name_entries = (*to); already_saved_name_entries != NULL;
798        already_saved_name_entries = already_saved_name_entries->next) {
799     if ((type_of_from_packet == NAME_HOST || type_of_from_packet == NAME_SERVICE)
800         && strncmp(already_saved_name_entries->name, name, len_of_name) == 0) {
801       OLSR_PRINTF(4, "NAME PLUGIN: received name or service entry %s (%s) already in hash table\n", name,
802                   olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
803       return;
804     } else if (type_of_from_packet == NAME_FORWARDER && ipequal(&already_saved_name_entries->ip, &from_packet->ip)) {
805       OLSR_PRINTF(4, "NAME PLUGIN: received forwarder entry %s (%s) already in hash table\n", name,
806                   olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
807       return;
808     } else if (type_of_from_packet == NAME_LATLON) {
809       if (0 != strncmp(already_saved_name_entries->name, name, len_of_name)) {
810         OLSR_PRINTF(4, "NAME PLUGIN: updating name %s -> %s (%s)\n", already_saved_name_entries->name, name,
811                     olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
812         free(already_saved_name_entries->name);
813         already_saved_name_entries->name = olsr_malloc(len_of_name + 1, "upd name_entry name");
814         strscpy(already_saved_name_entries->name, name, len_of_name + 1);
815
816         *this_table_changed = true;
817         olsr_start_write_file_timer();
818       }
819       if (!ipequal(&already_saved_name_entries->ip, &from_packet->ip)) {
820         struct ipaddr_str strbuf2, strbuf3;
821         OLSR_PRINTF(4, "NAME PLUGIN: updating ip %s -> %s (%s)\n", olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip),
822                     olsr_ip_to_string(&strbuf2, &from_packet->ip), olsr_ip_to_string(&strbuf3, &already_saved_name_entries->ip));
823         already_saved_name_entries->ip = from_packet->ip;
824
825         *this_table_changed = true;
826         olsr_start_write_file_timer();
827       }
828       if (!*this_table_changed) {
829         OLSR_PRINTF(4, "NAME PLUGIN: received latlon entry %s (%s) already in hash table\n", name,
830                     olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
831       }
832       return;
833     }
834   }
835
836   //if not yet known entry
837   tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry");
838   tmp->type = ntohs(from_packet->type);
839   tmp->len = len_of_name > MAX_NAME ? MAX_NAME : ntohs(from_packet->len);
840   tmp->name = olsr_malloc(tmp->len + 1, "new name_entry name");
841   tmp->ip = from_packet->ip;
842   strscpy(tmp->name, name, tmp->len + 1);
843
844   OLSR_PRINTF(3, "\nNAME PLUGIN: create new name/service/forwarder entry %s (%s) [len=%d] [type=%d] in linked list\n", tmp->name,
845               olsr_ip_to_string(&strbuf, &tmp->ip), tmp->len, tmp->type);
846
847   *this_table_changed = true;
848   olsr_start_write_file_timer();
849
850   // queue to front
851   tmp->next = *to;
852   *to = tmp;
853 }
854
855 /**
856  * unpack the received message and delegate to the decapsulation function for each
857  * name/service/forwarder entry in the message
858  */
859 void
860 update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, olsr_reltime vtime)
861 {
862   struct ipaddr_str strbuf;
863   char *pos, *end_pos;
864   struct name *from_packet;
865   int i;
866
867   OLSR_PRINTF(3, "NAME PLUGIN: Received Message from %s\n", olsr_ip_to_string(&strbuf, originator));
868
869   if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) {
870     OLSR_PRINTF(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version);
871     return;
872   }
873
874   /* now add the names from the message */
875   pos = (char *)msg + sizeof(struct namemsg);
876   end_pos = pos + msg_size - sizeof(struct name *);     // at least one struct name has to be left
877
878   for (i = ntohs(msg->nr_names); i > 0 && pos < end_pos; i--) {
879     from_packet = (struct name *)ARM_NOWARN_ALIGN(pos);
880
881     switch (ntohs(from_packet->type)) {
882     case NAME_HOST:
883       insert_new_name_in_list(originator, name_list, from_packet, &name_table_changed, vtime);
884       break;
885     case NAME_FORWARDER:
886       insert_new_name_in_list(originator, forwarder_list, from_packet, &forwarder_table_changed, vtime);
887       break;
888     case NAME_SERVICE:
889       insert_new_name_in_list(originator, service_list, from_packet, &service_table_changed, vtime);
890       break;
891     case NAME_MACADDR:
892       insert_new_name_in_list(originator, mac_list, from_packet, &mac_table_changed, vtime);
893       break;
894     case NAME_LATLON:
895       insert_new_name_in_list(originator, latlon_list, from_packet, &latlon_table_changed, vtime);
896       break;
897     default:
898       OLSR_PRINTF(3, "NAME PLUGIN: Received Message of unknown type [%d] from (%s)\n", from_packet->type,
899                   olsr_ip_to_string(&strbuf, originator));
900       break;
901     }
902
903     pos += sizeof(struct name);
904     pos += 1 + ((ntohs(from_packet->len) - 1) | 3);
905   }
906   if (i != 0)
907     OLSR_PRINTF(4, "NAME PLUGIN: Lost %d entries in received packet due to length inconsistency (%s)\n", i,
908                 olsr_ip_to_string(&strbuf, originator));
909 }
910
911 /**
912  * insert all the new names,services and forwarders from a received packet into the
913  * corresponding entry for this ip in the corresponding hash table
914  */
915 void
916 insert_new_name_in_list(union olsr_ip_addr *originator, struct list_node *this_list, struct name *from_packet,
917                         bool * this_table_changed, olsr_reltime vtime)
918 {
919   int hash;
920   struct db_entry *entry;
921   struct list_node *list_head, *list_node;
922
923   bool entry_found = false;
924
925   hash = olsr_ip_hashing(originator);
926
927   /* find the entry for originator, if there is already one */
928   list_head = &this_list[hash];
929   for (list_node = list_head->next; list_node != list_head; list_node = list_node->next) {
930
931     entry = list2db(list_node);
932
933     if (ipequal(originator, &entry->originator)) {
934       struct ipaddr_str strbuf;
935       // found
936       OLSR_PRINTF(4, "NAME PLUGIN: found entry for (%s) in its hash table\n", olsr_ip_to_string(&strbuf, originator));
937
938       //delegate to function for parsing the packet and linking it to entry->names
939       decap_namemsg(from_packet, &entry->names, this_table_changed);
940
941       olsr_set_timer(&entry->db_timer, vtime, OLSR_NAMESVC_DB_JITTER, OLSR_TIMER_ONESHOT, &olsr_nameservice_expire_db_timer, entry,
942                      0);
943
944       entry_found = true;
945     }
946   }
947
948   if (!entry_found) {
949     struct ipaddr_str strbuf;
950     OLSR_PRINTF(3, "NAME PLUGIN: create new db entry for ip (%s) in hash table\n", olsr_ip_to_string(&strbuf, originator));
951
952     /* insert a new entry */
953     entry = olsr_malloc(sizeof(struct db_entry), "new db_entry");
954     memset(entry, 0, sizeof(struct db_entry));
955
956     entry->originator = *originator;
957
958     olsr_set_timer(&entry->db_timer, vtime, OLSR_LINK_LOSS_JITTER, OLSR_TIMER_ONESHOT, &olsr_nameservice_expire_db_timer, entry, 0);
959
960     entry->names = NULL;
961
962     /* insert to the list */
963     list_add_before(&this_list[hash], &entry->db_list);
964
965     //delegate to function for parsing the packet and linking it to entry->names
966     decap_namemsg(from_packet, &entry->names, this_table_changed);
967   }
968 }
969
970 #ifndef WIN32
971 static void
972 send_sighup_to_pidfile(char *pid_file)
973 {
974   int fd;
975   int i = 0;
976   int result;
977   pid_t ipid;
978   char line[20];
979   char *endptr;
980
981   fd = open(pid_file, O_RDONLY);
982   if (fd < 0) {
983     OLSR_PRINTF(2, "NAME PLUGIN: can't open file %s\n", pid_file);
984     return;
985   }
986
987   while (i < 19) {
988     result = read(fd, line + i, 19 - i);
989     if (!result) {              /* EOF */
990       break;
991     } else if (result > 0) {
992       i += result;
993     } else if (errno != EINTR && errno != EAGAIN) {
994       OLSR_PRINTF(2, "NAME PLUGIN: can't read file %s\n", pid_file);
995       return;
996     }
997   }
998   line[i] = 0;
999   close(fd);
1000   ipid = strtol(line, &endptr, 0);
1001   if (endptr == line) {
1002     OLSR_PRINTF(2, "NAME PLUGIN: invalid pid at file %s\n", pid_file);
1003     return;
1004   }
1005
1006   result = kill(ipid, SIGHUP);
1007   if (result == 0) {
1008     OLSR_PRINTF(2, "NAME PLUGIN: SIGHUP sent to pid %i\n", ipid);
1009   } else {
1010     OLSR_PRINTF(2, "NAME PLUGIN: failed to send SIGHUP to pid %i\n", ipid);
1011   }
1012
1013 }
1014 #endif
1015
1016 /**
1017  * write names to a file in /etc/hosts compatible format
1018  */
1019 void
1020 write_hosts_file(void)
1021 {
1022   int hash;
1023   struct name_entry *name;
1024   struct db_entry *entry;
1025   struct list_node *list_head, *list_node;
1026   FILE *hosts;
1027   FILE *add_hosts;
1028   int c = 0;
1029   time_t currtime;
1030
1031 #ifdef MID_ENTRIES
1032   struct mid_address *alias;
1033 #endif
1034
1035   if (!name_table_changed)
1036     return;
1037
1038   OLSR_PRINTF(2, "NAME PLUGIN: writing hosts file\n");
1039
1040   hosts = fopen(my_hosts_file, "w");
1041   if (hosts == NULL) {
1042     OLSR_PRINTF(2, "NAME PLUGIN: cant write hosts file\n");
1043     return;
1044   }
1045
1046   fprintf(hosts, "### this /etc/hosts file is overwritten regularly by olsrd\n");
1047   fprintf(hosts, "### do not edit\n\n");
1048
1049   fprintf(hosts, "127.0.0.1\tlocalhost\n");
1050   fprintf(hosts, "::1\t\tlocalhost\n\n");
1051
1052   // copy content from additional hosts filename
1053   if (my_add_hosts[0] != '\0') {
1054     add_hosts = fopen(my_add_hosts, "r");
1055     if (add_hosts == NULL) {
1056       OLSR_PRINTF(2, "NAME PLUGIN: cant open additional hosts file\n");
1057     } else {
1058       fprintf(hosts, "### contents from '%s' ###\n\n", my_add_hosts);
1059       while ((c = getc(add_hosts)) != EOF)
1060         putc(c, hosts);
1061     }
1062     fclose(add_hosts);
1063     fprintf(hosts, "\n### olsr names ###\n\n");
1064   }
1065   // write own names
1066   for (name = my_names; name != NULL; name = name->next) {
1067     struct ipaddr_str strbuf;
1068     fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&strbuf, &name->ip), name->name, my_suffix);
1069   }
1070
1071   // write received names
1072   for (hash = 0; hash < HASHSIZE; hash++) {
1073     list_head = &name_list[hash];
1074     for (list_node = list_head->next; list_node != list_head; list_node = list_node->next) {
1075
1076       entry = list2db(list_node);
1077
1078       for (name = entry->names; name != NULL; name = name->next) {
1079         struct ipaddr_str strbuf;
1080         OLSR_PRINTF(6, "%s\t%s%s\t#%s\n", olsr_ip_to_string(&strbuf, &name->ip), name->name, my_suffix,
1081                     olsr_ip_to_string(&strbuf, &entry->originator));
1082
1083         fprintf(hosts, "%s\t%s%s\t# %s\n", olsr_ip_to_string(&strbuf, &name->ip), name->name, my_suffix,
1084                 olsr_ip_to_string(&strbuf, &entry->originator));
1085
1086 #ifdef MID_ENTRIES
1087         // write mid entries
1088         if ((alias = mid_lookup_aliases(&name->ip)) != NULL) {
1089           unsigned short mid_num = 1;
1090           char mid_prefix[MID_MAXLEN];
1091
1092           while (alias != NULL) {
1093             struct ipaddr_str midbuf;
1094
1095             // generate mid prefix
1096             sprintf(mid_prefix, MID_PREFIX, mid_num);
1097
1098             OLSR_PRINTF(6, "%s\t%s%s%s\t# %s (mid #%i)\n", olsr_ip_to_string(&midbuf, &alias->alias), mid_prefix, name->name,
1099                         my_suffix, olsr_ip_to_string(&strbuf, &entry->originator), mid_num);
1100
1101             fprintf(hosts, "%s\t%s%s%s\t# %s (mid #%i)\n", olsr_ip_to_string(&midbuf, &alias->alias), mid_prefix, name->name,
1102                     my_suffix, olsr_ip_to_string(&strbuf, &entry->originator), mid_num);
1103
1104             alias = alias->next_alias;
1105             mid_num++;
1106           }
1107         }
1108 #endif
1109       }
1110     }
1111   }
1112
1113   if (time(&currtime)) {
1114     fprintf(hosts, "\n### written by olsrd at %s", ctime(&currtime));
1115   }
1116
1117   fclose(hosts);
1118
1119 #ifndef WIN32
1120   if (*my_sighup_pid_file)
1121     send_sighup_to_pidfile(my_sighup_pid_file);
1122 #endif
1123   name_table_changed = false;
1124
1125   // Executes my_name_change_script after writing the hosts file
1126   if (my_name_change_script[0] != '\0') {
1127     if (system(my_name_change_script) != -1) {
1128       OLSR_PRINTF(2, "NAME PLUGIN: Name changed, %s executed\n", my_name_change_script);
1129     } else {
1130       OLSR_PRINTF(2, "NAME PLUGIN: WARNING! Failed to execute %s on hosts change\n", my_name_change_script);
1131     }
1132   }
1133 }
1134
1135 /**
1136  * write services or macs to a file in the format:
1137  * service-or-mac  #originator ip
1138  *
1139  * since service has a special format
1140  * each line will look similar to e.g.
1141  * http://me.olsr:80|tcp|my little homepage
1142  * while a mac line will look similar to
1143  * 02:ca:ff:ee:ba:be,1
1144  */
1145 void
1146 write_services_file(bool writemacs)
1147 {
1148   int hash;
1149   struct name_entry *name;
1150   struct db_entry *entry;
1151   struct list_node *list_head, *list_node;
1152   FILE *file;
1153   time_t currtime;
1154
1155   if ((writemacs && !mac_table_changed) || (!writemacs && !service_table_changed))
1156     return;
1157
1158   OLSR_PRINTF(2, "NAME PLUGIN: writing %s file\n", writemacs ? "macs" : "services");
1159
1160   file = fopen(writemacs ? my_macs_file : my_services_file, "w");
1161   if (file == NULL) {
1162     OLSR_PRINTF(2, "NAME PLUGIN: cant write %s\n", writemacs ? my_macs_file : my_services_file);
1163     return;
1164   }
1165
1166   fprintf(file, "### this file is overwritten regularly by olsrd\n");
1167   fprintf(file, "### do not edit\n\n");
1168
1169   // write own services or macs
1170   for (name = writemacs ? my_macs : my_services; name != NULL; name = name->next) {
1171     fprintf(file, "%s\t# my own %s\n", name->name, writemacs ? "mac" : "service");
1172   }
1173
1174   // write received services or macs
1175   for (hash = 0; hash < HASHSIZE; hash++) {
1176     list_head = writemacs ? &mac_list[hash] : &service_list[hash];
1177     for (list_node = list_head->next; list_node != list_head; list_node = list_node->next) {
1178
1179       entry = list2db(list_node);
1180
1181       for (name = entry->names; name != NULL; name = name->next) {
1182         struct ipaddr_str strbuf;
1183         OLSR_PRINTF(6, "%s\t", name->name);
1184         OLSR_PRINTF(6, "\t#%s\n", olsr_ip_to_string(&strbuf, &entry->originator));
1185
1186         fprintf(file, "%s\t", name->name);
1187         fprintf(file, "\t#%s\n", olsr_ip_to_string(&strbuf, &entry->originator));
1188       }
1189     }
1190   }
1191
1192   if (time(&currtime)) {
1193     fprintf(file, "\n### written by olsrd at %s", ctime(&currtime));
1194   }
1195
1196   fclose(file);
1197   if (writemacs) {
1198     // Executes my_macs_change_script after writing the macs file
1199     if (my_macs_change_script[0] != '\0') {
1200       if (system(my_macs_change_script) != -1) {
1201         OLSR_PRINTF(2, "NAME PLUGIN: Service changed, %s executed\n", my_macs_change_script);
1202       } else {
1203         OLSR_PRINTF(2, "NAME PLUGIN: WARNING! Failed to execute %s on mac change\n", my_macs_change_script);
1204       }
1205     }
1206     mac_table_changed = false;
1207   }
1208   else {
1209     // Executes my_services_change_script after writing the services file
1210     if (my_services_change_script[0] != '\0') {
1211       if (system(my_services_change_script) != -1) {
1212         OLSR_PRINTF(2, "NAME PLUGIN: Service changed, %s executed\n", my_services_change_script);
1213       } else {
1214         OLSR_PRINTF(2, "NAME PLUGIN: WARNING! Failed to execute %s on service change\n", my_services_change_script);
1215       }
1216     }
1217     service_table_changed = false;
1218   }
1219 }
1220
1221 /**
1222  * Sort the nameserver pointer array.
1223  *
1224  * fresh entries are at the beginning of the array and
1225  * the best entry is at the end of the array.
1226  */
1227 static void
1228 select_best_nameserver(struct rt_entry **rt)
1229 {
1230   int nameserver_idx;
1231   struct rt_entry *rt1, *rt2;
1232
1233   for (nameserver_idx = 0; nameserver_idx < NAMESERVER_COUNT; nameserver_idx++) {
1234
1235     rt1 = rt[nameserver_idx];
1236     rt2 = rt[nameserver_idx + 1];
1237
1238     /*
1239      * compare the next two pointers in the array.
1240      * if the second pointer is NULL then percolate it up.
1241      */
1242     if (!rt2 || olsr_cmp_rt(rt1, rt2)) {
1243 #ifndef NODEBUG
1244       struct ipaddr_str strbuf;
1245       struct lqtextbuffer lqbuffer;
1246 #endif
1247       /*
1248        * first is better, swap the pointers.
1249        */
1250       OLSR_PRINTF(6, "NAME PLUGIN: nameserver %s, cost %s\n", olsr_ip_to_string(&strbuf, &rt1->rt_dst.prefix),
1251                   get_linkcost_text(rt1->rt_best->rtp_metric.cost, true, &lqbuffer));
1252
1253       rt[nameserver_idx] = rt2;
1254       rt[nameserver_idx + 1] = rt1;
1255     }
1256   }
1257 }
1258
1259 /**
1260  * write the 3 best upstream DNS servers to resolv.conf file
1261  * best means the 3 with the best etx value in routing table
1262  */
1263 void
1264 write_resolv_file(void)
1265 {
1266   int hash;
1267   struct name_entry *name;
1268   struct db_entry *entry;
1269   struct list_node *list_head, *list_node;
1270   struct rt_entry *route;
1271   static struct rt_entry *nameserver_routes[NAMESERVER_COUNT + 1];
1272   FILE *resolv;
1273   int i = 0;
1274   time_t currtime;
1275
1276   if (!forwarder_table_changed || my_forwarders != NULL || my_resolv_file[0] == '\0')
1277     return;
1278
1279   /* clear the array of 3+1 nameserver routes */
1280   memset(nameserver_routes, 0, sizeof(nameserver_routes));
1281
1282   for (hash = 0; hash < HASHSIZE; hash++) {
1283     list_head = &forwarder_list[hash];
1284     for (list_node = list_head->next; list_node != list_head; list_node = list_node->next) {
1285
1286       entry = list2db(list_node);
1287
1288       for (name = entry->names; name != NULL; name = name->next) {
1289 #ifndef NODEBUG
1290         struct ipaddr_str strbuf;
1291         struct lqtextbuffer lqbuffer;
1292 #endif
1293         route = olsr_lookup_routing_table(&name->ip);
1294
1295         OLSR_PRINTF(6, "NAME PLUGIN: check route for nameserver %s %s", olsr_ip_to_string(&strbuf, &name->ip),
1296                     route ? "suceeded" : "failed");
1297
1298         if (route == NULL)      // it's possible that route is not present yet
1299           continue;
1300
1301         /* enqueue it on the head of list */
1302         *nameserver_routes = route;
1303         OLSR_PRINTF(6, "NAME PLUGIN: found nameserver %s, cost %s", olsr_ip_to_string(&strbuf, &name->ip),
1304                     get_linkcost_text(route->rt_best->rtp_metric.cost, true, &lqbuffer));
1305
1306         /* find the closet one */
1307         select_best_nameserver(nameserver_routes);
1308       }
1309     }
1310   }
1311
1312   /* if there is no best route we are done */
1313   if (nameserver_routes[NAMESERVER_COUNT] == NULL)
1314     return;
1315
1316   /* write to file */
1317   OLSR_PRINTF(2, "NAME PLUGIN: try to write to resolv file\n");
1318   resolv = fopen(my_resolv_file, "w");
1319   if (resolv == NULL) {
1320     OLSR_PRINTF(2, "NAME PLUGIN: can't write resolv file\n");
1321     return;
1322   }
1323   fprintf(resolv, "### this file is overwritten regularly by olsrd\n");
1324   fprintf(resolv, "### do not edit\n\n");
1325
1326   for (i = NAMESERVER_COUNT; i >= 0; i--) {
1327     struct ipaddr_str strbuf;
1328
1329     route = nameserver_routes[i];
1330
1331     OLSR_PRINTF(2, "NAME PLUGIN: nameserver_routes #%d %p\n", i, route);
1332
1333     if (!route) {
1334       continue;
1335     }
1336
1337     OLSR_PRINTF(2, "NAME PLUGIN: nameserver %s\n", olsr_ip_to_string(&strbuf, &route->rt_dst.prefix));
1338     fprintf(resolv, "nameserver %s\n", olsr_ip_to_string(&strbuf, &route->rt_dst.prefix));
1339   }
1340   if (time(&currtime)) {
1341     fprintf(resolv, "\n### written by olsrd at %s", ctime(&currtime));
1342   }
1343   fclose(resolv);
1344   forwarder_table_changed = false;
1345 }
1346
1347 /**
1348  * completely free a list of name_entries
1349  */
1350 void
1351 free_name_entry_list(struct name_entry **list)
1352 {
1353   struct name_entry **tmp = list;
1354   struct name_entry *to_delete;
1355   while (*tmp != NULL) {
1356     to_delete = *tmp;
1357     *tmp = (*tmp)->next;
1358
1359     /* flag changes */
1360     switch (to_delete->type) {
1361     case NAME_HOST:
1362       name_table_changed = true;
1363       break;
1364     case NAME_FORWARDER:
1365       forwarder_table_changed = true;
1366       break;
1367     case NAME_SERVICE:
1368       service_table_changed = true;
1369       break;
1370     case NAME_MACADDR:
1371       mac_table_changed = true;
1372       break;
1373     case NAME_LATLON:
1374       latlon_table_changed = true;
1375       break;
1376     default:
1377       break;
1378     }
1379
1380     free(to_delete->name);
1381     to_delete->name = NULL;
1382     free(to_delete);
1383     to_delete = NULL;
1384   }
1385 }
1386
1387 /**
1388  * we only allow names for IP addresses which we are
1389  * responsible for:
1390  * so the IP must either be from one of the interfaces
1391  * or inside a HNA which we have configured
1392  */
1393 bool
1394 allowed_ip(const union olsr_ip_addr *addr)
1395 {
1396   struct ip_prefix_list *hna;
1397   struct interface *iface;
1398   union olsr_ip_addr tmp_ip, tmp_msk;
1399   struct ipaddr_str strbuf;
1400
1401   OLSR_PRINTF(6, "checking %s\n", olsr_ip_to_string(&strbuf, addr));
1402
1403   for (iface = ifnet; iface; iface = iface->int_next) {
1404     OLSR_PRINTF(6, "interface %s\n", olsr_ip_to_string(&strbuf, &iface->ip_addr));
1405     if (ipequal(&iface->ip_addr, addr)) {
1406       OLSR_PRINTF(6, "MATCHED\n");
1407       return true;
1408     }
1409   }
1410
1411   if (olsr_cnf->ip_version == AF_INET) {
1412     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
1413       union olsr_ip_addr netmask;
1414       OLSR_PRINTF(6, "HNA %s/%d\n", olsr_ip_to_string(&strbuf, &hna->net.prefix), hna->net.prefix_len);
1415       if (hna->net.prefix_len == 0) {
1416         continue;
1417       }
1418       olsr_prefix_to_netmask(&netmask, hna->net.prefix_len);
1419       if ((addr->v4.s_addr & netmask.v4.s_addr) == hna->net.prefix.v4.s_addr) {
1420         OLSR_PRINTF(6, "MATCHED\n");
1421         return true;
1422       }
1423     }
1424   } else {
1425     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
1426       unsigned int i;
1427       OLSR_PRINTF(6, "HNA %s/%d\n", olsr_ip_to_string(&strbuf, &hna->net.prefix), hna->net.prefix_len);
1428       if (hna->net.prefix_len == 0)
1429         continue;
1430       olsr_prefix_to_netmask(&tmp_msk, hna->net.prefix_len);
1431       for (i = 0; i < sizeof(tmp_ip.v6.s6_addr); i++) {
1432         tmp_ip.v6.s6_addr[i] = addr->v6.s6_addr[i] & tmp_msk.v6.s6_addr[i];
1433       }
1434       if (ipequal(&tmp_ip, &hna->net.prefix)) {
1435         OLSR_PRINTF(6, "MATCHED\n");
1436         return true;
1437       }
1438     }
1439   }
1440   return false;
1441 }
1442
1443 /** check if name has the right syntax, i.e. it must adhere to a special regex
1444  * stored in regex_t_name
1445  * necessary to avaid names like "0.0.0.0 google.de\n etc"
1446  */
1447 bool
1448 is_name_wellformed(const char *name)
1449 {
1450   return regexec(&regex_t_name, name, 1, &regmatch_t_name, 0) == 0;
1451 }
1452
1453 /**
1454  * check if the service is in the right syntax and also that the hostname
1455  * or ip whithin the service is allowed
1456  */
1457 bool
1458 allowed_service(const char *service_line)
1459 {
1460   /* the call of is_service_wellformed generates the submatches stored in regmatch_t_service
1461    * these are then used by allowed_hostname_or_ip_in_service
1462    * see regexec(3) for more infos */
1463   if (!is_service_wellformed(service_line)) {
1464     return false;
1465   } else if (!allowed_hostname_or_ip_in_service(service_line, &(regmatch_t_service[1]))) {
1466     return false;
1467   }
1468
1469   return true;
1470 }
1471
1472 bool
1473 allowed_hostname_or_ip_in_service(const char *service_line, const regmatch_t * hostname_or_ip_match)
1474 {
1475   char *hostname_or_ip;
1476   union olsr_ip_addr olsr_ip;
1477   struct name_entry *name;
1478   if (hostname_or_ip_match->rm_so < 0 || hostname_or_ip_match->rm_eo < 0) {
1479     return false;
1480   }
1481
1482   hostname_or_ip = strndup(&service_line[hostname_or_ip_match->rm_so], hostname_or_ip_match->rm_eo - hostname_or_ip_match->rm_so);
1483   //hostname is one of the names, that I announce (i.e. one that i am allowed to announce)
1484   for (name = my_names; name != NULL; name = name->next) {
1485     if (strncmp(name->name, hostname_or_ip, name->len - strlen(my_suffix)) == 0) {
1486       OLSR_PRINTF(4, "NAME PLUGIN: hostname %s in service %s is OK\n", hostname_or_ip, service_line);
1487       free(hostname_or_ip);
1488       hostname_or_ip = NULL;
1489       return true;
1490     }
1491   }
1492
1493   //ip in service-line is allowed
1494   if (inet_pton(olsr_cnf->ip_version, hostname_or_ip, &olsr_ip) > 0) {
1495     if (allowed_ip(&olsr_ip)) {
1496       struct ipaddr_str strbuf;
1497       OLSR_PRINTF(2, "NAME PLUGIN: ip %s in service %s is OK\n", olsr_ip_to_string(&strbuf, &olsr_ip), service_line);
1498       free(hostname_or_ip);
1499       hostname_or_ip = NULL;
1500       return true;
1501     }
1502   }
1503
1504   OLSR_PRINTF(1, "NAME PLUGIN: ip or hostname %s in service %s is NOT allowed (does not belong to you)\n", hostname_or_ip,
1505               service_line);
1506   free(hostname_or_ip);
1507   hostname_or_ip = NULL;
1508
1509   return false;
1510 }
1511
1512 /**
1513  * check if the service matches the syntax
1514  * of "protocol://host:port/path|tcp_or_udp|a short description",
1515  * which is given in the regex regex_t_service
1516  */
1517 bool
1518 is_service_wellformed(const char *service_line)
1519 {
1520   return regexec(&regex_t_service, service_line, pmatch_service, regmatch_t_service, 0) == 0;
1521 }
1522
1523 /*
1524  * check if the mac matches the syntax
1525  */
1526 bool
1527 is_mac_wellformed(const char *mac_line)
1528 {
1529   size_t i;
1530   bool ret;
1531   int x[6], d = -1;
1532   for(i = 0; i < ARRAYSIZE(x); i++) x[i] = -1;
1533   sscanf(mac_line, "%02x:%02x:%02x:%02x:%02x:%02x,%d\n", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &d);
1534   ret = 0 <= d && d <= 0xffff;
1535   for(i = 0; i < ARRAYSIZE(x); i++) ret = ret && 0 <= x[i];
1536   return ret;
1537 }
1538
1539 /**
1540  * check if the latlot matches the syntax
1541  */
1542 bool
1543 is_latlon_wellformed(const char *latlon_line)
1544 {
1545   int hna = -1;
1546   float a = 0.0, b = 0.0;
1547   sscanf(latlon_line, "%f,%f,%d", &a, &b, &hna);
1548   return (a != 0.0 && b != 0.0 && -1 != hna);
1549 }
1550
1551 /**
1552  * Returns 1 if this olsrd announces inet
1553  */
1554 bool
1555 get_isdefhna_latlon(void)
1556 {
1557   struct ip_prefix_list *hna;
1558   for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
1559     if (hna->net.prefix_len == 0) {
1560       return true;
1561     }
1562   }
1563   return false;
1564 }
1565
1566 /**
1567  * Grabs the current HNA selected default route
1568  */
1569 void
1570 lookup_defhna_latlon(union olsr_ip_addr *ip)
1571 {
1572   struct rt_entry *rt;
1573   struct avl_node *rt_tree_node;
1574   struct olsr_ip_prefix prefix;
1575
1576   memset(ip, 0, sizeof(ip));
1577   memset(&prefix, 0, sizeof(prefix));
1578
1579   if (NULL != (rt_tree_node = avl_find(&routingtree, &prefix))) {
1580     rt = rt_tree2rt(rt_tree_node);
1581     *ip = rt->rt_best->rtp_nexthop.gateway;
1582   }
1583 }
1584
1585 /**
1586  * lookup a nodes name
1587  */
1588 const char *
1589 lookup_name_latlon(union olsr_ip_addr *ip)
1590 {
1591   int hash;
1592   struct db_entry *entry;
1593   struct list_node *list_head, *list_node;
1594   struct name_entry *name;
1595
1596   for (hash = 0; hash < HASHSIZE; hash++) {
1597     list_head = &name_list[hash];
1598     for (list_node = list_head->next; list_node != list_head; list_node = list_node->next) {
1599
1600       entry = list2db(list_node);
1601
1602       for (name = entry->names; name != NULL; name = name->next) {
1603         if (ipequal(&name->ip, ip))
1604           return name->name;
1605       }
1606     }
1607   }
1608   return "";
1609 }
1610
1611 #ifdef WIN32
1612
1613 /**
1614  * write latlon positions to a javascript file
1615  */
1616 void
1617 write_latlon_file(void)
1618 {
1619   FILE *fmap;
1620
1621   if (!my_names || !latlon_table_changed)
1622     return;
1623
1624   OLSR_PRINTF(2, "NAME PLUGIN: writing latlon file\n");
1625
1626   if (NULL == (fmap = fopen(my_latlon_file, "w"))) {
1627     OLSR_PRINTF(0, "NAME PLUGIN: cant write latlon file\n");
1628     return;
1629   }
1630   fprintf(fmap, "/* This file is overwritten regularly by olsrd */\n");
1631   mapwrite_work(fmap);
1632   fclose(fmap);
1633   latlon_table_changed = false;
1634 }
1635 #endif
1636
1637 /*
1638  * Local Variables:
1639  * mode: c
1640  * c-indent-tabs-mode: t
1641  * indent-tabs-mode: t
1642  * c-basic-offset: 4
1643  * tab-width: 4
1644  * End:
1645  */