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