/* Serval DNA MDP addressing Copyright (C) 2012-2013 Serval Project Inc. Copyright (C) 2012 Paul Gardner-Stephen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Smart-flooding of broadcast information is also a requirement. The long addresses help here, as we can make any address that begins with the first 192 bits all ones be broadcast, and use the remaining 64 bits as a "broadcast packet identifier" (BPI). Nodes can remember recently seen BPIs and not forward broadcast frames that have been seen recently. This should get us smart flooding of the majority of a mesh (with some node mobility issues being a factor). We could refine this later, but it will do for now, especially since for things like number resolution we are happy to send repeat requests. */ #include #include #include "serval.h" #include "conf.h" #include "str.h" #include "overlay_address.h" #include "overlay_buffer.h" #include "overlay_interface.h" #include "overlay_packet.h" #include "server.h" #include "route_link.h" #define MAX_BPIS 1024 #define BPI_MASK 0x3ff static struct broadcast bpilist[MAX_BPIS]; #define OA_CODE_SELF 0xff #define OA_CODE_PREVIOUS 0xfe #define OA_CODE_P2P_YOU 0xfd #define OA_CODE_P2P_ME 0xfc #define OA_CODE_SIGNKEY 0xfb // full sign key of an identity, from which a SID can be derived static __thread struct tree_root root={.binary_length=SID_SIZE}; static __thread struct subscriber *my_subscriber=NULL; struct subscriber *get_my_subscriber(){ if (!serverMode) return NULL; if (my_subscriber && my_subscriber->reachable != REACHABLE_SELF) my_subscriber = NULL; if (!my_subscriber){ keyring_identity *id = keyring->identities; while(id && id->subscriber->reachable != REACHABLE_SELF) id = id->next; // If there is no reachable self-identity in the keyring, then roll one in-memory, which will // persist until the server terminates. if (!id) id = keyring_inmemory_identity(); my_subscriber = id->subscriber; } return my_subscriber; } void release_my_subscriber(){ if (my_subscriber && my_subscriber->identity->slot==0) keyring_free_identity(my_subscriber->identity); my_subscriber = NULL; } static int free_node(void **record, void *UNUSED(context)) { struct subscriber *subscriber = (struct subscriber *)*record; if (subscriber->link_state || subscriber->destination) FATAL("Can't free a subscriber that is being used in routing"); if (subscriber->sync_state) FATAL("Can't free a subscriber that is being used by rhizome"); if (subscriber->identity) FATAL("Can't free a subscriber that is unlocked in the keyring"); free(subscriber); *record=NULL; return 0; } void free_subscribers() { // don't attempt to free anything if we're running as a server // who knows where subscriber ptr's may have leaked to. if (serverMode) FATAL("Freeing subscribers from a running daemon is not supported"); tree_walk(&root, NULL, 0, free_node, NULL); } static void *create_subscriber(void *UNUSED(context), const uint8_t *binary, size_t bin_length) { assert(bin_length == SID_SIZE); struct subscriber *ret = (struct subscriber *) emalloc_zero(sizeof(struct subscriber)); if (ret){ ret->sid = *(const sid_t *)binary; DEBUGF(subscriber, "Stored %s", alloca_tohex_sid_t(ret->sid)); } return ret; } // find a subscriber struct from a whole or abbreviated subscriber id struct subscriber *find_subscriber(const uint8_t *sidp, int len, int create) { struct subscriber *result; tree_find(&root, (void**)&result, sidp, len, create && len == SID_SIZE ? create_subscriber : NULL, NULL); // ignore return code, just return the result return result; } /* walk the tree, starting at start inclusive, calling the supplied callback function */ void enum_subscribers(struct subscriber *start, walk_callback callback, void *context) { tree_walk(&root, start?start->sid.binary:NULL, SID_SIZE, callback, context); } // generate a new random broadcast address int overlay_broadcast_generate_address(struct broadcast *addr) { int i; for(i=0;iid[i]=random()&0xff; return 0; } // test if the broadcast address has been seen int overlay_broadcast_drop_check(struct broadcast *addr) { /* Hash the BPI and see if we have seen it recently. If so, drop the frame. The occassional failure to supress a broadcast frame is not something we are going to worry about just yet. For byzantine robustness it is however required. */ int bpi_index=0; int i; for(i=0;i>13)&0x7); bpi_index^=addr->id[i]; } bpi_index&=BPI_MASK; if (memcmp(bpilist[bpi_index].id, addr->id, BROADCAST_LEN)){ DEBUGF(broadcasts, "BPI %s is new", alloca_tohex(addr->id, BROADCAST_LEN)); bcopy(addr->id, bpilist[bpi_index].id, BROADCAST_LEN); return 0; /* don't drop */ }else{ DEBUGF(broadcasts, "BPI %s is a duplicate", alloca_tohex(addr->id, BROADCAST_LEN)); return 1; /* drop frame because we have seen this BPI recently */ } } void overlay_broadcast_append(struct overlay_buffer *b, struct broadcast *broadcast) { ob_append_bytes(b, broadcast->id, BROADCAST_LEN); } // append an appropriate abbreviation into the address void overlay_address_append(struct decode_context *context, struct overlay_buffer *b, struct subscriber *subscriber) { assert(subscriber != NULL); if (context && subscriber == context->point_to_point_device) ob_append_byte(b, OA_CODE_P2P_YOU); else if(context && !subscriber->send_full && subscriber == get_my_subscriber() && context->point_to_point_device && ((context->flags & DECODE_FLAG_ENCODING_HEADER)==0 || !context->interface->local_echo)) ob_append_byte(b, OA_CODE_P2P_ME); else if (context && subscriber==context->sender) ob_append_byte(b, OA_CODE_SELF); else if (context && subscriber==context->previous) ob_append_byte(b, OA_CODE_PREVIOUS); else { if (subscriber->send_full){ // TODO work out when we can use OA_CODE_SIGNKEY ob_append_byte(b, SID_SIZE); ob_append_bytes(b, subscriber->sid.binary, SID_SIZE); subscriber->send_full=0; }else{ // always send 8-12 extra bits to disambiguate abbreviations int len=(subscriber->tree_depth >> 3) + 1; // add another 8 bits for our own packet headers if (context && (context->flags & DECODE_FLAG_ENCODING_HEADER)) len++; if (len>SID_SIZE) len=SID_SIZE; ob_append_byte(b, len); ob_append_bytes(b, subscriber->sid.binary, len); } } if (context) context->previous = subscriber; } static int add_explain_response(void **record, void *context) { struct subscriber *subscriber = *record; struct decode_context *response = context; // only explain a SID once every half second. time_ms_t now = gettime_ms(); if (now - subscriber->last_explained < 500) return 0; subscriber->last_explained = now; if (!response->please_explain){ if ((response->please_explain = emalloc_zero(sizeof(struct overlay_frame))) == NULL) return 1; // stop walking if ((response->please_explain->payload = ob_new()) == NULL) { free(response->please_explain); response->please_explain = NULL; return 1; // stop walking } ob_limitsize(response->please_explain->payload, 1024); } // if our primary routing identities is unknown, // the header of this packet must include our full sid. if (subscriber==get_my_subscriber()){ DEBUGF(subscriber, "Explaining SELF sid=%s", alloca_tohex_sid_t(subscriber->sid)); response->please_explain->source_full=1; return 0; } struct overlay_buffer *b = response->please_explain->payload; // add the whole subscriber id to the payload, stop if we run out of space DEBUGF(subscriber, "Explaining sid=%s", alloca_tohex_sid_t(subscriber->sid)); ob_checkpoint(b); if (subscriber->id_combined && response->sender && response->sender->id_combined){ // TODO better condition for when we should send this? ob_append_byte(b, OA_CODE_SIGNKEY); ob_append_bytes(b, subscriber->id_public.binary, crypto_sign_PUBLICKEYBYTES); }else{ ob_append_byte(b, SID_SIZE); ob_append_bytes(b, subscriber->sid.binary, SID_SIZE); } if (ob_overrun(b)) { ob_rewind(b); return 1; } // let the routing engine know that we had to explain this sid, we probably need to re-send routing info link_explained(subscriber); return 0; } static int find_subscr_buffer(struct decode_context *context, struct overlay_buffer *b, int len, struct subscriber **subscriber) { assert(subscriber); if (len<=0 || len>SID_SIZE) return WHYF("Invalid abbreviation length %d", len); uint8_t *id = ob_get_bytes_ptr(b, len); if (!id) return WHY("Not enough space in buffer to parse address"); *subscriber=find_subscriber(id, len, 1); if (!*subscriber){ if (!context) return WHYF("Unable to decode %s, with no context", alloca_tohex(id, len)); context->flags|=DECODE_FLAG_INVALID_ADDRESS; if (context->flags & DECODE_FLAG_DONT_EXPLAIN){ DEBUGF(subscriber, "Ignoring unknown prefix %s", alloca_tohex(id, len)); }else{ // generate a please explain in the passed in context // add the abbreviation you told me about if (!context->please_explain){ context->please_explain = calloc(sizeof(struct overlay_frame),1); if ((context->please_explain->payload = ob_new()) == NULL) return -1; ob_limitsize(context->please_explain->payload, MDP_MTU); } // And I'll tell you about any subscribers I know that match this abbreviation, // so you don't try to use an abbreviation that's too short in future. tree_walk_prefix(&root, id, len, add_explain_response, context); DEBUGF(subscriber, "Asking for explanation of %s", alloca_tohex(id, len)); ob_append_byte(context->please_explain->payload, len); ob_append_bytes(context->please_explain->payload, id, len); } }else{ if (context) context->previous=*subscriber; } return 0; } int overlay_broadcast_parse(struct overlay_buffer *b, struct broadcast *broadcast) { return ob_get_bytes(b, broadcast->id, BROADCAST_LEN); } static int decode_sid_from_signkey(struct overlay_buffer *b, struct subscriber **subscriber) { const uint8_t *id = ob_get_bytes_ptr(b, crypto_sign_PUBLICKEYBYTES); if (!id) return WHY("Not enough space in buffer to parse address"); sid_t sid; if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id)) return WHY("Failed to convert sign key to sid"); struct subscriber *s = find_subscriber(sid.binary, SID_SIZE, 1); if (s && !s->id_combined){ bcopy(id, s->id_public.binary, crypto_sign_PUBLICKEYBYTES); s->id_valid=1; s->id_combined=1; DEBUGF(subscriber, "Stored combined SID:SAS mapping, SID=%s SAS=%s", alloca_tohex_sid_t(s->sid), alloca_tohex_identity_t(&s->id_public) ); } if (subscriber) *subscriber=s; return 0; } // returns 0 = success, -1 = fatal parsing error, 1 = unable to identify address int overlay_address_parse(struct decode_context *context, struct overlay_buffer *b, struct subscriber **subscriber) { int len = ob_get(b); if (len<0) return WHY("Buffer too small"); switch(len){ case OA_CODE_P2P_YOU: // if we don't know who they are, we can't assume they mean us. if (context->point_to_point_device){ context->previous = *subscriber = get_my_subscriber(); }else{ WHYF("Could not resolve address on %s, this isn't a configured point to point link", context->interface->name); context->flags|=DECODE_FLAG_INVALID_ADDRESS; } return 0; case OA_CODE_P2P_ME: if (context->point_to_point_device){ *subscriber=context->point_to_point_device; context->previous=*subscriber; }else{ if ((context->flags & DECODE_FLAG_DONT_EXPLAIN) == 0){ // add the abbreviation you told me about if (!context->please_explain){ context->please_explain = calloc(sizeof(struct overlay_frame),1); if ((context->please_explain->payload = ob_new()) == NULL) return -1; ob_limitsize(context->please_explain->payload, MDP_MTU); } DEBUGF(subscriber, "Asking for explanation of YOU"); ob_append_byte(context->please_explain->payload, OA_CODE_P2P_YOU); } context->flags|=DECODE_FLAG_INVALID_ADDRESS; } return 0; case OA_CODE_SELF: if (!context->sender){ DEBUGF(subscriber, "Could not resolve address, sender has not been set"); context->flags|=DECODE_FLAG_INVALID_ADDRESS; }else{ *subscriber=context->sender; context->previous=context->sender; } return 0; case OA_CODE_PREVIOUS: if (!context->previous){ DEBUGF(subscriber, "Unable to decode previous address"); context->flags|=DECODE_FLAG_INVALID_ADDRESS; }else{ *subscriber=context->previous; } return 0; case OA_CODE_SIGNKEY: return decode_sid_from_signkey(b, subscriber); } return find_subscr_buffer(context, b, len, subscriber); } // once we've finished parsing a packet, complete and send a please explain if required. int send_please_explain(struct decode_context *context, struct subscriber *source, struct subscriber *destination) { IN(); struct overlay_frame *frame=context->please_explain; if (frame == NULL) RETURN(0); assert(frame->payload != NULL); frame->type = OF_TYPE_PLEASEEXPLAIN; if (source) frame->source = source; else frame->source = get_my_subscriber(); if (!context->sender) frame->source_full=1; frame->destination = destination; if (destination){ frame->ttl = PAYLOAD_TTL_DEFAULT; // MAX? frame->source_full=1; }else{ // send both a broadcast & unicast response out the same interface this packet arrived on. frame->ttl=1;// how will this work with olsr?? if (context->interface){ frame_add_destination(frame, NULL, context->interface->destination); struct network_destination *dest = create_unicast_destination(&context->addr, context->interface); if (dest) frame_add_destination(frame, NULL, dest); }else{ FATAL("This context doesn't have an interface?"); } } frame->queue=OQ_MESH_MANAGEMENT; if (overlay_payload_enqueue(frame) != -1) RETURN(0); op_free(frame); RETURN(-1); OUT(); } // process an incoming request for explanation of subscriber abbreviations int process_explain(struct overlay_frame *frame) { struct overlay_buffer *b=frame->payload; struct decode_context context; bzero(&context, sizeof context); context.sender = frame->source; context.interface = frame->interface; while(ob_remaining(b)>0){ int len = ob_get(b); switch (len){ case OA_CODE_P2P_YOU: { void *sid = get_my_subscriber(); add_explain_response(&sid, &context); } break; case OA_CODE_SIGNKEY: decode_sid_from_signkey(b, NULL); break; case SID_SIZE: { // This message is also used to inform people of previously unknown subscribers // make sure we know this one uint8_t *sid = ob_get_bytes_ptr(b, SID_SIZE); if (!sid) return WHY("Ran past end of buffer"); DEBUGF(subscriber, "Storing explain response for %s", alloca_tohex(sid, SID_SIZE)); find_subscriber(sid, SID_SIZE, 1); break; } default: { if (len<=0 || len>SID_SIZE) return WHY("Badly formatted explain message"); uint8_t *sid = ob_get_bytes_ptr(b, len); // reply to the sender with all subscribers that match this abbreviation DEBUGF(subscriber, "Sending explain responses for %s", alloca_tohex(sid, len)); tree_walk_prefix(&root, sid, len, add_explain_response, &context); } } } if (context.please_explain) send_please_explain(&context, frame->destination, frame->source); return 0; }