eacf2b93c870f8433276492cb4d608e44c1d1bfc
[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.6 2005/03/02 22:59:55 tlopatic 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_suffix[MAX_SUFFIX];
52 int my_interval = EMISSION_INTERVAL;
53 double my_timeout = NAME_VALID_TIME;
54
55 /* the database (using hashing) */
56 struct db_entry* list[HASHSIZE];
57 struct name_entry *my_names = NULL;
58 olsr_bool name_table_changed = OLSR_TRUE;
59
60 void
61 name_constructor() {
62 #ifdef WIN32
63         int len;
64
65         GetWindowsDirectory(my_filename, MAX_FILE - 12);
66
67         len = strlen(my_filename);
68  
69         if (my_filename[len - 1] != '\\')
70                 my_filename[len++] = '\\';
71  
72         strcpy(my_filename + len, "olsrd.hosts");
73 #else
74         strcpy(my_filename, "/var/run/hosts_olsr");
75 #endif
76         my_suffix[0] = '\0';
77 }
78
79
80 void 
81 free_name_entry_list(struct name_entry **list) 
82 {
83         struct name_entry **tmp = list;
84         struct name_entry *to_delete;
85         while (*tmp != NULL) {
86                 to_delete = *tmp;
87                 *tmp = (*tmp)->next;
88                 free( to_delete->name );
89                 free( to_delete );
90                 to_delete = NULL;
91         }
92 }
93
94
95 olsr_bool
96 allowed_ip(union olsr_ip_addr *addr)
97 {
98         // we only allow names for IP addresses which announce
99         // so the IP must either be from one of the interfaces
100         // or inside a HNA which we have configured
101         
102         struct hna4_entry *hna4;
103         struct olsr_if *ifs;
104         
105         olsr_printf(6, "checking %s\n", olsr_ip_to_string(addr));
106         
107         for(ifs = cfg->interfaces; ifs; ifs = ifs->next)
108         {
109                 struct interface *rifs = ifs->interf;
110                 olsr_printf(6, "interface %s\n", olsr_ip_to_string(&rifs->ip_addr));
111                 if (COMP_IP(&rifs->ip_addr, addr)) {
112                         olsr_printf(6, "MATCHED\n");
113                         return OLSR_TRUE;
114                         
115                 }
116         }
117         
118         for (hna4 = cfg->hna4_entries; hna4; hna4 = hna4->next)
119         {
120                 olsr_printf(6, "HNA %s/%s\n", 
121                         olsr_ip_to_string(&hna4->net),
122                         olsr_ip_to_string(&hna4->netmask));
123                 
124                 if ( hna4->netmask.v4 != 0 && (addr->v4 & hna4->netmask.v4) == hna4->net.v4 ) {
125                         olsr_printf(6, "MATCHED\n");
126                         return OLSR_TRUE;
127                 }
128         }
129         return OLSR_FALSE;
130 }
131
132
133 /**
134  * Do initialization
135  */
136 int
137 olsr_plugin_init()
138 {
139         int i;
140
141         /* Init list */
142         for(i = 0; i < HASHSIZE; i++) {
143                 list[i] = NULL;
144         }
145         
146         /* fix received parameters */
147         // we have to do this here because some things like main_addr 
148         // are not known before
149         struct name_entry *name;
150         for (name = my_names; name != NULL; name = name->next) {
151                 if (name->ip.v4 == 0) {
152                         // insert main_addr
153                         memcpy(&name->ip, main_addr, ipsize);
154                 } else {
155                         // IP from config file
156                         // check if we are allowed to announce a name for this IP
157                         // we can only do this if we also announce the IP
158                          
159                         if (!allowed_ip(&name->ip)) {
160                                 olsr_printf(1, "NAME PLUGIN: name for unknown IP %s not allowed, fix your config!\n", 
161                                         olsr_ip_to_string(&name->ip));
162                                         exit(-1);
163                         }       
164                 }
165         }
166         
167         /* Register functions with olsrd */
168         olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
169         olsr_register_timeout_function(&olsr_timeout);
170         olsr_register_scheduler_event(&olsr_event, NULL, my_interval, 0, NULL);
171
172         return 1;
173 }
174
175
176 /**
177  * Called at unload
178  */
179 void
180 olsr_plugin_exit()
181 {
182         int i;
183         struct db_entry **tmp;
184         struct db_entry *to_delete;
185         
186         olsr_printf(2, "NAME PLUGIN: exit. cleaning up...\n");
187         
188         free_name_entry_list(&my_names);
189         
190         /* free list entries */
191         for(i = 0; i < HASHSIZE; i++)
192         {
193                 tmp = &list[i];
194                 while(*tmp != NULL)
195                 {
196                         to_delete = *tmp;
197                         *tmp = (*tmp)->next;
198                         free_name_entry_list(&to_delete->names);
199                         free(to_delete);
200                         to_delete = NULL;
201                 }
202         }
203 }
204
205
206 /**
207  * Called for all plugin parameters
208  */
209 int
210 register_olsr_param(char *key, char *value)
211 {
212         if(!strcmp(key, "name")) {
213                 // name for main address
214                 struct name_entry *tmp;
215                 tmp = malloc(sizeof(struct name_entry));
216                 tmp->name = strndup( value, MAX_NAME );
217                 tmp->len = strlen( tmp->name );
218                 tmp->type = NAME_HOST;
219                 // will be set to main_addr later
220                 memset(&tmp->ip, 0, sizeof(tmp->ip));
221                 tmp->next = my_names;
222                 my_names = tmp;
223                 
224                 printf("\nNAME PLUGIN parameter name: %s (%s)\n", tmp->name, olsr_ip_to_string(&tmp->ip));
225         } 
226         else if(!strcmp(key, "filename")) {
227                 strncpy( my_filename, value, MAX_FILE );
228                 printf("\nNAME PLUGIN parameter filename: %s\n", my_filename);
229         }
230         else if(!strcmp(key, "interval")) {
231                 my_interval = atoi(value);
232                 printf("\n(NAME PLUGIN parameter interval: %d\n", my_interval);
233         }
234         else if(!strcmp(key, "timeout")) {
235                 my_timeout = atof(value);
236                 printf("\nNAME PLUGIN parameter timeout: %f\n", my_timeout);
237         }
238         else if(!strcmp(key, "suffix")) {
239                 strncpy(my_suffix, value, MAX_SUFFIX);
240                 printf("\nNAME PLUGIN parameter suffix: %s\n", my_suffix);
241         }
242
243         else {
244                 // assume this is an IP address and hostname
245                 // the IPs are validated later
246                 struct name_entry *tmp;
247                 tmp = malloc(sizeof(struct name_entry));
248                 tmp->name = strndup( value, MAX_NAME );
249                 tmp->len = strlen( tmp->name );
250                 tmp->type = NAME_HOST;
251                 struct in_addr ip;
252                 if (!inet_aton(key, &ip)) {
253                         printf("\nNAME PLUGIN invalid IP %s, fix your config!\n", key);
254                         exit(-1);
255                 }
256                 tmp->ip.v4 = ip.s_addr;
257                 tmp->next = my_names;
258                 my_names = tmp;
259                 
260                 printf("\nNAME PLUGIN parameter: %s (%s)\n", tmp->name, olsr_ip_to_string(&tmp->ip));
261         }
262                 
263         return 1;
264 }
265
266
267 /**
268  * A timeout function called every time
269  * the scheduler is polled: time out old list entries
270  */
271 void
272 olsr_timeout()
273 {
274         struct db_entry **tmp;
275         struct db_entry *to_delete;
276         int index;
277
278         for(index=0;index<HASHSIZE;index++)
279         {
280                 for (tmp = &list[index]; *tmp != NULL; )
281                 {
282                         /* check if the entry is timed out */
283                         if (olsr_timed_out(&(*tmp)->timer))
284                         {
285                                 to_delete = *tmp;
286                                 *tmp = (*tmp)->next;
287                                 
288                                 olsr_printf(2, "NAME PLUGIN: %s timed out... deleting\n", 
289                                         olsr_ip_to_string(&to_delete->originator));
290         
291                                 /* Delete */
292                                 free_name_entry_list(&to_delete->names);
293                                 free(to_delete);
294                                 name_table_changed = OLSR_TRUE;
295                         } else {
296                                 tmp = &(*tmp)->next;
297                         }
298                 }
299         }
300         write_name_table();
301 }
302
303
304 /**
305  * Scheduled event: generate and send NAME packet
306  */
307 void
308 olsr_event(void *foo)
309 {
310         union olsr_message *message = (union olsr_message*)buffer;
311         struct interface *ifn;
312         int namesize;
313   
314         olsr_printf(3, "NAME PLUGIN: Generating packet - ");
315
316         /* looping trough interfaces */
317         for (ifn = ifs; ifn ; ifn = ifn->int_next) 
318         {
319                 olsr_printf(3, "[%s]\n", ifn->int_name);
320                 /* fill message */
321                 if(ipversion == AF_INET)
322                 {
323                         /* IPv4 */
324                         message->v4.olsr_msgtype = MESSAGE_TYPE;
325                         message->v4.olsr_vtime = double_to_me(my_timeout);
326                         memcpy(&message->v4.originator, main_addr, ipsize);
327                         message->v4.ttl = MAX_TTL;
328                         message->v4.hopcnt = 0;
329                         message->v4.seqno = htons(get_msg_seqno());
330                 
331                         namesize = encap_namemsg(&message->v4.msg);
332                         namesize = namesize + sizeof(struct olsrmsg);
333                 
334                         message->v4.olsr_msgsize = htons(namesize);
335                 }
336                 else
337                 {
338                         /* IPv6 */
339                         message->v6.olsr_msgtype = MESSAGE_TYPE;
340                         message->v6.olsr_vtime = double_to_me(my_timeout);
341                         memcpy(&message->v6.originator, main_addr, ipsize);
342                         message->v6.ttl = MAX_TTL;
343                         message->v6.hopcnt = 0;
344                         message->v6.seqno = htons(get_msg_seqno());
345           
346                         namesize = encap_namemsg(&message->v6.msg);
347                         namesize = namesize + sizeof(struct olsrmsg6);
348           
349                         message->v6.olsr_msgsize = htons(namesize);
350                 }
351         
352                 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
353                         /* send data and try again */
354                         net_output(ifn);
355                         if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
356                                 olsr_printf(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
357                         }
358                 }
359         }
360 }
361
362
363 /**
364  * Parse name olsr message of NAME type
365  */
366 void
367 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
368 {
369         struct  namemsg *message;
370         union olsr_ip_addr originator;
371         double vtime;
372
373         /* Fetch the originator of the messsage */
374         memcpy(&originator, &m->v4.originator, ipsize);
375                 
376         /* Fetch the message based on IP version */
377         if(ipversion == AF_INET) {
378                 message = &m->v4.msg;
379                 vtime = me_to_double(m->v4.olsr_vtime);
380         }
381         else {
382                 message = &m->v6.msg;
383                 vtime = me_to_double(m->v6.olsr_vtime);
384         }
385
386         /* Check if message originated from this node. 
387         If so - back off */
388         if(memcmp(&originator, main_addr, ipsize) == 0)
389                 return;
390
391         /* Check that the neighbor this message was received from is symmetric. 
392         If not - back off*/
393         if(check_neighbor_link(in_addr) != SYM_LINK) {
394                 olsr_printf(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
395                 return;
396         }
397
398         /* Check if this message has been processed before
399         * Remeber that this also registeres the message as
400         * processed if nessecary
401         */
402         if(!check_dup_proc(&originator, ntohs(m->v4.seqno))) {
403                 /* If so - do not process */
404                 goto forward;
405         }
406
407         update_name_entry(&originator, message, vtime);
408
409 forward:
410         /* Forward the message if nessecary
411         * default_fwd does all the work for us! */
412         default_fwd(m, &originator, ntohs(m->v4.seqno), in_if, in_addr);
413 }
414
415
416 /**
417  * Encapsulate a name message into a packet. 
418  *
419  * It assumed that there is enough space in the buffer to do this!
420  *
421  * Returns: the length of the message that was appended
422  */
423 int
424 encap_namemsg(struct namemsg* msg)
425 {
426         struct name_entry *my_name = my_names;
427         struct name* to_packet;
428         char* pos = (char*)msg + sizeof(struct namemsg);
429         short i=0;
430         int k;
431         while (my_name!=NULL) 
432         {
433                 olsr_printf(3, "NAME PLUGIN: Announcing name %s (%s)\n", 
434                         my_name->name, olsr_ip_to_string(&my_name->ip));
435                         
436                 to_packet = (struct name*)pos;
437                 to_packet->type = htons(my_name->type);
438                 to_packet->len = htons(my_name->len);
439                 memcpy(&to_packet->ip, &my_name->ip, ipsize);
440                 pos += sizeof(struct name);
441                 strncpy(pos, my_name->name, my_name->len);
442                 pos += my_name->len;
443                 // padding to 4 byte boundaries
444                 for (k = my_name->len; (k & 3) != 0; k++)
445                   *pos++ = '\0';
446                 my_name = my_name->next;
447                 i++;
448         }
449         msg->nr_names = htons(i);
450         msg->version = htons(NAME_PROTOCOL_VERSION);
451         return pos - (char*)(msg + 1); //length
452 }
453
454
455 /**
456  * decapsulate a name message and update name_entries if necessary
457  */
458 void
459 decap_namemsg( struct namemsg *msg, struct name_entry **to )
460 {
461         char *pos;
462         struct name_entry *tmp;
463         struct name *from_packet; 
464         
465         olsr_printf(4, "NAME PLUGIN: decapsulating name msg\n");
466         
467         if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) {
468                 olsr_printf(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version);
469                 return;
470         }
471         
472         // for now ist easier to just delete everything, than
473         // to update selectively
474         free_name_entry_list(to);
475         
476         /* now add the names from the message */
477         pos = (char*)msg + sizeof(struct namemsg);
478         int i;
479         for (i=ntohs(msg->nr_names); i > 0; i--) {      
480                 tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry");
481                 
482                 from_packet = (struct name*)pos;
483                 from_packet->type = ntohs(from_packet->type);
484                 from_packet->len = ntohs(from_packet->len);
485                 tmp->type = from_packet->type;
486                 memcpy(&tmp->ip, &from_packet->ip, ipsize);
487                 
488                 tmp->name = olsr_malloc(from_packet->len+1, "new name_entry name");
489                 strncpy(tmp->name, (char*)from_packet+sizeof(struct name), from_packet->len);
490                 tmp->name[from_packet->len] = '\0';
491
492                 olsr_printf(3, "NAME PLUGIN: New name %s (%s) %d\n", 
493                         tmp->name, olsr_ip_to_string(&tmp->ip), from_packet->len);
494                         
495                 // queue to front
496                 tmp->next = *to;
497                 *to = tmp;
498
499                 // next name from packet
500                 pos += sizeof(struct name) + 1 + ((from_packet->len - 1) | 3);
501         }
502 }
503
504
505 /**
506  * Update or register a new name entry
507  */
508 void
509 update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, double vtime)
510 {
511         int hash;
512         struct db_entry *entry;
513
514         olsr_printf(3, "NAME PLUGIN: Received Name Message from %s\n", 
515                 olsr_ip_to_string(originator));
516
517         hash = olsr_hashing(originator);
518
519         /* find the entry for originator */
520         for (entry = list[hash]; entry != NULL; entry = entry->next)
521         {
522                 if (memcmp(originator, &entry->originator, ipsize) == 0) {
523                         // found
524                         olsr_printf(4, "NAME PLUGIN: %s found\n", 
525                                 olsr_ip_to_string(originator));
526                 
527                         decap_namemsg(msg, &entry->names);
528                         
529                         olsr_get_timestamp(vtime * 1000, &entry->timer);
530                         
531                         name_table_changed = OLSR_TRUE;
532                         return;
533                 }
534         }
535
536         olsr_printf(3, "NAME PLUGIN: New entry %s\n", 
537                 olsr_ip_to_string(originator));
538                 
539         /* insert a new entry */
540         entry = olsr_malloc(sizeof(struct db_entry), "new db_entry");
541         memcpy(&entry->originator, originator, ipsize);
542         olsr_get_timestamp(vtime * 1000, &entry->timer);
543         entry->names = NULL;
544         // queue to front
545         entry->next = list[hash];
546         list[hash] = entry;
547         
548         decap_namemsg(msg, &entry->names);
549
550         name_table_changed = OLSR_TRUE;
551 }
552
553
554 /**
555  * write names to a file in /etc/hosts compatible format
556  */
557 void
558 write_name_table()
559 {
560         int hash;
561         struct name_entry *name;
562         struct db_entry *entry;
563         FILE* hosts;
564
565         if(!name_table_changed)
566                 return;
567
568         olsr_printf(2, "NAME PLUGIN: writing hosts file\n");
569                       
570         hosts = fopen( my_filename, "w" );
571         if (hosts == NULL) {
572                 olsr_printf(2, "NAME PLUGIN: cant write hosts file\n");
573                 return;
574         }
575         
576         fprintf(hosts, "# this /etc/hosts file is overwritten regularly by olsrd\n");
577         fprintf(hosts, "# do not edit\n");
578         
579         // write own names
580         for (name = my_names; name != NULL; name = name->next) {
581                 fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&name->ip),
582                         name->name, my_suffix );
583         }
584         
585         // write received names
586         for(hash = 0; hash < HASHSIZE; hash++) 
587         {
588                 for(entry = list[hash]; entry != NULL; entry = entry->next)
589                 {
590                         for (name = entry->names; name != NULL; name = name->next) 
591                         {
592                                 olsr_printf(6, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
593                                 olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator));
594                                 
595                                 fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
596                                 fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&entry->originator));
597                         }
598                 }
599         }
600         
601         fclose(hosts);
602         name_table_changed = OLSR_FALSE;
603 }