Example #1
0
// send a registration packet
static void directory_send(struct subscriber *directory_service, const unsigned char *sid, const char *did, const char *name){
  overlay_mdp_frame request;
  
  memset(&request, 0, sizeof(overlay_mdp_frame));
  
  request.packetTypeAndFlags = MDP_TX;
  
  bcopy(sid, request.out.src.sid, SID_SIZE);
  request.out.src.port=MDP_PORT_NOREPLY;
  
  bcopy(directory_service->sid, request.out.dst.sid, SID_SIZE);
  request.out.dst.port=MDP_PORT_DIRECTORY;
  request.out.payload_length = snprintf((char *)request.out.payload, sizeof(request.out.payload), 
					"%s|%s", did, name);
  // Used by tests
  INFOF("Sending directory registration for %s, %s, %s to %s", 
	alloca_tohex(sid,7), did, name, alloca_tohex(directory_service->sid, 7));
  overlay_mdp_dispatch(&request, 0, NULL, 0);
}
Example #2
0
void rhizome_server_poll(struct sched_ent *alarm)
{
  if (alarm->poll.revents & (POLLIN | POLLOUT)) {
    struct sockaddr addr;
    unsigned int addr_len = sizeof addr;
    int sock;
    while ((sock = accept(rhizome_server_socket, &addr, &addr_len)) != -1) {
      if (addr.sa_family == AF_INET) {
	struct sockaddr_in *peerip = (struct sockaddr_in *)&addr;
	INFOF("RHIZOME HTTP SERVER, ACCEPT addrlen=%u family=%u port=%u addr=%u.%u.%u.%u",
	    addr_len, peerip->sin_family, peerip->sin_port,
	    ((unsigned char*)&peerip->sin_addr.s_addr)[0],
	    ((unsigned char*)&peerip->sin_addr.s_addr)[1],
	    ((unsigned char*)&peerip->sin_addr.s_addr)[2],
	    ((unsigned char*)&peerip->sin_addr.s_addr)[3]
	  );
      } else {
	INFOF("RHIZOME HTTP SERVER, ACCEPT addrlen=%u family=%u data=%s",
	  addr_len, addr.sa_family, alloca_tohex((unsigned char *)addr.sa_data, sizeof addr.sa_data)
	);
      }
      rhizome_http_request *request = calloc(sizeof(rhizome_http_request), 1);
      if (request == NULL) {
	WHYF_perror("calloc(%u, 1)", sizeof(rhizome_http_request));
	WHY("Cannot respond to request, out of memory");
      } else {
	/* We are now trying to read the HTTP request */
	request->request_type=RHIZOME_HTTP_REQUEST_RECEIVING;
	request->alarm.function = rhizome_client_poll;
	connection_stats.name="rhizome_client_poll";
	request->alarm.stats=&connection_stats;
	request->alarm.poll.fd=sock;
	request->alarm.poll.events=POLLIN;
	request->alarm.alarm = gettime_ms()+RHIZOME_IDLE_TIMEOUT;
	request->alarm.deadline = request->alarm.alarm+RHIZOME_IDLE_TIMEOUT;
	// watch for the incoming http request
	watch(&request->alarm);
	// set an inactivity timeout to close the connection
	schedule(&request->alarm);
      }
    }
    if (errno != EAGAIN) {
      WARN_perror("accept");
    }
  }
  
  if (alarm->poll.revents & (POLLHUP | POLLERR)) {
    INFO("Error on tcp listen socket");
  }
}
Example #3
0
int cmd_serval_sign(const char *sid_str, 
	 const size_t sid_len,
	 const unsigned char *msg,
	 const size_t msg_len,
	 char *sig_str_buf,
	 const size_t sig_str_size,
	 const char *keyring_path,
	 const size_t keyring_len) {
  
  int ret = 0;
  unsigned char signed_msg[msg_len + SIGNATURE_BYTES];
  keyring_file *_keyring = NULL;
  unsigned char *key = NULL;
  unsigned char packedSid[SID_SIZE] = {0};
  
  CHECK(sig_str_size >= 2*SIGNATURE_BYTES + 1,"Signature buffer too small");
  
  if (sid_str) {
    CHECK_ERR(sid_len == 2*SID_SIZE && str_is_subscriber_id(sid_str) == 1,"Invalid SID");
    stowSid(packedSid,0,sid_str);
  }
  
  if (keyring_path) {
    CHECK_ERR(serval_init_keyring(sid_str ? packedSid : NULL,
                     sid_str ? SID_SIZE : 0,
		     keyring_path,
		     keyring_len,
		     &_keyring,
		     &key,
		     NULL), "Failed to initialize Serval keyring");
  } else {
    CHECK_ERR(serval_extract_sas(&key,NULL,keyring,packedSid),"Failed to fetch SAS key");
  }
  
  CHECK_ERR(serval_create_signature(key, msg, msg_len, signed_msg, SIGNATURE_BYTES + msg_len),"Failed to create signature");
  
  strncpy(sig_str_buf,alloca_tohex(signed_msg + msg_len,SIGNATURE_BYTES),2*SIGNATURE_BYTES);
  sig_str_buf[2*SIGNATURE_BYTES] = '\0';

  ret = 1;
error:
  if (_keyring) keyring_free(_keyring);
  return ret;
}
Example #4
0
int serval_sign(const char *sid, 
	 const size_t sid_len,
	 const unsigned char *msg,
	 const size_t msg_len,
	 char *sig_buffer,
	 const size_t sig_size,
	 const char *keyringName,
	 const size_t keyring_len) {
  
  keyring_identity *new_ident;
  char keyringFile[1024];
  
  assert(msg_len);
  if (sid) assert(sid_len == 2*SID_SIZE);
  
  if (keyringName == NULL || keyring_len == 0) { 
    FORM_SERVAL_INSTANCE_PATH(keyringFile, "serval.keyring"); // if no keyring specified, use default keyring
  }
  else { // otherwise, use specified keyring (NOTE: if keyring does not exist, it will be created)
    strncpy(keyringFile,keyringName,keyring_len);
    keyringFile[keyring_len] = '\0';
  }
  
  keyring = keyring_open(keyringFile);
  keyring_enter_pin(keyring, KEYRING_PIN); // unlocks Serval keyring for using identities (also initializes global default identity my_subscriber)
  
  if (!sid) {
    //create new sid
    int c;
    for(c=0;c<keyring->context_count;c++) { // cycle through the keyring contexts until we find one with room for another identity
      new_ident = keyring_create_identity(keyring,keyring->contexts[c], KEYRING_PIN); // create new Serval identity
      if (new_ident)
	break;
    }
    if (!new_ident) {
      fprintf(stderr, "failed to create new SID\n");
      return 1;
    }
    if (keyring_commit(keyring)) { // need to commit keyring or else new identity won't be saved (needs root permissions)
      fprintf(stderr, "Failed to save new SID into keyring...make sure you are running as root!\n");
      return 1;
    }
    sid = alloca_tohex_sid(new_ident->subscriber->sid); // convert SID from binary to hex
  } else {
    if (!str_is_subscriber_id(sid)) {
      fprintf(stderr,"Invalid SID\n");
      return 1;
    }
  }
  
  unsigned char packedSid[SID_SIZE];
  stowSid(packedSid,0,sid);
  
  unsigned char *key=keyring_find_sas_private(keyring, packedSid, NULL); // get SAS key associated with our SID
  if (!key)
    return 1;
  
  unsigned char hash[crypto_hash_sha512_BYTES]; 
  unsigned long long sig_length = SIGNATURE_BYTES;
  crypto_hash_sha512(hash, msg, msg_len); // create sha512 hash of message, which will then be signed
  
  unsigned char signed_msg[msg_len + sig_length];
  memcpy(signed_msg,msg,msg_len);
  
  int ret = crypto_create_signature(key, hash, crypto_hash_sha512_BYTES, &signed_msg[msg_len], &sig_length); // create signature of message hash, append it to end of message
  
  if (!ret) { //success
    printf("%s\n", alloca_tohex(signed_msg + msg_len, sig_length));
    printf("%s\n",sid);
    if (sig_size > 0) {
      if (sig_size >= 2*sig_length + 1) {
        strncpy(sig_buffer,alloca_tohex(signed_msg + msg_len,sig_length),2*sig_length);
        sig_buffer[2*sig_length] = '\0';
      } else
	fprintf(stderr,"Insufficient signature buffer size\n");
    }
  }
  
  keyring_free(keyring);
  
  return ret;
}
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
		    unsigned char *transaction_id,int recvttl,
		    struct sockaddr *recvaddr, size_t recvaddrlen, int parseP)
{
  /* 
     This function decodes overlay packets which have been assembled for delivery overy IP networks.
     IP based wireless networks have a high, but limited rate of packets that can be sent. In order 
     to increase throughput of small payloads, we ammend many payloads together and have used a scheme 
     to compress common network identifiers.
   
     A different network type may have very different constraints on the number and size of packets,
     and may need a different encoding scheme to use the bandwidth efficiently.
   
     The current structure of an overlay packet is as follows;
     Fixed header [0x4F, 0x10]
     Version [0x00, 0x01]
     
     Each frame within the packet has the following fields:
     Frame type (8-24bits)
     TTL (8bits)
     Remaining frame size (RFS) (see overlay_payload.c or overlay_buffer.c for explanation of format)
     Next hop (variable length due to address abbreviation)
     Destination (variable length due to address abbreviation)
     Source (variable length due to address abbreviation)
     Payload (length = RFS- len(frame type) - len(next hop)

     This structure is intended to allow relaying nodes to quickly ignore frames that are
     not addressed to them as either the next hop or final destination.

     The RFS field uses additional bytes to encode the length of longer frames.  
     This provides us with a slight space saving for the common case of short frames.
     
     The frame payload itself can be enciphered with the final destination's public key, so 
     that it is not possible for the relaying 3rd parties to observe the content.  

     Naturally some information will leak simply based on the size, periodicity and other 
     characteristics of the traffic, and some 3rd parties may be malevolent, so noone should
     assume that this provides complete security.

     It would be possible to design a super-paranoid mode where onion routing is used with
     concentric shells of encryption so that each hop can only work out the next node to send it
     to.  However, that would result in rather large frames, which may well betray more information 
     than the super-paranoid mode would hide.

     Note also that it is possible to dispatch frames on a local link which are addressed to
     broadcast, but are enciphered.  In that situation only the intended recipient can
     decode the frame, but at the cost of having all nodes on the local link having to decrypt
     frame. Of course the nodes may elect to not decrypt such anonymous frames.  

     Such frames could even be flooded throughout part of the mesh by having the TTL>1, and
     optionally with an anonymous source address to provide some plausible deniability for both
     sending and reception if combined with a randomly selected TTL to give the impression of
     the source having received the frame from elsewhere.
  */

  struct overlay_frame f;
  struct subscriber *sender=NULL;
  struct decode_context context={
    .please_explain=NULL,
  };
  
  time_ms_t now = gettime_ms();
  struct overlay_buffer *b = ob_static(packet, len);
  ob_limitsize(b, len);
  // skip magic bytes and version as they have already been parsed
  b->position=4;
  
  bzero(&f,sizeof(struct overlay_frame));
  
  if (recvaddr->sa_family==AF_INET){
    f.recvaddr=recvaddr; 
    if (debug&DEBUG_OVERLAYFRAMES)
      DEBUG("Received overlay packet");
  } else {
    if (interface->fileP) {
      /* dummy interface, so tell to use localhost */
      loopback.sin_family = AF_INET;
      loopback.sin_port = 0;
      loopback.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
      f.recvaddr=(struct sockaddr *)&loopback;
    } else 
      /* some other sort of interface, so we can't offer any help here */
      f.recvaddr=NULL;
  }

  overlay_address_clear();

  // TODO put sender of packet and sequence number in envelope header
  // Then we can quickly drop reflected broadcast packets
  // currently we see annoying errors as we attempt to parse each payload
  // plus with a sequence number we can detect dropped packets and nack them for retransmission
  
  /* Skip magic bytes and version */
  while(b->position < b->sizeLimit){
    context.invalid_addresses=0;
    
    int flags = ob_get(b);
    
    /* Get normal form of packet type and modifiers */
    f.type=flags&OF_TYPE_BITS;
    f.modifiers=flags&OF_MODIFIER_BITS;

    switch(f.type){
      case OF_TYPE_EXTENDED20:
	/* Eat the next two bytes */
	f.type=OF_TYPE_FLAG_E20|flags|(ob_get(b)<<4)|(ob_get(b)<<12);
	f.modifiers=0;
	break;
	  
      case OF_TYPE_EXTENDED12:
	/* Eat the next byte */
	f.type=OF_TYPE_FLAG_E12|flags|(ob_get(b)<<4);
	f.modifiers=0;
	break;
    }
    
    /* Get time to live */
    f.ttl=ob_get(b);

    /* Decode length of remainder of frame */
    int payload_len=rfs_decode(b->bytes, &b->position);

    if (payload_len <=0) {
      /* assume we fell off the end of the packet */
      break;
    }

    int next_payload = b->position + payload_len;
    
    /* Always attempt to resolve all of the addresses in a packet, or we could fail to understand an important payload 
     eg, peer sends two payloads travelling in opposite directions;
	[Next, Dest, Sender] forwarding a payload we just send, so Sender == Me
	[Next, Dest, Sender] delivering a payload to us so Next == Me
     
     But Next would be encoded as OA_CODE_PREVIOUS, so we must parse all three addresses, 
     even if Next is obviously not intended for us
     */
    
    struct subscriber *nexthop=NULL;
    bzero(f.broadcast_id.id, BROADCAST_LEN);
    
    // if the structure of the addresses looks wrong, stop immediately
    if (overlay_address_parse(&context, b, &f.broadcast_id, &nexthop)
	|| overlay_address_parse(&context, b, NULL, &f.destination)
	|| overlay_address_parse(&context, b, NULL, &f.source)){
      goto next;
    }
    
    // if we can't understand one of the addresses, skip processing the payload
    if (context.invalid_addresses)
      goto next;

    if (debug&DEBUG_OVERLAYFRAMES){
      DEBUGF("Received payload type %x, len %d", f.type, next_payload - b->position);
      DEBUGF("Payload from %s", alloca_tohex_sid(f.source->sid));
      DEBUGF("Payload to %s", (f.destination?alloca_tohex_sid(f.destination->sid):"broadcast"));
      if (!is_all_matching(f.broadcast_id.id, BROADCAST_LEN, 0))
	DEBUGF("Broadcast id %s", alloca_tohex(f.broadcast_id.id, BROADCAST_LEN));
      if (nexthop)
	DEBUGF("Next hop %s", alloca_tohex_sid(nexthop->sid));
    }

    if (f.type==OF_TYPE_SELFANNOUNCE){
      sender = f.source;
      // skip the entire packet if it came from me
      if (sender->reachable==REACHABLE_SELF)
	break;
      
      overlay_address_set_sender(f.source);
      
      // if this is a dummy announcement for a node that isn't in our routing table
      if (f.destination && 
	(f.source->reachable == REACHABLE_NONE || f.source->reachable == REACHABLE_UNICAST) && 
	(!f.source->node) &&
	(interface->fileP || recvaddr->sa_family==AF_INET)){
	  struct sockaddr_in *addr=(struct sockaddr_in *)recvaddr;
	  
	  // mark this subscriber as reachable directly via unicast.
	  reachable_unicast(f.source, interface, addr->sin_addr, ntohs(addr->sin_port));
      }
    }
    
    // ignore any payload we sent
    if (f.source->reachable==REACHABLE_SELF){
      if (debug&DEBUG_OVERLAYFRAMES)
	DEBUGF("Ignoring payload from myself (%s)", alloca_tohex_sid(f.source->sid));
      goto next;
    }
    
    // skip unicast payloads that aren't for me
    if (nexthop && nexthop->reachable!=REACHABLE_SELF){
      if (debug&DEBUG_OVERLAYFRAMES)
	DEBUGF("Ignoring payload that is not meant for me (%s)", alloca_tohex_sid(nexthop->sid));
      goto next;
    }
      
    // skip broadcast payloads we've already seen
    if ((!nexthop) && overlay_broadcast_drop_check(&f.broadcast_id)){
      if (debug&DEBUG_OVERLAYFRAMES)
	DEBUGF("Ignoring duplicate broadcast (%s)", alloca_tohex(f.broadcast_id.id, BROADCAST_LEN));
      goto next;
    }
    
    f.payload = ob_slice(b, b->position, next_payload - b->position);
    if (!f.payload){
      WHY("Payload length is longer than remaining packet size");
      break;
    }
    // mark the entire payload as having valid data
    ob_limitsize(f.payload, next_payload - b->position);
    
    // forward payloads that are for someone else or everyone
    if ((!f.destination) || 
	(f.destination->reachable != REACHABLE_SELF && f.destination->reachable != REACHABLE_NONE)){
      overlay_forward_payload(&f);
    }
    
    // process payloads that are for me or everyone
    if ((!f.destination) || f.destination->reachable==REACHABLE_SELF){
      process_incoming_frame(now, interface, &f, &context);
    }
    
  next:
    if (f.payload){
      ob_free(f.payload);
      f.payload=NULL;
    }
    b->position=next_payload;
  }
  
  ob_free(b);
  
  send_please_explain(&context, my_subscriber, sender);
  return 0;
}
Example #6
0
static void
overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, time_ms_t now){
  struct overlay_frame *frame = queue->first;
  
  // TODO stop when the packet is nearly full?
  while(frame){
    if (frame->enqueued_at + queue->latencyTarget < now){
      if (config.debug.rejecteddata)
	DEBUGF("Dropping frame type %x for %s due to expiry timeout", 
	       frame->type, frame->destination?alloca_tohex_sid(frame->destination->sid):"All");
      frame = overlay_queue_remove(queue, frame);
      continue;
    }
    
    /* Note, once we queue a broadcast packet we are committed to sending it out every interface, 
     even if we hear it from somewhere else in the mean time
     */
    
    // ignore payloads that are waiting for ack / nack resends
    if (frame->dont_send_until > now)
      goto skip;

    // quickly skip payloads that have no chance of fitting
    if (packet->buffer && ob_limit(frame->payload) > ob_remaining(packet->buffer))
      goto skip;
    
    if (!frame->destination_resolved){
      frame->next_hop = frame->destination;
      
      if (frame->next_hop){
	// Where do we need to route this payload next?
	
	int r = subscriber_is_reachable(frame->next_hop);
	
	// first, should we try to bounce this payload off the directory service?
	if (r==REACHABLE_NONE && 
	    directory_service && 
	    frame->next_hop!=directory_service){
	  frame->next_hop=directory_service;
	  r=subscriber_is_reachable(directory_service);
	}
	
	// do we need to route via a neighbour?
	if (r&REACHABLE_INDIRECT){
	  frame->next_hop = frame->next_hop->next_hop;
	  r = subscriber_is_reachable(frame->next_hop);
	}
	
	if (!(r&REACHABLE_DIRECT)){
	  goto skip;
	}
	
	frame->interface = frame->next_hop->interface;
	
	// if both broadcast and unicast are available, pick on based on interface preference
	if ((r&(REACHABLE_UNICAST|REACHABLE_BROADCAST))==(REACHABLE_UNICAST|REACHABLE_BROADCAST)){
	  if (frame->interface->prefer_unicast){
	    r=REACHABLE_UNICAST;
	    // used by tests
	    if (config.debug.overlayframes)
	      DEBUGF("Choosing to send via unicast for %s", alloca_tohex_sid(frame->destination->sid));
	  }else
	    r=REACHABLE_BROADCAST;
	}
	
	if(r&REACHABLE_UNICAST){
	  frame->recvaddr = frame->next_hop->address;
	  frame->unicast = 1;
	}else
	  frame->recvaddr = frame->interface->broadcast_address;

	// degrade packet version if required to reach the destination
	if (frame->packet_version > frame->next_hop->max_packet_version)
	  frame->packet_version = frame->next_hop->max_packet_version;

	frame->destination_resolved=1;
      }else{
	
	if (packet->buffer){
	  // check if we can stuff into this packet
	  if (frame->interface_sent_sequence[packet->i]==FRAME_DONT_SEND || frame->interface_dont_send_until[packet->i] >now)
	    goto skip;
	  frame->interface = packet->interface;
	  frame->recvaddr = packet->interface->broadcast_address;
	  
	}else{
	  // find an interface that we haven't broadcast on yet
	  frame->interface = NULL;
	  int i, keep=0;
	  for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
	  {
	    if (overlay_interfaces[i].state!=INTERFACE_STATE_UP ||
                frame->interface_sent_sequence[i]==FRAME_DONT_SEND ||
	        !link_state_interface_has_neighbour(&overlay_interfaces[i]))
	      continue;
	    keep=1;
	    if (frame->interface_dont_send_until[i] >now)
	      continue;
	    time_ms_t next_allowed = limit_next_allowed(&overlay_interfaces[i].transfer_limit);
	    if (next_allowed > now)
	      continue;
	    frame->interface = &overlay_interfaces[i];
	    frame->recvaddr = overlay_interfaces[i].broadcast_address;
	    break;
	  }
	  
	  if (!keep){
	    // huh, we don't need to send it anywhere?
	    frame = overlay_queue_remove(queue, frame);
	    continue;
	  }
	  
	  if (!frame->interface)
	    goto skip;
	}
      }
    }
    
    if (!packet->buffer){
      if (frame->interface->socket_type==SOCK_STREAM){
	// skip this interface if the stream tx buffer has data
	if (frame->interface->tx_bytes_pending>0)
	  goto skip;
      }
      
      // can we send a packet on this interface now?
      if (limit_is_allowed(&frame->interface->transfer_limit))
	goto skip;
      
      if (frame->source_full)
	my_subscriber->send_full=1;

      if (frame->interface->encapsulation!=ENCAP_SINGLE)
        overlay_init_packet(packet, frame->next_hop, frame->unicast, frame->packet_version, frame->interface, frame->recvaddr);

    }else{
      // is this packet going our way?
      if (frame->interface!=packet->interface ||
	  frame->packet_version!=packet->packet_version ||
	  memcmp(&packet->dest, &frame->recvaddr, sizeof(packet->dest))!=0){
	goto skip;
      }
    }
    
    if (frame->send_hook){
      // last minute check if we really want to send this frame, or track when we sent it
      if (frame->send_hook(frame, packet->seq, frame->send_context)){
        // drop packet
        frame = overlay_queue_remove(queue, frame);
        continue;
      }
    }

    if (frame->mdp_sequence == -1){
      frame->mdp_sequence = mdp_sequence = (mdp_sequence+1)&0xFFFF;
    }else if(((mdp_sequence - frame->mdp_sequence)&0xFFFF) >= 64){
      // too late, we've sent too many packets for the next hop to correctly de-duplicate
      if (config.debug.overlayframes)
        DEBUGF("Retransmition of frame %p mdp seq %d, is too late to be de-duplicated", frame, frame->mdp_sequence, frame->interface_sent_sequence[packet->i], packet->seq);
      frame = overlay_queue_remove(queue, frame);
      continue;
    }else{
      if (config.debug.overlayframes)
        DEBUGF("Retransmitting frame %p mdp seq %d, from packet seq %d in seq %d", frame, frame->mdp_sequence, frame->interface_sent_sequence[packet->i], packet->seq);
    }

    if (frame->interface->encapsulation==ENCAP_SINGLE){
      // send MDP packets without aggregating them together
      struct overlay_buffer *buff = ob_new();

      int ret=single_packet_encapsulation(buff, frame);
      if (!ret){
	ret=overlay_broadcast_ensemble(frame->interface, &frame->recvaddr, ob_ptr(buff), ob_position(buff));
      }

      ob_free(buff);

      if (ret)
	goto skip;
    }else{
      if (overlay_frame_append_payload(&packet->context, packet->interface, frame, packet->buffer)){
        // payload was not queued
        goto skip;
      }
    }

    frame->interface_sent_sequence[packet->i] = packet->seq;
    frame->interface_dont_send_until[packet->i] = now+200;

    if (config.debug.overlayframes){
      DEBUGF("Sent payload %p, %d type %x len %d for %s via %s, seq %d", 
	     frame, frame->mdp_sequence,
	     frame->type, ob_position(frame->payload),
	     frame->destination?alloca_tohex_sid(frame->destination->sid):"All",
	     frame->next_hop?alloca_tohex_sid(frame->next_hop->sid):alloca_tohex(frame->broadcast_id.id, BROADCAST_LEN),
             frame->interface_sent_sequence[packet->i]);
    }
    
    if (frame->destination)
      frame->destination->last_tx=now;
    if (frame->next_hop)
      frame->next_hop->last_tx=now;
    
    // mark the payload as sent

    if (frame->destination_resolved){
      if (frame->resend>0 && frame->packet_version>=1 && frame->next_hop && packet->seq !=-1 && (!frame->unicast)){
        frame->dont_send_until = now+200;
	frame->destination_resolved = 0;
	if (config.debug.overlayframes)
	  DEBUGF("Holding onto payload for ack/nack resend in %lldms", frame->dont_send_until - now);
	goto skip;
      }
    }else{
      if (frame->resend<=0 || frame->packet_version<1 || packet->seq==-1 || frame->unicast){
	// dont retransmit if we aren't sending sequence numbers, or we've run out of allowed resends
        frame->interface_sent_sequence[packet->i] = FRAME_DONT_SEND;
      }
      int i;
      for(i=0;i<OVERLAY_MAX_INTERFACES;i++){
	if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
	    link_state_interface_has_neighbour(&overlay_interfaces[i]) &&
            frame->interface_sent_sequence[i]!=FRAME_DONT_SEND){
	  goto skip;
	}
      }
    }
    
    frame = overlay_queue_remove(queue, frame);
    continue;
    
  skip:
    // if we can't send the payload now, check when we should try next
    overlay_calc_queue_time(queue, frame);
    frame = frame->next;
  }
}
Example #7
0
int overlay_payload_enqueue(struct overlay_frame *p)
{
  /* Add payload p to queue q.
   
   Queues get scanned from first to last, so we should append new entries
   on the end of the queue.
   
   Complain if there are too many frames in the queue.
   */
  
  if (!p) return WHY("Cannot queue NULL");
  
  do{
    if (p->destination_resolved)
      break;
    if (!p->destination)
      break;
    int r = subscriber_is_reachable(p->destination);
    if (r&REACHABLE)
      break;
    
    if (directory_service){
      r = subscriber_is_reachable(directory_service);
      if (r&REACHABLE)
	break;
    }
    
    return WHYF("Cannot send %x packet, destination %s is %s", p->type, 
		alloca_tohex_sid(p->destination->sid), r==REACHABLE_SELF?"myself":"unreachable");
  } while(0);
  
  if (p->queue>=OQ_MAX) 
    return WHY("Invalid queue specified");
  
  /* queue a unicast probe if we haven't for a while. */
  if (p->destination && (p->destination->last_probe==0 || gettime_ms() - p->destination->last_probe > 5000))
    overlay_send_probe(p->destination, p->destination->address, p->destination->interface, OQ_MESH_MANAGEMENT);
  
  overlay_txqueue *queue = &overlay_tx[p->queue];

  if (config.debug.packettx)
    DEBUGF("Enqueuing packet for %s* (q[%d]length = %d)",
	   p->destination?alloca_tohex(p->destination->sid, 7): alloca_tohex(p->broadcast_id.id,BROADCAST_LEN),
	   p->queue, queue->length);
  
  if (p->payload && ob_remaining(p->payload)<0){
    // HACK, maybe should be done in each caller
    // set the size of the payload based on the position written
    ob_limitsize(p->payload,ob_position(p->payload));
  }
  
  if (queue->length>=queue->maxLength) 
    return WHYF("Queue #%d congested (size = %d)",p->queue,queue->maxLength);
  {
    int i;
    for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
      p->interface_sent_sequence[i]=FRAME_DONT_SEND;
  }

  if (p->destination_resolved){
    p->interface_sent_sequence[p->interface - overlay_interfaces]=FRAME_NOT_SENT;
  }else{
    if (p->destination){
      // allow the packet to be resent
      if (p->resend == 0)
        p->resend = 1;
    }else{
      int i;
      int interface_copies = 0;
      
      // hook to allow for flooding via olsr
      olsr_send(p);
      
      // make sure there is an interface up that allows broadcasts
      for(i=0;i<OVERLAY_MAX_INTERFACES;i++){
	if (overlay_interfaces[i].state!=INTERFACE_STATE_UP
	    || !overlay_interfaces[i].send_broadcasts)
	  continue;
	if (!link_state_interface_has_neighbour(&overlay_interfaces[i])){
          if (config.debug.verbose && config.debug.overlayframes)
	    DEBUGF("Skipping broadcast on interface %s, as we have no neighbours", overlay_interfaces[i].name);
	  continue;
	}
	p->interface_sent_sequence[i]=FRAME_NOT_SENT;
	interface_copies++;
      }
      
      // just drop it now
      if (interface_copies == 0){
        if (config.debug.verbose && config.debug.overlayframes)
	  DEBUGF("Not transmitting broadcast packet, as we have no neighbours on any interface");
	return -1;
      }

      // allow the packet to be resent
      if (p->resend == 0)
        p->resend = 1;
    }
  }
  
  struct overlay_frame *l=queue->last;
  if (l) l->next=p;
  p->prev=l;
  p->next=NULL;
  p->enqueued_at=gettime_ms();
  p->mdp_sequence = -1;
  // it should be safe to try sending all packets with an mdp sequence
  if (p->packet_version==0)
    p->packet_version=1;
  queue->last=p;
  if (!queue->first) queue->first=p;
  queue->length++;
  if (p->queue==OQ_ISOCHRONOUS_VOICE)
    rhizome_saw_voice_traffic();
  
  overlay_calc_queue_time(queue, p);
  return 0;
}
Example #8
0
int overlay_saw_mdp_frame(overlay_mdp_frame *mdp, time_ms_t now)
{
  IN();
  int i;
  int match=-1;

  switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
  case MDP_TX: 
    /* Regular MDP frame addressed to us.  Look for matching port binding,
       and if available, push to client.  Else do nothing, or if we feel nice
       send back a connection refused type message? Silence is probably the
       more prudent path.
    */

    if (debug & DEBUG_MDPREQUESTS) 
      DEBUGF("Received packet with listener (MDP ports: src=%s*:%d, dst=%d)",
	   alloca_tohex(mdp->out.src.sid, 7),
	   mdp->out.src.port,mdp->out.dst.port);

    // TODO pass in dest subscriber as an argument, we should know it by now
    struct subscriber *destination = NULL;
    if (!is_broadcast(mdp->out.dst.sid)){
      destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
    }
    
    for(i=0;i<MDP_MAX_BINDINGS;i++)
      {
	if (mdp_bindings[i].port!=mdp->out.dst.port)
	  continue;
	
	if ((!destination) || mdp_bindings[i].subscriber == destination){
	  /* exact match, so stop searching */
	  match=i;
	  break;
	}else if (!mdp_bindings[i].subscriber){
	  /* If we find an "ANY" binding, remember it. But we will prefer an exact match if we find one */
	  match=i;
	}
      }
    
    if (match>-1) {
      struct sockaddr_un addr;

      bcopy(mdp_bindings[match].socket_name,addr.sun_path,mdp_bindings[match].name_len);
      addr.sun_family=AF_UNIX;
      errno=0;
      int len=overlay_mdp_relevant_bytes(mdp);
      int r=sendto(mdp_named.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
      if (r==overlay_mdp_relevant_bytes(mdp)) {	
	RETURN(0);
      }
      WHY("didn't send mdp packet");
      if (errno==ENOENT) {
	/* far-end of socket has died, so drop binding */
	INFOF("Closing dead MDP client '%s'",mdp_bindings[match].socket_name);
	overlay_mdp_releasebindings(&addr,mdp_bindings[match].name_len);
      }
      WHY_perror("sendto(e)");
      RETURN(WHY("Failed to pass received MDP frame to client"));
    } else {
      /* No socket is bound, ignore the packet ... except for magic sockets */
      switch(mdp->out.dst.port) {
      case MDP_PORT_VOMP:
	RETURN(vomp_mdp_received(mdp));
      case MDP_PORT_KEYMAPREQUEST:
	/* Either respond with the appropriate SAS, or record this one if it
	   verifies out okay. */
	if (debug & DEBUG_MDPREQUESTS)
	  DEBUG("MDP_PORT_KEYMAPREQUEST");
	RETURN(keyring_mapping_request(keyring,mdp));
      case MDP_PORT_DNALOOKUP: /* attempt to resolve DID to SID */
	{
	  int cn=0,in=0,kp=0;
	  char did[64+1];
	  int pll=mdp->out.payload_length;
	  if (pll>64) pll=64;
	  /* get did from the packet */
	  if (mdp->out.payload_length<1) {
	    RETURN(WHY("Empty DID in DNA resolution request")); }
	  bcopy(&mdp->out.payload[0],&did[0],pll);
	  did[pll]=0;
	  
	  if (debug & DEBUG_MDPREQUESTS)
	    DEBUG("MDP_PORT_DNALOOKUP");
	  
	  int results=0;
	  while(keyring_find_did(keyring,&cn,&in,&kp,did))
	    {
	      /* package DID and Name into reply (we include the DID because
		 it could be a wild-card DID search, but the SID is implied 
		 in the source address of our reply). */
	      if (keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len > DID_MAXSIZE) 
		/* skip excessively long DID records */
		continue;
	      const unsigned char *packedSid = keyring->contexts[cn]->identities[in]->keypairs[0]->public_key;
	      const char *unpackedDid = (const char *) keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key;
	      const char *name = (const char *)keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key;
	      // URI is sid://SIDHEX/DID
	      strbuf b = strbuf_alloca(SID_STRLEN + DID_MAXSIZE + 10);
	      strbuf_puts(b, "sid://");
	      strbuf_tohex(b, packedSid, SID_SIZE);
	      strbuf_puts(b, "/local/");
	      strbuf_puts(b, unpackedDid);
	      overlay_mdp_dnalookup_reply(&mdp->out.src, packedSid, strbuf_str(b), unpackedDid, name);
	      kp++;
	      results++;
	    }
	  if (!results) {
	    /* No local results, so see if servald has been configured to use
	       a DNA-helper that can provide additional mappings.  This provides
	       a generalised interface for resolving telephone numbers into URIs.
	       The first use will be for resolving DIDs to SIP addresses for
	       OpenBTS boxes run by the OTI/Commotion project. 

	       The helper is run asynchronously, and the replies will be delivered
	       when results become available, so this function will return
	       immediately, so as not to cause blockages and delays in servald.
	    */
	    dna_helper_enqueue(mdp, did, mdp->out.src.sid);
	    monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n", alloca_tohex_sid(mdp->out.src.sid), mdp->out.src.port, did);
	  }
	  RETURN(0);
	}
	break;
      case MDP_PORT_ECHO: /* well known ECHO port for TCP/UDP and now MDP */
	{
	  /* Echo is easy: we swap the sender and receiver addresses (and thus port
	     numbers) and send the frame back. */

	  /* Swap addresses */
	  overlay_mdp_swap_src_dst(mdp);

	  /* Prevent echo:echo connections and the resulting denial of service from triggering endless pongs. */
	  if (mdp->out.dst.port==MDP_PORT_ECHO) {
	    RETURN(WHY("echo loop averted"));
	  }
	  /* If the packet was sent to broadcast, then replace broadcast address
	     with our local address. For now just responds with first local address */
	  if (is_broadcast(mdp->out.src.sid))
	    {
	      if (my_subscriber)		  
		bcopy(my_subscriber->sid,
		      mdp->out.src.sid,SID_SIZE);
	      else
		/* No local addresses, so put all zeroes */
		bzero(mdp->out.src.sid,SID_SIZE);
	    }

	  /* queue frame for delivery */	  
	  overlay_mdp_dispatch(mdp,0 /* system generated */,
			       NULL,0);
	  
	  /* and switch addresses back around in case the caller was planning on
	     using MDP structure again (this happens if there is a loop-back reply
	     and the frame needs sending on, as happens with broadcasts.  MDP ping
	     is a simple application where this occurs). */
	  overlay_mdp_swap_src_dst(mdp);
	  
	}
	break;
      default:
	/* Unbound socket.  We won't be sending ICMP style connection refused
	   messages, partly because they are a waste of bandwidth. */
	RETURN(WHYF("Received packet for which no listening process exists (MDP ports: src=%d, dst=%d",
		    mdp->out.src.port,mdp->out.dst.port));
      }
    }
    break;
  default:
    RETURN(WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)",
		mdp->packetTypeAndFlags));
  }

  RETURN(0);
}
Example #9
0
static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame *mdp, time_ms_t now)
{
  IN();
  int i;
  int match=-1;

  switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
  case MDP_TX: 
    /* Regular MDP frame addressed to us.  Look for matching port binding,
       and if available, push to client.  Else do nothing, or if we feel nice
       send back a connection refused type message? Silence is probably the
       more prudent path.
    */

    if (config.debug.mdprequests) 
      DEBUGF("Received packet with listener (MDP ports: src=%s*:%d, dst=%d)",
	   alloca_tohex(mdp->out.src.sid, 7),
	   mdp->out.src.port,mdp->out.dst.port);

    // TODO pass in dest subscriber as an argument, we should know it by now
    struct subscriber *destination = NULL;
    if (frame)
      destination = frame->destination;
    else if (!is_sid_broadcast(mdp->out.dst.sid)){
      destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
    }
    
    for(i=0;i<MDP_MAX_BINDINGS;i++)
      {
	if (mdp_bindings[i].port!=mdp->out.dst.port)
	  continue;
	
	if ((!destination) || mdp_bindings[i].subscriber == destination){
	  /* exact match, so stop searching */
	  match=i;
	  break;
	}else if (!mdp_bindings[i].subscriber){
	  /* If we find an "ANY" binding, remember it. But we will prefer an exact match if we find one */
	  match=i;
	}
      }
    
    if (match>-1) {
      struct sockaddr_un addr;

      bcopy(mdp_bindings[match].socket_name,addr.sun_path,mdp_bindings[match].name_len);
      addr.sun_family=AF_UNIX;
      errno=0;
      int len=overlay_mdp_relevant_bytes(mdp);
      int r=sendto(mdp_named.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
      if (r==overlay_mdp_relevant_bytes(mdp)) {	
	RETURN(0);
      }
      WHY("didn't send mdp packet");
      if (errno==ENOENT) {
	/* far-end of socket has died, so drop binding */
	INFOF("Closing dead MDP client '%s'",mdp_bindings[match].socket_name);
	overlay_mdp_releasebindings(&addr,mdp_bindings[match].name_len);
      }
      WHY_perror("sendto(e)");
      RETURN(WHY("Failed to pass received MDP frame to client"));
    } else {
      /* No socket is bound, ignore the packet ... except for magic sockets */
      RETURN(overlay_mdp_try_interal_services(frame, mdp));
    }
    break;
  default:
    RETURN(WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)",
		mdp->packetTypeAndFlags));
  }

  RETURN(0);
  OUT();
}
Example #10
0
int
serval_crypto_handler(co_obj_t *self, co_obj_t **output, co_obj_t *params)
{
  CLEAR_ERR();
  
  svl_crypto_ctx *ctx = NULL;
  int list_len = co_list_length(params);
  int keypath = 0;
  
  CHECK_ERR(IS_LIST(params) && list_len >= 2, "Invalid params");
  
  if (!strncmp("--keyring=", co_obj_data_ptr(co_list_get_last(params)), 10)) {
    keypath = 1;
    --list_len;
  }
  
  ctx = svl_crypto_ctx_new();
  
  if (co_str_cmp_str(co_list_element(params, 0), "sign") == 0) {
    
    CHECK_ERR(list_len == 2 || list_len == 3, "Invalid arguments");
    
    if (list_len == 3) {
      char *sid_str = _LIST_ELEMENT(params, 1);
      size_t sid_len = co_str_len(co_list_element(params, 1)) - 1;
      CHECK_ERR(sid_len == (2 * SID_SIZE) && str_is_subscriber_id(sid_str) == 1,
		"Invalid SID");
      stowSid(ctx->sid, 0, sid_str);
      ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 2);
      ctx->msg_len = co_str_len(co_list_element(params, 2)) - 1;
      if (keypath) {
	ctx->keyring_path = _LIST_ELEMENT(params, 3) + 10;
	ctx->keyring_len = co_str_len(co_list_element(params, 3)) - 11;
	CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long");
      }
    
    } else if (list_len == 2) {
      
      ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 1);
      ctx->msg_len = co_str_len(co_list_element(params, 1)) - 1;
      if (keypath) {
	ctx->keyring_path = _LIST_ELEMENT(params, 2) + 10;
	ctx->keyring_len = co_str_len(co_list_element(params, 2)) - 11;
	CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long");
      }

    }
    CHECK_ERR(cmd_serval_sign(ctx), "Failed to create signature");
    
    // convert ctx->signature, ctx->sas_public, and ctx->sid to hex: 
    char sid_str[(2 * SID_SIZE) + 1] = {0};
    strncpy(sid_str, alloca_tohex(ctx->sid, SID_SIZE), 2 * SID_SIZE);
    char sas_str[(2 * crypto_sign_PUBLICKEYBYTES) + 1] = {0};
    strncpy(sas_str, alloca_tohex(ctx->sas_public, crypto_sign_PUBLICKEYBYTES), 2 * crypto_sign_PUBLICKEYBYTES);
    char sig_str[(2 * SIGNATURE_BYTES) + 1] = {0};
    strncpy(sig_str, alloca_tohex(ctx->signature, SIGNATURE_BYTES), 2 * SIGNATURE_BYTES);
    CMD_OUTPUT("SID", co_str8_create(sid_str, (2 * SID_SIZE) + 1, 0));
    CMD_OUTPUT("SAS", co_str8_create(sas_str, (2 * crypto_sign_PUBLICKEYBYTES) + 1, 0));
    CMD_OUTPUT("signature", co_str8_create(sig_str, (2 * SIGNATURE_BYTES) + 1, 0));
    
  } else if (co_str_cmp_str(co_list_element(params, 0), "verify") == 0) {
    
    CHECK_ERR(!keypath, "Keyring option not available for verification");
    CHECK_ERR(list_len == 4, "Invalid arguments");
    // convert SAS and signature from hex to bin
    CHECK_ERR(fromhexstr(ctx->signature, _LIST_ELEMENT(params, 2), SIGNATURE_BYTES) == 0, "Invalid signature");
    CHECK_ERR(fromhexstr(ctx->sas_public, _LIST_ELEMENT(params, 1), crypto_sign_PUBLICKEYBYTES) == 0, "Invalid SAS key");
    ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 3);
    ctx->msg_len = co_str_len(co_list_element(params, 3)) - 1;

    int verdict = cmd_serval_verify(ctx);
    if (verdict == 1) {
      DEBUG("signature verified");
      CMD_OUTPUT("result", co_bool_create(true, 0));  // successfully verified
      CMD_OUTPUT("verified",co_str8_create("true",sizeof("true"),0));
    } else if (verdict == 0) {
      DEBUG("signature NOT verified");
      CMD_OUTPUT("result", co_bool_create(false, 0));
      CMD_OUTPUT("verified",co_str8_create("false",sizeof("false"),0));
    }
    
  }
  
error:
  INS_ERROR();
  if (ctx)
    svl_crypto_ctx_free(ctx);
  return 1;
}
Example #11
0
/* Read upto the <bars_requested> next BARs from the Rhizome database,
   beginning from the first BAR that corresponds to a manifest with 
   BID>=<bid_low>.
   Sets <bid_high> to the highest BID for which a BAR was returned.
   Return value is the number of BARs written into <bars_out>.

   Only returns BARs for bundles within the specified size range.
   This is used by the cursor wrapper function that passes over all of the
   BARs in prioritised order.

   XXX Once the rhizome database gets big, we will need to make sure
   that we have suitable indexes.  It is tempting to just pack BARs
   by row_id, but the far end needs them in an orderly manner so that
   it is possible to make provably complete comparison of the contents
   of the respective rhizome databases.
*/
int rhizome_direct_get_bars(const unsigned char bid_low[RHIZOME_MANIFEST_ID_BYTES],
			    unsigned char bid_high[RHIZOME_MANIFEST_ID_BYTES],
			    long long size_low,long long size_high,
			    const unsigned char bid_max[RHIZOME_MANIFEST_ID_BYTES],
			    unsigned char *bars_out,
			    int bars_requested)
{
  sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
  char query[1024];

  snprintf(query,1024,
	   "SELECT BAR,ROWID,ID,FILESIZE FROM MANIFESTS"
	   " WHERE"
	   " FILESIZE BETWEEN %lld AND %lld"
	   " AND ID>='%s' AND ID<='%s'"
	   // The following formulation doesn't remove the weird returning of
	   // bundles with out of range filesize values
	   //	   " WHERE ID>='%s' AND ID<='%s' AND FILESIZE > %lld AND FILESIZE < %lld"
	   " ORDER BY BAR LIMIT %d;",
	   size_low, size_high,
	   alloca_tohex(bid_low,RHIZOME_MANIFEST_ID_BYTES),
	   alloca_tohex(bid_max,RHIZOME_MANIFEST_ID_BYTES),
	   bars_requested);

  sqlite3_stmt *statement=sqlite_prepare(&retry, query);
  sqlite3_blob *blob=NULL;  

  int bars_written=0;
  
  while(bars_written<bars_requested
	&&  sqlite_step_retry(&retry, statement) == SQLITE_ROW)
    {
      int column_type=sqlite3_column_type(statement, 0);
      switch(column_type) {
      case SQLITE_BLOB:
	if (blob)
	  sqlite3_blob_close(blob);
	blob = NULL;
	int ret;
	int64_t filesize = sqlite3_column_int64(statement, 3);
	if (filesize<size_low||filesize>size_high) {
	  DEBUGF("WEIRDNESS ALERT: filesize=%lld, but query was: %s",
		 filesize,query);
	  break;
	} 
	int64_t rowid = sqlite3_column_int64(statement, 1);
	do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar",
				   rowid, 0 /* read only */, &blob);
	while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open"));
	if (!sqlite_code_ok(ret)) {
	  WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db));
	  continue;
	}
	sqlite_retry_done(&retry, "sqlite3_blob_open");
	
	int blob_bytes=sqlite3_blob_bytes(blob);
	if (blob_bytes!=RHIZOME_BAR_BYTES) {
	  if (config.debug.rhizome)
	    DEBUG("Found a BAR that is the wrong size - ignoring");
	  sqlite3_blob_close(blob);
	  blob=NULL;
	  continue;
	}	
	sqlite3_blob_read(blob,&bars_out[bars_written*RHIZOME_BAR_BYTES],
			  RHIZOME_BAR_BYTES,0);
	sqlite3_blob_close(blob);
	blob=NULL;

	/* Remember the BID so that we cant write it into bid_high so that the
	   caller knows how far we got. */
	fromhex(bid_high,
		(const char *)sqlite3_column_text(statement, 2),
		RHIZOME_MANIFEST_ID_BYTES);

	bars_written++;
	break;
      default:
	/* non-BLOB field.  This is an error, but we will persevere with subsequent
	   rows, because they might be fine. */
	break;
      }
    }
  if (statement)
    sqlite3_finalize(statement);
  statement = NULL;
  
  return bars_written;
}
Example #12
0
rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix,int prefix_length)
{
  /* Give a BID prefix, e.g., from a BAR, find the matching manifest and return it.
     Of course, it is possible that more than one manifest matches.  This should
     occur only very rarely (with the possible exception of intentional attack, and
     even then a 64-bit prefix creates a reasonable barrier.  If we move to a new
     BAR format with 120 or 128 bits of BID prefix, then we should be safe for some
     time, thus this function taking the BID prefix as an input in preparation for
     that change).

     Of course, we need to be able to find the manifest.
     Easiest way is to select with a BID range.  We could instead have an extra
     database column with the prefix.
  */
  assert(prefix_length>=0);
  assert(prefix_length<=RHIZOME_MANIFEST_ID_BYTES);
  unsigned char low[RHIZOME_MANIFEST_ID_BYTES];
  unsigned char high[RHIZOME_MANIFEST_ID_BYTES];

  memset(low,0x00,RHIZOME_MANIFEST_ID_BYTES);
  memset(high,0xff,RHIZOME_MANIFEST_ID_BYTES);
  bcopy(bid_prefix,low,prefix_length);
  bcopy(bid_prefix,high,prefix_length);

  char query[1024];
  snprintf(query,1024,"SELECT MANIFEST,ROWID FROM MANIFESTS WHERE ID>='%s' AND ID<='%s'",
	   alloca_tohex(low,RHIZOME_MANIFEST_ID_BYTES),
	   alloca_tohex(high,RHIZOME_MANIFEST_ID_BYTES));
  
  sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
  sqlite3_stmt *statement = sqlite_prepare(&retry, query);
  sqlite3_blob *blob=NULL;  
  if (sqlite_step_retry(&retry, statement) == SQLITE_ROW)
    {
      int ret;
      int64_t rowid = sqlite3_column_int64(statement, 1);
      do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar",
				 rowid, 0 /* read only */, &blob);
      while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open"));
      if (!sqlite_code_ok(ret)) {
	WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db));
	sqlite3_finalize(statement);
	return NULL;
	
      }
      sqlite_retry_done(&retry, "sqlite3_blob_open");

      /* Read manifest data from blob */

      size_t manifestblobsize = sqlite3_column_bytes(statement, 0);
      if (manifestblobsize<1||manifestblobsize>1024) goto error;

      const char *manifestblob = (char *) sqlite3_column_blob(statement, 0);
      if (!manifestblob) goto error;

      rhizome_manifest *m=rhizome_new_manifest();
      if (rhizome_read_manifest_file(m,manifestblob,manifestblobsize)==-1)
	{
	  rhizome_manifest_free(m);
	  goto error;
	}
      
      DEBUGF("Read manifest");
      sqlite3_blob_close(blob);
      sqlite3_finalize(statement);
      return m;

 error:
      sqlite3_blob_close(blob);
      sqlite3_finalize(statement);
      return NULL;
    }
  else 
    {
      DEBUGF("no matching manifests");
      sqlite3_finalize(statement);
      return NULL;
    }

}