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