Beispiel #1
0
// Decode peerinfo packet
static int peermgtDecodePacketPeerinfo(struct s_peermgt *mgt, const struct s_packet_data *data) {
	const int peerinfo_size = (packet_PEERID_SIZE + nodeid_SIZE + peeraddr_SIZE);
	struct s_nodeid nodeid;
	struct s_peeraddr addr;
	int peerinfo_count;
	int localid;
	int pos;
	int relayid;
	int relayct;
	int relaypeerid;
	int i;
	int64_t r;
	if(data->pl_length > 4) {
		peerinfo_count = utilReadInt32(data->pl_buf);
		/**
		 * JEWED: overflow on peerinfo_count >= (INT_MAX - 4) / peerinfo_size
		 */
		if(peerinfo_count > 0 && (((peerinfo_count * peerinfo_size) + 4) <= data->pl_length)) {
			if((peermgtGetRemoteFlag(mgt, data->peerid, peermgt_FLAG_RELAY)) && (!peeraddrIsInternal(&mgt->data[data->peerid].remoteaddr))) {
				// add indirect NodeDB entry
				relayid = data->peerid;
				relayct = mgt->data[relayid].conntime;
			}
			else {
				// don't change indirect NodeDB entry
				relayid = 0;
				relayct = 0;
			}
			r = (abs(cryptoRandInt()) % peerinfo_count); // randomly select a peer
			for(i=0; i<peerinfo_count; i++) {
				pos = (4 + (r * peerinfo_size));
				/**
				 * JEWED: OOB read pos + 4 > data->pl_length
				 */
				relaypeerid = utilReadInt32(&data->pl_buf[pos]);
				memcpy(nodeid.id, &data->pl_buf[(pos + (packet_PEERID_SIZE))], nodeid_SIZE);
				memcpy(addr.addr, &data->pl_buf[(pos + (packet_PEERID_SIZE + nodeid_SIZE))], peeraddr_SIZE);
				if(!peeraddrIsInternal(&addr)) { // only accept external PeerAddr
					localid = peermgtGetID(mgt, &nodeid);
					if(localid < 0) { // check if we are already connected to this NodeID
						// not connected yet
						nodedbUpdate(&mgt->nodedb, &nodeid, &addr, 1, 0, 0, relayid, relayct, relaypeerid);
					}
					else { if(localid > 0) {
						// already connected
						if(peeraddrIsInternal(&mgt->data[localid].remoteaddr)) {
							nodedbUpdate(&mgt->nodedb, &nodeid, &addr, 1, 1, 0, relayid, relayct, relaypeerid);
						}
						else {
							nodedbUpdate(&mgt->nodedb, &nodeid, NULL, 1, 1, 0, relayid, relayct, relaypeerid);
						}
					} }
				}
				r = ((r + 1) % peerinfo_count);
			}
			return 1;
		}
	}
	return 0;
}
Beispiel #2
0
// Decode auth message S3
static int authDecodeS3(struct s_auth_state *authstate, const unsigned char *msg, const int msg_len) {
	int msgnum;
	int decmsg_len;
	unsigned char decmsg[auth_MAXMSGSIZE_S3];
	if(msg_len > 6) {
		memcpy(decmsg, msg, 6);
		msgnum = utilReadInt16(&decmsg[4]);
		if(msgnum == (authstate->state + 1)) {
			decmsg_len = (4 + 2 + cryptoDec(&authstate->crypto_ctx[auth_CRYPTOCTX_CNEG], &decmsg[(4 + 2)], (auth_MAXMSGSIZE_S3 - 2 - 4), &msg[(4 + 2)], (msg_len - 2 - 4), auth_CNEGHMACSIZE, auth_CNEGIVSIZE));
			if(decmsg_len >= (4 + 2 + auth_NONCESIZE + seq_SIZE + 4 + 8)) {
				memcpy(authstate->remote_keygen_nonce, &decmsg[(4 + 2)], auth_NONCESIZE);
				if((msgnum % 2) == 0) {
					memcpy(&authstate->keygen_nonce[0], authstate->local_keygen_nonce, auth_NONCESIZE);
					memcpy(&authstate->keygen_nonce[auth_NONCESIZE], authstate->remote_keygen_nonce, auth_NONCESIZE);
				}
				else {
					memcpy(&authstate->keygen_nonce[0], authstate->remote_keygen_nonce, auth_NONCESIZE);
					memcpy(&authstate->keygen_nonce[auth_NONCESIZE], authstate->local_keygen_nonce, auth_NONCESIZE);
				}
				memcpy(authstate->remote_seq, &decmsg[(4 + 2 + auth_NONCESIZE)], seq_SIZE);
				authstate->remote_peerid = utilReadInt32(&decmsg[(4 + 2 + auth_NONCESIZE + seq_SIZE)]);
				memcpy(authstate->remote_flags, &decmsg[(4 + 2 + auth_NONCESIZE + seq_SIZE + 4)], 8);
				return 1;
			}
		}
	}
	return 0;
}
Beispiel #3
0
// Get indirect PeerAddr attributes. Returns 1 on success or 0 if the PeerAddr is not indirect.
static int peeraddrGetIndirect(const struct s_peeraddr *peeraddr, int *relayid, int *relayct, int *peerid) {
	if(peeraddrGetInternalType(peeraddr) == peeraddr_INTERNAL_INDIRECT) {
		if(relayid != NULL) {
			*relayid = utilReadInt32(&peeraddr->addr[8]);
		}
		if(relayct != NULL) {
			*relayct = utilReadInt32(&peeraddr->addr[12]);
		}
		if(peerid != NULL) {
			*peerid = utilReadInt32(&peeraddr->addr[16]);
		}
		return 1;
	}
	else {
		return 0;
	}
}
Beispiel #4
0
// Returns type of internal PeerAddr or -1 if it is not internal.
static int peeraddrGetInternalType(const struct s_peeraddr *peeraddr) {
	if(peeraddrIsInternal(peeraddr)) {
		return utilReadInt32(&peeraddr->addr[4]);
	}
	else {
		return -1;
	}
}
Beispiel #5
0
// Returns true if PeerAddr is internal.
static int peeraddrIsInternal(const struct s_peeraddr *peeraddr) {
	int i;
	i = utilReadInt32(&peeraddr->addr[0]);
	if(i == 0) {
		return 1;
	}
	else {
		return 0;
	}
}
Beispiel #6
0
// Decode relay-in packet
static int peermgtDecodePacketRelayIn(struct s_peermgt *mgt, const struct s_packet_data *data) {
	int targetpeerid;
	int len = data->pl_length;
	
	if((len > 4) && (len < (peermgt_MSGSIZE_MAX - 4))) {
		targetpeerid = utilReadInt32(data->pl_buf);
		if(peermgtIsActiveRemoteID(mgt, targetpeerid)) {
			utilWriteInt32(&mgt->rrmsg.msg[0], data->peerid);
			memcpy(&mgt->rrmsg.msg[4], &data->pl_buf[4], (len - 4));
			mgt->rrmsgpeerid = targetpeerid;
			mgt->rrmsgtype = packet_PLTYPE_RELAY_OUT;
			mgt->rrmsg.len = len;
			mgt->rrmsgusetargetaddr = 0;
			return 1;
		}
	}
	
	return 0;
}
Beispiel #7
0
// Decode auth message. Returns 1 if message is accepted.
int authmgtDecodeMsg(struct s_authmgt *mgt, const unsigned char *msg, const int msg_len, const struct s_peeraddr *peeraddr) {
	int authid;
	int authstateid;
	int tnow = utilGetClock();
	int newsession;
	int dupid;
    
    CREATE_HUMAN_IP(peeraddr);
    
    debugf("[%s] AUTH message received", humanIp);
    
	if(msg_len <= 4) {
        debugf("[%s] Wrong AUTH message size: %d", humanIp, msg_len);
        return 0;
    }
    
    authid = utilReadInt32(msg);
    if(authid > 0) {
        // message belongs to existing auth session
        authstateid = (authid - 1);
        
        debugf("Found active auth session: %d", authstateid);
        if(authstateid >= idspSize(&mgt->idsp)) {
            debugf("[%s] wrong auth state ID", humanIp);
            return 0;
        }
        
        if(!authDecodeMsg(&mgt->authstate[authstateid], msg, msg_len)) {
            debugf("[%s] failed to decode AUTH message", humanIp);
            return 0;
        }
        
        mgt->lastrecv[authstateid] = tnow;
        mgt->peeraddr[authstateid] = *peeraddr;
        if(mgt->fastauth) {
            mgt->lastsend[authstateid] = (tnow - authmgt_RESEND_TIMEOUT - 3);
        }
        
        if((authIsAuthed(&mgt->authstate[authstateid])) && (!authIsCompleted(&mgt->authstate[authstateid]))) mgt->current_authed_id = authstateid;
        
        if((authIsCompleted(&mgt->authstate[authstateid])) && (!authIsPeerCompleted(&mgt->authstate[authstateid]))) {
            msgf("Host %s authorized", humanIp);
            mgt->current_completed_id = authstateid;
        }
        
        return 1;
    } else if(authid == 0) {
        debugf("starting new session for %s, authid: %d", humanIp, authid);
        // message requests new auth session
        dupid = authmgtFindAddr(mgt, peeraddr);
        
        // we already have this session
        if(dupid >= 0) {
            // auth session with same PeerAddr found.
            if(authIsPreauth(&mgt->authstate[dupid])) {
                return 0;
            }
        
            authmgtDelete(mgt, dupid);
        }
        
        authstateid = authmgtNew(mgt, peeraddr);
        if(authstateid < 0) {
            // all auth slots are full, search for unused sessions that can be replaced
            dupid = authmgtFindUnused(mgt);
            if(!(dupid < 0)) {
                authmgtDelete(mgt, dupid);
                authstateid = authmgtNew(mgt, peeraddr);
                debugf("new auth session started for %s, authstateid %d", humanIp, authstateid);
            }
        }
        
        if(!(authstateid < 0)) {
            if(authDecodeMsg(&mgt->authstate[authstateid], msg, msg_len)) {
                mgt->lastrecv[authstateid] = tnow;
                mgt->peeraddr[authstateid] = *peeraddr;
                if(mgt->fastauth) {
                    mgt->lastsend[authstateid] = (tnow - authmgt_RESEND_TIMEOUT - 3);
                }
                return 1;
            }
            else {
                authmgtDelete(mgt, authstateid);
            }
        }
        
    }
    
    return 0;
}
Beispiel #8
0
// return the peer ID
static int packetGetPeerID(const unsigned char *pbuf) {
	int32_t *scr_peerid = ((int32_t *)pbuf);
	int32_t ne_peerid = (scr_peerid[0] ^ (scr_peerid[1] ^ scr_peerid[2]));
	return utilReadInt32((unsigned char *)&ne_peerid);
}
Beispiel #9
0
// Decode input packet recursively. Decapsulates relayed packets if necessary.
static int peermgtDecodePacketRecursive(struct s_peermgt *mgt, const unsigned char *packet, const int packet_len, const struct s_peeraddr *source_addr, const int tnow, const int depth) {
	int ret;
	int peerid;
	struct s_packet_data data = { .pl_buf_size = peermgt_MSGSIZE_MAX, .pl_buf = mgt->msgbuf };
	struct s_peeraddr indirect_addr;
	ret = 0;
	if(packet_len > (packet_PEERID_SIZE + packet_HMAC_SIZE) && (depth < peermgt_DECODE_RECURSION_MAX_DEPTH)) {
		peerid = packetGetPeerID(packet);
		if(peermgtIsActiveID(mgt, peerid)) {
			if(peerid > 0) {
				// packet has an active PeerID
				mgt->msgsize = 0;
				if(packetDecode(&data, packet, packet_len, &mgt->ctx[peerid], &mgt->data[peerid].seq) > 0) {
					if((data.pl_length > 0) && (data.pl_length < peermgt_MSGSIZE_MAX)) {
						switch(data.pl_type) {
							case packet_PLTYPE_USERDATA:
								if(peermgtGetFlag(mgt, peermgt_FLAG_USERDATA)) {
									ret = 1;
									mgt->msgsize = data.pl_length;
									mgt->msgpeerid = data.peerid;
								}
								else {
									ret = 0;
								}
								break;
							case packet_PLTYPE_USERDATA_FRAGMENT:
								if(peermgtGetFlag(mgt, peermgt_FLAG_USERDATA)) {
									ret = peermgtDecodeUserdataFragment(mgt, &data);
									if(ret > 0) {
										mgt->msgsize = data.pl_length;
										mgt->msgpeerid = data.peerid;
									}
								}
								else {
									ret = 0;
								}
								break;
							case packet_PLTYPE_PEERINFO:
								ret = peermgtDecodePacketPeerinfo(mgt, &data);
								break;
							case packet_PLTYPE_PING:
								ret = peermgtDecodePacketPing(mgt, &data);
								break;
							case packet_PLTYPE_PONG:
								ret = peermgtDecodePacketPong(mgt, &data);
								break;
							case packet_PLTYPE_RELAY_IN:
								if(peermgtGetFlag(mgt, peermgt_FLAG_RELAY)) {
									ret = peermgtDecodePacketRelayIn(mgt, &data);
								}
								else {
									ret = 0;
								}
								break;
							case packet_PLTYPE_RELAY_OUT:
								if(data.pl_length > packet_PEERID_SIZE) {
									memcpy(mgt->relaymsgbuf, &data.pl_buf[4], (data.pl_length - packet_PEERID_SIZE)); 
									peeraddrSetIndirect(&indirect_addr, peerid, mgt->data[peerid].conntime, utilReadInt32(&data.pl_buf[0])); // generate indirect PeerAddr
									ret = peermgtDecodePacketRecursive(mgt, mgt->relaymsgbuf, (data.pl_length - packet_PEERID_SIZE), &indirect_addr, tnow, (depth + 1)); // decode decapsulated packet
								}
								break;
							default:
								ret = 0;
								break;
						}
						if(ret > 0) {
							mgt->data[peerid].lastrecv = tnow;
							mgt->data[peerid].remoteaddr = *source_addr;
							return 1;
						}
					}
				}
			}
			else if(peerid == 0) {
				// packet has an anonymous PeerID
				if(packetDecode(&data, packet, packet_len, &mgt->ctx[0], NULL)) {
					switch(data.pl_type) {
						case packet_PLTYPE_AUTH:
							return peermgtDecodePacketAuth(mgt, &data, source_addr);
						default:
							return 0;
					}
				}
			}
		}
	}
	return 0;
}


// Decode input packet. Returns 1 on success.
static int peermgtDecodePacket(struct s_peermgt *mgt, const unsigned char *packet, const int packet_len, const struct s_peeraddr *source_addr) {
	int tnow;
	tnow = utilGetTime();
	return peermgtDecodePacketRecursive(mgt, packet, packet_len, source_addr, tnow, 0);
}