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