diff -Nur olsrd-0.4.10.orig/lib/nameservice/src/nameservice.c olsrd-0.4.10/lib/nameservice/src/nameservice.c --- olsrd-0.4.10.orig/lib/nameservice/src/nameservice.c 2005-05-29 14:47:42.000000000 +0200 +++ olsrd-0.4.10/lib/nameservice/src/nameservice.c 2006-12-01 08:26:58.000000000 +0100 @@ -1,4 +1,5 @@ /* + * Copyright (c) 2006, Jens Nachtigall * Copyright (c) 2005, Bruno Randolf * Copyright (c) 2004, Andreas Tønnesen(andreto-at-olsr.org) * All rights reserved. @@ -39,6 +40,9 @@ #include #include #include +#include +#include +#include #include "olsr.h" #include "net_olsr.h" @@ -53,6 +57,7 @@ #include "olsrd_copy.h" #include "compat.h" + /* send buffer: huge */ static char buffer[10240]; @@ -62,15 +67,35 @@ static char my_suffix[MAX_SUFFIX]; static int my_interval = EMISSION_INTERVAL; static double my_timeout = NAME_VALID_TIME; -static olsr_bool have_dns_server = OLSR_FALSE; -static union olsr_ip_addr my_dns_server; static char my_resolv_file[MAX_FILE +1]; +static char my_services_file[MAX_FILE + 1]; -/* the database (using hashing) */ +/* the databases (using hashing) + * for hostnames, service_lines and dns-servers + * + * my own hostnames, service_lines and dns-servers + * are store in a linked list (without hashing) + * */ struct db_entry* list[HASHSIZE]; struct name_entry *my_names = NULL; olsr_bool name_table_changed = OLSR_TRUE; +struct db_entry* service_list[HASHSIZE]; +struct name_entry *my_services = NULL; +olsr_bool service_table_changed = OLSR_TRUE; + +struct db_entry* forwarder_list[HASHSIZE]; +struct name_entry *my_forwarders = NULL; +olsr_bool forwarder_table_changed = OLSR_TRUE; + +/* regualar expression to be matched by valid hostnames, compiled in name_init() */ +regex_t regex_t_name; +regmatch_t regmatch_t_name; + +/* regualar expression to be matched by valid service_lines, compiled in name_init() */ +regex_t regex_t_service; +int pmatch_service = 10; +regmatch_t regmatch_t_service[10]; /** * do initialization @@ -84,27 +109,39 @@ int len; GetWindowsDirectory(my_hosts_file, MAX_FILE - 12); + GetWindowsDirectory(my_services_file, MAX_FILE - 12); len = strlen(my_hosts_file); - if (my_hosts_file[len - 1] != '\\') my_hosts_file[len++] = '\\'; - strcpy(my_hosts_file + len, "hosts_olsr"); + + len = strlen(my_services_file); + if (my_services_file[len - 1] != '\\') + my_services_file[len++] = '\\'; + strcpy(my_services_file + len, "services_olsr"); + + len = strlen(my_resolv_file); + if (my_resolv_file[len - 1] != '\\') + my_resolv_file[len++] = '\\'; + strcpy(my_resolv_file + len, "resolvconf_olsr"); #else strcpy(my_hosts_file, "/var/run/hosts_olsr"); + strcpy(my_services_file, "/var/run/services_olsr"); + strcpy(my_resolv_file, "/var/run/resolvconf_olsr"); #endif my_suffix[0] = '\0'; my_add_hosts[0] = '\0'; - my_resolv_file[0] = '\0'; - /* init list */ + /* init lists */ for(i = 0; i < HASHSIZE; i++) { list[i] = NULL; + forwarder_list[i] = NULL; + service_list[i] = NULL; } - memset(&my_dns_server, 0, sizeof(my_dns_server)); + } @@ -116,56 +153,53 @@ { if(!strcmp(key, "interval")) { my_interval = atoi(value); - printf("\nNAME PLUGIN: parameter interval: %d\n", my_interval); + olsr_printf(1,"\nNAME PLUGIN: parameter interval: %d", my_interval); } else if(!strcmp(key, "timeout")) { my_timeout = atof(value); - printf("\nNAME PLUGIN: parameter timeout: %f\n", my_timeout); + olsr_printf(1,"\nNAME PLUGIN: parameter timeout: %f", my_timeout); } else if(!strcmp(key, "hosts-file")) { strncpy( my_hosts_file, value, MAX_FILE ); - printf("\nNAME PLUGIN: parameter filename: %s\n", my_hosts_file); + olsr_printf(1,"\nNAME PLUGIN: parameter filename: %s", my_hosts_file); } else if(!strcmp(key, "resolv-file")) { strncpy(my_resolv_file, value, MAX_FILE); - printf("\nNAME PLUGIN: parameter resolv file: %s\n", my_resolv_file); + olsr_printf(1,"\nNAME PLUGIN: parameter resolv-file: %s", my_resolv_file); } else if(!strcmp(key, "suffix")) { strncpy(my_suffix, value, MAX_SUFFIX); - printf("\nNAME PLUGIN: parameter suffix: %s\n", my_suffix); + olsr_printf(1,"\nNAME PLUGIN: parameter suffix: %s", my_suffix); } else if(!strcmp(key, "add-hosts")) { strncpy(my_add_hosts, value, MAX_FILE); - printf("\nNAME PLUGIN: parameter additional host: %s\n", my_add_hosts); + olsr_printf(1,"\nNAME PLUGIN: parameter additional host: %s", my_add_hosts); + } + else if(!strcmp(key, "services-file")) { + strncpy(my_services_file, value, MAX_FILE); + olsr_printf(1,"\nNAME PLUGIN: parameter services-file: %s", my_services_file); } else if(!strcmp(key, "dns-server")) { struct in_addr ip; if (strlen(value) == 0) { - // set dns server ip to main address - // which is not known yet - have_dns_server = OLSR_TRUE; - } - else if (inet_aton(value, &ip)) { - my_dns_server.v4 = ip.s_addr; - have_dns_server = OLSR_TRUE; - } - else { - printf("\nNAME PLUGIN: invalid dns-server IP %s\n", value); - } + my_forwarders = add_name_to_list(my_forwarders, "", NAME_FORWARDER, NULL); + olsr_printf(1,"\nNAME PLUGIN: parameter dns-server: (main address)"); + } else if (inet_aton(value, &ip)) { + my_forwarders = add_name_to_list(my_forwarders, "", NAME_FORWARDER, &ip); + olsr_printf(1,"\nNAME PLUGIN: parameter dns-server: (%s)", value); + } else { + olsr_printf(1,"\nNAME PLUGIN: invalid parameter dns-server: %s ", value); + } } else if(!strcmp(key, "name")) { // name for main address - struct name_entry *tmp; - tmp = malloc(sizeof(struct name_entry)); - tmp->name = strndup( value, MAX_NAME ); - tmp->len = strlen( tmp->name ); - tmp->type = NAME_HOST; - // will be set to main_addr later - memset(&tmp->ip, 0, sizeof(tmp->ip)); - tmp->next = my_names; - my_names = tmp; - - printf("\nNAME PLUGIN: parameter name: %s (main address)\n", tmp->name); + my_names = add_name_to_list(my_names, value, NAME_HOST, NULL); + olsr_printf(1,"\nNAME PLUGIN: parameter name: %s (main address)", value); + } + else if(!strcmp(key, "service")) { + // name for main address + my_services = add_name_to_list(my_services, value, NAME_SERVICE, NULL); + olsr_printf(1,"\nNAME PLUGIN: parameter service: %s (main address)", value); } else { // assume this is an IP address and hostname @@ -173,33 +207,46 @@ if (inet_aton(key, &ip)) { // the IP is validated later - struct name_entry *tmp; - tmp = malloc(sizeof(struct name_entry)); - tmp->name = strndup( value, MAX_NAME ); - tmp->len = strlen( tmp->name ); - tmp->type = NAME_HOST; - tmp->ip.v4 = ip.s_addr; - tmp->next = my_names; - my_names = tmp; - printf("\nNAME PLUGIN: parameter %s (%s)\n", tmp->name, - olsr_ip_to_string(&tmp->ip)); + my_names = add_name_to_list(my_names, value, NAME_HOST, &ip); + olsr_printf(1,"\nNAME PLUGIN: parameter name %s (%s)", value, key); } else { - printf("\nNAME PLUGIN: invalid IP %s for name %s!\n", key, value); + olsr_printf(1,"\nNAME PLUGIN: invalid parameter name: %s (%s)!", value, key); } } return 1; } +/** + * queue the name/forwarder/service given in value + * to the front of my_list + */ +struct name_entry* +add_name_to_list(struct name_entry *my_list, char *value, int type, struct in_addr *ip) +{ + struct name_entry *tmp; + tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry add_name_to_list"); + tmp->name = strndup( value, MAX_NAME ); + tmp->len = strlen( tmp->name ); + tmp->type = type; + // all IPs with value 0 will be set to main_addr later + if (ip==NULL) + memset(&tmp->ip, 0, sizeof(tmp->ip)); + else + tmp->ip.v4 = ip->s_addr; + tmp->next = my_list; + return tmp; +} + /** * last initialization * * we have to do this here because some things like main_addr - * are not known before + * or the dns suffix (for validation) are not known before * - * this is beause of the order in which the plugin is initzalized + * this is beause of the order in which the plugin is initialized * by the plugin loader: * - first the parameters are sent * - then register_olsr_data() from olsrd_plugin.c is called @@ -210,50 +257,78 @@ name_init() { struct name_entry *name; - struct name_entry *prev=NULL; - - /* fixup names and IP addresses */ + int ret; + //regex string for validating the hostnames + char *regex_name = "^[[:alnum:]_.-]+$"; + //regex string for the service line + char *regex_service = olsr_malloc(256*sizeof(char) + strlen(my_suffix), "new *char from name_init for regex_service"); + + //compile the regex from the string + if ((ret = regcomp(®ex_t_name, regex_name , REG_EXTENDED)) != 0) + { + /* #2: call regerror() if regcomp failed + * commented out, because only for debuggin needed + * + int errmsgsz = regerror(ret, ®ex_t_name, NULL, 0); + char *errmsg = malloc(errmsgsz); + regerror(ret, ®ex_t_name, errmsg, errmsgsz); + fprintf(stderr, "regcomp: %s", errmsg); + free(errmsg); + regfree(®ex_t_name); + * */ + olsr_printf(0, "compilation of regex \"%s\" for hostname failed", regex_name); + } + + // a service line is something like prot://hostname.suffix:port|tcp|my little description about this service + // for example http://router.olsr:80|tcp|my homepage + // prot :// (hostname.suffix OR ip) + //regex_service = "^[[:alnum:]]+://(([[:alnum:]_.-]+.olsr)|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3})) + // : port /path |(tcp OR udp) |short description + // :[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$"; + strcat (strcat (strcat(regex_service, "^[[:alnum:]]+://(([[:alnum:]_.-]+"), + my_suffix), + ")|([[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3})):[[:digit:]]+[[:alnum:]/?._=#-]*\\|(tcp|udp)\\|[^|[:cntrl:]]+$"); + + /* #1: call regcomp() to compile the regex */ + if ((ret = regcomp(®ex_t_service, regex_service , REG_EXTENDED )) != 0) + { + /* #2: call regerror() if regcomp failed + * commented out, because only for debuggin needed + * + int errmsgsz = regerror(ret, ®ex_t_service, NULL, 0); + char *errmsg = malloc(errmsgsz); + regerror(ret, ®ex_t_service, errmsg, errmsgsz); + fprintf(stderr, "regcomp: %s", errmsg); + free(errmsg); + regfree(®ex_t_service); + * */ + olsr_printf(0, "compilation of regex \"%s\" for hostname failed", regex_name); + } + free(regex_service); + regex_service = NULL; + + //fill in main addr for all entries with ip==0 + //this does not matter for service, because the ip does not matter + //for service for (name = my_names; name != NULL; name = name->next) { - if (name->ip.v4 == 0) { - // insert main_addr + if (name->ip.v4 == 0) { + olsr_printf(2, "NAME PLUGIN: insert main addr for name %s \n", name->name); memcpy(&name->ip, &main_addr, ipsize); - prev = name; - } else { - // IP from config file - // check if we are allowed to announce a name for this IP - // we can only do this if we also announce the IP - if (!allowed_ip(&name->ip)) { - olsr_printf(1, "NAME PLUGIN: name for unknown IP %s not allowed, fix your config!\n", - olsr_ip_to_string(&name->ip)); - if (prev!=NULL) { - prev->next = name->next; - free(name->name); - free(name); - } - } - else { - prev = name; - } - } - } + } + } + for (name = my_forwarders; name != NULL; name = name->next) { + if (name->ip.v4 == 0) { + olsr_printf(2, "NAME PLUGIN: insert main addr for name %s \n", name->name); + memcpy(&name->ip, &main_addr, ipsize); + } + } + + //check if entries I want to announce myself are valid and allowed + my_names = remove_nonvalid_names_from_list(my_names, NAME_HOST); + my_forwarders = remove_nonvalid_names_from_list(my_forwarders, NAME_FORWARDER); + my_services = remove_nonvalid_names_from_list(my_services, NAME_SERVICE); + - if (have_dns_server) { - if (my_dns_server.v4 == 0) { - memcpy(&my_dns_server, &main_addr, ipsize); - printf("\nNAME PLUGIN: announcing upstream DNS server: %s\n", - olsr_ip_to_string(&my_dns_server)); - } - else if (!allowed_ip(&my_dns_server)) { - printf("NAME PLUGIN: announcing DNS server on unknown IP %s is not allowed, fix your config!\n", - olsr_ip_to_string(&my_dns_server)); - memset(&my_dns_server, 0, sizeof(my_dns_server)); - have_dns_server = OLSR_FALSE; - } - else { - printf("\nNAME PLUGIN: announcing upstream DNS server: %s\n", - olsr_ip_to_string(&my_dns_server)); - } - } /* register functions with olsrd */ olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1); @@ -263,22 +338,75 @@ return 1; } +struct name_entry* +remove_nonvalid_names_from_list(struct name_entry *my_list, int type) +{ + struct name_entry *next = my_list; + olsr_bool valid = OLSR_FALSE; + if (my_list == NULL) { + return NULL; + } + + switch (type) { + case NAME_HOST: + valid = is_name_wellformed(my_list->name) && allowed_ip(&my_list->ip); + break; + case NAME_FORWARDER: + valid = allowed_ip(&my_list->ip); + break; + case NAME_SERVICE: + valid = allowed_service(my_list->name); + break; + } + + if ( !valid ) { + 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)); + next = my_list->next; + free(my_list->name); + my_list->name = NULL; + free(my_list); + my_list = NULL; + return remove_nonvalid_names_from_list(next, type); + } else { + olsr_printf(2, "NAME PLUGIN: validate parameter %s (%s) -> OK\n", my_list->name, olsr_ip_to_string(&my_list->ip)); + my_list->next = remove_nonvalid_names_from_list(my_list->next, type); + return my_list; + } +} + + /** * called at unload: free everything + * + * XXX: should I delete the hosts/services/resolv.conf files on exit? */ void name_destructor() { - int i; - struct db_entry **tmp; - struct db_entry *to_delete; - olsr_printf(2, "NAME PLUGIN: exit. cleaning up...\n"); free_name_entry_list(&my_names); + free_name_entry_list(&my_services); + free_name_entry_list(&my_forwarders); + + free_all_list_entries(list); + free_all_list_entries(service_list); + free_all_list_entries(forwarder_list); + + regfree(®ex_t_name); + regfree(®ex_t_service); + +} + +/* free all list entries */ +void +free_all_list_entries(struct db_entry **this_db_list) +{ + int i; + struct db_entry **tmp; + struct db_entry *to_delete; - /* free list entries */ for(i = 0; i < HASHSIZE; i++) { tmp = &list[i]; @@ -296,24 +424,41 @@ /** * A timeout function called every time - * the scheduler is polled: time out old list entries + * + * XXX:the scheduler is polled (by default 10 times a sec, + * which is far too often): + * + * time out old list entries * and write changes to file */ void olsr_timeout() { + timeout_old_names(list, &name_table_changed); + timeout_old_names(forwarder_list, &forwarder_table_changed); + timeout_old_names(service_list, &service_table_changed); + + write_resolv_file(); + write_hosts_file(); + write_services_file(); +} + +void +timeout_old_names(struct db_entry **this_list, olsr_bool *this_table_changed) +{ struct db_entry **tmp; struct db_entry *to_delete; int index; for(index=0;indextimer)) { to_delete = *tmp; + /* update the pointer in the linked list */ *tmp = (*tmp)->next; olsr_printf(2, "NAME PLUGIN: %s timed out... deleting\n", @@ -322,17 +467,17 @@ /* Delete */ free_name_entry_list(&to_delete->names); free(to_delete); - name_table_changed = OLSR_TRUE; + *this_table_changed = OLSR_TRUE; } else { tmp = &(*tmp)->next; } } } - write_resolv_file(); - write_hosts_file(); } + + /** * Scheduled event: generate and send NAME packet */ @@ -429,21 +574,19 @@ return; } - /* Check if this message has been processed before - * Remeber that this also registeres the message as + /* Check if this message has not been processed before + * Remember that this also registers the message as * processed if nessecary */ - if(!olsr_check_dup_table_proc(&originator, ntohs(m->v4.seqno))) { - /* If so - do not process */ - goto forward; - } - - update_name_entry(&originator, namemessage, size, vtime); + if(olsr_check_dup_table_proc(&originator, ntohs(m->v4.seqno))) { + /* If not already processed - do so */ + update_name_entry(&originator, namemessage, size, vtime); + } + + /* Forward the message if nessecary + * default_fwd does all the work for us! */ + olsr_forward_message(m, &originator, ntohs(m->v4.seqno), in_if, in_addr); -forward: - /* Forward the message if nessecary - * default_fwd does all the work for us! */ - olsr_forward_message(m, &originator, ntohs(m->v4.seqno), in_if, in_addr); } @@ -457,152 +600,224 @@ int encap_namemsg(struct namemsg* msg) { - struct name_entry *my_name = my_names; - struct name* to_packet; + struct name_entry *my_name; + struct name_entry *my_service; + + // add the hostname, service and forwarder entries after the namemsg header char* pos = (char*)msg + sizeof(struct namemsg); short i=0; - int k; - - // upstream dns server - if (have_dns_server) { - olsr_printf(3, "NAME PLUGIN: Announcing DNS server (%s)\n", - olsr_ip_to_string(&my_dns_server)); - to_packet = (struct name*)pos; - to_packet->type = htons(NAME_FORWARDER); - to_packet->len = htons(0); - memcpy(&to_packet->ip, &my_dns_server, ipsize); - pos += sizeof(struct name); - i++; - } + // names for (my_name = my_names; my_name!=NULL; my_name = my_name->next) { - olsr_printf(3, "NAME PLUGIN: Announcing name %s (%s) %d\n", - my_name->name, olsr_ip_to_string(&my_name->ip), my_name->len); - - to_packet = (struct name*)pos; - to_packet->type = htons(my_name->type); - to_packet->len = htons(my_name->len); - memcpy(&to_packet->ip, &my_name->ip, ipsize); - pos += sizeof(struct name); - strncpy(pos, my_name->name, my_name->len); - pos += my_name->len; - // padding to 4 byte boundaries - for (k = my_name->len; (k & 3) != 0; k++) - *pos++ = '\0'; + pos = create_packet( (struct name*) pos, my_name); i++; } + // forwarders + for (my_name = my_forwarders; my_name!=NULL; my_name = my_name->next) + { + pos = create_packet( (struct name*) pos, my_name); + i++; + } + // services + for (my_service = my_services; my_service!=NULL; my_service = my_service->next) + { + pos = create_packet( (struct name*) pos, my_service); + i++; + } + + // write the namemsg header with the number of announced entries and the protocol version msg->nr_names = htons(i); msg->version = htons(NAME_PROTOCOL_VERSION); + return pos - (char*)msg; //length } /** - * decapsulate a name message and update name_entries if necessary + * convert each of my to be announced name_entries into network + * compatible format + * + * return the length of the name packet + */ +char* +create_packet(struct name* to, struct name_entry *from) +{ + char *pos = (char*) to; + int k; + olsr_printf(3, "NAME PLUGIN: Announcing name %s (%s) %d\n", + from->name, olsr_ip_to_string(&from->ip), from->len); + to->type = htons(from->type); + to->len = htons(from->len); + memcpy(&to->ip, &from->ip, ipsize); + pos += sizeof(struct name); + strncpy(pos, from->name, from->len); + pos += from->len; + for (k = from->len; (k & 3) != 0; k++) + *pos++ = '\0'; + return pos; +} + +/** + * decapsulate a received name, service or forwarder and update the corresponding hash table if necessary + */ +void +decap_namemsg(struct name *from_packet, struct name_entry **to, olsr_bool *this_table_changed ) +{ + struct name_entry *tmp; + struct name_entry *already_saved_name_entries; + char *name = (char*)from_packet + sizeof(struct name); + olsr_printf(4, "\nNAME PLUGIN: decapsulating received name, service or forwarder \n"); + int type_of_from_packet = ntohs(from_packet->type); + unsigned int len_of_name = ntohs(from_packet->len); + + // don't insert the received entry again, if it has already been inserted in the hash table. + // Instead only the validity time is set in insert_new_name_in_list function, which calls this one + for (already_saved_name_entries = (*to); already_saved_name_entries != NULL ; already_saved_name_entries = already_saved_name_entries->next) + { + if ( (type_of_from_packet==NAME_HOST || type_of_from_packet==NAME_SERVICE) && strncmp(already_saved_name_entries->name, name, len_of_name) == 0 ) { + 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)); + return; + } else if (type_of_from_packet==NAME_FORWARDER && COMP_IP(&already_saved_name_entries->ip, &from_packet->ip) ) { + 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)); + return; + } + } + + //XXX: should I check the from_packet->ip here? If so, why not also check the ip fro HOST and SERVICE? + if( (type_of_from_packet==NAME_HOST && !is_name_wellformed(name)) || (type_of_from_packet==NAME_SERVICE && !is_service_wellformed(name)) ) { + olsr_printf(4, "\nNAME PLUGIN: invalid name [%s] received, skipping.\n", name ); + return; + } + + //ignore all packets with a too long name + //or a spoofed len of its included name string + if (len_of_name > MAX_NAME || strlen(name) != len_of_name) { + olsr_printf(4, "\nNAME PLUGIN: from_packet->len %d > MAX_NAME %d or from_packet->len %d !0 strlen(name [%s] in packet)\n", + len_of_name, MAX_NAME, len_of_name, name ); + return; + } + + //if not yet known entry + tmp = olsr_malloc(sizeof(struct name_entry), "new name_entry"); + tmp->type = ntohs(from_packet->type); + tmp->len = len_of_name > MAX_NAME ? MAX_NAME : ntohs(from_packet->len); + tmp->name = olsr_malloc(tmp->len+1, "new name_entry name"); + memcpy(&tmp->ip, &from_packet->ip, ipsize); + strncpy(tmp->name, name, tmp->len); + tmp->name[tmp->len] = '\0'; + + olsr_printf(3, "\nNAME PLUGIN: create new name/service/forwarder entry %s (%s) [len=%d] [type=%d] in linked list\n", + tmp->name, olsr_ip_to_string(&tmp->ip), tmp->len, tmp->type); + + *this_table_changed = OLSR_TRUE; + + // queue to front + tmp->next = *to; + *to = tmp; +} + + +/** + * unpack the received message and delegate to the decapsilation function for each + * name/service/forwarder entry in the message */ void -decap_namemsg( struct namemsg *msg, int size, struct name_entry **to ) +update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, double vtime) { char *pos, *end_pos; - struct name_entry *tmp; struct name *from_packet; int i; + + olsr_printf(3, "NAME PLUGIN: Received Message from %s\n", + olsr_ip_to_string(originator)); - olsr_printf(4, "NAME PLUGIN: decapsulating name msg (size %d)\n", size); - - if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) { + if (ntohs(msg->version) != NAME_PROTOCOL_VERSION) { olsr_printf(3, "NAME PLUGIN: ignoring wrong version %d\n", msg->version); return; } - - // for now ist easier to just delete everything, than - // to update selectively - free_name_entry_list(to); - name_table_changed = OLSR_TRUE; - + + /* now add the names from the message */ pos = (char*)msg + sizeof(struct namemsg); - end_pos = pos + size - sizeof(struct name*); // at least one struct name has to be left - + end_pos = pos + msg_size - sizeof(struct name*); // at least one struct name has to be left + for (i=ntohs(msg->nr_names); i > 0 && postype = ntohs(from_packet->type); - tmp->len = ntohs(from_packet->len) > MAX_NAME ? MAX_NAME : ntohs(from_packet->len); - tmp->name = olsr_malloc(tmp->len+1, "new name_entry name"); - memcpy(&tmp->ip, &from_packet->ip, ipsize); + + switch (ntohs(from_packet->type)) { + case NAME_HOST: + insert_new_name_in_list(originator, list, from_packet, &name_table_changed, vtime); + break; + case NAME_FORWARDER: + insert_new_name_in_list(originator, forwarder_list, from_packet, &forwarder_table_changed, vtime); + break; + case NAME_SERVICE: + insert_new_name_in_list(originator, service_list, from_packet, &service_table_changed, vtime); + break; + default: + olsr_printf(3, "NAME PLUGIN: Received Message of unknown type [%d] from (%s)\n", from_packet->type, olsr_ip_to_string(originator)); + break; + } pos += sizeof(struct name); - strncpy(tmp->name, pos, tmp->len); - tmp->name[tmp->len] = '\0'; - - olsr_printf(3, "NAME PLUGIN: New name %s (%s) %d %d\n", - tmp->name, olsr_ip_to_string(&tmp->ip), tmp->len, tmp->type); - - // queue to front - tmp->next = *to; - *to = tmp; - - // name + padding - pos += 1 + ((tmp->len - 1) | 3); - } + pos += 1 + (( ntohs(from_packet->len) - 1) | 3); + } if (i!=0) - olsr_printf(4, "NAME PLUGIN: Lost %d names due to length inconsistency\n", i); + olsr_printf(4, "NAME PLUGIN: Lost %d entries in received packet due to length inconsistency (%s)\n", i, olsr_ip_to_string(originator)); } /** - * Update or register a new name entry + * insert all the new names,services and forwarders from a received packet into the + * corresponding entry for this ip in the corresponding hash table */ void -update_name_entry(union olsr_ip_addr *originator, struct namemsg *msg, int msg_size, double vtime) +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) { int hash; struct db_entry *entry; - - olsr_printf(3, "NAME PLUGIN: Received Name Message from %s\n", - olsr_ip_to_string(originator)); + olsr_bool entry_found = OLSR_FALSE; + entry_found = OLSR_FALSE; hash = olsr_hashing(originator); - /* find the entry for originator */ - for (entry = list[hash]; entry != NULL; entry = entry->next) - { - if (memcmp(originator, &entry->originator, ipsize) == 0) { - // found - olsr_printf(4, "NAME PLUGIN: %s found\n", - olsr_ip_to_string(originator)); - - decap_namemsg(msg, msg_size, &entry->names); - - olsr_get_timestamp(vtime * 1000, &entry->timer); - - return; - } - } - - olsr_printf(3, "NAME PLUGIN: New entry %s\n", - olsr_ip_to_string(originator)); - - /* insert a new entry */ - entry = olsr_malloc(sizeof(struct db_entry), "new db_entry"); - - memcpy(&entry->originator, originator, ipsize); - olsr_get_timestamp(vtime * 1000, &entry->timer); - entry->names = NULL; - // queue to front - entry->next = list[hash]; - list[hash] = entry; - - decap_namemsg(msg, msg_size, &entry->names); - - name_table_changed = OLSR_TRUE; + /* find the entry for originator, if there is already one */ + for (entry = this_list[hash]; entry != NULL; entry = entry->next) + { + if (memcmp(originator, &entry->originator, ipsize) == 0) { + // found + olsr_printf(4, "NAME PLUGIN: found entry for (%s) in its hash table\n", olsr_ip_to_string(originator)); + + //delegate to function for parsing the packet and linking it to entry->names + decap_namemsg(from_packet, &entry->names, this_table_changed); + + olsr_get_timestamp(vtime * 1000, &entry->timer); + + entry_found = OLSR_TRUE; + } + } + if (! entry_found) + { + olsr_printf(3, "NAME PLUGIN: create new db entry for ip (%s) in hash table\n", olsr_ip_to_string(originator)); + + /* insert a new entry */ + entry = olsr_malloc(sizeof(struct db_entry), "new db_entry"); + + memcpy(&entry->originator, originator, ipsize); + olsr_get_timestamp(vtime * 1000, &entry->timer); + entry->names = NULL; + + // queue to front + entry->next = this_list[hash]; + this_list[hash] = entry; + + //delegate to function for parsing the packet and linking it to entry->names + decap_namemsg(from_packet, &entry->names, this_table_changed); + } } - /** * write names to a file in /etc/hosts compatible format */ @@ -650,8 +865,7 @@ // write own names for (name = my_names; name != NULL; name = name->next) { - fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&name->ip), - name->name, my_suffix ); + fprintf(hosts, "%s\t%s%s\t# myself\n", olsr_ip_to_string(&name->ip), name->name, my_suffix ); } // write received names @@ -661,13 +875,11 @@ { for (name = entry->names; name != NULL; name = name->next) { - if (name->type == NAME_HOST) { - olsr_printf(6, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix); - olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator)); - - fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix); - fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&entry->originator)); - } + olsr_printf(6, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix); + olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator)); + + fprintf(hosts, "%s\t%s%s", olsr_ip_to_string(&name->ip), name->name, my_suffix); + fprintf(hosts, "\t# %s\n", olsr_ip_to_string(&entry->originator)); } } } @@ -682,7 +894,70 @@ /** - * write upstream DNS servers to resolv.conf file + * write services to a file in the format: + * service #originator ip + * + * since service has a special format + * each line will look similar to e.g. + * http://me.olsr:80|tcp|my little homepage + */ +void +write_services_file() +{ + int hash; + struct name_entry *name; + struct db_entry *entry; + FILE* services_file; + time_t currtime; + + + if (!service_table_changed) + return; + + olsr_printf(2, "NAME PLUGIN: writing services file\n"); + + services_file = fopen( my_services_file, "w" ); + if (services_file == NULL) { + olsr_printf(2, "NAME PLUGIN: cant write services_file file\n"); + return; + } + + fprintf(services_file, "### this file is overwritten regularly by olsrd\n"); + fprintf(services_file, "### do not edit\n\n"); + + + // write own services + for (name = my_services; name != NULL; name = name->next) { + fprintf(services_file, "%s\t# my own service\n", name->name); + } + + // write received services + for (hash = 0; hash < HASHSIZE; hash++) + { + for(entry = service_list[hash]; entry != NULL; entry = entry->next) + { + for (name = entry->names; name != NULL; name = name->next) + { + olsr_printf(6, "%s\t", name->name); + olsr_printf(6, "\t#%s\n", olsr_ip_to_string(&entry->originator)); + + fprintf(services_file, "%s\t", name->name ); + fprintf(services_file, "\t#%s\n", olsr_ip_to_string(&entry->originator)); + } + } + } + + if (time(&currtime)) { + fprintf(services_file, "\n### written by olsrd at %s", ctime(&currtime)); + } + + fclose(services_file); + service_table_changed = OLSR_FALSE; +} + +/** + * write the 3 best upstream DNS servers to resolv.conf file + * best means the 3 with the best etx value in routing table */ void write_resolv_file() @@ -694,23 +969,17 @@ struct rt_entry *route, *tmp, *last; FILE* resolv; int i=0; + time_t currtime; - if (my_resolv_file[0] == '\0') - return; - - if (!name_table_changed) + if (!forwarder_table_changed || my_forwarders != NULL || my_resolv_file[0] == '\0') return; - olsr_printf(2, "NAME PLUGIN: writing resolv file\n"); - for (hash = 0; hash < HASHSIZE; hash++) { - for(entry = list[hash]; entry != NULL; entry = entry->next) + for(entry = forwarder_list[hash]; entry != NULL; entry = entry->next) { for (name = entry->names; name != NULL; name = name->next) { - if (name->type != NAME_FORWARDER) - continue; /* find the nearest one */ route = olsr_lookup_routing_table(&name->ip); @@ -762,18 +1031,25 @@ return; /* write to file */ + olsr_printf(2, "NAME PLUGIN: try to write to resolv file\n"); resolv = fopen( my_resolv_file, "w" ); if (resolv == NULL) { olsr_printf(2, "NAME PLUGIN: can't write resolv file\n"); return; } + fprintf(resolv, "### this file is overwritten regularly by olsrd\n"); + fprintf(resolv, "### do not edit\n\n"); i=0; for (tmp=best_routes; tmp!=NULL && i<3; tmp=tmp->next) { olsr_printf(6, "NAME PLUGIN: nameserver %s\n", olsr_ip_to_string(&tmp->rt_dst)); fprintf(resolv, "nameserver %s\n", olsr_ip_to_string(&tmp->rt_dst)); i++; } + if (time(&currtime)) { + fprintf(resolv, "\n### written by olsrd at %s", ctime(&currtime)); + } fclose(resolv); + forwarder_table_changed = OLSR_FALSE; } @@ -789,6 +1065,7 @@ to_delete = *tmp; *tmp = (*tmp)->next; free( to_delete->name ); + to_delete->name = NULL; free( to_delete ); to_delete = NULL; } @@ -831,3 +1108,84 @@ } return OLSR_FALSE; } + +/** check if name has the right syntax, i.e. it must adhere to a special regex + * stored in regex_t_name + * necessary to avaid names like "0.0.0.0 google.de\n etc" + */ +olsr_bool +is_name_wellformed(char *name) { + return regexec(®ex_t_name, name, 1, ®match_t_name, 0) == 0 ; +} + + +/** + * check if the service is in the right syntax and also that the hostname + * or ip whithin the service is allowed + */ +olsr_bool +allowed_service(char *service_line) +{ + /* the call of is_service_wellformed generates the submatches stored in regmatch_t_service + * these are then used by allowed_hostname_or_ip_in_service + * see regexec(3) for more infos */ + if (!is_service_wellformed(service_line)) { + return OLSR_FALSE; + } else if (!allowed_hostname_or_ip_in_service(service_line, &(regmatch_t_service[1]))) { + return OLSR_FALSE; + } + + return OLSR_TRUE; +} + +olsr_bool +allowed_hostname_or_ip_in_service(char *service_line, regmatch_t *hostname_or_ip_match) +{ + char *hostname_or_ip; + struct in_addr ip; + union olsr_ip_addr olsr_ip; + struct name_entry *name; + if (hostname_or_ip_match->rm_so < 0 || hostname_or_ip_match->rm_eo < 0) { + return OLSR_FALSE; + } + + hostname_or_ip = strndup(&service_line[hostname_or_ip_match->rm_so], hostname_or_ip_match->rm_eo - hostname_or_ip_match->rm_so); + //hostname is one of the names, that I announce (i.e. one that i am allowed to announce) + for (name = my_names; name != NULL; name = name->next) { + if (strncmp(name->name, hostname_or_ip, name->len - strlen(my_suffix)) == 0 ) { + olsr_printf(4, "NAME PLUGIN: hostname %s in service %s is OK\n", hostname_or_ip, service_line); + free(hostname_or_ip); + hostname_or_ip = NULL; + return OLSR_TRUE; + } + } + + //ip in service-line is allowed + if (inet_aton(hostname_or_ip, &ip)) { + olsr_ip.v4 = ip.s_addr; + if (allowed_ip(&olsr_ip)) { + olsr_printf(2, "NAME PLUGIN: ip %s in service %s is OK\n", olsr_ip_to_string(&olsr_ip), service_line); + free(hostname_or_ip); + hostname_or_ip = NULL; + return OLSR_TRUE; + } + } + + 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); + free(hostname_or_ip); + hostname_or_ip = NULL; + + return OLSR_FALSE; +} + +/** + * check if the service matches the syntax + * of "protocol://host:port/path|tcp_or_udp|a short description", + * which is given in the regex regex_t_service + */ +olsr_bool +is_service_wellformed(char *service_line) +{ + return regexec(®ex_t_service, service_line, pmatch_service, regmatch_t_service, 0) == 0; +} + diff -Nur olsrd-0.4.10.orig/lib/nameservice/src/nameservice.h olsrd-0.4.10/lib/nameservice/src/nameservice.h --- olsrd-0.4.10.orig/lib/nameservice/src/nameservice.h 2005-06-02 17:34:00.000000000 +0200 +++ olsrd-0.4.10/lib/nameservice/src/nameservice.h 2006-12-01 08:26:58.000000000 +0100 @@ -39,6 +39,7 @@ #define _NAMESERVICE_PLUGIN #include +#include #include "olsr_types.h" #include "interfaces.h" @@ -51,19 +52,27 @@ #define PLUGIN_VERSION "0.2" #define PLUGIN_AUTHOR "Bruno Randolf" +// useful to set for the freifunkfirmware to remove all +// calls to olsr_printf by the empty statement ";" +//#define olsr_printf(...) ; #define MESSAGE_TYPE 130 #define PARSER_TYPE MESSAGE_TYPE #define EMISSION_INTERVAL 120 /* two minutes */ -#define NAME_VALID_TIME 3600 /* one hour */ +#define NAME_VALID_TIME 1800 /* half one hour */ #define NAME_PROTOCOL_VERSION 1 -#define MAX_NAME 255 +#define MAX_NAME 127 #define MAX_FILE 255 -#define MAX_SUFFIX 255 - +#define MAX_SUFFIX 63 +/** + * a linked list of name_entry + * if type is NAME_HOST, name is a hostname and ip its IP addr + * if type is NAME_FORWARDER, then ip is a dns-server (and name is irrelevant) + * if type is NAME_SERVICE, then name is a service-line (and the ip is irrelevant) + */ struct name_entry { union olsr_ip_addr ip; @@ -73,7 +82,17 @@ struct name_entry *next; /* linked list */ }; -/* database entry */ +/* * + * linked list of db_entries for each originator with + * originator being its main_addr + * + * names points to the name_entry with its hostname, dns-server or + * service-line entry + * + * all the db_entries are hashed in nameservice.c to avoid a too long list + * for many nodes in a net + * + * */ struct db_entry { union olsr_ip_addr originator; /* IP address of the node this entry describes */ @@ -98,8 +117,26 @@ int encap_namemsg(struct namemsg *); +struct name_entry* +add_name_to_list(struct name_entry *my_list, char *value, int type, struct in_addr *ip); + +struct name_entry* +remove_nonvalid_names_from_list(struct name_entry *my_list, int type); + +void +free_all_list_entries(struct db_entry **this_db_list) ; + void -decap_namemsg(struct namemsg *, int, struct name_entry**); +timeout_old_names(struct db_entry **this_list, olsr_bool *this_table_changed); + +void +decap_namemsg(struct name *from_packet, struct name_entry **to, olsr_bool *this_table_changed ); + +void +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); + +olsr_bool +allowed_hostname_or_ip_in_service(char *service_line, regmatch_t *hostname_or_ip); void update_name_entry(union olsr_ip_addr *, struct namemsg *, int, double); @@ -108,6 +145,9 @@ write_hosts_file(void); void +write_services_file(void); + +void write_resolv_file(void); int @@ -119,6 +159,18 @@ olsr_bool allowed_ip(union olsr_ip_addr *addr); +olsr_bool +allowed_service(char *service_line); + +olsr_bool +is_name_wellformed(char *service_line); + +olsr_bool +is_service_wellformed(char *service_line); + +char* +create_packet(struct name *to, struct name_entry *from); + void name_constructor(void); diff -Nur olsrd-0.4.10.orig/lib/nameservice/src/nameservice_msg.h olsrd-0.4.10/lib/nameservice/src/nameservice_msg.h --- olsrd-0.4.10.orig/lib/nameservice/src/nameservice_msg.h 2005-03-17 22:41:30.000000000 +0100 +++ olsrd-0.4.10/lib/nameservice/src/nameservice_msg.h 2006-12-01 08:26:58.000000000 +0100 @@ -38,29 +38,34 @@ #ifndef _NAMESEVICE_MSG #define _NAMESEVICE_MSG - +/* type of the packet of name_entry */ typedef enum { NAME_HOST = 0, NAME_FORWARDER = 1, - NAME_SERVICE = 2 + NAME_SERVICE = 2, } NAME_TYPE; - +/** + * the name, forwarder or service entry as found in a packet within a + * message + **/ struct name { olsr_u16_t type; olsr_u16_t len; // length of the name + // the ip of the hostname, or the ip of the dns-server + // ip is irrelevant for services union olsr_ip_addr ip; /* - * name is written in plain text after this struct and padded to 4 byte + * name or service is written in plain text after this struct and padded to 4 byte */ }; struct namemsg { - olsr_u16_t version; - olsr_u16_t nr_names; // number of following name messages + olsr_u16_t version; // version number of the nameservice plugin + olsr_u16_t nr_names; // number of following packets including names, forwarders or services /* * at least one struct name following */