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