// Get next auth manager message. int authmgtGetNextMsg(struct s_authmgt *mgt, struct s_msg *out_msg, struct s_peeraddr *target) { int used = idspUsedCount(&mgt->idsp); int tnow = utilGetClock(); int authstateid; int i; for(i=0; i<used; i++) { authstateid = idspNext(&mgt->idsp); if((tnow - mgt->lastrecv[authstateid]) >= AUTHMGT_RECV_TIMEOUT) { // check if auth session has expired authmgtDelete(mgt, authstateid); continue; } if((tnow - mgt->lastsend[authstateid]) <= AUTHMGT_RESEND_TIMEOUT) { // only send one auth message per specified time interval and session continue; } if(authGetNextMsg(&mgt->authstate[authstateid], out_msg)) { mgt->lastsend[authstateid] = tnow; *target = mgt->peeraddr[authstateid]; CREATE_HUMAN_IP(target); debugf("[%d] New AUTH packet for %s created, size: %d", authstateid, humanIp, out_msg->len); return 1; } } return 0; }
// Create new auth session. Returns ID of session if successful. int authmgtNew(struct s_authmgt *mgt, const struct s_peeraddr *peeraddr) { int authstateid = idspNew(&mgt->idsp); int tnow = utilGetClock(); if(authstateid < 0) { return -1; } mgt->lastsend[authstateid] = (mgt->fastauth) ? (tnow - authmgt_RESEND_TIMEOUT - 3) : tnow; mgt->lastrecv[authstateid] = tnow; mgt->peeraddr[authstateid] = *peeraddr; CREATE_HUMAN_IP(peeraddr); debugf("Starting new auth session for %s, ID: %d", humanIp, authstateid); return authstateid; }
// Update NodeDB entry. static void nodedbUpdate(struct s_nodedb *db, struct s_nodeid *nodeid, struct s_peeraddr *addr, const int update_lastseen, const int update_lastconnect, const int update_lastconntry) { int tnow = utilGetClock(); struct s_map *addrset; struct s_map *newaddrset; struct s_nodedb_addrdata *addrdata; struct s_nodedb_addrdata addrdata_new; if(db != NULL && nodeid != NULL && addr != NULL) { addrset = mapGet(db->addrdb, nodeid->id); if(addrset == NULL) { newaddrset = mapGetValueByID(db->addrdb, mapAddReturnID(db->addrdb, nodeid->id, NULL)); if(newaddrset != NULL) { if(mapMemInit(newaddrset, mapMemSize(db->num_peeraddrs, peeraddr_SIZE, sizeof(struct s_nodedb_addrdata)), db->num_peeraddrs, peeraddr_SIZE, sizeof(struct s_nodedb_addrdata))) { mapEnableReplaceOld(newaddrset); addrset = newaddrset; } } } if(addrset != NULL) { addrdata_new.lastseen = 0; addrdata_new.lastconnect = 0; addrdata_new.lastconntry = 0; addrdata_new.lastseen_t = 0; addrdata_new.lastconnect_t = 0; addrdata_new.lastconntry_t = 0; if((addrdata = mapGet(addrset, addr->addr)) != NULL) { addrdata_new = *addrdata; } if(update_lastseen > 0) { addrdata_new.lastseen = 1; addrdata_new.lastseen_t = tnow; } if(update_lastconnect > 0) { addrdata_new.lastconnect = 1; addrdata_new.lastconnect_t = tnow; } if(update_lastconntry > 0) { addrdata_new.lastconntry = 1; addrdata_new.lastconntry_t = tnow; } mapSet(addrset, addr->addr, &addrdata_new); } } }
// Returns a NodeDB ID that matches the specified criteria. static int nodedbGetDBID(struct s_nodedb *db, struct s_nodeid *nodeid, const int max_lastseen, const int max_lastconnect, const int min_lastconntry) { int i, i_max, nid, tnow, ret; tnow = utilGetClock(); i_max = mapGetKeyCount(db->addrdb); ret = -1; if(nodeid == NULL) { // find DBID for any NodeID i = 0; while((i < i_max) && (ret < 0)) { nid = mapGetNextKeyID(db->addrdb); ret = nodedbGetDBIDByID(db, nid, tnow, max_lastseen, max_lastconnect, min_lastconntry); i++; } } else { // find DBID for specified NodeID nid = mapGetKeyID(db->addrdb, nodeid->id); if(!(nid < 0)) { ret = nodedbGetDBIDByID(db, nid, tnow, max_lastseen, max_lastconnect, min_lastconntry); } } return ret; }
// Generate NodeDB status report. static void nodedbStatus(struct s_nodedb *db, char *report, const int report_len) { int i; int j; int size; int rpsize; int pos; int tnow; unsigned char timediff[4]; struct s_map *addrset; struct s_nodedb_addrdata *addrdata; tnow = utilGetClock(); size = mapGetKeyCount(db->addrdb); rpsize = (95 * (1 + db->num_peeraddrs)) + 2; pos = 0; memcpy(&report[pos], "NodeID + Address LastSeen LastConn LastTry ", 94); pos = pos + 94; report[pos++] = '\n'; i = 0; while(i < size && pos < (report_len - rpsize)) { if(mapIsValidID(db->addrdb, i)) { utilByteArrayToHexstring(&report[pos], ((nodeid_SIZE * 2) + 2), mapGetKeyByID(db->addrdb, i), nodeid_SIZE); pos = pos + (nodeid_SIZE * 2); addrset = mapGetValueByID(db->addrdb, i); memcpy(&report[pos], " ", 30); pos = pos + 30; j = 0; while(j < db->num_peeraddrs) { if(mapIsValidID(addrset, j)) { addrdata = mapGetValueByID(addrset, j); report[pos++] = '\n'; memcpy(&report[pos], " ", 12); pos = pos + 12; report[pos++] = '-'; report[pos++] = '-'; report[pos++] = '>'; report[pos++] = ' '; utilByteArrayToHexstring(&report[pos], ((peeraddr_SIZE * 2) + 2), mapGetKeyByID(addrset, j), peeraddr_SIZE); pos = pos + (peeraddr_SIZE * 2); report[pos++] = ' '; report[pos++] = ' '; if(addrdata->lastseen) { utilWriteInt32(timediff, (tnow - addrdata->lastseen_t)); utilByteArrayToHexstring(&report[pos], 10, timediff, 4); } else { memcpy(&report[pos], "--------", 8); } pos = pos + 8; report[pos++] = ' '; report[pos++] = ' '; if(addrdata->lastconnect) { utilWriteInt32(timediff, (tnow - addrdata->lastconnect_t)); utilByteArrayToHexstring(&report[pos], 10, timediff, 4); } else { memcpy(&report[pos], "--------", 8); } pos = pos + 8; report[pos++] = ' '; report[pos++] = ' '; if(addrdata->lastconntry) { utilWriteInt32(timediff, (tnow - addrdata->lastconntry_t)); utilByteArrayToHexstring(&report[pos], 10, timediff, 4); } else { memcpy(&report[pos], "--------", 8); } pos = pos + 8; } j++; } report[pos++] = '\n'; } i++; } report[pos++] = '\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; }