void UpdateLastSeen() // This function is temporarily or permanently deprecated { double lsea = LASTSEENEXPIREAFTER; int intermittency = false,qsize,ksize; struct CfKeyHostSeen q,newq; double lastseen,delta2; void *stored; CF_DB *dbp = NULL,*dbpent = NULL; CF_DBC *dbcp; char name[CF_BUFSIZE],*key; struct Rlist *rp; struct CfKeyBinding *kp; time_t now = time(NULL); static time_t then; if (now < then + 300 && then > 0 && then <= now + 300) { // Rate limiter return; } then = now; CfOut(cf_verbose,""," -> Writing last-seen observations"); ThreadLock(cft_server_keyseen); if (SERVER_KEYSEEN == NULL) { ThreadUnlock(cft_server_keyseen); CfOut(cf_verbose,""," -> Keyring is empty"); return; } if (BooleanControl("control_agent",CFA_CONTROLBODY[cfa_intermittency].lval)) { CfOut(cf_inform,""," -> Recording intermittency"); intermittency = true; } snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE); MapName(name); if (!OpenDB(name,&dbp)) { ThreadUnlock(cft_server_keyseen); return; } /* First scan for hosts that have moved address and purge their records so that the database always has a 1:1 relationship between keyhash and IP address */ if (!NewDBCursor(dbp,&dbcp)) { ThreadUnlock(cft_server_keyseen); CfOut(cf_inform,""," !! Unable to scan class db"); return; } while(NextDB(dbp,dbcp,&key,&ksize,&stored,&qsize)) { memcpy(&q,stored,sizeof(q)); lastseen = (double)now - q.Q.q; if (lastseen > lsea) { CfOut(cf_verbose,""," -> Last-seen record for %s expired after %.1lf > %.1lf hours\n",key,lastseen/3600,lsea/3600); DeleteDB(dbp,key); } for (rp = SERVER_KEYSEEN; rp != NULL; rp=rp->next) { kp = (struct CfKeyBinding *) rp->item; if ((strcmp(q.address,kp->address) == 0) && (strcmp(key+1,kp->name+1) != 0)) { CfOut(cf_verbose,""," ! Deleting %s's address (%s=%d) as this host %s seems to have moved elsewhere (%s=5d)",key,kp->address,strlen(kp->address),kp->name,q.address,strlen(q.address)); DeleteDB(dbp,key); } } } DeleteDBCursor(dbp,dbcp); /* Now perform updates with the latest data */ for (rp = SERVER_KEYSEEN; rp != NULL; rp=rp->next) { kp = (struct CfKeyBinding *) rp->item; now = kp->timestamp; if (intermittency) { /* Open special file for peer entropy record - INRIA intermittency */ snprintf(name,CF_BUFSIZE-1,"%s/lastseen/%s.%s",CFWORKDIR,CF_LASTDB_FILE,kp->name); MapName(name); if (!OpenDB(name,&dbpent)) { continue; } } if (ReadDB(dbp,kp->name,&q,sizeof(q))) { lastseen = (double)now - q.Q.q; if (q.Q.q <= 0) { lastseen = 300; q.Q.expect = 0; q.Q.var = 0; } newq.Q.q = (double)now; newq.Q.expect = GAverage(lastseen,q.Q.expect,0.4); delta2 = (lastseen - q.Q.expect)*(lastseen - q.Q.expect); newq.Q.var = GAverage(delta2,q.Q.var,0.4); strncpy(newq.address,kp->address,CF_ADDRSIZE-1); } else { lastseen = 0.0; newq.Q.q = (double)now; newq.Q.expect = 0.0; newq.Q.var = 0.0; strncpy(newq.address,kp->address,CF_ADDRSIZE-1); } if (lastseen > lsea) { CfOut(cf_verbose,""," -> Last-seen record for %s expired after %.1lf > %.1lf hours\n",kp->name,lastseen/3600,lsea/3600); DeleteDB(dbp,kp->name); } else { char timebuf[26]; CfOut(cf_verbose,""," -> Last saw %s (alias %s) at %s (noexpiry %.1lf <= %.1lf)\n",kp->name,kp->address,cf_strtimestamp_local(now,timebuf),lastseen/3600,lsea/3600); WriteDB(dbp,kp->name,&newq,sizeof(newq)); if (intermittency) { WriteDB(dbpent,GenTimeKey(now),&newq,sizeof(newq)); } } if (intermittency && dbpent) { CloseDB(dbpent); } } ThreadUnlock(cft_server_keyseen); }
void RecordPerformance(char *eventname,time_t t,double value) { DB *dbp; DB_ENV *dbenv = NULL; char name[CF_BUFSIZE]; struct Event e,newe; double lastseen,delta2; int lsea = CF_WEEK; time_t now = time(NULL); Debug("PerformanceEvent(%s,%.1f s)\n",eventname,value); snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_PERFORMANCE); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } if (ReadDB(dbp,eventname,&e,sizeof(e))) { lastseen = now - e.t; newe.t = t; newe.Q.q = value; newe.Q.expect = GAverage(value,e.Q.expect,0.3); delta2 = (value - e.Q.expect)*(value - e.Q.expect); newe.Q.var = GAverage(delta2,e.Q.var,0.3); /* Have to kickstart variance computation, assume 1% to start */ if (newe.Q.var <= 0.0009) { newe.Q.var = newe.Q.expect / 100.0; } } else { lastseen = 0.0; newe.t = t; newe.Q.q = value; newe.Q.expect = value; newe.Q.var = 0.001; } if (lastseen > (double)lsea) { Verbose("Performance record %s expired\n",eventname); DeleteDB(dbp,eventname); } else { Verbose("Performance(%s): time=%.4f secs, av=%.4f +/- %.4f\n",eventname,value,newe.Q.expect,sqrt(newe.Q.var)); WriteDB(dbp,eventname,&newe,sizeof(newe)); } dbp->close(dbp,0); }
void RecordClassUsage() { DB *dbp; DB_ENV *dbenv = NULL; DBC *dbcp; DBT key,stored; char name[CF_BUFSIZE]; struct Event e,entry,newe; double lsea = CF_WEEK * 52; /* expire after a year */ time_t now = time(NULL); struct Item *ip,*list = NULL; double lastseen,delta2; double vtrue = 1.0; /* end with a rough probability */ Debug("RecordClassUsage\n"); for (ip = VHEAP; ip != NULL; ip=ip->next) { if (!IsItemIn(list,ip->name)) { PrependItem(&list,ip->name,NULL); } } for (ip = VALLADDCLASSES; ip != NULL; ip=ip->next) { if (!IsItemIn(list,ip->name)) { PrependItem(&list,ip->name,NULL); } } snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_CLASSUSAGE); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open performance database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } /* First record the classes that are in use */ for (ip = list; ip != NULL; ip=ip->next) { if (ReadDB(dbp,ip->name,&e,sizeof(e))) { lastseen = now - e.t; newe.t = now; newe.Q.q = vtrue; newe.Q.expect = GAverage(vtrue,e.Q.expect,0.5); delta2 = (vtrue - e.Q.expect)*(vtrue - e.Q.expect); newe.Q.var = GAverage(delta2,e.Q.var,0.5); } else { lastseen = 0.0; newe.t = now; newe.Q.q = 0.5*vtrue; newe.Q.expect = 0.5*vtrue; /* With no data it's 50/50 what we can say */ newe.Q.var = 0.000; } if (lastseen > lsea) { Verbose("Class usage record %s expired\n",ip->name); DeleteDB(dbp,ip->name); } else { Debug("Upgrading %s %f\n",ip->name,newe.Q.expect); WriteDB(dbp,ip->name,&newe,sizeof(newe)); } } /* Then update with zero the ones we know about that are not active */ /* Acquire a cursor for the database. */ if ((errno = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { Debug("Error reading from class database: "); dbp->err(dbp, errno, "DB->cursor"); return; } /* Initialize the key/data return pair. */ memset(&key, 0, sizeof(key)); memset(&stored, 0, sizeof(stored)); memset(&entry, 0, sizeof(entry)); while (dbcp->c_get(dbcp, &key, &stored, DB_NEXT) == 0) { double measure,av,var; time_t then; char tbuf[CF_BUFSIZE],eventname[CF_BUFSIZE]; strcpy(eventname,(char *)key.data); if (stored.data != NULL) { memcpy(&entry,stored.data,sizeof(entry)); then = entry.t; measure = entry.Q.q; av = entry.Q.expect; var = entry.Q.var; lastseen = now - then; snprintf(tbuf,CF_BUFSIZE-1,"%s",ctime(&then)); tbuf[strlen(tbuf)-9] = '\0'; /* Chop off second and year */ if (lastseen > lsea) { Verbose("Class usage record %s expired\n",eventname); DeleteDB(dbp,eventname); } else if (!IsItemIn(list,eventname)) { newe.t = then; newe.Q.q = 0; newe.Q.expect = GAverage(0.0,av,0.5); delta2 = av*av; newe.Q.var = GAverage(delta2,var,0.5); Debug("Downgrading class %s from %lf to %lf\n",eventname,entry.Q.expect,newe.Q.expect); WriteDB(dbp,eventname,&newe,sizeof(newe)); } } } dbp->close(dbp,0); }
void LastSeen(char *hostname,enum roles role) { DB *dbp,*dbpent; DB_ENV *dbenv = NULL, *dbenv2 = NULL; char name[CF_BUFSIZE],databuf[CF_BUFSIZE]; time_t now = time(NULL); struct QPoint q,newq; double lastseen,delta2; int lsea = -1; if (strlen(hostname) == 0) { snprintf(OUTPUT,CF_BUFSIZE,"LastSeen registry for empty hostname with role %d",role); CfLog(cflogonly,OUTPUT,""); return; } Debug("LastSeen(%s) reg\n",hostname); /* Tidy old versions - temporary */ snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_OLDLASTDB_FILE); unlink(name); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't init last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE); #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } /* Now open special file for peer entropy record - INRIA intermittency */ snprintf(name,CF_BUFSIZE-1,"%s/%s.%s",CFWORKDIR,CF_LASTDB_FILE,hostname); if ((errno = db_create(&dbpent,dbenv2,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't init last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbpent->open)(dbpent,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbpent->open)(dbpent,NULL,name,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open last-seen database %s\n",name); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_lock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_lock failed","unlock"); exit(1); } #endif switch (role) { case cf_accept: snprintf(databuf,CF_BUFSIZE-1,"-%s",Hostname2IPString(hostname)); break; case cf_connect: snprintf(databuf,CF_BUFSIZE-1,"+%s",Hostname2IPString(hostname)); break; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_unlock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_unlock failed","unlock"); exit(1); } #endif if (GetMacroValue(CONTEXTID,"LastSeenExpireAfter")) { lsea = atoi(GetMacroValue(CONTEXTID,"LastSeenExpireAfter")); lsea *= CF_TICKS_PER_DAY; } if (lsea < 0) { lsea = CF_WEEK; } if (ReadDB(dbp,databuf,&q,sizeof(q))) { lastseen = (double)now - q.q; newq.q = (double)now; /* Last seen is now-then */ newq.expect = GAverage(lastseen,q.expect,0.3); delta2 = (lastseen - q.expect)*(lastseen - q.expect); newq.var = GAverage(delta2,q.var,0.3); } else { lastseen = 0.0; newq.q = (double)now; newq.expect = 0.0; newq.var = 0.0; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_lock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_lock failed","unlock"); exit(1); } #endif if (lastseen > (double)lsea) { Verbose("Last seen %s expired\n",databuf); DeleteDB(dbp,databuf); } else { WriteDB(dbp,databuf,&newq,sizeof(newq)); WriteDB(dbpent,GenTimeKey(now),&newq,sizeof(newq)); } #ifdef HAVE_PTHREAD_H if (pthread_mutex_unlock(&MUTEX_GETADDR) != 0) { CfLog(cferror,"pthread_mutex_unlock failed","unlock"); exit(1); } #endif dbp->close(dbp,0); dbpent->close(dbpent,0); }
static void UpdateLastSawHost(char *rkey, char *ipaddress) { CF_DB *dbp = NULL; KeyHostSeen q, newq; double lastseen, delta2; time_t now = time(NULL); char timebuf[26]; if (!OpenDB(&dbp, dbid_lastseen)) { CfOut(cf_inform, "", " !! Unable to open last seen db"); return; } if (ReadDB(dbp, rkey, &q, sizeof(q))) { lastseen = (double) now - q.Q.q; if (q.Q.q <= 0) { lastseen = 300; q.Q = QDefinite(0.0); } newq.Q.q = (double) now; newq.Q.dq = newq.Q.q - q.Q.q; newq.Q.expect = GAverage(lastseen, q.Q.expect, 0.4); delta2 = (lastseen - q.Q.expect) * (lastseen - q.Q.expect); newq.Q.var = GAverage(delta2, q.Q.var, 0.4); strncpy(newq.address, ipaddress, CF_ADDRSIZE - 1); } else { lastseen = 0.0; newq.Q.q = (double) now; newq.Q.dq = 0; newq.Q.expect = 0.0; newq.Q.var = 0.0; strncpy(newq.address, ipaddress, CF_ADDRSIZE - 1); } if (strcmp(rkey + 1, PUBKEY_DIGEST) == 0) { Item *ip; int match = false; for (ip = IPADDRESSES; ip != NULL; ip = ip->next) { if (strcmp(VIPADDRESS, ip->name) == 0) { match = true; break; } if (strcmp(ipaddress, ip->name) == 0) { match = true; break; } } if (!match) { CfOut(cf_verbose, "", " ! Not updating last seen, as this appears to be a host with a duplicate key"); CloseDB(dbp); return; } } CfOut(cf_verbose, "", " -> Last saw %s (alias %s) at %s\n", rkey, ipaddress, cf_strtimestamp_local(now, timebuf)); PurgeMultipleIPReferences(dbp, rkey, ipaddress); WriteDB(dbp, rkey, &newq, sizeof(newq)); CloseDB(dbp); }