Beispiel #1
0
int overlay_mdp_service_stun_req(overlay_mdp_frame *mdp)
{
  if (config.debug.overlayrouting)
    DEBUGF("Processing STUN request from %s", alloca_tohex_sid(mdp->out.src.sid));

  struct overlay_buffer *payload = ob_static(mdp->out.payload, mdp->out.payload_length);
  ob_limitsize(payload, mdp->out.payload_length);
  
  overlay_mdp_frame reply;
  bzero(&reply, sizeof(reply));
  reply.packetTypeAndFlags=MDP_TX;
  
  bcopy(mdp->out.src.sid, reply.out.dst.sid, SID_SIZE);
  bcopy(mdp->out.dst.sid, reply.out.src.sid, SID_SIZE);
  reply.out.src.port=MDP_PORT_STUNREQ;
  reply.out.dst.port=MDP_PORT_STUN;
  reply.out.queue=OQ_MESH_MANAGEMENT;
  
  struct overlay_buffer *replypayload = ob_static(reply.out.payload, sizeof(reply.out.payload));
  
  ob_checkpoint(replypayload);
  while(ob_remaining(payload)>0){
    struct subscriber *subscriber=NULL;
    
    if (overlay_address_parse(NULL, payload, &subscriber))
      break;
    
    if (!subscriber){
      if (config.debug.overlayrouting)
	DEBUGF("Unknown subscriber");
      continue;
    }
    
    if (overlay_append_unicast_address(subscriber, replypayload))
      break;
  }
  
  ob_rewind(replypayload);
  reply.out.payload_length=ob_position(replypayload);
  
  if (reply.out.payload_length){
    if (config.debug.overlayrouting)
      DEBUGF("Sending reply");
    overlay_mdp_dispatch(&reply,0 /* system generated */, NULL,0);
  }
  ob_free(replypayload);
  ob_free(payload);
  return 0;
}
 ObSqlReadParam::~ObSqlReadParam()
 {
   if (NULL != scalar_agg_)
   {
     scalar_agg_->~ObScalarAggregate();
     ob_free(scalar_agg_);
     scalar_agg_ = NULL;
   }
   if (NULL != group_)
   {
     group_->~ObMergeGroupBy();
     ob_free(group_);
     group_ = NULL;
   }
 }
Beispiel #3
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;
}
Beispiel #4
0
// fill a packet from our outgoing queues and send it
static int
overlay_fill_send_packet(struct outgoing_packet *packet, time_ms_t now) {
  int i;
  IN();
  // while we're looking at queues, work out when to schedule another packet
  unschedule(&next_packet);
  next_packet.alarm=0;
  next_packet.deadline=0;
  
  for (i=0;i<OQ_MAX;i++){
    overlay_txqueue *queue=&overlay_tx[i];
    
    overlay_stuff_packet(packet, queue, now);
  }
  
  if(packet->buffer){
    if (config.debug.packetconstruction)
      ob_dump(packet->buffer,"assembled packet");
      
    if (overlay_broadcast_ensemble(packet->interface, &packet->dest, ob_ptr(packet->buffer), ob_position(packet->buffer))){
      // sendto failed. We probably don't have a valid route
      if (packet->unicast_subscriber){
	set_reachable(packet->unicast_subscriber, REACHABLE_NONE);
      }
    }
    ob_free(packet->buffer);
    RETURN(1);
  }
  RETURN(0);
  OUT();
}
Beispiel #5
0
int overlay_mdp_service_stun(overlay_mdp_frame *mdp)
{
  struct overlay_buffer *buff = ob_static(mdp->out.payload, mdp->out.payload_length);
  ob_limitsize(buff, mdp->out.payload_length);

  if (config.debug.overlayrouting)
    DEBUGF("Processing STUN info from %s", alloca_tohex_sid(mdp->out.src.sid));

  while(ob_remaining(buff)>0){
    struct subscriber *subscriber=NULL;
    struct sockaddr_in addr;
    
    // TODO explain addresses, link expiry time, resolve differences between addresses...
    
    if (overlay_address_parse(NULL, buff, &subscriber)){
      break;
    }
    
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = ob_get_ui32(buff);
    addr.sin_port = ob_get_ui16(buff);
    
    if (!subscriber || (subscriber->reachable!=REACHABLE_NONE))
      continue;
    
    overlay_send_probe(subscriber, addr, NULL, OQ_MESH_MANAGEMENT);
  }
  
  ob_free(buff);
  return 0;
}
Beispiel #6
0
 ObRowCompaction::~ObRowCompaction()
 {
   if (NULL != nodes_)
   {
     ob_free(nodes_);
   }
 }
    int ObSSTableSchemaCache::clear()
    {
      int ret = OB_SUCCESS;

      rwlock_.wrlock();
      if (0 < schema_cnt_)
      {
        for (int64_t i = 0; i < schema_cnt_; ++i)
        {
          if (0 != schema_array_[i].ref_cnt_)
          {
            TBSYS_LOG(WARN, "schema array ref cnt !=0");
            ret = OB_ERROR;
          }

          if (NULL != schema_array_[i].schema_)
          {
            schema_array_[i].schema_->~ObSSTableSchema();
            ob_free(reinterpret_cast<void*>(schema_array_[i].schema_));
          }
        }
      }
      schema_cnt_ = 0;
      rwlock_.unlock();

      return ret;
    }
    void FIFOAllocator::destroy()
    {
      volatile ThreadNode *iter = thread_node_list_;
      while (NULL != iter)
      {
        revert_page_(iter->id, NULL);
        iter = iter->next;
      }
      thread_node_list_ = NULL;
      thread_node_allocator_.reuse();

      if (0 != id_map_.size())
      {
        TBSYS_LOG(ERROR, "still memory have not been free: ref_page_cnt=%d", id_map_.size());
        BACKTRACE(WARN, true, "fifo_allocator not clear");
      }

      Page *page = NULL;
      while (OB_SUCCESS == free_list_.pop(page))
      {
        if (NULL != page)
        {
          ob_free(page);
        }
      }
      free_list_.destroy();

      id_map_.destroy();

      total_limit_ = 0;
      hold_limit_ = 0;
      page_size_ = 0;
      allocated_size_ = 0;
      inited_ = false;
    }
 ObTicketQueue::~ObTicketQueue()
 {
   if (NULL != items_)
   {
     ob_free(items_);
     items_ = NULL;
   }
 }
 ObPermInfoKey::~ObPermInfoKey()
 {
   if (NULL != buffer_)
   {
     ob_free(buffer_);
     buffer_ = NULL;
   }
 }
Beispiel #11
0
 ObSchemaManagerWrapper::~ObSchemaManagerWrapper()
 {
   if (NULL != schema_mgr_buffer_)
   {
     schema_mgr_impl_->~ObSchemaManager();
     ob_free(schema_mgr_buffer_);
     schema_mgr_buffer_ = NULL;
     schema_mgr_impl_ = NULL;
   }
 }
Beispiel #12
0
int op_free(struct overlay_frame *p)
{
  if (!p) return WHY("Asked to free NULL");
  if (p->prev&&p->prev->next==p) return WHY("p->prev->next still points here");
  if (p->next&&p->next->prev==p) return WHY("p->next->prev still points here");
  p->prev=NULL;
  p->next=NULL;
  if (p->payload) ob_free(p->payload);
  p->payload=NULL;
  free(p);
  return 0;
}
 void FIFOAllocator::free_page_(Page *ptr)
 {
   if (NULL != ptr)
   {
     ATOMIC_ADD(&allocated_size_, -page_size_);
     if (hold_limit_ <= (free_list_.get_total() * page_size_)
         || OB_SUCCESS != free_list_.push(ptr))
     {
       ob_free(ptr);
     }
   }
 }
    int ObSSTableSchemaCache::revert_schema(const uint64_t table_id, 
        const int64_t version)
    {
      int ret                     = OB_SUCCESS;
      int64_t index               = 0;
      int64_t ref_cnt             = 0;
      ObSSTableSchema* free_schema = NULL;
      
      if (OB_INVALID_ID == table_id || 0 == table_id || version < 0)
      {
        TBSYS_LOG(WARN, "table id error:table_id=%lu", table_id);
        ret = OB_INVALID_ARGUMENT;
      }
      else
      {
        rwlock_.wrlock();
        index = find_schema_node_index(table_id, version);
        if (index < 0)
        {
          TBSYS_LOG(WARN, "find schema node index error");
          ret = OB_ERROR;
        }
        else
        {
          ref_cnt = schema_array_[index].dec_ref_cnt();
          if (0 == ref_cnt && NULL != schema_array_[index].schema_)
          {
            free_schema = schema_array_[index].schema_;
            if (index < schema_cnt_ - 1)
            {
              memmove(&schema_array_[index], &schema_array_[index + 1], 
                      sizeof(ObSSTableSchemaNode) * (schema_cnt_ - index));
            }
            --schema_cnt_;
          }
          else if (ref_cnt < 0 || NULL == schema_array_[index].schema_)
          {
            TBSYS_LOG(WARN, "ref cnt <0");
            ret = OB_ERROR;
          }
        }
        rwlock_.unlock();
      }

      if (NULL != free_schema)
      {
        free_schema->~ObSSTableSchema();
        ob_free(reinterpret_cast<void*>(free_schema));
      }

      return ret;
    }
Beispiel #15
0
 void ObRegex::destroy(void)
 {
   if (init_)
   {
     regfree(&reg_);
     if (NULL != match_)
     {
       ob_free(match_);
       match_ = NULL;
     }
     nmatch_ = 0;
     init_ = false;
   }
 }
Beispiel #16
0
Object *MemorySegment::add( char *identifier, Object *object ){
    Object *next = H_UNDEFINED,
           *prev = H_UNDEFINED,
           *retn = H_UNDEFINED;

    /*
     * If the object is already referenced OR is a constant, clone it.
	 */
    if( object->referenced == true || (object->attributes & H_OA_CONSTANT) == H_OA_CONSTANT ){
    	next = ob_clone(object);
    }
    /*
     * Otherwise just use it.
     */
    else{
    	next = object;
    	next->referenced = true;
    }

    pthread_mutex_lock( &mutex );

    /* if object does not exist yet, insert as a new one */
    if( (prev = get( identifier )) == H_UNDEFINED ){
    	retn = insert( identifier, next );
    }
    /* else set the new value */
    else{
		/*
		 * If the old value is just a reference to something else (otReference type),
		 * don't replace it in memory, but assign a new value to the object it
		 * references.
		 */
		 if( ob_is_reference(prev) && ob_ref_ucast(prev)->value != NULL ){
			 retn = ob_assign( prev, next );
		 }
		 /*
		  * Plain object, do a normal memory replacement and ob_free the old value.
		  */
		 else{
			 replace( identifier, prev, next );

			 ob_free(prev);

			 retn = next;
		 }
    }
    pthread_mutex_unlock( &mutex );

    return retn;
}
Beispiel #17
0
    int ObStringBuf :: free_mem_(void* ptr)
    {
      int err = OB_SUCCESS;

      if (NULL == ptr)
      {
        TBSYS_LOG(WARN, "invalid param, ptr=%p", ptr);
        err = OB_INVALID_ARGUMENT;
      }
      else
      {
        ob_free(ptr);
      }

      return err;
    }
Beispiel #18
0
 ThreadSpecificBuffer::Buffer* ThreadSpecificBuffer::get_buffer() const
 {
   Buffer * buffer = NULL;
   if (INVALID_THREAD_KEY != key_ && size_ > 0)
   {
     void* ptr = pthread_getspecific(key_);
     if (NULL == ptr)
     {
       ptr = ob_malloc(size_ + sizeof(Buffer), ObModIds::OB_THREAD_BUFFER);
       if (NULL != ptr)
       {
         int ret = pthread_setspecific(key_, ptr);
         if (0 != ret) 
         {
           TBSYS_LOG(ERROR, "pthread_setspecific failed:%d", ret);
           ob_free(ptr);
           ptr = NULL;
         }
         else
         {
           buffer = new (ptr) Buffer(static_cast<char*>(ptr) + sizeof(Buffer), size_);
         }
       }
       else
       {
         // malloc failed;
         TBSYS_LOG(ERROR, "malloc thread specific memeory failed.");
       }
     }
     else
     {
       // got exist ptr;
       buffer = reinterpret_cast<Buffer*>(ptr);
     }
   }
   else
   {
     TBSYS_LOG(ERROR, "thread key must be initialized "
         "and size must great than zero, key:%u,size:%d", key_, size_);
   }
   return buffer;
 }
Beispiel #19
0
int overlay_send_stun_request(struct subscriber *server, struct subscriber *request){
  if ((!server) || (!request))
    return -1;
  if (!(subscriber_is_reachable(server)&REACHABLE))
    return -1;
  // don't bother with a stun request if the peer is already reachable directly
  // TODO link timeouts
  if (subscriber_is_reachable(request)&REACHABLE_DIRECT)
    return -1;
  
  time_ms_t now = gettime_ms();
  if (request->last_stun_request +1000 > now)
    return -1;
  
  request->last_stun_request=now;
  
  overlay_mdp_frame mdp;
  bzero(&mdp, sizeof(mdp));
  mdp.packetTypeAndFlags=MDP_TX;
  
  bcopy(my_subscriber->sid, mdp.out.src.sid, SID_SIZE);
  bcopy(server->sid, mdp.out.dst.sid, SID_SIZE);
  mdp.out.src.port=MDP_PORT_STUN;
  mdp.out.dst.port=MDP_PORT_STUNREQ;
  mdp.out.queue=OQ_MESH_MANAGEMENT;
  
  struct overlay_buffer *payload = ob_static(mdp.out.payload, sizeof(mdp.out.payload));
  overlay_address_append(NULL, payload, request);
  mdp.out.payload_length=ob_position(payload);
  if (config.debug.overlayrouting)
    DEBUGF("Sending STUN request to %s", alloca_tohex_sid(server->sid));
  overlay_mdp_dispatch(&mdp,0 /* system generated */,
		       NULL,0);
  ob_free(payload);
  return 0;
}
Beispiel #20
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;
}
Beispiel #21
0
 void ThreadSpecificBuffer::destroy_thread_key(void* ptr)
 {
   TBSYS_LOG(DEBUG, "delete thread specific ptr:%p", ptr);
   if (NULL != ptr) ob_free(ptr);
 }
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;
}
Beispiel #23
0
int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
{
  IN();

  /* Indicate MDP message type */
  mdp->packetTypeAndFlags=MDP_TX;
  
  switch(f->modifiers&(OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED))  {
  case 0: 
    /* nothing to do, b already points to the plain text */
    mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN;
    RETURN(overlay_mdp_decode_header(f->payload, mdp));
      
  case OF_CRYPTO_CIPHERED:
    RETURN(WHY("decryption not implemented"));
      
  case OF_CRYPTO_SIGNED:
    {
      int len = ob_remaining(f->payload);
      if (crypto_verify_message(f->source, ob_ptr(f->payload), &len))
	RETURN(-1);
      
      mdp->packetTypeAndFlags|=MDP_NOCRYPT; 
      ob_limitsize(f->payload, len + ob_position(f->payload));
      RETURN(overlay_mdp_decode_header(f->payload, mdp));
    }
      
  case OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED:
    {
      if (0) DEBUGF("crypted MDP frame for %s", alloca_tohex_sid(f->destination->sid));

      int nm=crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES;
      int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
      int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
      int cz=crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES;
      
      unsigned char *k=keyring_get_nm_bytes(f->destination->sid, f->source->sid);
      if (!k) 
	RETURN(WHY("I don't have the private key required to decrypt that"));
      
      if (0){
	dump("frame",&f->payload->bytes[f->payload->position],
	     ob_remaining(f->payload));
      }
      
      unsigned char *nonce=ob_get_bytes_ptr(f->payload, nb);
      if (!nonce)
	RETURN(WHYF("Expected %d bytes of nonce", nb));
      
      int cipher_len=ob_remaining(f->payload);
      unsigned char *cipher_text=ob_get_bytes_ptr(f->payload, cipher_len);
      if (!cipher_text)
	RETURN(WHYF("Expected %d bytes of cipher text", cipher_len));
      
      unsigned char plain_block[cipher_len+cz];
      
      bzero(&plain_block[0],cz);
      
      bcopy(cipher_text,&plain_block[cz],cipher_len);
      
      if (0) {
	dump("nm bytes",k,nm);
	dump("nonce",nonce,nb);
	dump("cipher block",plain_block,sizeof(plain_block)); 
      }
      cipher_len+=cz;
      
      if (crypto_box_curve25519xsalsa20poly1305_open_afternm
	  (plain_block,plain_block,cipher_len,nonce,k)) {
	RETURN(WHYF("crypto_box_open_afternm() failed (from %s, to %s, len %d)",
		    alloca_tohex_sid(f->source->sid), alloca_tohex_sid(f->destination->sid), cipher_len));
      }
      
      if (0) dump("plain block",plain_block,sizeof(plain_block));
      
      cipher_len -= zb;
      struct overlay_buffer *plaintext = ob_static(&plain_block[zb], cipher_len);
      ob_limitsize(plaintext,cipher_len);
      int ret=overlay_mdp_decode_header(plaintext, mdp);
      ob_free(plaintext);
      RETURN(ret);
    }    
  }
  RETURN(WHY("Failed to decode mdp payload"));
  OUT();
}
Beispiel #24
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;
  }
}
Beispiel #25
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();
}