Exemplo n.º 1
0
int overlay_mdp_client_init()
{
  if (mdp_client_socket==-1) {
    /* Open socket to MDP server (thus connection is always local) */
    if (0) WHY("Use of abstract name space socket for Linux not implemented");
    
    mdp_client_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (mdp_client_socket < 0) {
      WHY_perror("socket");
      return WHY("Could not open socket to MDP server");
    }
    
    /* We must bind to a temporary file name */
    struct sockaddr_un name;
    unsigned int random_value;
    if (urandombytes((unsigned char *)&random_value,sizeof(int)))
      return WHY("urandombytes() failed");
    name.sun_family = AF_UNIX;
    if (overlay_mdp_client_socket_path_len==-1) {
      char fmt[1024];
      if (!FORM_SERVAL_INSTANCE_PATH(fmt, "mdp-client-%d-%08x.socket"))
	return WHY("Could not form MDP client socket name");
      snprintf(overlay_mdp_client_socket_path,1024,fmt,getpid(),random_value);
      overlay_mdp_client_socket_path_len=strlen(overlay_mdp_client_socket_path)+1;
      if(config.debug.io) DEBUGF("MDP client socket name='%s'",overlay_mdp_client_socket_path);
    }
    if (overlay_mdp_client_socket_path_len > sizeof(name.sun_path) - 1)
      FATALF("MDP socket path too long (%d > %d)", overlay_mdp_client_socket_path_len, sizeof(name.sun_path) - 1);
    
    bcopy(overlay_mdp_client_socket_path,name.sun_path,
	  overlay_mdp_client_socket_path_len);
    unlink(name.sun_path);
    int len = 1 + strlen(name.sun_path) + sizeof(name.sun_family) + 1;
    int r=bind(mdp_client_socket, (struct sockaddr *)&name, len);
    if (r) {
      WHY_perror("bind");
      return WHY("Could not bind MDP client socket to file name");
    }
    
    int send_buffer_size=128*1024;
    if (setsockopt(mdp_client_socket, SOL_SOCKET, SO_RCVBUF, 
		   &send_buffer_size, sizeof(send_buffer_size)) == -1)
      WARN_perror("setsockopt");
  }
  
  return 0;
}
Exemplo n.º 2
0
int keyring_pack_identity(keyring_context *c,keyring_identity *i,
			  unsigned char packed[KEYRING_PAGE_SIZE])
{
  int ofs=0;
  int exit_code=-1;

  /* Convert an identity to a KEYRING_PAGE_SIZE bytes long block that
     consists of 32 bytes of random salt, a 64 byte (512 bit) message
     authentication code (MAC) and the list of key pairs. */
  if (urandombytes(&packed[0],PKR_SALT_BYTES)) return WHY("Could not generate salt");
  ofs+=PKR_SALT_BYTES;
  /* Calculate MAC */
  keyring_identity_mac(c,i,&packed[0] /* pkr salt */,
		       &packed[0+PKR_SALT_BYTES] /* write mac in after salt */);
  ofs+=PKR_MAC_BYTES;

  /* Leave 2 bytes for rotation (put zeroes for now) */
  int rotate_ofs=ofs;
  packed[ofs]=0; packed[ofs+1]=0;
  ofs+=2;

  /* Write keypairs */
  int kp;
  for(kp=0;kp<i->keypair_count;kp++)
    {
      if (ofs>=KEYRING_PAGE_SIZE) {
	WHY("too many or too long key pairs");
	ofs=0; goto kpi_safeexit;
      }
      packed[ofs++]=i->keypairs[kp]->type;
      switch(i->keypairs[kp]->type) {
      case KEYTYPE_RHIZOME:
      case KEYTYPE_DID:
	/* 32 chars for unpacked DID/rhizome secret, 
	   64 chars for name (for DIDs only) */
	if ((ofs
	     +i->keypairs[kp]->private_key_len
	     +i->keypairs[kp]->public_key_len
	     )>=KEYRING_PAGE_SIZE)
	  {
	    WHY("too many or too long key pairs");
	    ofs=0;
	    goto kpi_safeexit;
	  }
	bcopy(i->keypairs[kp]->private_key,&packed[ofs],
	      i->keypairs[kp]->private_key_len);
	ofs+=i->keypairs[kp]->private_key_len;
	if (i->keypairs[kp]->type==KEYTYPE_DID) {
	  bcopy(i->keypairs[kp]->public_key,&packed[ofs],
		i->keypairs[kp]->private_key_len);
	  ofs+=i->keypairs[kp]->public_key_len; 
	}
	break;
      case KEYTYPE_CRYPTOBOX:
	/* For cryptobox we only need the private key, as we compute the public
	   key from it when extracting the identity */
	if ((ofs+i->keypairs[kp]->private_key_len)>=KEYRING_PAGE_SIZE)
	  {
	    WHY("too many or too long key pairs");
	    ofs=0;
	    goto kpi_safeexit;
	  }
	bcopy(i->keypairs[kp]->private_key,&packed[ofs],
	      i->keypairs[kp]->private_key_len);
	ofs+=i->keypairs[kp]->private_key_len;
	break;
      case KEYTYPE_CRYPTOSIGN:
	/* For cryptosign keys there is no public API in NaCl to compute the
	   public key from the private key (although we could subvert the API
	   abstraction and do it anyway). But in the interests of niceness we
	   just store the public and private key pair together */
	if ((ofs
	     +i->keypairs[kp]->private_key_len
	     +i->keypairs[kp]->public_key_len)>=KEYRING_PAGE_SIZE)
	  {
	    WHY("too many or too long key pairs");
	    ofs=0;
	    goto kpi_safeexit;
	  }
	/* Write private then public */
	bcopy(i->keypairs[kp]->private_key,&packed[ofs],
	      i->keypairs[kp]->private_key_len);
	ofs+=i->keypairs[kp]->private_key_len;
	bcopy(i->keypairs[kp]->public_key,&packed[ofs],
	      i->keypairs[kp]->public_key_len);
	ofs+=i->keypairs[kp]->public_key_len;
	break;
	
      default:
	WHY("unknown key type");
	goto kpi_safeexit;
      }
    }

  if (ofs>=KEYRING_PAGE_SIZE) {
    WHY("too many or too long key pairs");
    ofs=0; goto kpi_safeexit;
  }
  packed[ofs++]=0x00; /* Terminate block */

  /* We are now all done, give or take the zeroeing of the trailing bytes. */
  exit_code=0;


 kpi_safeexit:
  /* Clear out remainder of block so that we don't leak info.
     We could have zeroed the thing to begin with, but that means extra
     memory writes that are otherwise avoidable.
     Actually, we don't want zeroes (known plain-text attack against most
     of the block's contents in the typical case), we want random data. */
  if (urandombytes(&packed[ofs],KEYRING_PAGE_SIZE-ofs))
    return WHY("urandombytes() failed to back-fill packed identity block");

  /* Rotate block by a random amount (get the randomness safely) */
  unsigned int rotation;
  if (urandombytes((unsigned char *)&rotation,sizeof(rotation)))
    return WHY("urandombytes() failed to generate random rotation");
  rotation&=0xffff;
#ifdef NO_ROTATION
  rotation=0;
#endif
  unsigned char slot[KEYRING_PAGE_SIZE];
  /* XXX There has to be a more efficient way to do this! */
  int n;
  for(n=0;n<(KEYRING_PAGE_SIZE-(PKR_SALT_BYTES+PKR_MAC_BYTES+2));n++)
    slot_byte(n)=packed[PKR_SALT_BYTES+PKR_MAC_BYTES+2+n];
  bcopy(&slot[PKR_SALT_BYTES+PKR_MAC_BYTES+2],&packed[PKR_SALT_BYTES+PKR_MAC_BYTES+2],
	KEYRING_PAGE_SIZE-(PKR_SALT_BYTES+PKR_MAC_BYTES+2));
  packed[rotate_ofs]=rotation>>8;
  packed[rotate_ofs+1]=rotation&0xff;

  return exit_code;
}
Exemplo n.º 3
0
/*
  Open keyring file, read BAM and create initial context using the 
  stored salt. */
keyring_file *keyring_open(char *file)
{
  /* Allocate structure */
  keyring_file *k=calloc(sizeof(keyring_file),1);
  if (!k) {
    WHY_perror("calloc");
    return NULL;
  }
  /* Open keyring file read-write if we can, else use it read-only */
  k->file=fopen(file,"r+");
  if (!k->file) k->file=fopen(file,"r");
  if (!k->file) k->file=fopen(file,"w+");
  if (!k->file) {
    WHY_perror("fopen");
    WHYF("Could not open keyring file %s", file);
    keyring_free(k);
    return NULL;
  }
  if (fseeko(k->file,0,SEEK_END)) {
    WHY_perror("fseeko");
    WHYF("Could not seek to end of keyring file %s", file);
    keyring_free(k);
    return NULL;
  }
  k->file_size=ftello(k->file);
  if (k->file_size<KEYRING_PAGE_SIZE) {
    /* Uninitialised, so write 2KB of zeroes, 
       followed by 2KB of random bytes as salt. */
    if (fseeko(k->file,0,SEEK_SET)) {
      WHY_perror("fseeko");
      WHYF("Could not seek to start of keyring file %s", file);
      keyring_free(k);
      return NULL;
    }
    unsigned char buffer[KEYRING_PAGE_SIZE];
    bzero(&buffer[0],KEYRING_BAM_BYTES);
    if (fwrite(&buffer[0],2048,1,k->file)!=1) {
      WHY_perror("fwrite");
      WHYF("Could not write empty bitmap in fresh keyring file %s", file);
      keyring_free(k);
      return NULL;
    }
    if (urandombytes(&buffer[0],KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES)) {
      WHYF("Could not get random keyring salt to put in fresh keyring file %s", file);
      keyring_free(k);
      return NULL;
    }
    if (fwrite(&buffer[0],KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES,1,k->file) != 1) {
      WHY_perror("fwrite");
      WHYF("Could not write keyring salt in fresh keyring file %s", file);
      keyring_free(k);
      return NULL;
    }
    k->file_size=KEYRING_PAGE_SIZE;
  }

  /* Read BAMs for each slab in the file */
  keyring_bam **b=&k->bam;
  off_t offset=0;
  while(offset<k->file_size) {
    /* Read bitmap from slab.
       Also, if offset is zero, read the salt */
    if (fseeko(k->file,offset,SEEK_SET)) {
      WHY_perror("fseeko");
      WHYF("Could not seek to BAM in keyring file %s", file);
      keyring_free(k);
      return NULL;
    }
    *b=calloc(sizeof(keyring_bam),1);
    if (!(*b)) {
      WHY_perror("calloc");
      WHYF("Could not allocate keyring_bam structure for key ring file %s", file);
      keyring_free(k);
      return NULL;
    }
    (*b)->file_offset=offset;
    /* Read bitmap */
    int r=fread(&(*b)->bitmap[0],KEYRING_BAM_BYTES,1,k->file);
    if (r!=1) {
      WHY_perror("fread");
      WHYF("Could not read BAM from keyring file %s", file);
      keyring_free(k);
      return NULL;
    }

    /* Read salt if this is the first bitmap block.
       We setup a context for this self-supplied key-ring salt.
       (other keyring salts may be provided later on, resulting in
       multiple contexts being loaded) */
    if (!offset) {     
      k->contexts[0]=calloc(sizeof(keyring_context),1);     
      if (!k->contexts[0]) {
	WHY_perror("calloc");
	WHYF("Could not allocate keyring_context for keyring file %s", file);
	keyring_free(k);
	return NULL;
      }
      k->contexts[0]->KeyRingPin=strdup(""); /* Implied empty PIN if none provided */
      k->contexts[0]->KeyRingSaltLen=KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES;
      k->contexts[0]->KeyRingSalt=malloc(k->contexts[0]->KeyRingSaltLen);
      if (!k->contexts[0]->KeyRingSalt) {
	WHY_perror("malloc");
	WHYF("Could not allocate keyring_context->salt for keyring file %s", file);
	keyring_free(k);
	return NULL;
      }
      r=fread(&k->contexts[0]->KeyRingSalt[0],k->contexts[0]->KeyRingSaltLen,1,k->file);
      if (r!=1) {
	WHY_perror("fread");
	WHYF("Could not read salt from keyring file %s", file);
	keyring_free(k);
	return NULL;
      }
      k->context_count=1;
    }

    /* Skip to next slab, and find next bam pointer. */
    offset+=KEYRING_PAGE_SIZE*(KEYRING_BAM_BYTES<<3);
    b=&(*b)->next;
  }

  return k;
}
Exemplo n.º 4
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);
}