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