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)
5 * Copyright (c) 2007, Sven-Ola <sven-ola@gmx.de>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * * Neither the name of the UniK olsr daemon nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Dynamic linked library for UniK OLSRd
44 #include <sys/types.h>
50 #include "routing_table.h"
52 #include "scheduler.h"
54 #include "duplicate_set.h"
60 #include "plugin_util.h"
61 #include "nameservice.h"
63 #include "olsrd_copy.h"
67 /* config parameters */
68 static char my_hosts_file[MAX_FILE + 1];
69 static char my_add_hosts[MAX_FILE + 1];
70 static char my_suffix[MAX_SUFFIX];
71 static int my_interval = EMISSION_INTERVAL;
72 static double my_timeout = NAME_VALID_TIME;
73 static char my_resolv_file[MAX_FILE +1];
74 static char my_services_file[MAX_FILE + 1];
75 static char latlon_in_file[MAX_FILE + 1];
76 static char my_latlon_file[MAX_FILE + 1];
77 float my_lat = 0.0, my_lon = 0.0;
79 /* the databases (using hashing)
80 * for hostnames, service_lines and dns-servers
82 * my own hostnames, service_lines and dns-servers
83 * are store in a linked list (without hashing)
85 static struct db_entry* list[HASHSIZE];
86 struct name_entry *my_names = NULL;
87 static olsr_bool name_table_changed = OLSR_TRUE;
89 static struct db_entry* service_list[HASHSIZE];
90 static struct name_entry *my_services = NULL;
91 static olsr_bool service_table_changed = OLSR_TRUE;
93 static struct db_entry* forwarder_list[HASHSIZE];
94 static struct name_entry *my_forwarders = NULL;
95 static olsr_bool forwarder_table_changed = OLSR_TRUE;
97 struct db_entry* latlon_list[HASHSIZE];
98 static olsr_bool latlon_table_changed = OLSR_TRUE;
100 /* regular expression to be matched by valid hostnames, compiled in name_init() */
101 static regex_t regex_t_name;
102 static regmatch_t regmatch_t_name;
104 /* regular expression to be matched by valid service_lines, compiled in name_init() */
105 static regex_t regex_t_service;
106 static int pmatch_service = 10;
107 static regmatch_t regmatch_t_service[10];
113 name_constructor(void)
120 GetWindowsDirectory(my_hosts_file, MAX_FILE - 12);
121 GetWindowsDirectory(my_services_file, MAX_FILE - 12);
122 GetWindowsDirectory(my_resolv_file, MAX_FILE - 12);
124 len = strlen(my_hosts_file);
125 if (my_hosts_file[len - 1] != '\\')
126 my_hosts_file[len++] = '\\';
127 strcpy(my_hosts_file + len, "hosts_olsr");
129 len = strlen(my_services_file);
130 if (my_services_file[len - 1] != '\\')
131 my_services_file[len++] = '\\';
132 strcpy(my_services_file + len, "services_olsr");
134 len = strlen(my_resolv_file);
135 if (my_resolv_file[len - 1] != '\\')
136 my_resolv_file[len++] = '\\';
137 strcpy(my_resolv_file + len, "resolvconf_olsr");
139 strcpy(my_hosts_file, "/var/run/hosts_olsr");
140 strcpy(my_services_file, "/var/run/services_olsr");
141 strcpy(my_resolv_file, "/var/run/resolvconf_olsr");
145 my_add_hosts[0] = '\0';
146 my_latlon_file[0] = '\0';
147 latlon_in_file[0] = '\0';
150 for(i = 0; i < HASHSIZE; i++) {
152 forwarder_list[i] = NULL;
153 service_list[i] = NULL;
154 latlon_list[i] = NULL;
161 static int set_nameservice_server(const char *value, void *data, set_plugin_parameter_addon addon)
163 union olsr_ip_addr ip;
164 struct name_entry **v = data;
165 if (0 == strlen(value))
167 *v = add_name_to_list(*v, "", addon.ui, NULL);
168 OLSR_PRINTF(1, "%s got %s (main address)\n", "Got", value);
171 else if (0 < inet_pton(olsr_cnf->ip_version, value, &ip))
173 *v = add_name_to_list(*v, "", addon.ui, &ip);
174 OLSR_PRINTF(1, "%s got %s\n", "Got", value);
179 OLSR_PRINTF(0, "Illegal IP address \"%s\"", value);
184 static int set_nameservice_name(const char *value, void *data, set_plugin_parameter_addon addon)
186 struct name_entry **v = data;
187 if (0 < strlen(value))
189 *v = add_name_to_list(*v, value, addon.ui, NULL);
190 OLSR_PRINTF(1, "%s got %s (main address)\n", "Got", value);
195 OLSR_PRINTF(0, "Illegal name \"%s\"", value);
200 static int set_nameservice_host(const char *value, void *data, set_plugin_parameter_addon addon)
202 union olsr_ip_addr ip;
203 struct name_entry **v = data;
204 if (0 < inet_pton(olsr_cnf->ip_version, addon.pc, &ip))
206 // the IP is validated later
207 *v = add_name_to_list(*v, value, NAME_HOST, &ip);
208 OLSR_PRINTF(1, "%s: %s got %s\n", "Got", addon.pc, value);
213 OLSR_PRINTF(0, "%s: Illegal IP address \"%s\"", addon.pc, value);
218 static int set_nameservice_float(const char *value, void *data, set_plugin_parameter_addon addon __attribute__((unused)))
220 const float thefloat = atof(value);
225 OLSR_PRINTF(1, "%s float %f\n", "Got", thefloat);
229 OLSR_PRINTF(0, "%s float %f\n", "Ignored", thefloat);
234 static const struct olsrd_plugin_parameters plugin_parameters[] = {
235 { .name = "interval", .set_plugin_parameter = &set_plugin_int, .data = &my_interval },
236 { .name = "timeout", .set_plugin_parameter = &set_nameservice_float, .data = &my_timeout },
237 { .name = "hosts-file", .set_plugin_parameter = &set_plugin_string, .data = &my_hosts_file, .addon = {sizeof(my_hosts_file)} },
238 { .name = "resolv-file", .set_plugin_parameter = &set_plugin_string, .data = &my_resolv_file, .addon = {sizeof(my_resolv_file)} },
239 { .name = "suffix", .set_plugin_parameter = &set_plugin_string, .data = &my_suffix, .addon = {sizeof(my_suffix)} },
240 { .name = "add-hosts", .set_plugin_parameter = &set_plugin_string, .data = &my_add_hosts, .addon = {sizeof(my_add_hosts)} },
241 { .name = "services-file", .set_plugin_parameter = &set_plugin_string, .data = &my_services_file, .addon = {sizeof(my_services_file)} },
242 { .name = "lat", .set_plugin_parameter = &set_nameservice_float, .data = &my_lat },
243 { .name = "lon", .set_plugin_parameter = &set_nameservice_float, .data = &my_lon },
244 { .name = "latlon-file", .set_plugin_parameter = &set_plugin_string, .data = &my_latlon_file, .addon = {sizeof(my_latlon_file)} },
245 { .name = "latlon-infile", .set_plugin_parameter = &set_plugin_string, .data = &latlon_in_file, .addon = {sizeof(latlon_in_file)} },
246 { .name = "dns-server", .set_plugin_parameter = &set_nameservice_server, .data = &my_forwarders, .addon = {NAME_FORWARDER} },
247 { .name = "name", .set_plugin_parameter = &set_nameservice_name, .data = &my_names, .addon = {NAME_HOST} },
248 { .name = "service", .set_plugin_parameter = &set_nameservice_name, .data = &my_services, .addon = {NAME_SERVICE} },
249 { .name = "", .set_plugin_parameter = &set_nameservice_host, .data = &my_names },
252 void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
254 *params = plugin_parameters;
255 *size = sizeof(plugin_parameters)/sizeof(*plugin_parameters);
260 * queue the name/forwarder/service given in value
261 * to the front of my_list
264 add_name_to_list(struct name_entry *my_list, const char *value, int type, const union olsr_ip_addr *ip)
266 struct name_entry *tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry add_name_to_list");
267 tmp->name = strndup( value, MAX_NAME );
268 tmp->len = strlen( tmp->name );
270 // all IPs with value 0 will be set to main_addr later
272 memset(&tmp->ip, 0, sizeof(tmp->ip));
281 * last initialization
283 * we have to do this here because some things like main_addr
284 * or the dns suffix (for validation) are not known before
286 * this is beause of the order in which the plugin is initialized
287 * by the plugin loader:
288 * - first the parameters are sent
289 * - then register_olsr_data() from olsrd_plugin.c is called
290 * which sets up main_addr and some other variables
291 * - register_olsr_data() then then finally calls this function
296 struct name_entry *name;
297 union olsr_ip_addr ipz;
300 //regex string for validating the hostnames
301 const char *regex_name = "^[[:alnum:]_.-]+$";
302 //regex string for the service line
303 char *regex_service = olsr_malloc(256*sizeof(char) + strlen(my_suffix), "new *char from name_init for regex_service");
304 memset(&ipz, 0, sizeof(ipz));
306 //compile the regex from the string
307 if ((ret = regcomp(®ex_t_name, regex_name , REG_EXTENDED)) != 0)
309 /* #2: call regerror() if regcomp failed
310 * commented out, because only for debuggin needed
312 int errmsgsz = regerror(ret, ®ex_t_name, NULL, 0);
313 char *errmsg = malloc(errmsgsz);
314 regerror(ret, ®ex_t_name, errmsg, errmsgsz);
315 fprintf(stderr, "regcomp: %s", errmsg);
317 regfree(®ex_t_name);
319 OLSR_PRINTF(0, "compilation of regex \"%s\" for hostname failed", regex_name);
322 // a service line is something like prot://hostname.suffix:port|tcp|my little description about this service
323 // for example http://router.olsr:80|tcp|my homepage
324 // prot :// (hostname.suffix OR ip)
325 //regex_service = "^[[:alnum:]]+://(([[:alnum:]_.-]+.olsr)|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}))
326 // : port /path |(tcp OR udp) |short description
327 // :[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$";
328 strcpy(regex_service, "^[[:alnum:]]+://(([[:alnum:]_.-]+");
329 strcat(regex_service, my_suffix);
330 strcat(regex_service, ")|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3})):[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$");
332 /* #1: call regcomp() to compile the regex */
333 if ((ret = regcomp(®ex_t_service, regex_service , REG_EXTENDED )) != 0)
335 /* #2: call regerror() if regcomp failed
336 * commented out, because only for debuggin needed
338 int errmsgsz = regerror(ret, ®ex_t_service, NULL, 0);
339 char *errmsg = malloc(errmsgsz);
340 regerror(ret, ®ex_t_service, errmsg, errmsgsz);
341 fprintf(stderr, "regcomp: %s", errmsg);
343 regfree(®ex_t_service);
345 OLSR_PRINTF(0, "compilation of regex \"%s\" for hostname failed", regex_name);
348 regex_service = NULL;
350 //fill in main addr for all entries with ip==0
351 //this does not matter for service, because the ip does not matter
354 for (name = my_names; name != NULL; name = name->next) {
355 if (ipequal(&name->ip, &ipz)) {
356 OLSR_PRINTF(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
357 name->ip = olsr_cnf->main_addr;
360 for (name = my_forwarders; name != NULL; name = name->next) {
361 if (name->ip.v4.s_addr == 0) {
362 OLSR_PRINTF(2, "NAME PLUGIN: insert main addr for name %s \n", name->name);
363 name->ip = olsr_cnf->main_addr;
367 //check if entries I want to announce myself are valid and allowed
368 my_names = remove_nonvalid_names_from_list(my_names, NAME_HOST);
369 my_forwarders = remove_nonvalid_names_from_list(my_forwarders, NAME_FORWARDER);
370 my_services = remove_nonvalid_names_from_list(my_services, NAME_SERVICE);
373 /* register functions with olsrd */
374 olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
375 olsr_register_timeout_function(&olsr_timeout, OLSR_TRUE);
376 olsr_register_scheduler_event(&olsr_event, NULL, my_interval, 0, NULL);
377 mapwrite_init(my_latlon_file);
384 remove_nonvalid_names_from_list(struct name_entry *my_list, int type)
386 struct name_entry *next = my_list;
387 olsr_bool valid = OLSR_FALSE;
388 if (my_list == NULL) {
394 valid = is_name_wellformed(my_list->name) && allowed_ip(&my_list->ip);
397 valid = allowed_ip(&my_list->ip);
400 valid = allowed_service(my_list->name);
403 valid = is_latlon_wellformed(my_list->name);
409 struct ipaddr_str strbuf;
411 OLSR_PRINTF(1, "NAME PLUGIN: invalid or malformed parameter %s (%s), fix your config!\n", my_list->name, olsr_ip_to_string(&strbuf, &my_list->ip));
412 next = my_list->next;
414 my_list->name = NULL;
417 return remove_nonvalid_names_from_list(next, type);
420 struct ipaddr_str strbuf;
422 OLSR_PRINTF(2, "NAME PLUGIN: validate parameter %s (%s) -> OK\n", my_list->name, olsr_ip_to_string(&strbuf, &my_list->ip));
423 my_list->next = remove_nonvalid_names_from_list(my_list->next, type);
431 * called at unload: free everything
433 * XXX: should I delete the hosts/services/resolv.conf files on exit?
436 name_destructor(void)
438 OLSR_PRINTF(2, "NAME PLUGIN: exit. cleaning up...\n");
440 free_name_entry_list(&my_names);
441 free_name_entry_list(&my_services);
442 free_name_entry_list(&my_forwarders);
444 free_all_list_entries(list);
445 free_all_list_entries(service_list);
446 free_all_list_entries(forwarder_list);
447 free_all_list_entries(latlon_list);
449 regfree(®ex_t_name);
450 regfree(®ex_t_service);
454 /* free all list entries */
456 free_all_list_entries(struct db_entry **this_db_list)
460 for(i = 0; i < HASHSIZE; i++)
462 struct db_entry **tmp = &this_db_list[i];
465 struct db_entry *to_delete = *tmp;
467 free_name_entry_list(&to_delete->names);
476 * A timeout function called every time
478 * XXX:the scheduler is polled (by default 10 times a sec,
479 * which is far too often):
481 * time out old list entries
482 * and write changes to file
485 static int timeout_roundrobin = 0;
490 switch(timeout_roundrobin++)
493 timeout_old_names(list, &name_table_changed);
494 timeout_old_names(forwarder_list, &forwarder_table_changed);
495 timeout_old_names(service_list, &service_table_changed);
496 timeout_old_names(latlon_list, &latlon_table_changed);
499 write_resolv_file(); // if forwarder_table_changed
502 write_hosts_file(); // if name_table_changed
505 write_services_file(); // if service_table_changed
509 write_latlon_file(); // latlon_table_changed
513 timeout_roundrobin = 0;
518 timeout_old_names(struct db_entry **this_list, olsr_bool *this_table_changed)
520 struct db_entry **tmp;
521 struct db_entry *to_delete;
524 for(index=0;index<HASHSIZE;index++)
526 for (tmp = &this_list[index]; *tmp != NULL; )
528 /* check if the entry for this ip is timed out */
529 if (olsr_timed_out(&(*tmp)->timer))
532 struct ipaddr_str strbuf;
535 /* update the pointer in the linked list */
538 OLSR_PRINTF(2, "NAME PLUGIN: %s timed out... deleting\n",
539 olsr_ip_to_string(&strbuf, &to_delete->originator));
542 free_name_entry_list(&to_delete->names);
544 *this_table_changed = OLSR_TRUE;
554 * Scheduled event: generate and send NAME packet
557 olsr_event(void *foo __attribute__((unused)))
559 /* send buffer: huge */
561 union olsr_message *message = (union olsr_message *)buffer;
562 struct interface *ifn;
566 if(olsr_cnf->ip_version == AF_INET)
569 message->v4.olsr_msgtype = MESSAGE_TYPE;
570 message->v4.olsr_vtime = double_to_me(my_timeout);
571 memcpy(&message->v4.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
572 message->v4.ttl = MAX_TTL;
573 message->v4.hopcnt = 0;
574 message->v4.seqno = htons(get_msg_seqno());
576 namesize = encap_namemsg((struct namemsg*)&message->v4.message);
577 namesize = namesize + sizeof(struct olsrmsg);
579 message->v4.olsr_msgsize = htons(namesize);
584 message->v6.olsr_msgtype = MESSAGE_TYPE;
585 message->v6.olsr_vtime = double_to_me(my_timeout);
586 memcpy(&message->v6.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
587 message->v6.ttl = MAX_TTL;
588 message->v6.hopcnt = 0;
589 message->v6.seqno = htons(get_msg_seqno());
591 namesize = encap_namemsg((struct namemsg*)&message->v6.message);
592 namesize = namesize + sizeof(struct olsrmsg6);
594 message->v6.olsr_msgsize = htons(namesize);
597 /* looping trough interfaces */
598 for (ifn = ifnet; ifn ; ifn = ifn->int_next)
600 OLSR_PRINTF(3, "NAME PLUGIN: Generating packet - [%s]\n", ifn->int_name);
602 if(net_outbuffer_push(ifn, message, namesize) != namesize ) {
603 /* send data and try again */
605 if(net_outbuffer_push(ifn, message, namesize) != namesize ) {
606 OLSR_PRINTF(1, "NAME PLUGIN: could not send on interface: %s\n", ifn->int_name);
614 * Parse name olsr message of NAME type
617 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *ipaddr)
619 struct namemsg *namemessage;
620 union olsr_ip_addr originator;
625 /* Fetch the originator of the messsage */
626 if(olsr_cnf->ip_version == AF_INET) {
627 memcpy(&originator, &m->v4.originator, olsr_cnf->ipsize);
628 seqno = ntohs(m->v4.seqno);
630 memcpy(&originator, &m->v6.originator, olsr_cnf->ipsize);
631 seqno = ntohs(m->v6.seqno);
634 /* Fetch the message based on IP version */
635 if(olsr_cnf->ip_version == AF_INET) {
636 vtime = me_to_double(m->v4.olsr_vtime);
637 size = ntohs(m->v4.olsr_msgsize);
638 namemessage = (struct namemsg*)&m->v4.message;
641 vtime = me_to_double(m->v6.olsr_vtime);
642 size = ntohs(m->v6.olsr_msgsize);
643 namemessage = (struct namemsg*)&m->v6.message;
646 /* Check if message originated from this node.
648 if(ipequal(&originator, &olsr_cnf->main_addr))
651 /* Check that the neighbor this message was received from is symmetric.
653 if(check_neighbor_link(ipaddr) != SYM_LINK) {
655 struct ipaddr_str strbuf;
657 OLSR_PRINTF(3, "NAME PLUGIN: Received msg from NON SYM neighbor %s\n", olsr_ip_to_string(&strbuf, ipaddr));
661 /* Check if this message has been processed before
662 * Remeber that this also registeres the message as
663 * processed if nessecary
665 if(olsr_check_dup_table_proc(&originator, seqno)) {
666 /* If not so - process */
667 update_name_entry(&originator, namemessage, size, vtime);
670 /* Forward the message if nessecary
671 * default_fwd does all the work for us! */
672 olsr_forward_message(m, &originator, seqno, in_if, ipaddr);
676 * Encapsulate a name message into a packet.
678 * It assumed that there is enough space in the buffer to do this!
680 * Returns: the length of the message that was appended
683 encap_namemsg(struct namemsg* msg)
685 struct name_entry *my_name;
686 struct name_entry *my_service;
688 // add the hostname, service and forwarder entries after the namemsg header
689 char* pos = (char*)msg + sizeof(struct namemsg);
693 for (my_name = my_names; my_name!=NULL; my_name = my_name->next)
695 pos = create_packet( (struct name*) pos, my_name);
699 for (my_name = my_forwarders; my_name!=NULL; my_name = my_name->next)
701 pos = create_packet( (struct name*) pos, my_name);
705 for (my_service = my_services; my_service!=NULL; my_service = my_service->next)
707 pos = create_packet( (struct name*) pos, my_service);
711 if ('\0' != latlon_in_file[0])
713 FILE* in = fopen( latlon_in_file, "r" );
715 fscanf(in, "%f,%f", &my_lat, &my_lon);
720 OLSR_PRINTF(0, "NAME PLUGIN: cant read latlon in file %s\n", latlon_in_file);
723 if (0.0 != my_lat && 0.0 != my_lon)
727 memset(&e, 0, sizeof(e));
728 sprintf(s, "%f,%f,%d", my_lat, my_lon, get_isdefhna_latlon());
730 e.type = NAME_LATLON;
732 lookup_defhna_latlon(&e.ip);
733 pos = create_packet( (struct name*) pos, &e);
737 // write the namemsg header with the number of announced entries and the protocol version
738 msg->nr_names = htons(i);
739 msg->version = htons(NAME_PROTOCOL_VERSION);
741 return pos - (char*)msg; //length
746 * convert each of my to be announced name_entries into network
749 * return the length of the name packet
752 create_packet(struct name* to, struct name_entry *from)
754 char *pos = (char*) to;
757 struct ipaddr_str strbuf;
759 OLSR_PRINTF(3, "NAME PLUGIN: Announcing name %s (%s) %d\n",
760 from->name, olsr_ip_to_string(&strbuf, &from->ip), from->len);
761 to->type = htons(from->type);
762 to->len = htons(from->len);
764 pos += sizeof(struct name);
765 strncpy(pos, from->name, from->len);
767 for (k = from->len; (k & 3) != 0; k++)
773 * decapsulate a received name, service or forwarder and update the corresponding hash table if necessary
776 decap_namemsg(struct name *from_packet, struct name_entry **to, olsr_bool *this_table_changed )
779 struct ipaddr_str strbuf;
781 struct name_entry *tmp;
782 struct name_entry *already_saved_name_entries;
783 char *name = (char*)from_packet + sizeof(struct name);
784 int type_of_from_packet = ntohs(from_packet->type);
785 unsigned int len_of_name = ntohs(from_packet->len);
786 OLSR_PRINTF(4, "NAME PLUGIN: decap type=%d, len=%d, name=%s\n",
787 type_of_from_packet, len_of_name, name);
789 //XXX: should I check the from_packet->ip here? If so, why not also check the ip from HOST and SERVICE?
790 if( (type_of_from_packet==NAME_HOST && !is_name_wellformed(name)) ||
791 (type_of_from_packet==NAME_SERVICE && !is_service_wellformed(name)) ||
792 (type_of_from_packet==NAME_LATLON && !is_latlon_wellformed(name)))
794 OLSR_PRINTF(4, "NAME PLUGIN: invalid name [%s] received, skipping.\n", name );
798 //ignore all packets with a too long name
799 //or a spoofed len of its included name string
800 if (len_of_name > MAX_NAME || strlen(name) != len_of_name || NULL != strchr(name, '\\') || NULL != strchr(name, '\'')) {
801 OLSR_PRINTF(4, "NAME PLUGIN: from_packet->len %d > MAX_NAME %d or from_packet->len %d !0 strlen(name [%s] in packet)\n",
802 len_of_name, MAX_NAME, len_of_name, name );
806 // don't insert the received entry again, if it has already been inserted in the hash table.
807 // Instead only the validity time is set in insert_new_name_in_list function, which calls this one
808 for (already_saved_name_entries = (*to); already_saved_name_entries != NULL ; already_saved_name_entries = already_saved_name_entries->next)
810 if ( (type_of_from_packet==NAME_HOST || type_of_from_packet==NAME_SERVICE) && strncmp(already_saved_name_entries->name, name, len_of_name) == 0 ) {
811 OLSR_PRINTF(4, "NAME PLUGIN: received name or service entry %s (%s) already in hash table\n",
812 name, olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
814 } else if (type_of_from_packet==NAME_FORWARDER && ipequal(&already_saved_name_entries->ip, &from_packet->ip) ) {
815 OLSR_PRINTF(4, "NAME PLUGIN: received forwarder entry %s (%s) already in hash table\n",
816 name, olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
818 } else if (type_of_from_packet==NAME_LATLON ) {
819 if (0 != strncmp(already_saved_name_entries->name, name, len_of_name))
821 OLSR_PRINTF(4, "NAME PLUGIN: updating name %s -> %s (%s)\n",
822 already_saved_name_entries->name, name,
823 olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
824 free(already_saved_name_entries->name);
825 already_saved_name_entries->name = olsr_malloc(len_of_name + 1, "upd name_entry name");
826 strncpy(already_saved_name_entries->name, name, len_of_name);
827 *this_table_changed = OLSR_TRUE;
829 if (!ipequal(&already_saved_name_entries->ip, &from_packet->ip))
832 struct ipaddr_str strbuf2, strbuf3;
834 OLSR_PRINTF(4, "NAME PLUGIN: updating ip %s -> %s (%s)\n",
835 olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip),
836 olsr_ip_to_string(&strbuf2, &from_packet->ip),
837 olsr_ip_to_string(&strbuf3, &already_saved_name_entries->ip));
838 already_saved_name_entries->ip = from_packet->ip;
839 *this_table_changed = OLSR_TRUE;
841 if (!*this_table_changed)
843 OLSR_PRINTF(4, "NAME PLUGIN: received latlon entry %s (%s) already in hash table\n",
844 name, olsr_ip_to_string(&strbuf, &already_saved_name_entries->ip));
850 //if not yet known entry
851 tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry");
852 tmp->type = ntohs(from_packet->type);
853 tmp->len = len_of_name > MAX_NAME ? MAX_NAME : ntohs(from_packet->len);
854 tmp->name = olsr_malloc(tmp->len+1, "new name_entry name");
855 tmp->ip = from_packet->ip;
856 strncpy(tmp->name, name, tmp->len);
857 tmp->name[tmp->len] = '\0';
859 OLSR_PRINTF(3, "\nNAME PLUGIN: create new name/service/forwarder entry %s (%s) [len=%d] [type=%d] in linked list\n",
860 tmp->name, olsr_ip_to_string(&strbuf, &tmp->ip), tmp->len, tmp->type);
862 *this_table_changed = OLSR_TRUE;
871 * unpack the received message and delegate to the decapsulation function for each
872 * name/service/forwarder entry in the message
875 update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, double vtime)
878 struct ipaddr_str strbuf;
881 struct name *from_packet;
884 OLSR_PRINTF(3, "NAME PLUGIN: Received Message from %s\n",
885 olsr_ip_to_string(&strbuf, originator));
887 if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) {
888 OLSR_PRINTF(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version);
892 /* now add the names from the message */
893 pos = (char*)msg + sizeof(struct namemsg);
894 end_pos = pos + msg_size - sizeof(struct name*); // at least one struct name has to be left
896 for (i=ntohs(msg->nr_names); i > 0 && pos<end_pos; i--)
898 from_packet = (struct name*)pos;
900 switch (ntohs(from_packet->type)) {
902 insert_new_name_in_list(originator, list, from_packet, &name_table_changed, vtime);
905 insert_new_name_in_list(originator, forwarder_list, from_packet, &forwarder_table_changed, vtime);
908 insert_new_name_in_list(originator, service_list, from_packet, &service_table_changed, vtime);
911 insert_new_name_in_list(originator, latlon_list, from_packet, &latlon_table_changed, vtime);
914 OLSR_PRINTF(3, "NAME PLUGIN: Received Message of unknown type [%d] from (%s)\n", from_packet->type, olsr_ip_to_string(&strbuf, originator));
918 pos += sizeof(struct name);
919 pos += 1 + (( ntohs(from_packet->len) - 1) | 3);
922 OLSR_PRINTF(4, "NAME PLUGIN: Lost %d entries in received packet due to length inconsistency (%s)\n", i, olsr_ip_to_string(&strbuf, originator));
927 * insert all the new names,services and forwarders from a received packet into the
928 * corresponding entry for this ip in the corresponding hash table
931 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)
934 struct db_entry *entry;
936 olsr_bool entry_found = OLSR_FALSE;
938 hash = olsr_hashing(originator);
940 /* find the entry for originator, if there is already one */
941 for (entry = this_list[hash]; entry != NULL; entry = entry->next)
943 if (ipequal(originator, &entry->originator)) {
945 struct ipaddr_str strbuf;
948 OLSR_PRINTF(4, "NAME PLUGIN: found entry for (%s) in its hash table\n", olsr_ip_to_string(&strbuf, originator));
950 //delegate to function for parsing the packet and linking it to entry->names
951 decap_namemsg(from_packet, &entry->names, this_table_changed);
953 olsr_get_timestamp(vtime * 1000, &entry->timer);
955 entry_found = OLSR_TRUE;
961 struct ipaddr_str strbuf;
963 OLSR_PRINTF(3, "NAME PLUGIN: create new db entry for ip (%s) in hash table\n", olsr_ip_to_string(&strbuf, originator));
965 /* insert a new entry */
966 entry = olsr_malloc(sizeof(struct db_entry), "new db_entry");
968 entry->originator = *originator;
969 olsr_get_timestamp(vtime * 1000, &entry->timer);
973 entry->next = this_list[hash];
974 this_list[hash] = entry;
976 //delegate to function for parsing the packet and linking it to entry->names
977 decap_namemsg(from_packet, &entry->names, this_table_changed);
982 * write names to a file in /etc/hosts compatible format
985 write_hosts_file(void)
988 struct name_entry *name;
989 struct db_entry *entry;
995 if (!name_table_changed)
998 OLSR_PRINTF(2, "NAME PLUGIN: writing hosts file\n");
1000 hosts = fopen( my_hosts_file, "w" );
1001 if (hosts == NULL) {
1002 OLSR_PRINTF(2, "NAME PLUGIN: cant write hosts file\n");
1006 fprintf(hosts, "### this /etc/hosts file is overwritten regularly by olsrd\n");
1007 fprintf(hosts, "### do not edit\n\n");
1009 fprintf(hosts, "127.0.0.1\tlocalhost\n");
1010 fprintf(hosts, "::1\t\tlocalhost\n\n");
1012 // copy content from additional hosts filename
1013 if (my_add_hosts[0] != '\0') {
1014 add_hosts = fopen( my_add_hosts, "r" );
1015 if (add_hosts == NULL) {
1016 OLSR_PRINTF(2, "NAME PLUGIN: cant open additional hosts file\n");
1019 fprintf(hosts, "### contents from '%s' ###\n\n", my_add_hosts);
1020 while ((c = getc(add_hosts)) != EOF)
1024 fprintf(hosts, "\n### olsr names ###\n\n");
1028 for (name = my_names; name != NULL; name = name->next) {
1029 struct ipaddr_str strbuf;
1030 fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&strbuf, &name->ip), name->name, my_suffix );
1033 // write received names
1034 for (hash = 0; hash < HASHSIZE; hash++)
1036 for(entry = list[hash]; entry != NULL; entry = entry->next)
1038 for (name = entry->names; name != NULL; name = name->next)
1040 struct ipaddr_str strbuf;
1041 OLSR_PRINTF(6, "%s\t%s%s", olsr_ip_to_string(&strbuf, &name->ip), name->name, my_suffix);
1042 OLSR_PRINTF(6, "\t#%s\n", olsr_ip_to_string(&strbuf, &entry->originator));
1044 fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&strbuf, &name->ip), name->name, my_suffix);
1045 fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&strbuf, &entry->originator));
1050 if (time(&currtime)) {
1051 fprintf(hosts, "\n### written by olsrd at %s", ctime(&currtime));
1055 name_table_changed = OLSR_FALSE;
1060 * write services to a file in the format:
1061 * service #originator ip
1063 * since service has a special format
1064 * each line will look similar to e.g.
1065 * http://me.olsr:80|tcp|my little homepage
1068 write_services_file(void)
1071 struct name_entry *name;
1072 struct db_entry *entry;
1073 FILE* services_file;
1077 if (!service_table_changed)
1080 OLSR_PRINTF(2, "NAME PLUGIN: writing services file\n");
1082 services_file = fopen( my_services_file, "w" );
1083 if (services_file == NULL) {
1084 OLSR_PRINTF(2, "NAME PLUGIN: cant write services_file file\n");
1088 fprintf(services_file, "### this file is overwritten regularly by olsrd\n");
1089 fprintf(services_file, "### do not edit\n\n");
1092 // write own services
1093 for (name = my_services; name != NULL; name = name->next) {
1094 fprintf(services_file, "%s\t# my own service\n", name->name);
1097 // write received services
1098 for (hash = 0; hash < HASHSIZE; hash++)
1100 for(entry = service_list[hash]; entry != NULL; entry = entry->next)
1102 for (name = entry->names; name != NULL; name = name->next)
1104 struct ipaddr_str strbuf;
1105 OLSR_PRINTF(6, "%s\t", name->name);
1106 OLSR_PRINTF(6, "\t#%s\n", olsr_ip_to_string(&strbuf, &entry->originator));
1108 fprintf(services_file, "%s\t", name->name );
1109 fprintf(services_file, "\t#%s\n", olsr_ip_to_string(&strbuf, &entry->originator));
1114 if (time(&currtime)) {
1115 fprintf(services_file, "\n### written by olsrd at %s", ctime(&currtime));
1118 fclose(services_file);
1119 service_table_changed = OLSR_FALSE;
1123 * Sort the nameserver pointer array.
1125 * fresh entries are at the beginning of the array and
1126 * the best entry is at the end of the array.
1129 select_best_nameserver(struct rt_entry **rt)
1132 struct rt_entry *rt1, *rt2;
1134 for (nameserver_idx = 0;
1135 nameserver_idx < NAMESERVER_COUNT;
1138 rt1 = rt[nameserver_idx];
1139 rt2 = rt[nameserver_idx+1];
1142 * compare the next two pointers in the array.
1143 * if the second pointer is NULL then percolate it up.
1145 if (!rt2 || olsr_cmp_rt(rt1, rt2)) {
1147 struct ipaddr_str strbuf;
1150 * first is better, swap the pointers.
1152 OLSR_PRINTF(6, "NAME PLUGIN: nameserver %s, etx %.3f\n",
1153 olsr_ip_to_string(&strbuf, &rt1->rt_dst.prefix),
1154 rt1->rt_best->rtp_metric.etx);
1156 rt[nameserver_idx] = rt2;
1157 rt[nameserver_idx+1] = rt1;
1163 * write the 3 best upstream DNS servers to resolv.conf file
1164 * best means the 3 with the best etx value in routing table
1167 write_resolv_file(void)
1170 struct name_entry *name;
1171 struct db_entry *entry;
1172 struct rt_entry *route;
1173 static struct rt_entry *nameserver_routes[NAMESERVER_COUNT+1];
1178 if (!forwarder_table_changed || my_forwarders != NULL || my_resolv_file[0] == '\0')
1181 /* clear the array of 3+1 nameserver routes */
1182 memset(nameserver_routes, 0, sizeof(nameserver_routes));
1184 for (hash = 0; hash < HASHSIZE; hash++)
1186 for(entry = forwarder_list[hash]; entry != NULL; entry = entry->next)
1188 for (name = entry->names; name != NULL; name = name->next)
1191 struct ipaddr_str strbuf;
1193 route = olsr_lookup_routing_table(&name->ip);
1195 OLSR_PRINTF(6, "NAME PLUGIN: check route for nameserver %s %s",
1196 olsr_ip_to_string(&strbuf, &name->ip),
1197 route ? "suceeded" : "failed");
1199 if (route==NULL) // it's possible that route is not present yet
1202 /* enqueue it on the head of list */
1203 *nameserver_routes = route;
1204 OLSR_PRINTF(6, "NAME PLUGIN: found nameserver %s, etx %.3f",
1205 olsr_ip_to_string(&strbuf, &name->ip),
1206 route->rt_best->rtp_metric.etx);
1208 /* find the closet one */
1209 select_best_nameserver(nameserver_routes);
1214 /* if there is no best route we are done */
1215 if (nameserver_routes[NAMESERVER_COUNT]==NULL)
1219 OLSR_PRINTF(2, "NAME PLUGIN: try to write to resolv file\n");
1220 resolv = fopen( my_resolv_file, "w" );
1221 if (resolv == NULL) {
1222 OLSR_PRINTF(2, "NAME PLUGIN: can't write resolv file\n");
1225 fprintf(resolv, "### this file is overwritten regularly by olsrd\n");
1226 fprintf(resolv, "### do not edit\n\n");
1228 for (i = NAMESERVER_COUNT; i >= 0; i--) {
1229 struct ipaddr_str strbuf;
1231 route = nameserver_routes[i];
1233 OLSR_PRINTF(2, "NAME PLUGIN: nameserver_routes #%d %p\n", i, route);
1239 OLSR_PRINTF(2, "NAME PLUGIN: nameserver %s\n",
1240 olsr_ip_to_string(&strbuf, &route->rt_dst.prefix));
1241 fprintf(resolv, "nameserver %s\n",
1242 olsr_ip_to_string(&strbuf, &route->rt_dst.prefix));
1244 if (time(&currtime)) {
1245 fprintf(resolv, "\n### written by olsrd at %s", ctime(&currtime));
1248 forwarder_table_changed = OLSR_FALSE;
1253 * completely free a list of name_entries
1256 free_name_entry_list(struct name_entry **list)
1258 struct name_entry **tmp = list;
1259 struct name_entry *to_delete;
1260 while (*tmp != NULL) {
1262 *tmp = (*tmp)->next;
1263 free( to_delete->name );
1264 to_delete->name = NULL;
1272 * we only allow names for IP addresses which we are
1274 * so the IP must either be from one of the interfaces
1275 * or inside a HNA which we have configured
1278 allowed_ip(const union olsr_ip_addr *addr)
1280 struct ip_prefix_list *hna;
1281 struct interface *iface;
1282 union olsr_ip_addr tmp_ip, tmp_msk;
1284 struct ipaddr_str strbuf;
1287 OLSR_PRINTF(6, "checking %s\n", olsr_ip_to_string(&strbuf, addr));
1289 for(iface = ifnet; iface; iface = iface->int_next)
1291 OLSR_PRINTF(6, "interface %s\n", olsr_ip_to_string(&strbuf, &iface->ip_addr));
1292 if (ipequal(&iface->ip_addr, addr)) {
1293 OLSR_PRINTF(6, "MATCHED\n");
1298 if (olsr_cnf->ip_version == AF_INET) {
1299 for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
1300 union olsr_ip_addr netmask;
1301 OLSR_PRINTF(6, "HNA %s/%d\n",
1302 olsr_ip_to_string(&strbuf, &hna->net.prefix),
1303 hna->net.prefix_len);
1304 if (hna->net.prefix_len == 0) {
1307 olsr_prefix_to_netmask(&netmask, hna->net.prefix_len);
1308 if ((addr->v4.s_addr & netmask.v4.s_addr) == hna->net.prefix.v4.s_addr) {
1309 OLSR_PRINTF(6, "MATCHED\n");
1314 for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next)
1317 OLSR_PRINTF(6, "HNA %s/%d\n",
1318 olsr_ip_to_string(&strbuf, &hna->net.prefix),
1319 hna->net.prefix_len);
1320 if ( hna->net.prefix_len == 0 )
1322 olsr_prefix_to_netmask(&tmp_msk, hna->net.prefix_len);
1323 for (i = 0; i < sizeof(tmp_ip.v6.s6_addr); i++) {
1324 tmp_ip.v6.s6_addr[i] = addr->v6.s6_addr[i] & tmp_msk.v6.s6_addr[i];
1326 if (ipequal(&tmp_ip, &hna->net.prefix)) {
1327 OLSR_PRINTF(6, "MATCHED\n");
1335 /** check if name has the right syntax, i.e. it must adhere to a special regex
1336 * stored in regex_t_name
1337 * necessary to avaid names like "0.0.0.0 google.de\n etc"
1340 is_name_wellformed(const char *name) {
1341 return regexec(®ex_t_name, name, 1, ®match_t_name, 0) == 0 ;
1346 * check if the service is in the right syntax and also that the hostname
1347 * or ip whithin the service is allowed
1350 allowed_service(const char *service_line)
1352 /* the call of is_service_wellformed generates the submatches stored in regmatch_t_service
1353 * these are then used by allowed_hostname_or_ip_in_service
1354 * see regexec(3) for more infos */
1355 if (!is_service_wellformed(service_line)) {
1357 } else if (!allowed_hostname_or_ip_in_service(service_line, &(regmatch_t_service[1]))) {
1365 allowed_hostname_or_ip_in_service(const char *service_line, const regmatch_t *hostname_or_ip_match)
1367 char *hostname_or_ip;
1368 union olsr_ip_addr olsr_ip;
1369 struct name_entry *name;
1370 if (hostname_or_ip_match->rm_so < 0 || hostname_or_ip_match->rm_eo < 0) {
1374 hostname_or_ip = strndup(&service_line[hostname_or_ip_match->rm_so], hostname_or_ip_match->rm_eo - hostname_or_ip_match->rm_so);
1375 //hostname is one of the names, that I announce (i.e. one that i am allowed to announce)
1376 for (name = my_names; name != NULL; name = name->next) {
1377 if (strncmp(name->name, hostname_or_ip, name->len - strlen(my_suffix)) == 0 ) {
1378 OLSR_PRINTF(4, "NAME PLUGIN: hostname %s in service %s is OK\n", hostname_or_ip, service_line);
1379 free(hostname_or_ip);
1380 hostname_or_ip = NULL;
1385 //ip in service-line is allowed
1386 if (inet_pton(olsr_cnf->ip_version, hostname_or_ip, &olsr_ip) > 0) {
1387 if (allowed_ip(&olsr_ip)) {
1389 struct ipaddr_str strbuf;
1391 OLSR_PRINTF(2, "NAME PLUGIN: ip %s in service %s is OK\n", olsr_ip_to_string(&strbuf, &olsr_ip), service_line);
1392 free(hostname_or_ip);
1393 hostname_or_ip = NULL;
1398 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);
1399 free(hostname_or_ip);
1400 hostname_or_ip = NULL;
1406 * check if the service matches the syntax
1407 * of "protocol://host:port/path|tcp_or_udp|a short description",
1408 * which is given in the regex regex_t_service
1411 is_service_wellformed(const char *service_line)
1413 return regexec(®ex_t_service, service_line, pmatch_service, regmatch_t_service, 0) == 0;
1417 * check if the latlot matches the syntax
1420 is_latlon_wellformed(const char *latlon_line)
1423 float a = 0.0, b = 0.0;
1424 sscanf(latlon_line, "%f,%f,%d", &a, &b, &hna);
1425 return (a != 0.0 && b != 0.0 && -1 != hna);
1429 * Returns 1 if this olsrd announces inet
1431 olsr_bool get_isdefhna_latlon(void)
1433 struct ip_prefix_list *hna;
1434 for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next){
1435 if (hna->net.prefix_len == 0) {
1443 * Grabs the current HNA selected default route
1445 void lookup_defhna_latlon(union olsr_ip_addr *ip)
1447 struct avl_node *rt_tree_node;
1448 struct olsr_ip_prefix prefix;
1450 memset(ip, 0, sizeof(ip));
1451 memset(&prefix, 0, sizeof(prefix));
1453 if (NULL != (rt_tree_node = avl_find(&routingtree, &prefix)))
1455 *ip = ((struct rt_entry *)rt_tree_node->data)->rt_best->rtp_nexthop.gateway;
1460 * lookup a nodes name
1463 lookup_name_latlon(union olsr_ip_addr *ip)
1466 struct db_entry *entry;
1467 struct name_entry *name;
1468 for (hash = 0; hash < HASHSIZE; hash++)
1470 for(entry = list[hash]; entry != NULL; entry = entry->next)
1472 for (name = entry->names; name != NULL; name = name->next)
1474 if (ipequal(&name->ip, ip)) return name->name;
1483 * write latlon positions to a javascript file
1486 write_latlon_file(void)
1490 if (!my_names || !latlon_table_changed) return;
1492 OLSR_PRINTF(2, "NAME PLUGIN: writing latlon file\n");
1494 if (NULL == (fmap = fopen(my_latlon_file, "w"))) {
1495 OLSR_PRINTF(0, "NAME PLUGIN: cant write latlon file\n");
1498 fprintf(fmap, "/* This file is overwritten regularly by olsrd */\n");
1499 mapwrite_work(fmap);
1501 latlon_table_changed = OLSR_FALSE;
1508 * c-indent-tabs-mode: t
1509 * indent-tabs-mode: t