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)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
33 /* $Id: nameservice.c,v 1.23 2007/04/28 19:58:49 bernd67 Exp $ */
36 * Dynamic linked library for UniK OLSRd
44 #include <sys/types.h>
49 #include "routing_table.h"
51 #include "scheduler.h"
53 #include "duplicate_set.h"
56 #include "nameservice.h"
57 #include "olsrd_copy.h"
61 /* send buffer: huge */
62 static char buffer[10240];
64 /* config parameters */
65 static char my_hosts_file[MAX_FILE + 1];
66 static char my_add_hosts[MAX_FILE + 1];
67 static char my_suffix[MAX_SUFFIX];
68 static int my_interval = EMISSION_INTERVAL;
69 static double my_timeout = NAME_VALID_TIME;
70 static char my_resolv_file[MAX_FILE +1];
71 static char my_services_file[MAX_FILE + 1];
73 /* the databases (using hashing)
74 * for hostnames, service_lines and dns-servers
76 * my own hostnames, service_lines and dns-servers
77 * are store in a linked list (without hashing)
79 struct db_entry* list[HASHSIZE];
80 struct name_entry *my_names = NULL;
81 olsr_bool name_table_changed = OLSR_TRUE;
83 struct db_entry* service_list[HASHSIZE];
84 struct name_entry *my_services = NULL;
85 olsr_bool service_table_changed = OLSR_TRUE;
87 struct db_entry* forwarder_list[HASHSIZE];
88 struct name_entry *my_forwarders = NULL;
89 olsr_bool forwarder_table_changed = OLSR_TRUE;
91 /* regualar expression to be matched by valid hostnames, compiled in name_init() */
93 regmatch_t regmatch_t_name;
95 /* regualar expression to be matched by valid service_lines, compiled in name_init() */
96 regex_t regex_t_service;
97 int pmatch_service = 10;
98 regmatch_t regmatch_t_service[10];
100 static void free_routing_table_list(struct rt_entry **list) ;
101 static struct rt_entry *host_lookup_routing_table(union olsr_ip_addr *);
107 name_constructor(void)
114 GetWindowsDirectory(my_hosts_file, MAX_FILE - 12);
115 GetWindowsDirectory(my_services_file, MAX_FILE - 12);
117 len = strlen(my_hosts_file);
118 if (my_hosts_file[len - 1] != '\\')
119 my_hosts_file[len++] = '\\';
120 strcpy(my_hosts_file + len, "hosts_olsr");
122 len = strlen(my_services_file);
123 if (my_services_file[len - 1] != '\\')
124 my_services_file[len++] = '\\';
125 strcpy(my_services_file + len, "services_olsr");
127 len = strlen(my_resolv_file);
128 if (my_resolv_file[len - 1] != '\\')
129 my_resolv_file[len++] = '\\';
130 strcpy(my_resolv_file + len, "resolvconf_olsr");
132 strcpy(my_hosts_file, "/var/run/hosts_olsr");
133 strcpy(my_services_file, "/var/run/services_olsr");
134 strcpy(my_resolv_file, "/var/run/resolvconf_olsr");
138 my_add_hosts[0] = '\0';
141 for(i = 0; i < HASHSIZE; i++) {
143 forwarder_list[i] = NULL;
144 service_list[i] = NULL;
152 * called for all plugin parameters
155 olsrd_plugin_register_param(char *key, char *value)
157 if(!strcmp(key, "interval")) {
158 my_interval = atoi(value);
159 olsr_printf(1, "\nNAME PLUGIN: parameter interval: %d\n", my_interval);
161 else if(!strcmp(key, "timeout")) {
162 my_timeout = atof(value);
163 olsr_printf(1, "\nNAME PLUGIN: parameter timeout: %f\n", my_timeout);
165 else if(!strcmp(key, "hosts-file")) {
166 strncpy( my_hosts_file, value, MAX_FILE );
167 olsr_printf(1, "\nNAME PLUGIN: parameter filename: %s\n", my_hosts_file);
169 else if(!strcmp(key, "resolv-file")) {
170 strncpy(my_resolv_file, value, MAX_FILE);
171 olsr_printf(1, "\nNAME PLUGIN: parameter resolv file: %s\n", my_resolv_file);
173 else if(!strcmp(key, "suffix")) {
174 strncpy(my_suffix, value, MAX_SUFFIX);
175 olsr_printf(1, "\nNAME PLUGIN: parameter suffix: %s\n", my_suffix);
177 else if(!strcmp(key, "add-hosts")) {
178 strncpy(my_add_hosts, value, MAX_FILE);
179 olsr_printf(1, "\nNAME PLUGIN: parameter additional host: %s\n", my_add_hosts);
181 else if(!strcmp(key, "services-file")) {
182 strncpy(my_services_file, value, MAX_FILE);
183 olsr_printf(1,"\nNAME PLUGIN: parameter services-file: %s", my_services_file);
185 else if(!strcmp(key, "dns-server")) {
186 union olsr_ip_addr ip;
187 if (strlen(value) == 0) {
188 my_forwarders = add_name_to_list(my_forwarders, "", NAME_FORWARDER, NULL);
189 olsr_printf(1,"\nNAME PLUGIN: parameter dns-server: (main address)");
190 } else if (inet_pton(olsr_cnf->ip_version, value, &ip) > 0) {
191 my_forwarders = add_name_to_list(my_forwarders, "", NAME_FORWARDER, &ip);
192 olsr_printf(1,"\nNAME PLUGIN: parameter dns-server: (%s)", value);
194 olsr_printf(1,"\nNAME PLUGIN: invalid parameter dns-server: %s ", value);
197 else if(!strcmp(key, "name")) {
198 // name for main address
199 my_names = add_name_to_list(my_names, value, NAME_HOST, NULL);
200 olsr_printf(1,"\nNAME PLUGIN: parameter name: %s (main address)", value);
202 else if(!strcmp(key, "service")) {
203 // name for main address
204 my_services = add_name_to_list(my_services, value, NAME_SERVICE, NULL);
205 olsr_printf(1,"\nNAME PLUGIN: parameter service: %s (main address)", value);
208 // assume this is an IP address and hostname
209 union olsr_ip_addr ip;
211 if (inet_pton(olsr_cnf->ip_version, key, &ip) > 0) {
212 // the IP is validated later
213 my_names = add_name_to_list(my_names, value, NAME_HOST, &ip);
214 olsr_printf(1,"\nNAME PLUGIN: parameter name %s (%s)", value, key);
217 olsr_printf(1, "\nNAME PLUGIN: invalid IP %s for name %s!\n", key, value);
226 * queue the name/forwarder/service given in value
227 * to the front of my_list
230 add_name_to_list(struct name_entry *my_list, char *value, int type, const union olsr_ip_addr *ip)
232 struct name_entry *tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry add_name_to_list");
233 tmp->name = strndup( value, MAX_NAME );
234 tmp->len = strlen( tmp->name );
236 // all IPs with value 0 will be set to main_addr later
238 memset(&tmp->ip, 0, sizeof(tmp->ip));
247 * last initialization
249 * we have to do this here because some things like main_addr
250 * or the dns suffix (for validation) are not known before
252 * this is beause of the order in which the plugin is initialized
253 * by the plugin loader:
254 * - first the parameters are sent
255 * - then register_olsr_data() from olsrd_plugin.c is called
256 * which sets up main_addr and some other variables
257 * - register_olsr_data() then then finally calls this function
262 struct name_entry *name;
263 union olsr_ip_addr ipz;
266 //regex string for validating the hostnames
267 char *regex_name = "^[[:alnum:]_.-]+$";
268 //regex string for the service line
269 char *regex_service = olsr_malloc(256*sizeof(char) + strlen(my_suffix), "new *char from name_init for regex_service");
270 memset(&ipz, 0, sizeof(ipz));
272 //compile the regex from the string
273 if ((ret = regcomp(®ex_t_name, regex_name , REG_EXTENDED)) != 0)
275 /* #2: call regerror() if regcomp failed
276 * commented out, because only for debuggin needed
278 int errmsgsz = regerror(ret, ®ex_t_name, NULL, 0);
279 char *errmsg = malloc(errmsgsz);
280 regerror(ret, ®ex_t_name, errmsg, errmsgsz);
281 fprintf(stderr, "regcomp: %s", errmsg);
283 regfree(®ex_t_name);
285 olsr_printf(0, "compilation of regex \"%s\" for hostname failed", regex_name);
288 // a service line is something like prot://hostname.suffix:port|tcp|my little description about this service
289 // for example http://router.olsr:80|tcp|my homepage
290 // prot :// (hostname.suffix OR ip)
291 //regex_service = "^[[:alnum:]]+://(([[:alnum:]_.-]+.olsr)|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}))
292 // : port /path |(tcp OR udp) |short description
293 // :[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$";
294 strcat (strcat (strcat(regex_service, "^[[:alnum:]]+://(([[:alnum:]_.-]+"),
296 ")|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3})):[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$");
298 /* #1: call regcomp() to compile the regex */
299 if ((ret = regcomp(®ex_t_service, regex_service , REG_EXTENDED )) != 0)
301 /* #2: call regerror() if regcomp failed
302 * commented out, because only for debuggin needed
304 int errmsgsz = regerror(ret, ®ex_t_service, NULL, 0);
305 char *errmsg = malloc(errmsgsz);
306 regerror(ret, ®ex_t_service, errmsg, errmsgsz);
307 fprintf(stderr, "regcomp: %s", errmsg);
309 regfree(®ex_t_service);
311 olsr_printf(0, "compilation of regex \"%s\" for hostname failed", regex_name);
314 regex_service = NULL;
316 //fill in main addr for all entries with ip==0
317 //this does not matter for service, because the ip does not matter
320 for (name = my_names; name != NULL; name = name->next) {
321 if (memcmp(&name->ip, &ipz, olsr_cnf->ipsize) == 0) {
322 olsr_printf(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
323 memcpy(&name->ip, &olsr_cnf->main_addr, olsr_cnf->ipsize);
326 for (name = my_forwarders; name != NULL; name = name->next) {
327 if (name->ip.v4 == 0) {
328 olsr_printf(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
329 memcpy(&name->ip, &olsr_cnf->main_addr, olsr_cnf->ipsize);
333 //check if entries I want to announce myself are valid and allowed
334 my_names = remove_nonvalid_names_from_list(my_names, NAME_HOST);
335 my_forwarders = remove_nonvalid_names_from_list(my_forwarders, NAME_FORWARDER);
336 my_services = remove_nonvalid_names_from_list(my_services, NAME_SERVICE);
339 /* register functions with olsrd */
340 olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
341 olsr_register_timeout_function(&olsr_timeout);
342 olsr_register_scheduler_event(&olsr_event, NULL, my_interval, 0, NULL);
349 remove_nonvalid_names_from_list(struct name_entry *my_list, int type)
351 struct name_entry *next = my_list;
352 olsr_bool valid = OLSR_FALSE;
353 if (my_list == NULL) {
359 valid = is_name_wellformed(my_list->name) && allowed_ip(&my_list->ip);
362 valid = allowed_ip(&my_list->ip);
365 valid = allowed_service(my_list->name);
370 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));
371 next = my_list->next;
373 my_list->name = NULL;
376 return remove_nonvalid_names_from_list(next, type);
378 olsr_printf(2, "NAME PLUGIN: validate parameter %s (%s) -> OK\n", my_list->name, olsr_ip_to_string(&my_list->ip));
379 my_list->next = remove_nonvalid_names_from_list(my_list->next, type);
387 * called at unload: free everything
389 * XXX: should I delete the hosts/services/resolv.conf files on exit?
392 name_destructor(void)
394 olsr_printf(2, "NAME PLUGIN: exit. cleaning up...\n");
396 free_name_entry_list(&my_names);
397 free_name_entry_list(&my_services);
398 free_name_entry_list(&my_forwarders);
400 free_all_list_entries(list);
401 free_all_list_entries(service_list);
402 free_all_list_entries(forwarder_list);
404 regfree(®ex_t_name);
405 regfree(®ex_t_service);
409 /* free all list entries */
411 free_all_list_entries(struct db_entry **this_db_list)
415 for(i = 0; i < HASHSIZE; i++)
417 struct db_entry **tmp = &this_db_list[i];
420 struct db_entry *to_delete = *tmp;
422 free_name_entry_list(&to_delete->names);
431 * A timeout function called every time
433 * XXX:the scheduler is polled (by default 10 times a sec,
434 * which is far too often):
436 * time out old list entries
437 * and write changes to file
442 timeout_old_names(list, &name_table_changed);
443 timeout_old_names(forwarder_list, &forwarder_table_changed);
444 timeout_old_names(service_list, &service_table_changed);
448 write_services_file();
452 timeout_old_names(struct db_entry **this_list, olsr_bool *this_table_changed)
454 struct db_entry **tmp;
455 struct db_entry *to_delete;
458 for(index=0;index<HASHSIZE;index++)
460 for (tmp = &this_list[index]; *tmp != NULL; )
462 /* check if the entry for this ip is timed out */
463 if (olsr_timed_out(&(*tmp)->timer))
466 /* update the pointer in the linked list */
469 olsr_printf(2, "NAME PLUGIN: %s timed out... deleting\n",
470 olsr_ip_to_string(&to_delete->originator));
473 free_name_entry_list(&to_delete->names);
475 *this_table_changed = OLSR_TRUE;
485 * Scheduled event: generate and send NAME packet
488 olsr_event(void *foo __attribute__((unused)))
490 union olsr_message *message = (union olsr_message*)buffer;
491 struct interface *ifn;
494 /* looping trough interfaces */
495 for (ifn = ifnet; ifn ; ifn = ifn->int_next)
497 olsr_printf(3, "NAME PLUGIN: Generating packet - [%s]\n", ifn->int_name);
500 if(olsr_cnf->ip_version == AF_INET)
503 message->v4.olsr_msgtype = MESSAGE_TYPE;
504 message->v4.olsr_vtime = double_to_me(my_timeout);
505 memcpy(&message->v4.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
506 message->v4.ttl = MAX_TTL;
507 message->v4.hopcnt = 0;
508 message->v4.seqno = htons(get_msg_seqno());
510 namesize = encap_namemsg((struct namemsg*)&message->v4.message);
511 namesize = namesize + sizeof(struct olsrmsg);
513 message->v4.olsr_msgsize = htons(namesize);
518 message->v6.olsr_msgtype = MESSAGE_TYPE;
519 message->v6.olsr_vtime = double_to_me(my_timeout);
520 memcpy(&message->v6.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
521 message->v6.ttl = MAX_TTL;
522 message->v6.hopcnt = 0;
523 message->v6.seqno = htons(get_msg_seqno());
525 namesize = encap_namemsg((struct namemsg*)&message->v6.message);
526 namesize = namesize + sizeof(struct olsrmsg6);
528 message->v6.olsr_msgsize = htons(namesize);
531 if(net_outbuffer_push(ifn, message, namesize) != namesize ) {
532 /* send data and try again */
534 if(net_outbuffer_push(ifn, message, namesize) != namesize ) {
535 olsr_printf(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
543 * Parse name olsr message of NAME type
546 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *ipaddr)
548 struct namemsg *namemessage;
549 union olsr_ip_addr originator;
554 /* Fetch the originator of the messsage */
555 if(olsr_cnf->ip_version == AF_INET) {
556 memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);
557 seqno = ntohs(m->v4.seqno);
559 memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);
560 seqno = ntohs(m->v6.seqno);
563 /* Fetch the message based on IP version */
564 if(olsr_cnf->ip_version == AF_INET) {
565 vtime = ME_TO_DOUBLE(m->v4.olsr_vtime);
566 size = ntohs(m->v4.olsr_msgsize);
567 namemessage = (struct namemsg*)&m->v4.message;
570 vtime = ME_TO_DOUBLE(m->v6.olsr_vtime);
571 size = ntohs(m->v6.olsr_msgsize);
572 namemessage = (struct namemsg*)&m->v6.message;
575 /* Check if message originated from this node.
577 if(memcmp(&originator, &olsr_cnf->main_addr, olsr_cnf->ipsize) == 0)
580 /* Check that the neighbor this message was received from is symmetric.
582 if(check_neighbor_link(ipaddr) != SYM_LINK) {
583 olsr_printf(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(ipaddr));
587 /* Check if this message has been processed before
588 * Remeber that this also registeres the message as
589 * processed if nessecary
591 if(olsr_check_dup_table_proc(&originator, seqno)) {
592 /* If not so - process */
593 update_name_entry(&originator, namemessage, size, vtime);
596 /* Forward the message if nessecary
597 * default_fwd does all the work for us! */
598 olsr_forward_message(m, &originator, seqno, in_if, ipaddr);
603 * Encapsulate a name message into a packet.
605 * It assumed that there is enough space in the buffer to do this!
607 * Returns: the length of the message that was appended
610 encap_namemsg(struct namemsg* msg)
612 struct name_entry *my_name;
613 struct name_entry *my_service;
615 // add the hostname, service and forwarder entries after the namemsg header
616 char* pos = (char*)msg + sizeof(struct namemsg);
620 for (my_name = my_names; my_name!=NULL; my_name = my_name->next)
622 pos = create_packet( (struct name*) pos, my_name);
626 for (my_name = my_forwarders; my_name!=NULL; my_name = my_name->next)
628 pos = create_packet( (struct name*) pos, my_name);
632 for (my_service = my_services; my_service!=NULL; my_service = my_service->next)
634 pos = create_packet( (struct name*) pos, my_service);
638 // write the namemsg header with the number of announced entries and the protocol version
639 msg->nr_names = htons(i);
640 msg->version = htons(NAME_PROTOCOL_VERSION);
642 return pos - (char*)msg; //length
647 * convert each of my to be announced name_entries into network
650 * return the length of the name packet
653 create_packet(struct name* to, struct name_entry *from)
655 char *pos = (char*) to;
657 olsr_printf(3, "NAME PLUGIN: Announcing name %s (%s) %d\n",
658 from->name, olsr_ip_to_string(&from->ip), from->len);
659 to->type = htons(from->type);
660 to->len = htons(from->len);
661 memcpy(&to->ip, &from->ip, olsr_cnf->ipsize);
662 pos += sizeof(struct name);
663 strncpy(pos, from->name, from->len);
665 for (k = from->len; (k & 3) != 0; k++)
671 * decapsulate a received name, service or forwarder and update the corresponding hash table if necessary
674 decap_namemsg(struct name *from_packet, struct name_entry **to, olsr_bool *this_table_changed )
676 struct name_entry *tmp;
677 struct name_entry *already_saved_name_entries;
678 char *name = (char*)from_packet + sizeof(struct name);
679 int type_of_from_packet = ntohs(from_packet->type);
680 unsigned int len_of_name = ntohs(from_packet->len);
681 olsr_printf(4, "\nNAME PLUGIN: decapsulating received name, service or forwarder \n");
683 // don't insert the received entry again, if it has already been inserted in the hash table.
684 // Instead only the validity time is set in insert_new_name_in_list function, which calls this one
685 for (already_saved_name_entries = (*to); already_saved_name_entries != NULL ; already_saved_name_entries = already_saved_name_entries->next)
687 if ( (type_of_from_packet==NAME_HOST || type_of_from_packet==NAME_SERVICE) && strncmp(already_saved_name_entries->name, name, len_of_name) == 0 ) {
688 olsr_printf(4, "\nNAME PLUGIN: received name or service entry %s (%s) already in hash table\n", name, olsr_ip_to_string(&already_saved_name_entries->ip));
690 } else if (type_of_from_packet==NAME_FORWARDER && COMP_IP(&already_saved_name_entries->ip, &from_packet->ip) ) {
691 olsr_printf(4, "\nNAME PLUGIN: received forwarder entry %s (%s) already in hash table\n", name, olsr_ip_to_string(&already_saved_name_entries->ip));
696 //XXX: should I check the from_packet->ip here? If so, why not also check the ip fro HOST and SERVICE?
697 if( (type_of_from_packet==NAME_HOST && !is_name_wellformed(name)) || (type_of_from_packet==NAME_SERVICE && !is_service_wellformed(name)) ) {
698 olsr_printf(4, "\nNAME PLUGIN: invalid name [%s] received, skipping.\n", name );
702 //ignore all packets with a too long name
703 //or a spoofed len of its included name string
704 if (len_of_name > MAX_NAME || strlen(name) != len_of_name) {
705 olsr_printf(4, "\nNAME PLUGIN: from_packet->len %d > MAX_NAME %d or from_packet->len %d !0 strlen(name [%s] in packet)\n",
706 len_of_name, MAX_NAME, len_of_name, name );
710 //if not yet known entry
711 tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry");
712 tmp->type = ntohs(from_packet->type);
713 tmp->len = len_of_name > MAX_NAME ? MAX_NAME : ntohs(from_packet->len);
714 tmp->name = olsr_malloc(tmp->len+1, "new name_entry name");
715 memcpy(&tmp->ip, &from_packet->ip, olsr_cnf->ipsize);
716 strncpy(tmp->name, name, tmp->len);
717 tmp->name[tmp->len] = '\0';
719 olsr_printf(3, "\nNAME PLUGIN: create new name/service/forwarder entry %s (%s) [len=%d] [type=%d] in linked list\n",
720 tmp->name, olsr_ip_to_string(&tmp->ip), tmp->len, tmp->type);
722 *this_table_changed = OLSR_TRUE;
731 * unpack the received message and delegate to the decapsilation function for each
732 * name/service/forwarder entry in the message
735 update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, double vtime)
738 struct name *from_packet;
741 olsr_printf(3, "NAME PLUGIN: Received Message from %s\n",
742 olsr_ip_to_string(originator));
744 if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) {
745 olsr_printf(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version);
749 /* now add the names from the message */
750 pos = (char*)msg + sizeof(struct namemsg);
751 end_pos = pos + msg_size - sizeof(struct name*); // at least one struct name has to be left
753 for (i=ntohs(msg->nr_names); i > 0 && pos<end_pos; i--)
755 from_packet = (struct name*)pos;
757 switch (ntohs(from_packet->type)) {
759 insert_new_name_in_list(originator, list, from_packet, &name_table_changed, vtime);
762 insert_new_name_in_list(originator, forwarder_list, from_packet, &forwarder_table_changed, vtime);
765 insert_new_name_in_list(originator, service_list, from_packet, &service_table_changed, vtime);
768 olsr_printf(3, "NAME PLUGIN: Received Message of unknown type [%d] from (%s)\n", from_packet->type, olsr_ip_to_string(originator));
772 pos += sizeof(struct name);
773 pos += 1 + (( ntohs(from_packet->len) - 1) | 3);
776 olsr_printf(4, "NAME PLUGIN: Lost %d entries in received packet due to length inconsistency (%s)\n", i, olsr_ip_to_string(originator));
781 * insert all the new names,services and forwarders from a received packet into the
782 * corresponding entry for this ip in the corresponding hash table
785 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)
788 struct db_entry *entry;
790 olsr_bool entry_found = OLSR_FALSE;
792 hash = olsr_hashing(originator);
794 /* find the entry for originator, if there is already one */
795 for (entry = this_list[hash]; entry != NULL; entry = entry->next)
797 if (memcmp(originator, &entry->originator, olsr_cnf->ipsize) == 0) {
799 olsr_printf(4, "NAME PLUGIN: found entry for (%s) in its hash table\n", olsr_ip_to_string(originator));
801 //delegate to function for parsing the packet and linking it to entry->names
802 decap_namemsg(from_packet, &entry->names, this_table_changed);
804 olsr_get_timestamp(vtime * 1000, &entry->timer);
806 entry_found = OLSR_TRUE;
811 olsr_printf(3, "NAME PLUGIN: create new db entry for ip (%s) in hash table\n", olsr_ip_to_string(originator));
813 /* insert a new entry */
814 entry = olsr_malloc(sizeof(struct db_entry), "new db_entry");
816 memcpy(&entry->originator, originator, olsr_cnf->ipsize);
817 olsr_get_timestamp(vtime * 1000, &entry->timer);
821 entry->next = this_list[hash];
822 this_list[hash] = entry;
824 //delegate to function for parsing the packet and linking it to entry->names
825 decap_namemsg(from_packet, &entry->names, this_table_changed);
830 * write names to a file in /etc/hosts compatible format
833 write_hosts_file(void)
836 struct name_entry *name;
837 struct db_entry *entry;
843 if (!name_table_changed)
846 olsr_printf(2, "NAME PLUGIN: writing hosts file\n");
848 hosts = fopen( my_hosts_file, "w" );
850 olsr_printf(2, "NAME PLUGIN: cant write hosts file\n");
854 fprintf(hosts, "### this /etc/hosts file is overwritten regularly by olsrd\n");
855 fprintf(hosts, "### do not edit\n\n");
857 fprintf(hosts, "127.0.0.1\tlocalhost\n");
858 fprintf(hosts, "::1\t\tlocalhost\n\n");
860 // copy content from additional hosts filename
861 if (my_add_hosts[0] != '\0') {
862 add_hosts = fopen( my_add_hosts, "r" );
863 if (add_hosts == NULL) {
864 olsr_printf(2, "NAME PLUGIN: cant open additional hosts file\n");
867 fprintf(hosts, "### contents from '%s' ###\n\n", my_add_hosts);
868 while ((c = getc(add_hosts)) != EOF)
872 fprintf(hosts, "\n### olsr names ###\n\n");
876 for (name = my_names; name != NULL; name = name->next) {
877 fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&name->ip), name->name, my_suffix );
880 // write received names
881 for (hash = 0; hash < HASHSIZE; hash++)
883 for(entry = list[hash]; entry != NULL; entry = entry->next)
885 for (name = entry->names; name != NULL; name = name->next)
887 olsr_printf(6, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
888 olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator));
890 fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
891 fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&entry->originator));
896 if (time(&currtime)) {
897 fprintf(hosts, "\n### written by olsrd at %s", ctime(&currtime));
901 name_table_changed = OLSR_FALSE;
906 * write services to a file in the format:
907 * service #originator ip
909 * since service has a special format
910 * each line will look similar to e.g.
911 * http://me.olsr:80|tcp|my little homepage
914 write_services_file(void)
917 struct name_entry *name;
918 struct db_entry *entry;
923 if (!service_table_changed)
926 olsr_printf(2, "NAME PLUGIN: writing services file\n");
928 services_file = fopen( my_services_file, "w" );
929 if (services_file == NULL) {
930 olsr_printf(2, "NAME PLUGIN: cant write services_file file\n");
934 fprintf(services_file, "### this file is overwritten regularly by olsrd\n");
935 fprintf(services_file, "### do not edit\n\n");
938 // write own services
939 for (name = my_services; name != NULL; name = name->next) {
940 fprintf(services_file, "%s\t# my own service\n", name->name);
943 // write received services
944 for (hash = 0; hash < HASHSIZE; hash++)
946 for(entry = service_list[hash]; entry != NULL; entry = entry->next)
948 for (name = entry->names; name != NULL; name = name->next)
950 olsr_printf(6, "%s\t", name->name);
951 olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator));
953 fprintf(services_file, "%s\t", name->name );
954 fprintf(services_file, "\t#%s\n", olsr_ip_to_string(&entry->originator));
959 if (time(&currtime)) {
960 fprintf(services_file, "\n### written by olsrd at %s", ctime(&currtime));
963 fclose(services_file);
964 service_table_changed = OLSR_FALSE;
968 * write the 3 best upstream DNS servers to resolv.conf file
969 * best means the 3 with the best etx value in routing table
972 write_resolv_file(void)
975 struct name_entry *name, *tmp_dns, *last_dns, *dnslist = NULL;
976 struct db_entry *entry;
977 struct rt_entry *best_routes = NULL;
978 struct rt_entry *route, *tmp = NULL, *last;
983 if (!forwarder_table_changed || my_forwarders != NULL || my_resolv_file[0] == '\0')
986 for (hash = 0; hash < HASHSIZE; hash++)
988 for(entry = forwarder_list[hash]; entry != NULL; entry = entry->next)
990 for (name = entry->names; name != NULL; name = name->next)
993 /* find the nearest one */
994 route = host_lookup_routing_table(&name->ip);
995 if (route==NULL) // it's possible that route is not present yet
998 if (best_routes == NULL || route->rt_etx < best_routes->rt_etx) {
999 olsr_printf(6, "NAME PLUGIN: best nameserver %s\n",
1000 olsr_ip_to_string(&name->ip));
1001 if (best_routes!=NULL)
1002 olsr_printf(6, "NAME PLUGIN: better than %f (%s)\n",
1003 best_routes->rt_etx,
1004 olsr_ip_to_string(&best_routes->rt_dst));
1006 tmp = olsr_malloc(sizeof(struct rt_entry), "new rt_entry");
1007 memcpy(&tmp->rt_dst, &route->rt_dst, olsr_cnf->ipsize);
1008 tmp->rt_etx = route->rt_etx;
1009 tmp->next = best_routes;
1011 tmp_dns = olsr_malloc(sizeof(struct name_entry), "write_resolv name_entry");
1012 COPY_IP(&tmp_dns->ip, &name->ip);
1013 tmp_dns->type = name->type;
1015 tmp_dns->name = NULL;
1016 tmp_dns->next = dnslist;
1019 // queue in etx order
1022 while ( last->next!=NULL && i<3 ) {
1023 if (last->next->rt_etx > route->rt_etx)
1026 last_dns = last_dns->next;
1030 olsr_printf(6, "NAME PLUGIN: queue %f (%s)",
1032 olsr_ip_to_string(&name->ip));
1033 olsr_printf(6, " after %f (%s)\n",
1034 last->rt_etx, olsr_ip_to_string(&last_dns->ip));
1036 tmp = olsr_malloc(sizeof(struct rt_entry), "new rt_entry");
1037 memcpy(&tmp->rt_dst, &route->rt_dst, olsr_cnf->ipsize);
1038 tmp->rt_etx = route->rt_etx;
1039 tmp->next = last->next;
1042 tmp_dns = olsr_malloc(sizeof(struct name_entry), "write_resolv name_entry");
1043 COPY_IP(&tmp_dns->ip, &name->ip);
1044 tmp_dns->type = name->type;
1046 tmp_dns->name = NULL;
1047 tmp_dns->next = last_dns->next;
1048 last_dns->next = tmp_dns;
1050 olsr_printf(6, "NAME PLUGIN: don't need more than 3 nameservers\n");
1056 if (best_routes==NULL)
1060 olsr_printf(2, "NAME PLUGIN: try to write to resolv file\n");
1061 resolv = fopen( my_resolv_file, "w" );
1062 if (resolv == NULL) {
1063 olsr_printf(2, "NAME PLUGIN: can't write resolv file\n");
1066 fprintf(resolv, "### this file is overwritten regularly by olsrd\n");
1067 fprintf(resolv, "### do not edit\n\n");
1069 for (tmp_dns=dnslist; tmp_dns!=NULL && i<3; tmp_dns=tmp_dns->next) {
1070 olsr_printf(6, "NAME PLUGIN: nameserver %s\n", olsr_ip_to_string(&tmp_dns->ip));
1071 fprintf(resolv, "nameserver %s\n", olsr_ip_to_string(&tmp_dns->ip));
1074 free_name_entry_list(&dnslist);
1076 free_routing_table_list(&tmp);
1078 if (time(&currtime)) {
1079 fprintf(resolv, "\n### written by olsrd at %s", ctime(&currtime));
1082 forwarder_table_changed = OLSR_FALSE;
1087 * completely free a list of name_entries
1090 free_name_entry_list(struct name_entry **list)
1092 struct name_entry **tmp = list;
1093 struct name_entry *to_delete;
1094 while (*tmp != NULL) {
1096 *tmp = (*tmp)->next;
1097 free( to_delete->name );
1098 to_delete->name = NULL;
1106 * completely free a list of rt_entries
1109 free_routing_table_list(struct rt_entry **list)
1111 struct rt_entry **tmp = list;
1112 struct rt_entry *to_delete;
1113 while (*tmp != NULL) {
1115 *tmp = (*tmp)->next;
1123 * we only allow names for IP addresses which we are
1125 * so the IP must either be from one of the interfaces
1126 * or inside a HNA which we have configured
1129 allowed_ip(union olsr_ip_addr *addr)
1131 struct hna4_entry *hna4;
1132 struct hna6_entry *hna6;
1133 struct interface *iface;
1134 union olsr_ip_addr tmp_ip, tmp_msk;
1136 olsr_printf(6, "checking %s\n", olsr_ip_to_string(addr));
1138 for(iface = ifnet; iface; iface = iface->int_next)
1140 olsr_printf(6, "interface %s\n", olsr_ip_to_string(&iface->ip_addr));
1141 if (COMP_IP(&iface->ip_addr, addr)) {
1142 olsr_printf(6, "MATCHED\n");
1147 if (olsr_cnf->ip_version == AF_INET) {
1148 for (hna4 = olsr_cnf->hna4_entries; hna4; hna4 = hna4->next)
1150 olsr_printf(6, "HNA %s/%s\n",
1151 olsr_ip_to_string(&hna4->net),
1152 olsr_ip_to_string(&hna4->netmask));
1154 if ( hna4->netmask.v4 != 0 &&
1155 (addr->v4 & hna4->netmask.v4) == hna4->net.v4 ) {
1156 olsr_printf(6, "MATCHED\n");
1163 for (hna6 = olsr_cnf->hna6_entries; hna6; hna6 = hna6->next)
1165 olsr_printf(6, "HNA %s/%d\n",
1166 olsr_ip_to_string(&hna6->net),
1168 if ( hna6->prefix_len == 0 )
1170 olsr_prefix_to_netmask(&tmp_msk, hna6->prefix_len);
1171 for (i = 0; i < 16; i++) {
1172 tmp_ip.v6.s6_addr[i] = addr->v6.s6_addr[i] &
1173 tmp_msk.v6.s6_addr[i];
1175 if (COMP_IP(&tmp_ip, &hna6->net)) {
1176 olsr_printf(6, "MATCHED\n");
1184 static struct rt_entry *
1185 host_lookup_routing_table(union olsr_ip_addr *dst)
1188 union olsr_ip_addr tmp_ip, tmp_msk;
1189 struct rt_entry *walker;
1191 walker = olsr_lookup_routing_table(dst);
1195 for (index = 0; index < HASHSIZE; index++) {
1196 for (walker = hna_routes[index].next;
1197 walker != &hna_routes[index]; walker = walker->next) {
1198 if (COMP_IP(&walker->rt_dst, dst))
1200 if (olsr_cnf->ip_version == AF_INET) {
1201 if ( walker->rt_mask.v4 != 0 &&
1202 (dst->v4 & walker->rt_mask.v4) ==
1203 walker->rt_dst.v4 ) {
1204 olsr_printf(6, "MATCHED\n");
1210 if ( walker->rt_mask.v6 == 0 )
1212 olsr_prefix_to_netmask(&tmp_msk,
1213 walker->rt_mask.v6);
1214 for (i = 0; i < 16; i++) {
1215 tmp_ip.v6.s6_addr[i] =
1216 dst->v6.s6_addr[i] &
1217 tmp_msk.v6.s6_addr[i];
1219 if (COMP_IP(&tmp_ip, &walker->rt_dst)) {
1220 olsr_printf(6, "MATCHED\n");
1229 /** check if name has the right syntax, i.e. it must adhere to a special regex
1230 * stored in regex_t_name
1231 * necessary to avaid names like "0.0.0.0 google.de\n etc"
1234 is_name_wellformed(char *name) {
1235 return regexec(®ex_t_name, name, 1, ®match_t_name, 0) == 0 ;
1240 * check if the service is in the right syntax and also that the hostname
1241 * or ip whithin the service is allowed
1244 allowed_service(char *service_line)
1246 /* the call of is_service_wellformed generates the submatches stored in regmatch_t_service
1247 * these are then used by allowed_hostname_or_ip_in_service
1248 * see regexec(3) for more infos */
1249 if (!is_service_wellformed(service_line)) {
1251 } else if (!allowed_hostname_or_ip_in_service(service_line, &(regmatch_t_service[1]))) {
1259 allowed_hostname_or_ip_in_service(char *service_line, regmatch_t *hostname_or_ip_match)
1261 char *hostname_or_ip;
1262 union olsr_ip_addr olsr_ip;
1263 struct name_entry *name;
1264 if (hostname_or_ip_match->rm_so < 0 || hostname_or_ip_match->rm_eo < 0) {
1268 hostname_or_ip = strndup(&service_line[hostname_or_ip_match->rm_so], hostname_or_ip_match->rm_eo - hostname_or_ip_match->rm_so);
1269 //hostname is one of the names, that I announce (i.e. one that i am allowed to announce)
1270 for (name = my_names; name != NULL; name = name->next) {
1271 if (strncmp(name->name, hostname_or_ip, name->len - strlen(my_suffix)) == 0 ) {
1272 olsr_printf(4, "NAME PLUGIN: hostname %s in service %s is OK\n", hostname_or_ip, service_line);
1273 free(hostname_or_ip);
1274 hostname_or_ip = NULL;
1279 //ip in service-line is allowed
1280 if (inet_pton(olsr_cnf->ip_version, hostname_or_ip, &olsr_ip) > 0) {
1281 if (allowed_ip(&olsr_ip)) {
1282 olsr_printf(2, "NAME PLUGIN: ip %s in service %s is OK\n", olsr_ip_to_string(&olsr_ip), service_line);
1283 free(hostname_or_ip);
1284 hostname_or_ip = NULL;
1289 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);
1290 free(hostname_or_ip);
1291 hostname_or_ip = NULL;
1297 * check if the service matches the syntax
1298 * of "protocol://host:port/path|tcp_or_udp|a short description",
1299 * which is given in the regex regex_t_service
1302 is_service_wellformed(char *service_line)
1304 return regexec(®ex_t_service, service_line, pmatch_service, regmatch_t_service, 0) == 0;
1310 * c-indent-tabs-mode: t