2 * Copyright (c) 2005, Bruno Randolf <bruno.randolf@4g-systems.biz>
3 * Copyright (c) 2004, Andreas Tønnesen(andreto-at-olsr.org)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
32 /* $Id: nameservice.c,v 1.11 2005/04/20 17:57:00 br1 Exp $ */
35 * Dynamic linked library for UniK OLSRd
42 #include "nameservice.h"
43 #include "olsrd_copy.h"
45 #include "routing_table.h"
47 /* send buffer: huge */
48 static char buffer[10240];
50 /* config parameters */
51 static char my_hosts_file[MAX_FILE + 1];
52 static char my_add_hosts[MAX_FILE + 1];
53 static char my_suffix[MAX_SUFFIX];
54 static int my_interval = EMISSION_INTERVAL;
55 static double my_timeout = NAME_VALID_TIME;
56 static olsr_bool have_dns_server = OLSR_FALSE;
57 static union olsr_ip_addr my_dns_server;
58 static char my_resolv_file[MAX_FILE +1];
60 /* the database (using hashing) */
61 struct db_entry* list[HASHSIZE];
62 struct name_entry *my_names = NULL;
63 olsr_bool name_table_changed = OLSR_TRUE;
77 GetWindowsDirectory(my_hosts_file, MAX_FILE - 12);
79 len = strlen(my_hosts_file);
81 if (my_hosts_file[len - 1] != '\\')
82 my_hosts_file[len++] = '\\';
84 strcpy(my_hosts_file + len, "hosts_olsr");
86 strcpy(my_hosts_file, "/var/run/hosts_olsr");
90 my_add_hosts[0] = '\0';
91 my_resolv_file[0] = '\0';
94 for(i = 0; i < HASHSIZE; i++) {
98 memset(&my_dns_server, 0, sizeof(my_dns_server));
103 * called for all plugin parameters
106 register_olsr_param(char *key, char *value)
108 if(!strcmp(key, "interval")) {
109 my_interval = atoi(value);
110 printf("\nNAME PLUGIN: parameter interval: %d\n", my_interval);
112 else if(!strcmp(key, "timeout")) {
113 my_timeout = atof(value);
114 printf("\nNAME PLUGIN: parameter timeout: %f\n", my_timeout);
116 else if(!strcmp(key, "hosts-file")) {
117 strncpy( my_hosts_file, value, MAX_FILE );
118 printf("\nNAME PLUGIN: parameter filename: %s\n", my_hosts_file);
120 else if(!strcmp(key, "resolv-file")) {
121 strncpy(my_resolv_file, value, MAX_FILE);
122 printf("\nNAME PLUGIN: parameter resolv file: %s\n", my_resolv_file);
124 else if(!strcmp(key, "suffix")) {
125 strncpy(my_suffix, value, MAX_SUFFIX);
126 printf("\nNAME PLUGIN: parameter suffix: %s\n", my_suffix);
128 else if(!strcmp(key, "add-hosts")) {
129 strncpy(my_add_hosts, value, MAX_FILE);
130 printf("\nNAME PLUGIN: parameter additional host: %s\n", my_add_hosts);
132 else if(!strcmp(key, "dns-server")) {
134 if (strlen(value) == 0) {
135 // set dns server ip to main address
136 // which is not known yet
137 have_dns_server = OLSR_TRUE;
139 else if (inet_aton(value, &ip)) {
140 my_dns_server.v4 = ip.s_addr;
141 have_dns_server = OLSR_TRUE;
144 printf("\nNAME PLUGIN: invalid dns-server IP %s\n", value);
147 else if(!strcmp(key, "name")) {
148 // name for main address
149 struct name_entry *tmp;
150 tmp = malloc(sizeof(struct name_entry));
151 tmp->name = strndup( value, MAX_NAME );
152 tmp->len = strlen( tmp->name );
153 tmp->type = NAME_HOST;
154 // will be set to main_addr later
155 memset(&tmp->ip, 0, sizeof(tmp->ip));
156 tmp->next = my_names;
159 printf("\nNAME PLUGIN: parameter name: %s (main address)\n", tmp->name);
162 // assume this is an IP address and hostname
165 if (inet_aton(key, &ip)) {
166 // the IP is validated later
167 struct name_entry *tmp;
168 tmp = malloc(sizeof(struct name_entry));
169 tmp->name = strndup( value, MAX_NAME );
170 tmp->len = strlen( tmp->name );
171 tmp->type = NAME_HOST;
172 tmp->ip.v4 = ip.s_addr;
173 tmp->next = my_names;
175 printf("\nNAME PLUGIN: parameter %s (%s)\n", tmp->name,
176 olsr_ip_to_string(&tmp->ip));
179 printf("\nNAME PLUGIN: invalid IP %s for name %s!\n", key, value);
188 * last initialization
190 * we have to do this here because some things like main_addr
191 * are not known before
193 * this is beause of the order in which the plugin is initzalized
194 * by the plugin loader:
195 * - first the parameters are sent
196 * - then register_olsr_data() from olsrd_plugin.c is called
197 * which sets up main_addr and some other variables
198 * - register_olsr_data() then then finally calls this function
203 struct name_entry *name;
204 struct name_entry *prev=NULL;
206 /* fixup names and IP addresses */
207 for (name = my_names; name != NULL; name = name->next) {
208 if (name->ip.v4 == 0) {
210 memcpy(&name->ip, main_addr, ipsize);
213 // IP from config file
214 // check if we are allowed to announce a name for this IP
215 // we can only do this if we also announce the IP
216 if (!allowed_ip(&name->ip)) {
217 olsr_printf(1, "NAME PLUGIN: name for unknown IP %s not allowed, fix your config!\n",
218 olsr_ip_to_string(&name->ip));
220 prev->next = name->next;
231 if (have_dns_server) {
232 if (my_dns_server.v4 == 0) {
233 memcpy(&my_dns_server, main_addr, ipsize);
234 printf("\nNAME PLUGIN: announcing upstream DNS server: %s\n",
235 olsr_ip_to_string(&my_dns_server));
237 else if (!allowed_ip(&my_dns_server)) {
238 printf("NAME PLUGIN: announcing DNS server on unknown IP %s is not allowed, fix your config!\n",
239 olsr_ip_to_string(&my_dns_server));
240 memset(&my_dns_server, 0, sizeof(my_dns_server));
241 have_dns_server = OLSR_FALSE;
244 printf("\nNAME PLUGIN: announcing upstream DNS server: %s\n",
245 olsr_ip_to_string(&my_dns_server));
249 /* register functions with olsrd */
250 olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
251 olsr_register_timeout_function(&olsr_timeout);
252 olsr_register_scheduler_event(&olsr_event, NULL, my_interval, 0, NULL);
259 * called at unload: free everything
265 struct db_entry **tmp;
266 struct db_entry *to_delete;
268 olsr_printf(2, "NAME PLUGIN: exit. cleaning up...\n");
270 free_name_entry_list(&my_names);
272 /* free list entries */
273 for(i = 0; i < HASHSIZE; i++)
280 free_name_entry_list(&to_delete->names);
289 * A timeout function called every time
290 * the scheduler is polled: time out old list entries
291 * and write changes to file
296 struct db_entry **tmp;
297 struct db_entry *to_delete;
300 for(index=0;index<HASHSIZE;index++)
302 for (tmp = &list[index]; *tmp != NULL; )
304 /* check if the entry is timed out */
305 if (olsr_timed_out(&(*tmp)->timer))
310 olsr_printf(2, "NAME PLUGIN: %s timed out... deleting\n",
311 olsr_ip_to_string(&to_delete->originator));
314 free_name_entry_list(&to_delete->names);
316 name_table_changed = OLSR_TRUE;
328 * Scheduled event: generate and send NAME packet
331 olsr_event(void *foo)
333 union olsr_message *message = (union olsr_message*)buffer;
334 struct interface *ifn;
337 /* looping trough interfaces */
338 for (ifn = ifs; ifn ; ifn = ifn->int_next)
340 olsr_printf(3, "NAME PLUGIN: Generating packet - [%s]\n", ifn->int_name);
343 if(ipversion == AF_INET)
346 message->v4.olsr_msgtype = MESSAGE_TYPE;
347 message->v4.olsr_vtime = double_to_me(my_timeout);
348 memcpy(&message->v4.originator, main_addr, ipsize);
349 message->v4.ttl = MAX_TTL;
350 message->v4.hopcnt = 0;
351 message->v4.seqno = htons(get_msg_seqno());
353 namesize = encap_namemsg((struct namemsg*)&message->v4.message);
354 namesize = namesize + sizeof(struct olsrmsg);
356 message->v4.olsr_msgsize = htons(namesize);
361 message->v6.olsr_msgtype = MESSAGE_TYPE;
362 message->v6.olsr_vtime = double_to_me(my_timeout);
363 memcpy(&message->v6.originator, main_addr, ipsize);
364 message->v6.ttl = MAX_TTL;
365 message->v6.hopcnt = 0;
366 message->v6.seqno = htons(get_msg_seqno());
368 namesize = encap_namemsg((struct namemsg*)&message->v6.message);
369 namesize = namesize + sizeof(struct olsrmsg6);
371 message->v6.olsr_msgsize = htons(namesize);
374 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
375 /* send data and try again */
377 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, namesize) != namesize ) {
378 olsr_printf(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
386 * Parse name olsr message of NAME type
389 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
391 struct namemsg *namemessage;
392 union olsr_ip_addr originator;
396 /* Fetch the originator of the messsage */
397 memcpy(&originator, &m->v4.originator, ipsize);
399 /* Fetch the message based on IP version */
400 if(ipversion == AF_INET) {
401 vtime = me_to_double(m->v4.olsr_vtime);
402 size = ntohs(m->v4.olsr_msgsize);
403 namemessage = (struct namemsg*)&m->v4.message;
406 vtime = me_to_double(m->v6.olsr_vtime);
407 size = ntohs(m->v6.olsr_msgsize);
408 namemessage = (struct namemsg*)&m->v4.message;
411 /* Check if message originated from this node.
413 if(memcmp(&originator, main_addr, ipsize) == 0)
416 /* Check that the neighbor this message was received from is symmetric.
418 if(check_neighbor_link(in_addr) != SYM_LINK) {
419 olsr_printf(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
423 /* Check if this message has been processed before
424 * Remeber that this also registeres the message as
425 * processed if nessecary
427 if(!check_dup_proc(&originator, ntohs(m->v4.seqno))) {
428 /* If so - do not process */
432 update_name_entry(&originator, namemessage, size, vtime);
435 /* Forward the message if nessecary
436 * default_fwd does all the work for us! */
437 default_fwd(m, &originator, ntohs(m->v4.seqno), in_if, in_addr);
442 * Encapsulate a name message into a packet.
444 * It assumed that there is enough space in the buffer to do this!
446 * Returns: the length of the message that was appended
449 encap_namemsg(struct namemsg* msg)
451 struct name_entry *my_name = my_names;
452 struct name* to_packet;
453 char* pos = (char*)msg + sizeof(struct namemsg);
457 // upstream dns server
458 if (have_dns_server) {
459 olsr_printf(3, "NAME PLUGIN: Announcing DNS server (%s)\n",
460 olsr_ip_to_string(&my_dns_server));
461 to_packet = (struct name*)pos;
462 to_packet->type = htons(NAME_FORWARDER);
463 to_packet->len = htons(0);
464 memcpy(&to_packet->ip, &my_dns_server, ipsize);
465 pos += sizeof(struct name);
470 for (my_name = my_names; my_name!=NULL; my_name = my_name->next)
472 olsr_printf(3, "NAME PLUGIN: Announcing name %s (%s) %d\n",
473 my_name->name, olsr_ip_to_string(&my_name->ip), my_name->len);
475 to_packet = (struct name*)pos;
476 to_packet->type = htons(my_name->type);
477 to_packet->len = htons(my_name->len);
478 memcpy(&to_packet->ip, &my_name->ip, ipsize);
479 pos += sizeof(struct name);
480 strncpy(pos, my_name->name, my_name->len);
482 // padding to 4 byte boundaries
483 for (k = my_name->len; (k & 3) != 0; k++)
487 msg->nr_names = htons(i);
488 msg->version = htons(NAME_PROTOCOL_VERSION);
489 return pos - (char*)msg; //length
494 * decapsulate a name message and update name_entries if necessary
497 decap_namemsg( struct namemsg *msg, int size, struct name_entry **to )
500 struct name_entry *tmp;
501 struct name *from_packet;
504 olsr_printf(4, "NAME PLUGIN: decapsulating name msg (size %d)\n", size);
506 if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) {
507 olsr_printf(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version);
511 // for now ist easier to just delete everything, than
512 // to update selectively
513 free_name_entry_list(to);
514 name_table_changed = OLSR_TRUE;
516 /* now add the names from the message */
517 pos = (char*)msg + sizeof(struct namemsg);
518 end_pos = pos + size - sizeof(struct name*); // at least one struct name has to be left
520 for (i=ntohs(msg->nr_names); i > 0 && pos<end_pos; i--)
522 from_packet = (struct name*)pos;
524 tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry");
525 tmp->type = ntohs(from_packet->type);
526 tmp->len = ntohs(from_packet->len) > MAX_NAME ? MAX_NAME : ntohs(from_packet->len);
527 tmp->name = olsr_malloc(tmp->len+1, "new name_entry name");
528 memcpy(&tmp->ip, &from_packet->ip, ipsize);
529 pos += sizeof(struct name);
530 strncpy(tmp->name, pos, tmp->len);
531 tmp->name[tmp->len] = '\0';
533 olsr_printf(3, "NAME PLUGIN: New name %s (%s) %d %d\n",
534 tmp->name, olsr_ip_to_string(&tmp->ip), tmp->len, tmp->type);
541 pos += 1 + ((tmp->len - 1) | 3);
544 olsr_printf(4, "NAME PLUGIN: Lost %d names due to length inconsistency\n", i);
549 * Update or register a new name entry
552 update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, double vtime)
555 struct db_entry *entry;
557 olsr_printf(3, "NAME PLUGIN: Received Name Message from %s\n",
558 olsr_ip_to_string(originator));
560 hash = olsr_hashing(originator);
562 /* find the entry for originator */
563 for (entry = list[hash]; entry != NULL; entry = entry->next)
565 if (memcmp(originator, &entry->originator, ipsize) == 0) {
567 olsr_printf(4, "NAME PLUGIN: %s found\n",
568 olsr_ip_to_string(originator));
570 decap_namemsg(msg, msg_size, &entry->names);
572 olsr_get_timestamp(vtime * 1000, &entry->timer);
578 olsr_printf(3, "NAME PLUGIN: New entry %s\n",
579 olsr_ip_to_string(originator));
581 /* insert a new entry */
582 entry = olsr_malloc(sizeof(struct db_entry), "new db_entry");
583 memcpy(&entry->originator, originator, ipsize);
584 olsr_get_timestamp(vtime * 1000, &entry->timer);
587 entry->next = list[hash];
590 decap_namemsg(msg, msg_size, &entry->names);
592 name_table_changed = OLSR_TRUE;
597 * write names to a file in /etc/hosts compatible format
603 struct name_entry *name;
604 struct db_entry *entry;
610 if (!name_table_changed)
613 olsr_printf(2, "NAME PLUGIN: writing hosts file\n");
615 hosts = fopen( my_hosts_file, "w" );
617 olsr_printf(2, "NAME PLUGIN: cant write hosts file\n");
621 fprintf(hosts, "### this /etc/hosts file is overwritten regularly by olsrd\n");
622 fprintf(hosts, "### do not edit\n\n");
624 // copy content from additional hosts filename
625 if (my_add_hosts[0] != '\0') {
626 add_hosts = fopen( my_add_hosts, "r" );
627 if (add_hosts == NULL) {
628 olsr_printf(2, "NAME PLUGIN: cant open additional hosts file\n");
631 fprintf(hosts, "### contents from '%s' ###\n\n", my_add_hosts);
632 while ((c = getc(add_hosts)) != EOF)
636 fprintf(hosts, "\n### olsr names ###\n\n");
640 for (name = my_names; name != NULL; name = name->next) {
641 fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&name->ip),
642 name->name, my_suffix );
645 // write received names
646 for (hash = 0; hash < HASHSIZE; hash++)
648 for(entry = list[hash]; entry != NULL; entry = entry->next)
650 for (name = entry->names; name != NULL; name = name->next)
652 if (name->type == NAME_HOST) {
653 olsr_printf(6, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
654 olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator));
656 fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
657 fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&entry->originator));
663 if (time(&currtime)) {
664 fprintf(hosts, "\n### written by olsrd at %s", ctime(&currtime));
668 name_table_changed = OLSR_FALSE;
673 * write upstream DNS servers to resolv.conf file
679 struct name_entry *name;
680 struct db_entry *entry;
681 struct rt_entry *best_routes = NULL;
682 struct rt_entry *route, *tmp, *last;
686 if (my_resolv_file[0] == '\0')
689 if (!name_table_changed)
692 olsr_printf(2, "NAME PLUGIN: writing resolv file\n");
694 for (hash = 0; hash < HASHSIZE; hash++)
696 for(entry = list[hash]; entry != NULL; entry = entry->next)
698 for (name = entry->names; name != NULL; name = name->next)
700 if (name->type != NAME_FORWARDER)
703 /* find the nearest one */
704 route = olsr_lookup_routing_table(&name->ip);
705 if (route==NULL) // it's possible that route is not present yet
708 if (best_routes == NULL || route->rt_etx < best_routes->rt_etx) {
709 olsr_printf(6, "NAME PLUGIN: best nameserver %s\n",
710 olsr_ip_to_string(&route->rt_dst));
711 if (best_routes!=NULL)
712 olsr_printf(6, "NAME PLUGIN: better than %f (%s)\n",
714 olsr_ip_to_string(&best_routes->rt_dst));
716 tmp = olsr_malloc(sizeof(struct rt_entry), "new rt_entry");
717 memcpy(&tmp->rt_dst, &route->rt_dst, ipsize);
718 tmp->rt_etx = route->rt_etx;
719 tmp->next = best_routes;
722 // queue in etx order
724 while ( last->next!=NULL && i<3 ) {
725 if (last->next->rt_etx > route->rt_etx)
731 olsr_printf(6, "NAME PLUGIN: queue %f (%s)",
733 olsr_ip_to_string(&route->rt_dst));
734 olsr_printf(6, " after %f (%s)\n",
735 last->rt_etx, olsr_ip_to_string(&last->rt_dst));
737 tmp = olsr_malloc(sizeof(struct rt_entry), "new rt_entry");
738 memcpy(&tmp->rt_dst, &route->rt_dst, ipsize);
739 tmp->rt_etx = route->rt_etx;
740 tmp->next = last->next;
743 olsr_printf(6, "NAME PLUGIN: don't need more than 3 nameservers\n");
749 if (best_routes==NULL)
753 resolv = fopen( my_resolv_file, "w" );
754 if (resolv == NULL) {
755 olsr_printf(2, "NAME PLUGIN: can't write resolv file\n");
759 for (tmp=best_routes; tmp!=NULL && i<3; tmp=tmp->next) {
760 olsr_printf(6, "NAME PLUGIN: nameserver %s\n", olsr_ip_to_string(&tmp->rt_dst));
761 fprintf(resolv, "nameserver %s\n", olsr_ip_to_string(&tmp->rt_dst));
769 * completely free a list of name_entries
772 free_name_entry_list(struct name_entry **list)
774 struct name_entry **tmp = list;
775 struct name_entry *to_delete;
776 while (*tmp != NULL) {
779 free( to_delete->name );
787 * we only allow names for IP addresses which we are
789 * so the IP must either be from one of the interfaces
790 * or inside a HNA which we have configured
793 allowed_ip(union olsr_ip_addr *addr)
795 struct hna4_entry *hna4;
796 struct interface *iface;
798 olsr_printf(6, "checking %s\n", olsr_ip_to_string(addr));
800 for(iface = ifs; iface; iface = iface->int_next)
802 olsr_printf(6, "interface %s\n", olsr_ip_to_string(&iface->ip_addr));
803 if (COMP_IP(&iface->ip_addr, addr)) {
804 olsr_printf(6, "MATCHED\n");
809 for (hna4 = cfg->hna4_entries; hna4; hna4 = hna4->next)
811 olsr_printf(6, "HNA %s/%s\n",
812 olsr_ip_to_string(&hna4->net),
813 olsr_ip_to_string(&hna4->netmask));
815 if ( hna4->netmask.v4 != 0 && (addr->v4 & hna4->netmask.v4) == hna4->net.v4 ) {
816 olsr_printf(6, "MATCHED\n");