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