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