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.22 2007/04/25 22:08:06 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;
265 memset(&ipz, 0, sizeof(ipz));
268 //regex string for validating the hostnames
269 char *regex_name = "^[[:alnum:]_.-]+$";
270 //regex string for the service line
271 char *regex_service = olsr_malloc(256*sizeof(char) + strlen(my_suffix), "new *char from name_init for regex_service");
273 //compile the regex from the string
274 if ((ret = regcomp(®ex_t_name, regex_name , REG_EXTENDED)) != 0)
276 /* #2: call regerror() if regcomp failed
277 * commented out, because only for debuggin needed
279 int errmsgsz = regerror(ret, ®ex_t_name, NULL, 0);
280 char *errmsg = malloc(errmsgsz);
281 regerror(ret, ®ex_t_name, errmsg, errmsgsz);
282 fprintf(stderr, "regcomp: %s", errmsg);
284 regfree(®ex_t_name);
286 olsr_printf(0, "compilation of regex \"%s\" for hostname failed", regex_name);
289 // a service line is something like prot://hostname.suffix:port|tcp|my little description about this service
290 // for example http://router.olsr:80|tcp|my homepage
291 // prot :// (hostname.suffix OR ip)
292 //regex_service = "^[[:alnum:]]+://(([[:alnum:]_.-]+.olsr)|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}))
293 // : port /path |(tcp OR udp) |short description
294 // :[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$";
295 strcat (strcat (strcat(regex_service, "^[[:alnum:]]+://(([[:alnum:]_.-]+"),
297 ")|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3})):[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$");
299 /* #1: call regcomp() to compile the regex */
300 if ((ret = regcomp(®ex_t_service, regex_service , REG_EXTENDED )) != 0)
302 /* #2: call regerror() if regcomp failed
303 * commented out, because only for debuggin needed
305 int errmsgsz = regerror(ret, ®ex_t_service, NULL, 0);
306 char *errmsg = malloc(errmsgsz);
307 regerror(ret, ®ex_t_service, errmsg, errmsgsz);
308 fprintf(stderr, "regcomp: %s", errmsg);
310 regfree(®ex_t_service);
312 olsr_printf(0, "compilation of regex \"%s\" for hostname failed", regex_name);
315 regex_service = NULL;
317 //fill in main addr for all entries with ip==0
318 //this does not matter for service, because the ip does not matter
321 for (name = my_names; name != NULL; name = name->next) {
322 if (memcmp(&name->ip, &ipz, olsr_cnf->ipsize) == 0) {
323 olsr_printf(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
324 memcpy(&name->ip, &olsr_cnf->main_addr, olsr_cnf->ipsize);
327 for (name = my_forwarders; name != NULL; name = name->next) {
328 if (name->ip.v4 == 0) {
329 olsr_printf(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
330 memcpy(&name->ip, &olsr_cnf->main_addr, olsr_cnf->ipsize);
334 //check if entries I want to announce myself are valid and allowed
335 my_names = remove_nonvalid_names_from_list(my_names, NAME_HOST);
336 my_forwarders = remove_nonvalid_names_from_list(my_forwarders, NAME_FORWARDER);
337 my_services = remove_nonvalid_names_from_list(my_services, NAME_SERVICE);
340 /* register functions with olsrd */
341 olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
342 olsr_register_timeout_function(&olsr_timeout);
343 olsr_register_scheduler_event(&olsr_event, NULL, my_interval, 0, NULL);
350 remove_nonvalid_names_from_list(struct name_entry *my_list, int type)
352 struct name_entry *next = my_list;
353 olsr_bool valid = OLSR_FALSE;
354 if (my_list == NULL) {
360 valid = is_name_wellformed(my_list->name) && allowed_ip(&my_list->ip);
363 valid = allowed_ip(&my_list->ip);
366 valid = allowed_service(my_list->name);
371 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));
372 next = my_list->next;
374 my_list->name = NULL;
377 return remove_nonvalid_names_from_list(next, type);
379 olsr_printf(2, "NAME PLUGIN: validate parameter %s (%s) -> OK\n", my_list->name, olsr_ip_to_string(&my_list->ip));
380 my_list->next = remove_nonvalid_names_from_list(my_list->next, type);
388 * called at unload: free everything
390 * XXX: should I delete the hosts/services/resolv.conf files on exit?
393 name_destructor(void)
395 olsr_printf(2, "NAME PLUGIN: exit. cleaning up...\n");
397 free_name_entry_list(&my_names);
398 free_name_entry_list(&my_services);
399 free_name_entry_list(&my_forwarders);
401 free_all_list_entries(list);
402 free_all_list_entries(service_list);
403 free_all_list_entries(forwarder_list);
405 regfree(®ex_t_name);
406 regfree(®ex_t_service);
410 /* free all list entries */
412 free_all_list_entries(struct db_entry **this_db_list)
416 for(i = 0; i < HASHSIZE; i++)
418 struct db_entry **tmp = &this_db_list[i];
421 struct db_entry *to_delete = *tmp;
423 free_name_entry_list(&to_delete->names);
432 * A timeout function called every time
434 * XXX:the scheduler is polled (by default 10 times a sec,
435 * which is far too often):
437 * time out old list entries
438 * and write changes to file
443 timeout_old_names(list, &name_table_changed);
444 timeout_old_names(forwarder_list, &forwarder_table_changed);
445 timeout_old_names(service_list, &service_table_changed);
449 write_services_file();
453 timeout_old_names(struct db_entry **this_list, olsr_bool *this_table_changed)
455 struct db_entry **tmp;
456 struct db_entry *to_delete;
459 for(index=0;index<HASHSIZE;index++)
461 for (tmp = &this_list[index]; *tmp != NULL; )
463 /* check if the entry for this ip is timed out */
464 if (olsr_timed_out(&(*tmp)->timer))
467 /* update the pointer in the linked list */
470 olsr_printf(2, "NAME PLUGIN: %s timed out... deleting\n",
471 olsr_ip_to_string(&to_delete->originator));
474 free_name_entry_list(&to_delete->names);
476 *this_table_changed = OLSR_TRUE;
486 * Scheduled event: generate and send NAME packet
489 olsr_event(void *foo __attribute__((unused)))
491 union olsr_message *message = (union olsr_message*)buffer;
492 struct interface *ifn;
495 /* looping trough interfaces */
496 for (ifn = ifnet; ifn ; ifn = ifn->int_next)
498 olsr_printf(3, "NAME PLUGIN: Generating packet - [%s]\n", ifn->int_name);
501 if(olsr_cnf->ip_version == AF_INET)
504 message->v4.olsr_msgtype = MESSAGE_TYPE;
505 message->v4.olsr_vtime = double_to_me(my_timeout);
506 memcpy(&message->v4.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
507 message->v4.ttl = MAX_TTL;
508 message->v4.hopcnt = 0;
509 message->v4.seqno = htons(get_msg_seqno());
511 namesize = encap_namemsg((struct namemsg*)&message->v4.message);
512 namesize = namesize + sizeof(struct olsrmsg);
514 message->v4.olsr_msgsize = htons(namesize);
519 message->v6.olsr_msgtype = MESSAGE_TYPE;
520 message->v6.olsr_vtime = double_to_me(my_timeout);
521 memcpy(&message->v6.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
522 message->v6.ttl = MAX_TTL;
523 message->v6.hopcnt = 0;
524 message->v6.seqno = htons(get_msg_seqno());
526 namesize = encap_namemsg((struct namemsg*)&message->v6.message);
527 namesize = namesize + sizeof(struct olsrmsg6);
529 message->v6.olsr_msgsize = htons(namesize);
532 if(net_outbuffer_push(ifn, message, namesize) != namesize ) {
533 /* send data and try again */
535 if(net_outbuffer_push(ifn, message, namesize) != namesize ) {
536 olsr_printf(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
544 * Parse name olsr message of NAME type
547 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *ipaddr)
549 struct namemsg *namemessage;
550 union olsr_ip_addr originator;
555 /* Fetch the originator of the messsage */
556 if(olsr_cnf->ip_version == AF_INET) {
557 memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);
558 seqno = ntohs(m->v4.seqno);
560 memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);
561 seqno = ntohs(m->v6.seqno);
564 /* Fetch the message based on IP version */
565 if(olsr_cnf->ip_version == AF_INET) {
566 vtime = ME_TO_DOUBLE(m->v4.olsr_vtime);
567 size = ntohs(m->v4.olsr_msgsize);
568 namemessage = (struct namemsg*)&m->v4.message;
571 vtime = ME_TO_DOUBLE(m->v6.olsr_vtime);
572 size = ntohs(m->v6.olsr_msgsize);
573 namemessage = (struct namemsg*)&m->v6.message;
576 /* Check if message originated from this node.
578 if(memcmp(&originator, &olsr_cnf->main_addr, olsr_cnf->ipsize) == 0)
581 /* Check that the neighbor this message was received from is symmetric.
583 if(check_neighbor_link(ipaddr) != SYM_LINK) {
584 olsr_printf(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(ipaddr));
588 /* Check if this message has been processed before
589 * Remeber that this also registeres the message as
590 * processed if nessecary
592 if(olsr_check_dup_table_proc(&originator, seqno)) {
593 /* If not so - process */
594 update_name_entry(&originator, namemessage, size, vtime);
597 /* Forward the message if nessecary
598 * default_fwd does all the work for us! */
599 olsr_forward_message(m, &originator, seqno, in_if, ipaddr);
604 * Encapsulate a name message into a packet.
606 * It assumed that there is enough space in the buffer to do this!
608 * Returns: the length of the message that was appended
611 encap_namemsg(struct namemsg* msg)
613 struct name_entry *my_name;
614 struct name_entry *my_service;
616 // add the hostname, service and forwarder entries after the namemsg header
617 char* pos = (char*)msg + sizeof(struct namemsg);
621 for (my_name = my_names; my_name!=NULL; my_name = my_name->next)
623 pos = create_packet( (struct name*) pos, my_name);
627 for (my_name = my_forwarders; my_name!=NULL; my_name = my_name->next)
629 pos = create_packet( (struct name*) pos, my_name);
633 for (my_service = my_services; my_service!=NULL; my_service = my_service->next)
635 pos = create_packet( (struct name*) pos, my_service);
639 // write the namemsg header with the number of announced entries and the protocol version
640 msg->nr_names = htons(i);
641 msg->version = htons(NAME_PROTOCOL_VERSION);
643 return pos - (char*)msg; //length
648 * convert each of my to be announced name_entries into network
651 * return the length of the name packet
654 create_packet(struct name* to, struct name_entry *from)
656 char *pos = (char*) to;
658 olsr_printf(3, "NAME PLUGIN: Announcing name %s (%s) %d\n",
659 from->name, olsr_ip_to_string(&from->ip), from->len);
660 to->type = htons(from->type);
661 to->len = htons(from->len);
662 memcpy(&to->ip, &from->ip, olsr_cnf->ipsize);
663 pos += sizeof(struct name);
664 strncpy(pos, from->name, from->len);
666 for (k = from->len; (k & 3) != 0; k++)
672 * decapsulate a received name, service or forwarder and update the corresponding hash table if necessary
675 decap_namemsg(struct name *from_packet, struct name_entry **to, olsr_bool *this_table_changed )
677 struct name_entry *tmp;
678 struct name_entry *already_saved_name_entries;
679 char *name = (char*)from_packet + sizeof(struct name);
680 olsr_printf(4, "\nNAME PLUGIN: decapsulating received name, service or forwarder \n");
681 int type_of_from_packet = ntohs(from_packet->type);
682 unsigned int len_of_name = ntohs(from_packet->len);
684 // don't insert the received entry again, if it has already been inserted in the hash table.
685 // Instead only the validity time is set in insert_new_name_in_list function, which calls this one
686 for (already_saved_name_entries = (*to); already_saved_name_entries != NULL ; already_saved_name_entries = already_saved_name_entries->next)
688 if ( (type_of_from_packet==NAME_HOST || type_of_from_packet==NAME_SERVICE) && strncmp(already_saved_name_entries->name, name, len_of_name) == 0 ) {
689 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));
691 } else if (type_of_from_packet==NAME_FORWARDER && COMP_IP(&already_saved_name_entries->ip, &from_packet->ip) ) {
692 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));
697 //XXX: should I check the from_packet->ip here? If so, why not also check the ip fro HOST and SERVICE?
698 if( (type_of_from_packet==NAME_HOST && !is_name_wellformed(name)) || (type_of_from_packet==NAME_SERVICE && !is_service_wellformed(name)) ) {
699 olsr_printf(4, "\nNAME PLUGIN: invalid name [%s] received, skipping.\n", name );
703 //ignore all packets with a too long name
704 //or a spoofed len of its included name string
705 if (len_of_name > MAX_NAME || strlen(name) != len_of_name) {
706 olsr_printf(4, "\nNAME PLUGIN: from_packet->len %d > MAX_NAME %d or from_packet->len %d !0 strlen(name [%s] in packet)\n",
707 len_of_name, MAX_NAME, len_of_name, name );
711 //if not yet known entry
712 tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry");
713 tmp->type = ntohs(from_packet->type);
714 tmp->len = len_of_name > MAX_NAME ? MAX_NAME : ntohs(from_packet->len);
715 tmp->name = olsr_malloc(tmp->len+1, "new name_entry name");
716 memcpy(&tmp->ip, &from_packet->ip, olsr_cnf->ipsize);
717 strncpy(tmp->name, name, tmp->len);
718 tmp->name[tmp->len] = '\0';
720 olsr_printf(3, "\nNAME PLUGIN: create new name/service/forwarder entry %s (%s) [len=%d] [type=%d] in linked list\n",
721 tmp->name, olsr_ip_to_string(&tmp->ip), tmp->len, tmp->type);
723 *this_table_changed = OLSR_TRUE;
732 * unpack the received message and delegate to the decapsilation function for each
733 * name/service/forwarder entry in the message
736 update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, double vtime)
739 struct name *from_packet;
742 olsr_printf(3, "NAME PLUGIN: Received Message from %s\n",
743 olsr_ip_to_string(originator));
745 if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) {
746 olsr_printf(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version);
750 /* now add the names from the message */
751 pos = (char*)msg + sizeof(struct namemsg);
752 end_pos = pos + msg_size - sizeof(struct name*); // at least one struct name has to be left
754 for (i=ntohs(msg->nr_names); i > 0 && pos<end_pos; i--)
756 from_packet = (struct name*)pos;
758 switch (ntohs(from_packet->type)) {
760 insert_new_name_in_list(originator, list, from_packet, &name_table_changed, vtime);
763 insert_new_name_in_list(originator, forwarder_list, from_packet, &forwarder_table_changed, vtime);
766 insert_new_name_in_list(originator, service_list, from_packet, &service_table_changed, vtime);
769 olsr_printf(3, "NAME PLUGIN: Received Message of unknown type [%d] from (%s)\n", from_packet->type, olsr_ip_to_string(originator));
773 pos += sizeof(struct name);
774 pos += 1 + (( ntohs(from_packet->len) - 1) | 3);
777 olsr_printf(4, "NAME PLUGIN: Lost %d entries in received packet due to length inconsistency (%s)\n", i, olsr_ip_to_string(originator));
782 * insert all the new names,services and forwarders from a received packet into the
783 * corresponding entry for this ip in the corresponding hash table
786 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)
789 struct db_entry *entry;
791 olsr_bool entry_found = OLSR_FALSE;
793 hash = olsr_hashing(originator);
795 /* find the entry for originator, if there is already one */
796 for (entry = this_list[hash]; entry != NULL; entry = entry->next)
798 if (memcmp(originator, &entry->originator, olsr_cnf->ipsize) == 0) {
800 olsr_printf(4, "NAME PLUGIN: found entry for (%s) in its hash table\n", olsr_ip_to_string(originator));
802 //delegate to function for parsing the packet and linking it to entry->names
803 decap_namemsg(from_packet, &entry->names, this_table_changed);
805 olsr_get_timestamp(vtime * 1000, &entry->timer);
807 entry_found = OLSR_TRUE;
812 olsr_printf(3, "NAME PLUGIN: create new db entry for ip (%s) in hash table\n", olsr_ip_to_string(originator));
814 /* insert a new entry */
815 entry = olsr_malloc(sizeof(struct db_entry), "new db_entry");
817 memcpy(&entry->originator, originator, olsr_cnf->ipsize);
818 olsr_get_timestamp(vtime * 1000, &entry->timer);
822 entry->next = this_list[hash];
823 this_list[hash] = entry;
825 //delegate to function for parsing the packet and linking it to entry->names
826 decap_namemsg(from_packet, &entry->names, this_table_changed);
831 * write names to a file in /etc/hosts compatible format
834 write_hosts_file(void)
837 struct name_entry *name;
838 struct db_entry *entry;
844 if (!name_table_changed)
847 olsr_printf(2, "NAME PLUGIN: writing hosts file\n");
849 hosts = fopen( my_hosts_file, "w" );
851 olsr_printf(2, "NAME PLUGIN: cant write hosts file\n");
855 fprintf(hosts, "### this /etc/hosts file is overwritten regularly by olsrd\n");
856 fprintf(hosts, "### do not edit\n\n");
858 fprintf(hosts, "127.0.0.1\tlocalhost\n");
859 fprintf(hosts, "::1\t\tlocalhost\n\n");
861 // copy content from additional hosts filename
862 if (my_add_hosts[0] != '\0') {
863 add_hosts = fopen( my_add_hosts, "r" );
864 if (add_hosts == NULL) {
865 olsr_printf(2, "NAME PLUGIN: cant open additional hosts file\n");
868 fprintf(hosts, "### contents from '%s' ###\n\n", my_add_hosts);
869 while ((c = getc(add_hosts)) != EOF)
873 fprintf(hosts, "\n### olsr names ###\n\n");
877 for (name = my_names; name != NULL; name = name->next) {
878 fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&name->ip), name->name, my_suffix );
881 // write received names
882 for (hash = 0; hash < HASHSIZE; hash++)
884 for(entry = list[hash]; entry != NULL; entry = entry->next)
886 for (name = entry->names; name != NULL; name = name->next)
888 olsr_printf(6, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
889 olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator));
891 fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix);
892 fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&entry->originator));
897 if (time(&currtime)) {
898 fprintf(hosts, "\n### written by olsrd at %s", ctime(&currtime));
902 name_table_changed = OLSR_FALSE;
907 * write services to a file in the format:
908 * service #originator ip
910 * since service has a special format
911 * each line will look similar to e.g.
912 * http://me.olsr:80|tcp|my little homepage
915 write_services_file(void)
918 struct name_entry *name;
919 struct db_entry *entry;
924 if (!service_table_changed)
927 olsr_printf(2, "NAME PLUGIN: writing services file\n");
929 services_file = fopen( my_services_file, "w" );
930 if (services_file == NULL) {
931 olsr_printf(2, "NAME PLUGIN: cant write services_file file\n");
935 fprintf(services_file, "### this file is overwritten regularly by olsrd\n");
936 fprintf(services_file, "### do not edit\n\n");
939 // write own services
940 for (name = my_services; name != NULL; name = name->next) {
941 fprintf(services_file, "%s\t# my own service\n", name->name);
944 // write received services
945 for (hash = 0; hash < HASHSIZE; hash++)
947 for(entry = service_list[hash]; entry != NULL; entry = entry->next)
949 for (name = entry->names; name != NULL; name = name->next)
951 olsr_printf(6, "%s\t", name->name);
952 olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator));
954 fprintf(services_file, "%s\t", name->name );
955 fprintf(services_file, "\t#%s\n", olsr_ip_to_string(&entry->originator));
960 if (time(&currtime)) {
961 fprintf(services_file, "\n### written by olsrd at %s", ctime(&currtime));
964 fclose(services_file);
965 service_table_changed = OLSR_FALSE;
969 * write the 3 best upstream DNS servers to resolv.conf file
970 * best means the 3 with the best etx value in routing table
973 write_resolv_file(void)
976 struct name_entry *name, *tmp_dns, *last_dns, *dnslist = NULL;
977 struct db_entry *entry;
978 struct rt_entry *best_routes = NULL;
979 struct rt_entry *route, *tmp = NULL, *last;
984 if (!forwarder_table_changed || my_forwarders != NULL || my_resolv_file[0] == '\0')
987 for (hash = 0; hash < HASHSIZE; hash++)
989 for(entry = forwarder_list[hash]; entry != NULL; entry = entry->next)
991 for (name = entry->names; name != NULL; name = name->next)
994 /* find the nearest one */
995 route = host_lookup_routing_table(&name->ip);
996 if (route==NULL) // it's possible that route is not present yet
999 if (best_routes == NULL || route->rt_etx < best_routes->rt_etx) {
1000 olsr_printf(6, "NAME PLUGIN: best nameserver %s\n",
1001 olsr_ip_to_string(&name->ip));
1002 if (best_routes!=NULL)
1003 olsr_printf(6, "NAME PLUGIN: better than %f (%s)\n",
1004 best_routes->rt_etx,
1005 olsr_ip_to_string(&best_routes->rt_dst));
1007 tmp = olsr_malloc(sizeof(struct rt_entry), "new rt_entry");
1008 memcpy(&tmp->rt_dst, &route->rt_dst, olsr_cnf->ipsize);
1009 tmp->rt_etx = route->rt_etx;
1010 tmp->next = best_routes;
1012 tmp_dns = olsr_malloc(sizeof(struct name_entry), "write_resolv name_entry");
1013 COPY_IP(&tmp_dns->ip, &name->ip);
1014 tmp_dns->type = name->type;
1016 tmp_dns->name = NULL;
1017 tmp_dns->next = dnslist;
1020 // queue in etx order
1023 while ( last->next!=NULL && i<3 ) {
1024 if (last->next->rt_etx > route->rt_etx)
1027 last_dns = last_dns->next;
1031 olsr_printf(6, "NAME PLUGIN: queue %f (%s)",
1033 olsr_ip_to_string(&name->ip));
1034 olsr_printf(6, " after %f (%s)\n",
1035 last->rt_etx, olsr_ip_to_string(&last_dns->ip));
1037 tmp = olsr_malloc(sizeof(struct rt_entry), "new rt_entry");
1038 memcpy(&tmp->rt_dst, &route->rt_dst, olsr_cnf->ipsize);
1039 tmp->rt_etx = route->rt_etx;
1040 tmp->next = last->next;
1043 tmp_dns = olsr_malloc(sizeof(struct name_entry), "write_resolv name_entry");
1044 COPY_IP(&tmp_dns->ip, &name->ip);
1045 tmp_dns->type = name->type;
1047 tmp_dns->name = NULL;
1048 tmp_dns->next = last_dns->next;
1049 last_dns->next = tmp_dns;
1051 olsr_printf(6, "NAME PLUGIN: don't need more than 3 nameservers\n");
1057 if (best_routes==NULL)
1061 olsr_printf(2, "NAME PLUGIN: try to write to resolv file\n");
1062 resolv = fopen( my_resolv_file, "w" );
1063 if (resolv == NULL) {
1064 olsr_printf(2, "NAME PLUGIN: can't write resolv file\n");
1067 fprintf(resolv, "### this file is overwritten regularly by olsrd\n");
1068 fprintf(resolv, "### do not edit\n\n");
1070 for (tmp_dns=dnslist; tmp_dns!=NULL && i<3; tmp_dns=tmp_dns->next) {
1071 olsr_printf(6, "NAME PLUGIN: nameserver %s\n", olsr_ip_to_string(&tmp_dns->ip));
1072 fprintf(resolv, "nameserver %s\n", olsr_ip_to_string(&tmp_dns->ip));
1075 free_name_entry_list(&dnslist);
1077 free_routing_table_list(&tmp);
1079 if (time(&currtime)) {
1080 fprintf(resolv, "\n### written by olsrd at %s", ctime(&currtime));
1083 forwarder_table_changed = OLSR_FALSE;
1088 * completely free a list of name_entries
1091 free_name_entry_list(struct name_entry **list)
1093 struct name_entry **tmp = list;
1094 struct name_entry *to_delete;
1095 while (*tmp != NULL) {
1097 *tmp = (*tmp)->next;
1098 free( to_delete->name );
1099 to_delete->name = NULL;
1107 * completely free a list of rt_entries
1110 free_routing_table_list(struct rt_entry **list)
1112 struct rt_entry **tmp = list;
1113 struct rt_entry *to_delete;
1114 while (*tmp != NULL) {
1116 *tmp = (*tmp)->next;
1124 * we only allow names for IP addresses which we are
1126 * so the IP must either be from one of the interfaces
1127 * or inside a HNA which we have configured
1130 allowed_ip(union olsr_ip_addr *addr)
1132 struct hna4_entry *hna4;
1133 struct hna6_entry *hna6;
1134 struct interface *iface;
1135 union olsr_ip_addr tmp_ip, tmp_msk;
1137 olsr_printf(6, "checking %s\n", olsr_ip_to_string(addr));
1139 for(iface = ifnet; iface; iface = iface->int_next)
1141 olsr_printf(6, "interface %s\n", olsr_ip_to_string(&iface->ip_addr));
1142 if (COMP_IP(&iface->ip_addr, addr)) {
1143 olsr_printf(6, "MATCHED\n");
1148 if (olsr_cnf->ip_version == AF_INET) {
1149 for (hna4 = olsr_cnf->hna4_entries; hna4; hna4 = hna4->next)
1151 olsr_printf(6, "HNA %s/%s\n",
1152 olsr_ip_to_string(&hna4->net),
1153 olsr_ip_to_string(&hna4->netmask));
1155 if ( hna4->netmask.v4 != 0 &&
1156 (addr->v4 & hna4->netmask.v4) == hna4->net.v4 ) {
1157 olsr_printf(6, "MATCHED\n");
1164 for (hna6 = olsr_cnf->hna6_entries; hna6; hna6 = hna6->next)
1166 olsr_printf(6, "HNA %s/%d\n",
1167 olsr_ip_to_string(&hna6->net),
1169 if ( hna6->prefix_len == 0 )
1171 olsr_prefix_to_netmask(&tmp_msk, hna6->prefix_len);
1172 for (i = 0; i < 16; i++) {
1173 tmp_ip.v6.s6_addr[i] = addr->v6.s6_addr[i] &
1174 tmp_msk.v6.s6_addr[i];
1176 if (COMP_IP(&tmp_ip, &hna6->net)) {
1177 olsr_printf(6, "MATCHED\n");
1185 static struct rt_entry *
1186 host_lookup_routing_table(union olsr_ip_addr *dst)
1189 union olsr_ip_addr tmp_ip, tmp_msk;
1190 struct rt_entry *walker;
1192 walker = olsr_lookup_routing_table(dst);
1196 for (index = 0; index < HASHSIZE; index++) {
1197 for (walker = hna_routes[index].next;
1198 walker != &hna_routes[index]; walker = walker->next) {
1199 if (COMP_IP(&walker->rt_dst, dst))
1201 if (olsr_cnf->ip_version == AF_INET) {
1202 if ( walker->rt_mask.v4 != 0 &&
1203 (dst->v4 & walker->rt_mask.v4) ==
1204 walker->rt_dst.v4 ) {
1205 olsr_printf(6, "MATCHED\n");
1211 if ( walker->rt_mask.v6 == 0 )
1213 olsr_prefix_to_netmask(&tmp_msk,
1214 walker->rt_mask.v6);
1215 for (i = 0; i < 16; i++) {
1216 tmp_ip.v6.s6_addr[i] =
1217 dst->v6.s6_addr[i] &
1218 tmp_msk.v6.s6_addr[i];
1220 if (COMP_IP(&tmp_ip, &walker->rt_dst)) {
1221 olsr_printf(6, "MATCHED\n");
1230 /** check if name has the right syntax, i.e. it must adhere to a special regex
1231 * stored in regex_t_name
1232 * necessary to avaid names like "0.0.0.0 google.de\n etc"
1235 is_name_wellformed(char *name) {
1236 return regexec(®ex_t_name, name, 1, ®match_t_name, 0) == 0 ;
1241 * check if the service is in the right syntax and also that the hostname
1242 * or ip whithin the service is allowed
1245 allowed_service(char *service_line)
1247 /* the call of is_service_wellformed generates the submatches stored in regmatch_t_service
1248 * these are then used by allowed_hostname_or_ip_in_service
1249 * see regexec(3) for more infos */
1250 if (!is_service_wellformed(service_line)) {
1252 } else if (!allowed_hostname_or_ip_in_service(service_line, &(regmatch_t_service[1]))) {
1260 allowed_hostname_or_ip_in_service(char *service_line, regmatch_t *hostname_or_ip_match)
1262 char *hostname_or_ip;
1263 union olsr_ip_addr olsr_ip;
1264 struct name_entry *name;
1265 if (hostname_or_ip_match->rm_so < 0 || hostname_or_ip_match->rm_eo < 0) {
1269 hostname_or_ip = strndup(&service_line[hostname_or_ip_match->rm_so], hostname_or_ip_match->rm_eo - hostname_or_ip_match->rm_so);
1270 //hostname is one of the names, that I announce (i.e. one that i am allowed to announce)
1271 for (name = my_names; name != NULL; name = name->next) {
1272 if (strncmp(name->name, hostname_or_ip, name->len - strlen(my_suffix)) == 0 ) {
1273 olsr_printf(4, "NAME PLUGIN: hostname %s in service %s is OK\n", hostname_or_ip, service_line);
1274 free(hostname_or_ip);
1275 hostname_or_ip = NULL;
1280 //ip in service-line is allowed
1281 if (inet_pton(olsr_cnf->ip_version, hostname_or_ip, &olsr_ip) > 0) {
1282 if (allowed_ip(&olsr_ip)) {
1283 olsr_printf(2, "NAME PLUGIN: ip %s in service %s is OK\n", olsr_ip_to_string(&olsr_ip), service_line);
1284 free(hostname_or_ip);
1285 hostname_or_ip = NULL;
1290 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);
1291 free(hostname_or_ip);
1292 hostname_or_ip = NULL;
1298 * check if the service matches the syntax
1299 * of "protocol://host:port/path|tcp_or_udp|a short description",
1300 * which is given in the regex regex_t_service
1303 is_service_wellformed(char *service_line)
1305 return regexec(®ex_t_service, service_line, pmatch_service, regmatch_t_service, 0) == 0;
1311 * c-indent-tabs-mode: t