Beispiel #1
0
int op_append_type(overlay_buffer *headers,overlay_frame *p)
{
  unsigned char c[3];
  switch(p->type&OF_TYPE_FLAG_BITS)
    {
    case OF_TYPE_FLAG_NORMAL:
      c[0]=p->type|p->modifiers;
      if (debug&DEBUG_PACKETFORMATS) fprintf(stderr,"type resolves to %02x\n",c[0]);
      if (ob_append_bytes(headers,c,1)) return -1;
      break;
    case OF_TYPE_FLAG_E12:
      c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED12;
      c[1]=(p->type>>4)&0xff;
      if (debug&DEBUG_PACKETFORMATS) fprintf(stderr,"type resolves to %02x%02x\n",c[0],c[1]);
      if (ob_append_bytes(headers,c,2)) return -1;
      break;
    case OF_TYPE_FLAG_E20:
      c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED20;
      c[1]=(p->type>>4)&0xff;
      c[2]=(p->type>>12)&0xff;
      if (debug&DEBUG_PACKETFORMATS) fprintf(stderr,"type resolves to %02x%02x%02x\n",c[0],c[1],c[2]);
      if (ob_append_bytes(headers,c,3)) return -1;
      break;
    default: 
      /* Don't know this type of frame */
      WHY("Asked for format frame with unknown TYPE_FLAG bits");
      return -1;
    }
  return 0;
}
Beispiel #2
0
int overlay_payload_package_fmt1(overlay_payload *p,overlay_buffer *b)
{
  /* Convert a payload structure into a series of bytes.
     Also select next-hop address to help payload get to its' destination */

  unsigned char nexthop[SIDDIDFIELD_LEN+1];
  int nexthoplen=0;

  overlay_buffer *headers=ob_new(256);

  if (!headers) return -1;
  if (!p) return -1;
  if (!b) return -1;

  /* Build header */
  int fail=0;

  if (overlay_get_nexthop(p,nexthop,&nexthoplen)) fail++;
  if (ob_append_bytes(headers,nexthop,nexthoplen)) fail++;

  /* XXX Can use shorter fields for different address types */
  if (ob_append_bytes(headers,(unsigned char *)p->src,SIDDIDFIELD_LEN)) fail++;
  if (ob_append_bytes(headers,(unsigned char *)p->dst,SIDDIDFIELD_LEN)) fail++;
  
  if (fail) {
    ob_free(headers);
    return -1;
  }

  /* Write payload format plus total length of header bits */
  if (ob_makespace(b,2+headers->length+p->payloadLength)) {
    /* Not enough space free in output buffer */
    ob_free(headers);
    return -1;
  }

  /* Package up headers and payload */
  ob_checkpoint(b);
  if (ob_append_short(b,0x1000|(p->payloadLength+headers->length))) fail++;
  if (ob_append_bytes(b,headers->bytes,headers->length)) fail++;
  if (ob_append_bytes(b,p->payload,p->payloadLength)) fail++;

  /* XXX SIGNATURE! */

  ob_free(headers);

  if (fail) { ob_rewind(b); return -1; } else return 0;
}
int overlay_frame_append_payload(struct decode_context *context, overlay_interface *interface, 
				 struct overlay_frame *p, struct 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.
  */

  ob_checkpoint(b);
  
  if (config.debug.packetconstruction){
    DEBUGF( "+++++\nFrame from %s to %s of type 0x%02x %s:",
	   alloca_tohex_sid(p->source->sid),
	   alloca_tohex_sid(p->destination->sid),p->type,
	   "append_payload stuffing into packet");
    if (p->payload)
      dump("payload contents", &p->payload->bytes[0],p->payload->position);
  }
  
  struct broadcast *broadcast=NULL;
  if ((!p->destination) && !is_all_matching(p->broadcast_id.id,BROADCAST_LEN,0)){
    broadcast = &p->broadcast_id;
  }

  if (overlay_frame_build_header(p->packet_version, context, b,
			     p->queue, p->type, p->modifiers, p->ttl, p->mdp_sequence&0xFF,
			     broadcast, p->next_hop, 
			     p->destination, p->source))
    goto cleanup;
  
  if (ob_append_ui16(b, ob_position(p->payload)))
      goto cleanup;
      
  if (ob_append_bytes(b, ob_ptr(p->payload), ob_position(p->payload))) {
    WHY("could not append payload"); 
    goto cleanup;
  }
      
  return 0;
  
cleanup:
  ob_rewind(b);
  return -1;
}
Beispiel #4
0
int ob_append_rfs(overlay_buffer *b,int l)
{
  /* Encode the specified length and append it to the buffer */
  if (l<0||l>0xffff) return -1;

  /* First work out how long the field needs to be, then write dummy bytes
     and use ob_patch_length to set the value.  That way we have only one
     lot of code that does the encoding. */

  b->var_length_offset=b->length;
  b->var_length_bytes=rfs_length(l);

  unsigned char c[3]={0,0,0};
  if (ob_append_bytes(b,c,b->var_length_bytes)) {
    b->var_length_offset=0;
    return -1;
  }

  return ob_patch_rfs(b,l);

}
Beispiel #5
0
int ob_append_int(overlay_buffer *b,unsigned int v)
{
  unsigned int s=htonl(v);
  return ob_append_bytes(b,(unsigned char *)&s,sizeof(unsigned int));
}
Beispiel #6
0
int ob_append_short(overlay_buffer *b,unsigned short v)
{
  unsigned short s=htons(v);
  return ob_append_bytes(b,(unsigned char *)&s,sizeof(unsigned short));
}
Beispiel #7
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);
}
Beispiel #8
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_sid_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_sid_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 = mdp->out.ttl;
  if (frame->ttl == 0) 
    frame->ttl = PAYLOAD_TTL_DEFAULT;
  else if (frame->ttl > PAYLOAD_TTL_MAX) {
    op_free(frame);
    RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
				    recvaddr,recvaddrlen,9,
				    "TTL out of range"));
  }
  
  if (!frame->destination || frame->destination->reachable == REACHABLE_SELF)
    {
      /* Packet is addressed such that we should process it. */
      overlay_saw_mdp_frame(NULL,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);
      }
    }
  
  frame->type=OF_TYPE_DATA;
  frame->prev=NULL;
  frame->next=NULL;
  struct overlay_buffer *plaintext=ob_new();
  
  if (overlay_mdp_encode_ports(plaintext, mdp->out.dst.port, mdp->out.src.port)){
    ob_free(plaintext);
    RETURN (-1);
  }
  
  if (ob_append_bytes(plaintext, mdp->out.payload, mdp->out.payload_length)){
    ob_free(plaintext);
    RETURN(-1);
  }
  
  /* 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;
    {
      int nm=crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES;
      int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
      int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
      int cz=crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES;
      
      /* generate plain message with zero bytes and get ready to cipher it */
      int cipher_len=ob_position(plaintext);
      
      // TODO, add support for leading zero's in overlay_buffer's, then we don't need to copy the plain text again.
      unsigned char plain[zb+cipher_len];
      
      /* zero bytes */
      bzero(&plain[0],zb);
      bcopy(ob_ptr(plaintext),&plain[zb],cipher_len);
      
      cipher_len+=zb;
      
      ob_free(plaintext);
      
      frame->payload = ob_new();
      
      unsigned char *nonce = ob_append_space(frame->payload, nb+cipher_len);
      unsigned char *cipher_text = nonce + nb;
      if (!nonce)
	RETURN(-1);
      if (generate_nonce(nonce,nb)) {
	op_free(frame);
	RETURN(WHY("generate_nonce() failed to generate nonce"));
      }
      // reserve the high bit of the nonce as a flag for transmitting a shorter nonce.
      nonce[0]&=0x7f;
      
      /* 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.sid, mdp->out.dst.sid);
      if (!k) {
	op_free(frame);
	RETURN(WHY("could not compute Curve25519(NxM)")); 
      }
      /* 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")); 
      }
      if (0) {
	DEBUG("authcrypted mdp frame");
	dump("nm",k,nm);
	dump("plain text",plain,sizeof(plain));
	dump("nonce",nonce,nb);
	dump("cipher text",cipher_text,cipher_len);
      }
      /* now shuffle down to get rid of the temporary space that crypto_box
       uses. 
       TODO extend overlay buffer so we don't need this.
       */
      bcopy(&cipher_text[cz],&cipher_text[0],cipher_len-cz);
      frame->payload->position-=cz;
      if (0){
	dump("frame",&frame->payload->bytes[0],
	     frame->payload->position);
      }
    }
    break;
      
  case MDP_NOCRYPT: 
    /* Payload is sent unencrypted, but signed. */
    frame->modifiers=OF_CRYPTO_SIGNED;
    frame->payload = plaintext;
    ob_makespace(frame->payload,SIGNATURE_BYTES);
    if (crypto_sign_message(frame->source, frame->payload->bytes, frame->payload->allocSize, &frame->payload->position)){
      op_free(frame);
      RETURN(-1);
    }
    break;
      
  case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
    frame->modifiers=0; 
    frame->payload = plaintext;
    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"));
  }
  
  frame->queue=mdp->out.queue;
  if (frame->queue==0)
    frame->queue = OQ_ORDINARY;
  
  if (overlay_payload_enqueue(frame))
    op_free(frame);
  RETURN(0);
  OUT();
}
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;
}
Beispiel #10
0
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;
}