static int overlay_frame_build_header(int packet_version, struct decode_context *context, struct overlay_buffer *buff, int queue, int type, int modifiers, int ttl, int sequence, struct broadcast *broadcast, struct subscriber *next_hop, struct subscriber *destination, struct subscriber *source) { if (ttl < 0 || ttl > PAYLOAD_TTL_MAX) return WHYF("invalid ttl=%d", ttl); int flags = modifiers & (PAYLOAD_FLAG_CIPHERED | PAYLOAD_FLAG_SIGNED); if (ttl==1 && !broadcast) flags |= PAYLOAD_FLAG_ONE_HOP; if (destination && destination==next_hop) flags |= PAYLOAD_FLAG_ONE_HOP; if (source == context->sender) flags |= PAYLOAD_FLAG_SENDER_SAME; if (!destination) flags |= PAYLOAD_FLAG_TO_BROADCAST; if (type!=OF_TYPE_DATA) flags |= PAYLOAD_FLAG_LEGACY_TYPE; if (ob_append_byte(buff, flags)) return -1; if (!(flags & PAYLOAD_FLAG_SENDER_SAME)){ if (overlay_address_append(context, buff, source)) return -1; } if (flags & PAYLOAD_FLAG_TO_BROADCAST){ if (!(flags & PAYLOAD_FLAG_ONE_HOP)){ if (overlay_broadcast_append(buff, broadcast)) return -1; } }else{ if (overlay_address_append(context, buff, destination)) return -1; if (!(flags & PAYLOAD_FLAG_ONE_HOP)){ if (overlay_address_append(context, buff, next_hop)) return -1; } } if (!(flags & PAYLOAD_FLAG_ONE_HOP)){ if (ob_append_byte(buff, ttl | ((queue&3)<<5))) return -1; } if (flags & PAYLOAD_FLAG_LEGACY_TYPE){ if (ob_append_byte(buff, type)) return -1; } if (packet_version >= 1) if (ob_append_byte(buff, sequence)) return -1; return 0; }
int overlay_add_selfannouncement(int interface,struct overlay_buffer *b) { /* Pull the first record from the HLR database and turn it into a self-announcment. These are shorter than regular Subscriber Observation Notices (SON) because they are just single-hop announcments of presence. Do we really need to push the whole SID (32 bytes), or will just, say, 8 do so that we use a prefix of the SID which is still very hard to forge? A hearer of a self-announcement who has not previously seen the sender might like to get some authentication to prevent naughty people from spoofing routes. We can do this by having ourselves, the sender, keep track of the last few frames we have sent, so that we can be asked to sign them. Actually, we won't sign them, as that is too slow/energy intensive, but we could use a D-H exchange with the neighbour, performed once to get a shared secret that can be used to feed a stream cipher to produce some sort of verification. XXX - But this functionality really needs to move up a level to whole frame composition. */ time_ms_t now = gettime_ms(); /* Header byte */ if (ob_append_byte(b, OF_TYPE_SELFANNOUNCE)) return WHY("Could not add self-announcement header"); /* A TTL for this frame. XXX - BATMAN uses various TTLs, but I think that it may just be better to have all TTL=1, and have the onward nodes selectively choose which nodes to on-announce. If we prioritise newly arrived nodes somewhat (or at least reserve some slots for them), then we can still get the good news travels fast property of BATMAN, but without having to flood in the formal sense. */ if (ob_append_byte(b,1)) return WHY("Could not add TTL to self-announcement"); /* Add space for Remaining Frame Size field. This will always be a single byte for self-announcments as they are always <256 bytes. */ if (ob_append_rfs(b,1+8+1+SID_SIZE+4+4+1)) return WHY("Could not add RFS for self-announcement frame"); /* Add next-hop address. Always link-local broadcast for self-announcements */ struct broadcast broadcast_id; overlay_broadcast_generate_address(&broadcast_id); if (overlay_broadcast_append(b, &broadcast_id)) return WHY("Could not write broadcast address to self-announcement"); /* Add final destination. Always broadcast for self-announcments. */ if (ob_append_byte(b, OA_CODE_PREVIOUS)) return WHY("Could not add self-announcement header"); /* Add our SID to the announcement as sender */ if (overlay_address_append_self(&overlay_interfaces[interface], b)) return -1; overlay_address_set_sender(my_subscriber); /* Sequence number range. Based on one tick per millisecond. */ time_ms_t last_ms = overlay_interfaces[interface].last_tick_ms; // If this interface has not been ticked yet (no selfannounce sent) then invent the prior sequence // number: one millisecond ago. if (last_ms == -1) last_ms = now - 1; if (ob_append_ui32(b, last_ms)) return WHY("Could not add low sequence number to self-announcement"); if (ob_append_ui32(b, now)) return WHY("Could not add high sequence number to self-announcement"); if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("interface #%d: last_tick_ms=%lld, now=%lld (delta=%lld)", interface, (long long)overlay_interfaces[interface].last_tick_ms, (long long)now, (long long)(now - last_ms) ); overlay_interfaces[interface].last_tick_ms = now; /* A byte that indicates which interface we are sending over */ if (ob_append_byte(b,interface)) return WHY("Could not add interface number to self-announcement"); ob_patch_rfs(b, COMPUTE_RFS_LENGTH); return 0; }
/* Construct MDP packet frame from overlay_mdp_frame structure (need to add return address from bindings list, and copy payload etc). This is for use by the SERVER. Clients should use overlay_mdp_send() */ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, struct sockaddr_un *recvaddr,int recvaddrlen) { IN(); /* Prepare the overlay frame for dispatch */ struct overlay_frame *frame = calloc(1,sizeof(struct overlay_frame)); if (!frame) FATAL("Couldn't allocate frame buffer"); if (is_sid_any(mdp->out.src.sid)){ /* set source to ourselves */ frame->source = my_subscriber; bcopy(frame->source->sid, mdp->out.src.sid, SID_SIZE); }else if (is_broadcast(mdp->out.src.sid)){ /* This is rather naughty if it happens, since broadcasting a response can lead to all manner of nasty things. Picture a packet with broadcast as the source address, sent to, say, the MDP echo port on another node, and with a source port also of the echo port. Said echo will get multiplied many, many, many times over before the TTL finally reaches zero. So we just say no to any packet with a broadcast source address. (Of course we have other layers of protection against such shenanigens, such as using BPIs to smart-flood broadcasts, but security comes through depth.) */ op_free(frame); RETURN(WHY("Packet had broadcast address as source address")); }else{ // assume all local identities have already been unlocked and marked as SELF. frame->source = find_subscriber(mdp->out.src.sid, SID_SIZE, 0); if (!frame->source){ op_free(frame); RETURN(WHYF("Possible spoofing attempt, tried to send a packet from %s, which is an unknown SID", alloca_tohex_sid(mdp->out.src.sid))); } if (frame->source->reachable!=REACHABLE_SELF){ op_free(frame); RETURN(WHYF("Possible spoofing attempt, tried to send a packet from %s", alloca_tohex_sid(mdp->out.src.sid))); } } /* Work out if destination is broadcast or not */ if (overlay_mdp_check_binding(frame->source, mdp->out.src.port, userGeneratedFrameP, recvaddr, recvaddrlen)){ op_free(frame); RETURN(overlay_mdp_reply_error (mdp_named.poll.fd, (struct sockaddr_un *)recvaddr, recvaddrlen,8, "Source address is invalid (you must bind to a source address before" " you can send packets")); } if (is_broadcast(mdp->out.dst.sid)){ /* broadcast packets cannot be encrypted, so complain if MDP_NOCRYPT flag is not set. Also, MDP_NOSIGN must also be applied, until NaCl cryptobox keys can be used for signing. */ if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT)){ op_free(frame); RETURN(overlay_mdp_reply_error(mdp_named.poll.fd, recvaddr,recvaddrlen,5, "Broadcast packets cannot be encrypted ")); } overlay_broadcast_generate_address(&frame->broadcast_id); frame->destination = NULL; }else{ frame->destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1); } frame->ttl=64; /* normal TTL (XXX allow setting this would be a good idea) */ if (!frame->destination || frame->destination->reachable == REACHABLE_SELF) { /* Packet is addressed such that we should process it. */ overlay_saw_mdp_frame(mdp,gettime_ms()); if (frame->destination) { /* Is local, and is not broadcast, so shouldn't get sent out on the wire. */ op_free(frame); RETURN(0); } } /* give voice packets priority */ if (mdp->out.dst.port==MDP_PORT_VOMP) frame->type=OF_TYPE_DATA_VOICE; else frame->type=OF_TYPE_DATA; frame->prev=NULL; frame->next=NULL; frame->payload=ob_new(); int fe=0; /* Work out the disposition of the frame-> For now we are only worried about the crypto matters, and not compression that may be applied before encryption (since applying it after is useless as ciphered text should have maximum entropy). */ switch(mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) { case 0: /* crypted and signed (using CryptoBox authcryption primitive) */ frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED; /* Prepare payload */ ob_makespace(frame->payload, 1 // frame type (MDP) +1 // MDP version +4 // dst port +4 // src port +crypto_box_curve25519xsalsa20poly1305_NONCEBYTES +crypto_box_curve25519xsalsa20poly1305_ZEROBYTES +mdp->out.payload_length); { /* write cryptobox nonce */ unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES]; if (urandombytes(nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES)) { op_free(frame); RETURN(WHY("urandombytes() failed to generate nonce")); } fe|= ob_append_bytes(frame->payload,nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES); /* generate plain message with zero bytes and get ready to cipher it */ unsigned char plain[crypto_box_curve25519xsalsa20poly1305_ZEROBYTES +10+mdp->out.payload_length]; /* zero bytes */ int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES; bzero(&plain[0],zb); /* MDP version 1 */ plain[zb+0]=0x01; plain[zb+1]=0x01; /* Ports */ plain[zb+2]=(mdp->out.src.port>>24)&0xff; plain[zb+3]=(mdp->out.src.port>>16)&0xff; plain[zb+4]=(mdp->out.src.port>>8)&0xff; plain[zb+5]=(mdp->out.src.port>>0)&0xff; plain[zb+6]=(mdp->out.dst.port>>24)&0xff; plain[zb+7]=(mdp->out.dst.port>>16)&0xff; plain[zb+8]=(mdp->out.dst.port>>8)&0xff; plain[zb+9]=(mdp->out.dst.port>>0)&0xff; /* payload */ bcopy(&mdp->out.payload,&plain[zb+10],mdp->out.payload_length); int cipher_len=zb+10+mdp->out.payload_length; /* get pre-computed PKxSK bytes (the slow part of auth-cryption that can be retained and reused, and use that to do the encryption quickly. */ unsigned char *k=keyring_get_nm_bytes(&mdp->out.src,&mdp->out.dst); if (!k) { op_free(frame); RETURN(WHY("could not compute Curve25519(NxM)")); } /* Get pointer to place in frame where the ciphered text needs to go */ int cipher_offset=frame->payload->position; unsigned char *cipher_text=ob_append_space(frame->payload,cipher_len); if (fe||(!cipher_text)){ op_free(frame); RETURN(WHY("could not make space for ciphered text")); } /* Actually authcrypt the payload */ if (crypto_box_curve25519xsalsa20poly1305_afternm (cipher_text,plain,cipher_len,nonce,k)){ op_free(frame); RETURN(WHY("crypto_box_afternm() failed")); } /* now shuffle down 16 bytes to get rid of the temporary space that crypto_box uses. */ bcopy(&cipher_text[16],&cipher_text[0],cipher_len-16); frame->payload->position-=16; if (0) { DEBUG("authcrypted mdp frame"); dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES); dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES); dump("plain text",&plain[16],cipher_len-16); dump("cipher text",cipher_text,cipher_len-16); DEBUGF("frame->payload->length=%d,cipher_len-16=%d,cipher_offset=%d", frame->payload->position,cipher_len-16,cipher_offset); dump("frame",&frame->payload->bytes[0], frame->payload->position); } } break; case MDP_NOCRYPT: /* Payload is sent unencrypted, but signed. To save space we do a trick where we hash the payload, and get the signature of that, but do not send the hash itself, since that can be reproduced (and indeed must be for verification) at the receiver's end. As the signing key is implicit, and the hash is also implicit, we can chop out part of the signature and thus save some bytes. */ frame->modifiers=OF_CRYPTO_SIGNED; /* Prepare payload */ ob_makespace(frame->payload, 1 // frame type (MDP) +1 // MDP version +4 // dst port +4 // src port +crypto_sign_edwards25519sha512batch_BYTES +mdp->out.payload_length); { unsigned char *key=keyring_find_sas_private(keyring, frame->source->sid, NULL); if (!key) { op_free(frame); RETURN(WHY("could not find signing key")); } /* Build plain-text that includes header and hash it so that we can sign that hash. */ unsigned char hash[crypto_hash_sha512_BYTES]; int plain_len = 10+mdp->out.payload_length; unsigned char *plain = frame->payload->bytes + frame->payload->position; if (!plain) return WHY("Unable to allocate space for payload and signature"); /* MDP version 1 */ ob_append_byte(frame->payload,0x01); ob_append_byte(frame->payload,0x01); /* Destination port */ ob_append_ui32(frame->payload,mdp->out.src.port); ob_append_ui32(frame->payload,mdp->out.dst.port); ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length); /* now hash it */ crypto_hash_sha512(hash,plain,plain_len); unsigned char signature[crypto_hash_sha512_BYTES +crypto_sign_edwards25519sha512batch_BYTES]; unsigned long long sig_len=0; crypto_sign_edwards25519sha512batch(signature,&sig_len, hash,crypto_hash_sha512_BYTES, key); if (!sig_len) { op_free(frame); RETURN(WHY("Signing MDP frame failed")); } if (0){ dump("payload", plain, plain_len); dump("signature", signature, sizeof(signature)); } /* chop hash out of middle of signature since it has to be recomputed at the far end, anyway, and ammend the two halves of the signature. */ ob_append_bytes(frame->payload,&signature[0],32); ob_append_bytes(frame->payload,&signature[32+crypto_hash_sha512_BYTES],32); } break; case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */ frame->modifiers=0; /* Copy payload body in */ ob_makespace(frame->payload, 1 // frame type (MDP) +1 // MDP version +4 // dst port +4 // src port +mdp->out.payload_length); /* MDP version 1 */ ob_append_byte(frame->payload,0x01); ob_append_byte(frame->payload,0x01); /* Destination port */ ob_append_ui32(frame->payload,mdp->out.src.port); ob_append_ui32(frame->payload,mdp->out.dst.port); ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length); break; case MDP_NOSIGN: default: /* ciphered, but not signed. This means we don't use CryptoBox, but rather a more compact means of representing the ciphered stream segment. */ op_free(frame); RETURN(WHY("Not implemented")); break; } // TODO include priority in packet header int qn=OQ_ORDINARY; /* Make sure voice traffic gets priority */ if ((frame->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) { qn=OQ_ISOCHRONOUS_VOICE; rhizome_saw_voice_traffic(); } frame->send_copies = mdp->out.send_copies; if (overlay_payload_enqueue(qn, frame)) op_free(frame); RETURN(0); }
int overlay_route_add_advertisements(int interface,overlay_buffer *e) { /* Construct a route advertisement frame and append it to e. Work out available space in packet for advertisments, and fit the highest scoring nodes from the current portion in. Each advertisement consists of an address prefix followed by score. We will use 6 bytes of prefix to make it reasonably hard to generate collisions, including by birthday paradox (good for networks upto about 20million nodes), and one byte each for score gateways_en_route. XXX - We need to send full addresses sometimes so that receiver can resolve them. Either that or we need to start supporting the PLEASEEXPLAIN packets, which is probably a better solution. The receiver will discount the score based on their measured reliability for packets to arrive from us; we just repeat what discounted score we have remembered. Hacking the frame together this way is less flexible, but much faster than messing about with malloc() and setting address fields. The src,dst and nexthop can each be encoded with a single byte. Thus using a fixed 1-byte RFS field we are limited to RFS<0xfa, which gives us 30 available advertisement slots per packet. */ int i; int bytes=e->sizeLimit-e->length; int overhead=1+8+1+3+32+1+1; /* maximum overhead */ int slots=(bytes-overhead)/8; if (slots>30) slots=30; int slots_used=0; if (slots<1) return WHY("No room for node advertisements"); if (ob_append_byte(e,OF_TYPE_NODEANNOUNCE)) return WHY("could not add node advertisement header"); ob_append_byte(e,1); /* TTL */ int rfs_offset=e->length; /* remember where the RFS byte gets stored so that we can patch it later */ ob_append_byte(e,1+8+1+1+8*slots_used/* RFS */); /* Stuff in dummy address fields */ ob_append_byte(e,OA_CODE_BROADCAST); for(i=0;i<8;i++) ob_append_byte(e,random()&0xff); /* random BPI */ ob_append_byte(e,OA_CODE_PREVIOUS); ob_append_byte(e,OA_CODE_SELF); int count; while (slots>0&&oad_request_count) { oad_request_count--; ob_append_bytes(e,oad_requests[oad_request_count]->sid,6); ob_append_byte(e,oad_requests[oad_request_count]->best_link_score); ob_append_byte(e,oad_requests[oad_request_count] ->observations[oad_requests[oad_request_count] ->best_observation].gateways_en_route); slots--; slots_used++; } while(slots>0) { /* find next node */ int bin=oad_bin; int slot=oad_slot; /* XXX Skipping priority advertised nodes could be done faster, e.g., by adding a flag to the overlay_node structure to indicate if it has been sent priority, and if so, skip it. The flags could then be reset at the end of this function. But this will do for now. */ int skip=0; for(i=0;i<count;i++) if (oad_requests[i]==&overlay_nodes[oad_bin][oad_slot]) skip=1; if (!skip) { if(overlay_nodes[oad_bin][oad_slot].sid[0]) { overlay_node *n=&overlay_nodes[oad_bin][oad_slot]; ob_append_bytes(e,n->sid,6); ob_append_byte(e,n->best_link_score); ob_append_byte(e,n->observations[n->best_observation].gateways_en_route); slots--; slots_used++; } } /* Find next node */ oad_slot++; if (oad_slot>=overlay_bin_size) { oad_slot=0; oad_bin++; } /* Stop stuffing if we get to the end of the node list so that we can implement an appropriate pause between rounds to avoid unneeded repeated TX of nodes. */ if (oad_bin>=overlay_bin_count) { oad_bin=0; oad_round++; break; } /* Stop if we have advertised everyone */ if (oad_bin==bin&&oad_slot==slot) break; } e->bytes[rfs_offset]=1+8+1+1+8*slots_used; return 0; }
int overlay_route_ack_selfannounce(overlay_frame *f,overlay_neighbour *n) { /* Acknowledge the receipt of a self-announcement of an immediate neighbour. We could acknowledge immediately, but that requires the transmission of an extra packet with all the overhead that entails. However, there is no real need to send the ack out immediately. It should be entirely reasonable to send the ack out with the next interface tick. So we can craft the ack and submit it to the queue. As the next-hop will get determined at TX time, this will ensure that we send the packet out on the right interface to reach the originator of the self-assessment. So all we need to do is craft the payload and put it onto the queue for OVERLAY_MESH_MANAGEMENT messages. Also, we should check for older such frames on the queue and drop them. There is one caveat to the above: until the first selfannounce gets returned, we don't have an open route. Thus we need to just make sure that the ack goes out broadcast if we don't know about a return path. Once the return path starts getting built, it should be fine. */ /* XXX Allocate overlay_frame structure and populate it */ overlay_frame *out=NULL; out=calloc(sizeof(overlay_frame),1); if (!out) return WHY("calloc() failed to allocate an overlay frame"); out->type=OF_TYPE_SELFANNOUNCE_ACK; out->modifiers=0; out->ttl=6; /* maximum time to live for an ack taking an indirect route back to the originator. If it were 1, then we would not be able to handle mono-directional links (which WiFi is notorious for). XXX 6 is quite an arbitrary selection however. */ /* Set destination of ack to source of observed frame */ if (overlay_frame_set_neighbour_as_destination(out,n)) { op_free(out); return WHY("overlay_frame_set_neighbour_as_source() failed"); } /* set source to ourselves */ overlay_frame_set_me_as_source(out); /* Next-hop will get set at TX time, so no need to set it here. However, if there is no known next-hop for this node (because the return path has not yet begun to be built), then we need to set the nexthop to broadcast. */ out->nexthop_address_status=OA_UNINITIALISED; { unsigned char nexthop[SID_SIZE]; int nexthoplen,interface; if (overlay_get_nexthop(out->destination,nexthop,&nexthoplen,&interface)) { /* No path, so set nexthop to be broadcast, but don't broadcast it too far. */ int i; for(i=0;i<SID_SIZE;i++) out->nexthop[i]=0xff; out->nexthop_address_status=OA_RESOLVED; out->ttl=2; if (debug&DEBUG_OVERLAYROUTING) fprintf(stderr,"Broadcasting ack to selfannounce"); } else if (debug&DEBUG_OVERLAYROUTING) fprintf(stderr,"singlecasting ack to selfannounce via known route"); } /* Set the time in the ack. Use the last sequence number we have seen from this neighbour, as that may be helpful information for that neighbour down the track. My policy is to communicate that information which should be helpful for forming and maintaining the health of the mesh, as that way each node can in potentially implement a different mesh routing protocol, without breaking the wire protocol. This makes over-the-air software updates much safer. Combining of adjacent observation reports may mean that the most recent observation is not the last one in the list, also the wrapping of the sequence numbers means we can't just take the highest-numbered sequence number. So we need to take the observation which was most recently received. */ out->payload=ob_new(4+32*2+1); /* will grow if it isn't big enough, but let's try to avoid a realloc() if possible */ int i; int best_obs_id=-1; long long best_obs_time=0; for(i=0;i<OVERLAY_MAX_OBSERVATIONS;i++) { if (n->observations[i].time_ms>best_obs_time) { best_obs_id=i; best_obs_time=n->observations[i].time_ms; } } /* Observation time is presented in seconds to save space in transit. This is used to base score decay on when the last ACTUAL FIRST-HAND was made, rather than when someone heard that someone else heard from the nodes third cousin's step-uncle's room-mate-in-law, twice removed. */ ob_append_int(out->payload,n->observations[best_obs_id].s2/1000); /* The ack needs to contain the per-interface scores that we have built up for this neighbour. We expect that for most neighbours they will have many fewer than 32 interfaces, and even when they have multiple interfaces that we will only be able to hear them on one or a few. So we will structure the format so that we use fewer bytes when fewer interfaces are involved. Probably the simplest is to put each non-zero score followed by it's interface. That way the whole list will be easy to parse, and as short as 3 bytes for a single interface. We could use the spare 2 bits at the top of the interface id to indicate multiple interfaces with same score? */ for(i=0;i<OVERLAY_MAX_INTERFACES;i++) { /* Only include interfaces with score >0 */ if (n->scores[i]) { ob_append_byte(out->payload,n->scores[i]); ob_append_byte(out->payload,i); } } /* Terminate list */ ob_append_byte(out->payload,0); /* Add to queue */ if (overlay_payload_enqueue(OQ_MESH_MANAGEMENT,out)) { op_free(out); return WHY("overlay_payload_enqueue(self-announce ack) failed"); } /* XXX Remove any stale versions (or should we just freshen, and forget making a new one, since it would be more efficient). */ return 0; }
int overlay_rhizome_add_advertisements(int interface_number,overlay_buffer *e) { int pass; int bytes=e->sizeLimit-e->length; int overhead=1+8+1+3+1+1+1; /* maximum overhead */ int slots=(bytes-overhead)/RHIZOME_BAR_BYTES; if (slots>30) slots=30; int slots_used=0; int bytes_used=0; int bytes_available=bytes-overhead-1 /* one byte held for expanding RFS */; int bundles_advertised=0; if (slots<1) return WHY("No room for node advertisements"); if (!rhizome_db) return WHY("Rhizome not enabled"); if (ob_append_byte(e,OF_TYPE_RHIZOME_ADVERT)) return WHY("could not add rhizome bundle advertisement header"); ob_append_byte(e,1); /* TTL */ int rfs_offset=e->length; /* remember where the RFS byte gets stored so that we can patch it later */ ob_append_byte(e,1+8+1+1+1+RHIZOME_BAR_BYTES*slots_used/* RFS */); /* Stuff in dummy address fields */ ob_append_byte(e,OA_CODE_BROADCAST); { int i; for(i=0;i<8;i++) ob_append_byte(e,random()&0xff); } /* BPI for broadcast */ ob_append_byte(e,OA_CODE_PREVIOUS); ob_append_byte(e,OA_CODE_SELF); /* Randomly choose whether to advertise manifests or BARs first. */ int skipmanifests=random()&1; /* Version of rhizome advert block: 1 = manifests then BARs, 2 = BARs only */ ob_append_byte(e,1+skipmanifests); /* XXX Should add priority bundles here. XXX Should prioritise bundles for subscribed groups, Serval-authorised files etc over common bundles. XXX Should wait a while after going through bundle list so that we don't waste CPU on db queries if there are not many bundles. Actually, we probably just shouldn't be sending bundles blindly on every tick. XXX How do we indicate group membership with BARs? Or do groups actively poll? */ if (debug&DEBUG_RHIZOME) WHY("Group handling not completely thought out here yet."); /* Get number of bundles available if required */ bundles_available=sqlite_exec_int64("SELECT COUNT(BAR) FROM MANIFESTS;"); if (bundles_available==-1||(bundle_offset[0]>=bundles_available)) bundle_offset[0]=0; if (bundles_available==-1||(bundle_offset[1]>=bundles_available)) bundle_offset[1]=0; for(pass=skipmanifests;pass<2;pass++) { sqlite3_stmt *statement; char query[1024]; switch(pass) { case 0: /* Full manifests */ snprintf(query,1024,"SELECT MANIFEST,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass],slots); break; case 1: /* BARs */ snprintf(query,1024,"SELECT BAR,ROWID FROM MANIFESTS LIMIT %d,%d", bundle_offset[pass],slots); break; } switch (sqlite3_prepare_v2(rhizome_db,query,-1,&statement,NULL)) { case SQLITE_OK: case SQLITE_DONE: case SQLITE_ROW: break; default: sqlite3_finalize(statement); sqlite3_close(rhizome_db); rhizome_db=NULL; WHY(query); WHY(sqlite3_errmsg(rhizome_db)); return WHY("Could not prepare sql statement for fetching BARs for advertisement."); } while((bytes_used<bytes_available)&&(sqlite3_step(statement)==SQLITE_ROW)&& (e->length+RHIZOME_BAR_BYTES<=e->sizeLimit)) { sqlite3_blob *blob; int column_type=sqlite3_column_type(statement, 0); switch(column_type) { case SQLITE_BLOB: if (sqlite3_blob_open(rhizome_db,"main","manifests", pass?"bar":"manifest", sqlite3_column_int64(statement,1) /* rowid */, 0 /* read only */,&blob)!=SQLITE_OK) { WHY("Couldn't open blob"); continue; } int blob_bytes=sqlite3_blob_bytes(blob); if (pass&&(blob_bytes!=RHIZOME_BAR_BYTES)) { if (debug&DEBUG_RHIZOME) fprintf(stderr,"Found a BAR that is the wrong size - ignoring\n"); continue; } /* Only include manifests that are <=1KB inline. Longer ones are only advertised by BAR */ if (blob_bytes>1024) continue; int overhead=0; if (!pass) overhead=2; if (ob_makespace(e,overhead+blob_bytes)) { if (debug&DEBUG_RHIZOME) fprintf(stderr,"Stopped cramming %s into Rhizome advertisement frame.\n", pass?"BARs":"manifests"); break; } if (!pass) { /* put manifest length field and manifest ID */ e->bytes[e->length]=(blob_bytes>>8)&0xff; e->bytes[e->length+1]=(blob_bytes>>0)&0xff; if (debug&DEBUG_RHIZOME) fprintf(stderr,"length bytes written at offset 0x%x\n",e->length); } if (sqlite3_blob_read(blob,&e->bytes[e->length+overhead],blob_bytes,0) !=SQLITE_OK) { if (debug&DEBUG_RHIZOME) WHY("Couldn't read from blob"); sqlite3_blob_close(blob); continue; } e->length+=overhead+blob_bytes; bytes_used+=overhead+blob_bytes; bundles_advertised++; sqlite3_blob_close(blob); } } sqlite3_finalize(statement); if (!pass) { /* Mark end of whole manifests by writing 0xff, which is more than the MSB of a manifest's length is allowed to be. */ ob_append_byte(e,0xff); } }
int overlay_frame_package_fmt1(overlay_frame *p,overlay_buffer *b) { /* Convert a payload (frame) structure into a series of bytes. Assumes that any encryption etc has already been done. Will pick a next hop if one has not been chosen. */ int nexthoplen=0; overlay_buffer *headers=ob_new(256); if (!headers) return WHY("could not allocate overlay buffer for headers"); if (!p) return WHY("p is NULL"); if (!b) return WHY("b is NULL"); /* Build header */ int fail=0; if (p->nexthop_address_status!=OA_RESOLVED) { if (overlay_get_nexthop((unsigned char *)p->destination,p->nexthop,&nexthoplen,&p->nexthop_interface)) fail++; else p->nexthop_address_status=OA_RESOLVED; } if (p->source[0]<0x10) { // Make sure that addresses do not overload the special address spaces of 0x00*-0x0f* fail++; return WHY("packet source address begins with reserved value 0x00-0x0f"); } if (p->destination[0]<0x10) { // Make sure that addresses do not overload the special address spaces of 0x00*-0x0f* fail++; return WHY("packet destination address begins with reserved value 0x00-0x0f"); } if (p->nexthop[0]<0x10) { // Make sure that addresses do not overload the special address spaces of 0x00*-0x0f* fail++; return WHY("packet nexthop address begins with reserved value 0x00-0x0f"); } /* XXX Write fields in correct order */ /* Write out type field byte(s) */ if (!fail) if (op_append_type(headers,p)) fail++; /* Write out TTL */ if (!fail) if (ob_append_byte(headers,p->ttl)) fail++; /* Length. This is the fun part, because we cannot calculate how many bytes we need until we have abbreviated the addresses, and the length encoding we use varies according to the length encoded. The simple option of running the abbreviations twice won't work because we rely on context for abbreviating the addresses. So we write it initially and then patch it after. */ if (!fail) { int max_len=((SID_SIZE+3)*3+headers->length+p->payload->length); ob_append_rfs(headers,max_len); int addrs_start=headers->length; /* Write out addresses as abbreviated as possible */ overlay_abbreviate_append_address(headers,p->nexthop); overlay_abbreviate_set_most_recent_address(p->nexthop); overlay_abbreviate_append_address(headers,p->destination); overlay_abbreviate_set_most_recent_address(p->destination); overlay_abbreviate_append_address(headers,p->source); overlay_abbreviate_set_most_recent_address(p->source); int addrs_len=headers->length-addrs_start; int actual_len=addrs_len+p->payload->length; ob_patch_rfs(headers,actual_len); } if (fail) { ob_free(headers); return WHY("failure count was non-zero"); } /* Write payload format plus total length of header bits */ if (ob_makespace(b,2+headers->length+p->payload->length)) { /* Not enough space free in output buffer */ ob_free(headers); if (debug&DEBUG_PACKETFORMATS) WHY("Could not make enough space free in output buffer"); return -1; } /* Package up headers and payload */ ob_checkpoint(b); if (ob_append_bytes(b,headers->bytes,headers->length)) { fail++; WHY("could not append header"); } if (ob_append_bytes(b,p->payload->bytes,p->payload->length)) { fail++; WHY("could not append payload"); } /* XXX SIGN &/or ENCRYPT */ ob_free(headers); if (fail) { ob_rewind(b); return WHY("failure count was non-zero"); } else return 0; }