new parameter "addhosts" to include other hosts files
[olsrd.git] / lib / nameservice / src / nameservice.c
1 /*
2  * Copyright (c) 2005, Bruno Randolf <bruno.randolf@4g-systems.biz>
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto-at-olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, 
11  *   this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright notice, 
13  *   this list of conditions and the following disclaimer in the documentation 
14  *   and/or other materials provided with the distribution.
15  * * Neither the name of the UniK olsr daemon nor the names of its contributors 
16  *   may be used to endorse or promote products derived from this software 
17  *   without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
22  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31
32 /* $Id: nameservice.c,v 1.9 2005/03/13 22:25:05 br1 Exp $ */
33
34 /*
35  * Dynamic linked library for UniK OLSRd
36  */
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include "nameservice.h"
43 #include "olsrd_copy.h"
44
45
46 /* send buffer: huge */
47 static char buffer[10240];
48
49 /* config parameters */
50 static char my_filename[MAX_FILE + 1];
51 static char my_add_hosts[MAX_FILE + 1];
52 static char my_suffix[MAX_SUFFIX];
53 int my_interval = EMISSION_INTERVAL;
54 double my_timeout = NAME_VALID_TIME;
55
56 /* the database (using hashing) */
57 struct db_entry* list[HASHSIZE];
58 struct name_entry *my_names = NULL;
59 olsr_bool name_table_changed = OLSR_TRUE;
60
61
62 /**
63  * do initialization
64  */
65 void
66 name_constructor() 
67 {
68         int i;
69         
70 #ifdef WIN32
71         int len;
72
73         GetWindowsDirectory(my_filename, MAX_FILE - 12);
74
75         len = strlen(my_filename);
76  
77         if (my_filename[len - 1] != '\\')
78                 my_filename[len++] = '\\';
79  
80         strcpy(my_filename + len, "hosts_olsr");
81 #else
82         strcpy(my_filename, "/var/run/hosts_olsr");
83 #endif
84
85         my_suffix[0] = '\0';
86         my_add_hosts[0] = '\0';
87         
88         /* init list */
89         for(i = 0; i < HASHSIZE; i++) {
90                 list[i] = NULL;
91         }
92 }
93
94
95 /**
96  * called for all plugin parameters
97  */
98 int
99 register_olsr_param(char *key, char *value)
100 {
101         if(!strcmp(key, "name")) {
102                 // name for main address
103                 struct name_entry *tmp;
104                 tmp = malloc(sizeof(struct name_entry));
105                 tmp->name = strndup( value, MAX_NAME );
106                 tmp->len = strlen( tmp->name );
107                 tmp->type = NAME_HOST;
108                 // will be set to main_addr later
109                 memset(&tmp->ip, 0, sizeof(tmp->ip));
110                 tmp->next = my_names;
111                 my_names = tmp;
112                 
113                 printf("\nNAME PLUGIN: parameter name: %s (main address)\n", tmp->name);
114         } 
115         else if(!strcmp(key, "filename")) {
116                 strncpy( my_filename, value, MAX_FILE );
117                 printf("\nNAME PLUGIN: parameter filename: %s\n", my_filename);
118         }
119         else if(!strcmp(key, "interval")) {
120                 my_interval = atoi(value);
121                 printf("\nNAME PLUGIN: parameter interval: %d\n", my_interval);
122         }
123         else if(!strcmp(key, "timeout")) {
124                 my_timeout = atof(value);
125                 printf("\nNAME PLUGIN: parameter timeout: %f\n", my_timeout);
126         }
127         else if(!strcmp(key, "suffix")) {
128                 strncpy(my_suffix, value, MAX_SUFFIX);
129                 printf("\nNAME PLUGIN: parameter suffix: %s\n", my_suffix);
130         }
131         else if(!strcmp(key, "addhosts")) {
132                 strncpy(my_add_hosts, value, MAX_FILE);
133                 printf("\nNAME PLUGIN: parameter additional host: %s\n", my_add_hosts);
134         }
135         else {
136                 // assume this is an IP address and hostname
137                 struct in_addr ip;
138                 
139                 if (inet_aton(key, &ip)) {
140                         // the IP is validated later
141                         struct name_entry *tmp;
142                         tmp = malloc(sizeof(struct name_entry));
143                         tmp->name = strndup( value, MAX_NAME );
144                         tmp->len = strlen( tmp->name );
145                         tmp->type = NAME_HOST;
146                         tmp->ip.v4 = ip.s_addr;
147                         tmp->next = my_names;
148                         my_names = tmp;
149                         printf("\nNAME PLUGIN: parameter %s (%s)\n", tmp->name,
150                                 olsr_ip_to_string(&tmp->ip));
151                 } 
152                 else {
153                         printf("\nNAME PLUGIN: invalid IP %s, fix your config!\n", key);
154                 }
155         }
156
157         return 1;
158 }
159
160
161 /**
162  * last initialization
163  *
164  * we have to do this here because some things like main_addr 
165  * are not known before
166  *
167  * this is beause of the order in which the plugin is initzalized 
168  * by the plugin loader:
169  *   - first the parameters are sent
170  *   - then register_olsr_data() from olsrd_plugin.c is called
171  *     which sets up main_addr and some other variables
172  *   - register_olsr_data() then then finally calls this function
173  */
174 int
175 olsr_plugin_init()
176 {
177         struct name_entry *name;
178         struct name_entry *prev=NULL;
179
180         /* fixup names and IP addresses */
181         for (name = my_names; name != NULL; name = name->next) {
182                 if (name->ip.v4 == 0) {
183                         // insert main_addr
184                         memcpy(&name->ip, main_addr, ipsize);
185                         prev = name;
186                 } else {
187                         // IP from config file
188                         // check if we are allowed to announce a name for this IP
189                         // we can only do this if we also announce the IP
190                          
191                         if (!allowed_ip(&name->ip)) {
192                                 olsr_printf(1, "NAME PLUGIN: name for unknown IP %s not allowed, fix your config!\n", 
193                                         olsr_ip_to_string(&name->ip));
194                                 if (prev!=NULL) {
195                                         prev->next = name->next;
196                                         free(name->name);
197                                         free(name);
198                                 }
199                         }
200                         else {
201                                 prev = name;
202                         }
203                 }
204         }
205         
206         /* register functions with olsrd */
207         olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
208         olsr_register_timeout_function(&olsr_timeout);
209         olsr_register_scheduler_event(&olsr_event, NULL, my_interval, 0, NULL);
210
211         return 1;
212 }
213
214
215 /**
216  * called at unload: free everything
217  */
218 void
219 olsr_plugin_exit()
220 {
221         int i;
222         struct db_entry **tmp;
223         struct db_entry *to_delete;
224         
225         olsr_printf(2, "NAME PLUGIN: exit. cleaning up...\n");
226         
227         free_name_entry_list(&my_names);
228         
229         /* free list entries */
230         for(i = 0; i < HASHSIZE; i++)
231         {
232                 tmp = &list[i];
233                 while(*tmp != NULL)
234                 {
235                         to_delete = *tmp;
236                         *tmp = (*tmp)->next;
237                         free_name_entry_list(&to_delete->names);
238                         free(to_delete);
239                         to_delete = NULL;
240                 }
241         }
242 }
243
244
245 /**
246  * A timeout function called every time
247  * the scheduler is polled: time out old list entries
248  */
249 void
250 olsr_timeout()
251 {
252         struct db_entry **tmp;
253         struct db_entry *to_delete;
254         int index;
255
256         for(index=0;index<HASHSIZE;index++)
257         {
258                 for (tmp = &list[index]; *tmp != NULL; )
259                 {
260                         /* check if the entry is timed out */
261                         if (olsr_timed_out(&(*tmp)->timer))
262                         {
263                                 to_delete = *tmp;
264                                 *tmp = (*tmp)->next;
265                                 
266                                 olsr_printf(2, "NAME PLUGIN: %s timed out... deleting\n", 
267                                         olsr_ip_to_string(&to_delete->originator));
268         
269                                 /* Delete */
270                                 free_name_entry_list(&to_delete->names);
271                                 free(to_delete);
272                                 name_table_changed = OLSR_TRUE;
273                         } else {
274                                 tmp = &(*tmp)->next;
275                         }
276                 }
277         }
278         write_name_table();
279 }
280
281
282 /**
283  * Scheduled event: generate and send NAME packet
284  */
285 void
286 olsr_event(void *foo)
287 {
288         union olsr_message *message = (union olsr_message*)buffer;
289         struct interface *ifn;
290         int namesize;
291   
292         /* looping trough interfaces */
293         for (ifn = ifs; ifn ; ifn = ifn->int_next) 
294         {
295                 olsr_printf(3, "NAME PLUGIN: Generating packet - [%s]\n", ifn->int_name);
296
297                 /* fill message */
298                 if(ipversion == AF_INET)
299                 {
300                         /* IPv4 */
301                         message->v4.olsr_msgtype = MESSAGE_TYPE;
302                         message->v4.olsr_vtime = double_to_me(my_timeout);
303                         memcpy(&message->v4.originator, main_addr, ipsize);
304                         message->v4.ttl = MAX_TTL;
305                         message->v4.hopcnt = 0;
306                         message->v4.seqno = htons(get_msg_seqno());
307                         
308                         namesize = encap_namemsg((struct namemsg*)&message->v4.message);
309                         namesize = namesize + sizeof(struct olsrmsg);
310                         
311                         message->v4.olsr_msgsize = htons(namesize);
312                 }
313                 else
314                 {
315                         /* IPv6 */
316                         message->v6.olsr_msgtype = MESSAGE_TYPE;
317                         message->v6.olsr_vtime = double_to_me(my_timeout);
318                         memcpy(&message->v6.originator, main_addr, ipsize);
319                         message->v6.ttl = MAX_TTL;
320                         message->v6.hopcnt = 0;
321                         message->v6.seqno = htons(get_msg_seqno());
322                         
323                         namesize = encap_namemsg((struct namemsg*)&message->v6.message);
324                         namesize = namesize + sizeof(struct olsrmsg6);
325                         
326                         message->v6.olsr_msgsize = htons(namesize);
327                 }
328                 
329                 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
330                         /* send data and try again */
331                         net_output(ifn);
332                         if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
333                                 olsr_printf(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
334                         }
335                 }
336         }
337 }
338
339
340 /**
341  * Parse name olsr message of NAME type
342  */
343 void
344 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
345 {
346         struct namemsg *namemessage;
347         union olsr_ip_addr originator;
348         double vtime;
349         int size;
350
351         /* Fetch the originator of the messsage */
352         memcpy(&originator, &m->v4.originator, ipsize);
353                 
354         /* Fetch the message based on IP version */
355         if(ipversion == AF_INET) {
356                 vtime = me_to_double(m->v4.olsr_vtime);
357                 size = ntohs(m->v4.olsr_msgsize);
358                 namemessage = (struct namemsg*)&m->v4.message;
359         }
360         else {
361                 vtime = me_to_double(m->v6.olsr_vtime);
362                 size = ntohs(m->v6.olsr_msgsize);
363                 namemessage = (struct namemsg*)&m->v4.message;
364         }
365
366         /* Check if message originated from this node. 
367         If so - back off */
368         if(memcmp(&originator, main_addr, ipsize) == 0)
369                 return;
370
371         /* Check that the neighbor this message was received from is symmetric. 
372         If not - back off*/
373         if(check_neighbor_link(in_addr) != SYM_LINK) {
374                 olsr_printf(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
375                 return;
376         }
377
378         /* Check if this message has been processed before
379         * Remeber that this also registeres the message as
380         * processed if nessecary
381         */
382         if(!check_dup_proc(&originator, ntohs(m->v4.seqno))) {
383                 /* If so - do not process */
384                 goto forward;
385         }
386
387         update_name_entry(&originator, namemessage, size, vtime);
388
389 forward:
390         /* Forward the message if nessecary
391         * default_fwd does all the work for us! */
392         default_fwd(m, &originator, ntohs(m->v4.seqno), in_if, in_addr);
393 }
394
395
396 /**
397  * Encapsulate a name message into a packet. 
398  *
399  * It assumed that there is enough space in the buffer to do this!
400  *
401  * Returns: the length of the message that was appended
402  */
403 int
404 encap_namemsg(struct namemsg* msg)
405 {
406         struct name_entry *my_name = my_names;
407         struct name* to_packet;
408         char* pos = (char*)msg + sizeof(struct namemsg);
409         short i=0;
410         int k;
411         for (my_name = my_names; my_name!=NULL; my_name = my_name->next)
412         {
413                 olsr_printf(3, "NAME PLUGIN: Announcing name %s (%s) %d\n", 
414                         my_name->name, olsr_ip_to_string(&my_name->ip), my_name->len);
415                         
416                 to_packet = (struct name*)pos;
417                 to_packet->type = htons(my_name->type);
418                 to_packet->len = htons(my_name->len);
419                 memcpy(&to_packet->ip, &my_name->ip, ipsize);
420                 pos += sizeof(struct name);
421                 strncpy(pos, my_name->name, my_name->len);
422                 pos += my_name->len;
423                 // padding to 4 byte boundaries
424                 for (k = my_name->len; (k & 3) != 0; k++)
425                         *pos++ = '\0';
426                 i++;
427         }
428         msg->nr_names = htons(i);
429         msg->version = htons(NAME_PROTOCOL_VERSION);
430         return pos - (char*)msg; //length
431 }
432
433
434 /**
435  * decapsulate a name message and update name_entries if necessary
436  */
437 void
438 decap_namemsg( struct namemsg *msg, int size, struct name_entry **to )
439 {
440         char *pos, *end_pos;
441         struct name_entry *tmp;
442         struct name *from_packet; 
443         int i;
444         
445         olsr_printf(4, "NAME PLUGIN: decapsulating name msg (size %d)\n", size);
446         
447         if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) {
448                 olsr_printf(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version);
449                 return;
450         }
451         
452         // for now ist easier to just delete everything, than
453         // to update selectively
454         free_name_entry_list(to);
455         
456         /* now add the names from the message */
457         pos = (char*)msg + sizeof(struct namemsg);
458         end_pos = pos + size - sizeof(struct name*); // at least one struct name hast to be left
459         
460         for (i=ntohs(msg->nr_names); i > 0 && pos<end_pos; i--) 
461         {
462                 from_packet = (struct name*)pos;
463                 
464                 tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry");         
465                 tmp->type = ntohs(from_packet->type);
466                 tmp->len = ntohs(from_packet->len) > MAX_NAME ? MAX_NAME : ntohs(from_packet->len);
467                 tmp->name = olsr_malloc(tmp->len+1, "new name_entry name");
468                 memcpy(&tmp->ip, &from_packet->ip, ipsize);
469                 pos += sizeof(struct name);
470                 strncpy(tmp->name, pos, tmp->len);
471                 tmp->name[tmp->len] = '\0';
472
473                 olsr_printf(3, "NAME PLUGIN: New name %s (%s) %d %d\n", 
474                         tmp->name, olsr_ip_to_string(&tmp->ip), tmp->len, tmp->type);
475
476                 // queue to front
477                 tmp->next = *to;
478                 *to = tmp;
479
480                 // name + padding
481                 pos += 1 + ((tmp->len - 1) | 3);
482         }
483         if (i!=0)
484                 olsr_printf(4, "NAME PLUGIN: Lost %d names due to length inconsistency\n", i);
485 }
486
487
488 /**
489  * Update or register a new name entry
490  */
491 void
492 update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, double vtime)
493 {
494         int hash;
495         struct db_entry *entry;
496
497         olsr_printf(3, "NAME PLUGIN: Received Name Message from %s\n", 
498                 olsr_ip_to_string(originator));
499
500         hash = olsr_hashing(originator);
501
502         /* find the entry for originator */
503         for (entry = list[hash]; entry != NULL; entry = entry->next)
504         {
505                 if (memcmp(originator, &entry->originator, ipsize) == 0) {
506                         // found
507                         olsr_printf(4, "NAME PLUGIN: %s found\n", 
508                                 olsr_ip_to_string(originator));
509                 
510                         decap_namemsg(msg, msg_size, &entry->names);
511                         
512                         olsr_get_timestamp(vtime * 1000, &entry->timer);
513                         
514                         name_table_changed = OLSR_TRUE;
515                         return;
516                 }
517         }
518
519         olsr_printf(3, "NAME PLUGIN: New entry %s\n", 
520                 olsr_ip_to_string(originator));
521                 
522         /* insert a new entry */
523         entry = olsr_malloc(sizeof(struct db_entry), "new db_entry");
524         memcpy(&entry->originator, originator, ipsize);
525         olsr_get_timestamp(vtime * 1000, &entry->timer);
526         entry->names = NULL;
527         // queue to front
528         entry->next = list[hash];
529         list[hash] = entry;
530         
531         decap_namemsg(msg, msg_size, &entry->names);
532
533         name_table_changed = OLSR_TRUE;
534 }
535
536
537 /**
538  * write names to a file in /etc/hosts compatible format
539  */
540 void
541 write_name_table()
542 {
543         int hash;
544         struct name_entry *name;
545         struct db_entry *entry;
546         FILE* hosts;
547         FILE* add_hosts;
548         int c=0;
549         time_t currtime;
550   
551         if(!name_table_changed)
552                 return;
553
554         olsr_printf(2, "NAME PLUGIN: writing hosts file\n");
555                       
556         hosts = fopen( my_filename, "w" );
557         if (hosts == NULL) {
558                 olsr_printf(2, "NAME PLUGIN: cant write hosts file\n");
559                 return;
560         }
561         
562         fprintf(hosts, "### this /etc/hosts file is overwritten regularly by olsrd\n");
563         fprintf(hosts, "### do not edit\n\n");
564         
565         // copy content from additional hosts filename
566         if (my_add_hosts[0] != '\0') {
567                 add_hosts = fopen( my_add_hosts, "r" );
568                 if (add_hosts == NULL) {
569                         olsr_printf(2, "NAME PLUGIN: cant open additional hosts file\n");
570                 }
571                 else {
572                         fprintf(hosts, "### contents from '%s' ###\n\n", my_add_hosts);
573                         while ((c = getc(add_hosts)) != EOF)
574                                 putc(c, hosts);
575                 }
576                 fclose(add_hosts);              
577                 fprintf(hosts, "\n### olsr names ###\n\n");
578         }
579         
580         // write own names
581         for (name = my_names; name != NULL; name = name->next) {
582                 fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&name->ip),
583                         name->name, my_suffix );
584         }
585         
586         // write received names
587         for(hash = 0; hash < HASHSIZE; hash++) 
588         {
589                 for(entry = list[hash]; entry != NULL; entry = entry->next)
590                 {
591                         for (name = entry->names; name != NULL; name = name->next) 
592                         {
593                                 olsr_printf(6, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
594                                 olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator));
595                                 
596                                 fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
597                                 fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&entry->originator));
598                         }
599                 }
600         }
601
602         if(time(&currtime)) {
603                 fprintf(hosts, "\n### written by olsrd at %s", ctime(&currtime));
604         }
605           
606         fclose(hosts);
607         name_table_changed = OLSR_FALSE;
608 }
609
610 /**
611  * completely free a list of name_entries
612  */
613 void 
614 free_name_entry_list(struct name_entry **list) 
615 {
616         struct name_entry **tmp = list;
617         struct name_entry *to_delete;
618         while (*tmp != NULL) {
619                 to_delete = *tmp;
620                 *tmp = (*tmp)->next;
621                 free( to_delete->name );
622                 free( to_delete );
623                 to_delete = NULL;
624         }
625 }
626
627
628 /**
629  * we only allow names for IP addresses which we are
630  * responsible for: 
631  * so the IP must either be from one of the interfaces
632  * or inside a HNA which we have configured 
633  */
634 olsr_bool
635 allowed_ip(union olsr_ip_addr *addr)
636 {
637         struct hna4_entry *hna4;
638         struct olsr_if *ifs;
639         
640         olsr_printf(6, "checking %s\n", olsr_ip_to_string(addr));
641         
642         for(ifs = cfg->interfaces; ifs; ifs = ifs->next)
643         {
644                 struct interface *rifs = ifs->interf;
645                 olsr_printf(6, "interface %s\n", olsr_ip_to_string(&rifs->ip_addr));
646                 if (COMP_IP(&rifs->ip_addr, addr)) {
647                         olsr_printf(6, "MATCHED\n");
648                         return OLSR_TRUE;
649                         
650                 }
651         }
652         
653         for (hna4 = cfg->hna4_entries; hna4; hna4 = hna4->next)
654         {
655                 olsr_printf(6, "HNA %s/%s\n", 
656                         olsr_ip_to_string(&hna4->net),
657                         olsr_ip_to_string(&hna4->netmask));
658                 
659                 if ( hna4->netmask.v4 != 0 && (addr->v4 & hna4->netmask.v4) == hna4->net.v4 ) {
660                         olsr_printf(6, "MATCHED\n");
661                         return OLSR_TRUE;
662                 }
663         }
664         return OLSR_FALSE;
665 }