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; } }
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; }
// 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(); }
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; }
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; } }
ObSchemaManagerWrapper::~ObSchemaManagerWrapper() { if (NULL != schema_mgr_buffer_) { schema_mgr_impl_->~ObSchemaManager(); ob_free(schema_mgr_buffer_); schema_mgr_buffer_ = NULL; schema_mgr_impl_ = NULL; } }
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; }
void ObRegex::destroy(void) { if (init_) { regfree(®_); if (NULL != match_) { ob_free(match_); match_ = NULL; } nmatch_ = 0; init_ = false; } }
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; }
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; }
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; }
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; }
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; }
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; }
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(); }
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; } }
/* 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(); }