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