#include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_NETDB_H #include #endif /* Required for getpwuid */ #include #include #include #include /* Required for SNMP support*/ #ifdef HAVE_UCD_SNMP_UCD_SNMP_CONFIG_H #include #include #include #endif #include "common.h" #include "cfg.h" #include "db.h" #include "functions.h" #include "expression.h" #include "log.h" static pid_t *pids=NULL; static int sucker_num=0; static int CONFIG_SUCKERD_FORKS =SUCKER_FORKS; static int CONFIG_NOTIMEWAIT =0; static int CONFIG_TIMEOUT =SUCKER_TIMEOUT; static int CONFIG_HOUSEKEEPING_FREQUENCY = 1; static int CONFIG_SENDER_FREQUENCY = 30; static int CONFIG_DISABLE_HOUSEKEEPING = 0; static int CONFIG_LOG_LEVEL = LOG_LEVEL_WARNING; static char *CONFIG_PID_FILE = NULL; static char *CONFIG_LOG_FILE = NULL; static char *CONFIG_DBHOST = NULL; static char *CONFIG_DBNAME = NULL; static char *CONFIG_DBUSER = NULL; static char *CONFIG_DBPASSWORD = NULL; static char *CONFIG_DBSOCKET = NULL; void uninit(void) { int i; if(sucker_num == 0) { if(pids != NULL) { for(i=0;ipw_gid) ==-1) || (setuid(pwd->pw_uid) == -1) ) { fprintf(stderr,"Cannot setgid or setuid to zabbix"); exit(FAIL); } #ifdef HAVE_FUNCTION_SETEUID if( (setegid(pwd->pw_gid) ==-1) || (seteuid(pwd->pw_uid) == -1) ) { fprintf(stderr,"Cannot setegid or seteuid to zabbix"); exit(FAIL); } #endif } if( (pid = fork()) != 0 ) { exit( 0 ); } setsid(); signal( SIGHUP, SIG_IGN ); if( (pid = fork()) !=0 ) { exit( 0 ); } chdir("/"); umask(0); for(i=0;iuseip == 1) { session.peername = item->ip; } else { session.peername = item->host; } zabbix_log( LOG_LEVEL_DEBUG, "Peername [%s]", session.peername); session.community = item->snmp_community; zabbix_log( LOG_LEVEL_DEBUG, "Community [%s]", session.community); zabbix_log( LOG_LEVEL_DEBUG, "OID [%s]", item->snmp_oid); session.community_len = strlen(session.community); zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMPv1() 0.1"); SOCK_STARTUP; ss = snmp_open(&session); zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMPv1() 0.2"); pdu = snmp_pdu_create(SNMP_MSG_GET); read_objid(item->snmp_oid, anOID, &anOID_len); #if OTHER_METHODS get_node("sysDescr.0", anOID, &anOID_len); read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len); read_objid("system.sysDescr.0", anOID, &anOID_len); #endif snmp_add_null_var(pdu, anOID, anOID_len); zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMPv1() 0.3"); status = snmp_synch_response(ss, pdu, &response); zabbix_log( LOG_LEVEL_DEBUG, "Status send [%d]", status); zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMPv1() 0.4"); zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMPv1() 1"); if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) { zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMPv1() 2"); /* for(vars = response->variables; vars; vars = vars->next_variable) { print_variable(vars->name, vars->name_length, vars); }*/ for(vars = response->variables; vars; vars = vars->next_variable) { int count=1; zabbix_log( LOG_LEVEL_DEBUG, "AV loop()"); if( (vars->type == ASN_INTEGER) || (vars->type == ASN_UINTEGER)|| (vars->type == ASN_COUNTER) || (vars->type == ASN_GAUGE) ) { *result=*vars->val.integer; sprintf(result_str,"%ld",(long)*vars->val.integer); } else if(vars->type == ASN_OCTET_STR) { memcpy(result_str,vars->val.string,vars->val_len); result_str[vars->val_len] = '\0'; if(item->type == 0) { ret = NOTSUPPORTED; } } else { zabbix_log( LOG_LEVEL_WARNING,"value #%d has unknow type", count++); ret = NOTSUPPORTED; } } } else { if (status == STAT_SUCCESS) { zabbix_log( LOG_LEVEL_WARNING, "Error in packet\nReason: %s\n", snmp_errstring(response->errstat)); if(response->errstat == SNMP_ERR_NOSUCHNAME) { ret=NOTSUPPORTED; } else { ret=FAIL; } } else { zabbix_log( LOG_LEVEL_WARNING, "Error [%d]", status); snmp_sess_perror("snmpget", ss); ret=FAIL; } } if (response) { snmp_free_pdu(response); } snmp_close(ss); SOCK_CLEANUP; return ret; } #endif int get_value_zabbix(double *result,char *result_str,DB_ITEM *item) { int s; int i; char c[MAX_STRING_LEN+1]; char *e; struct hostent *hp; struct sockaddr_in myaddr_in; struct sockaddr_in servaddr_in; struct linger ling; zabbix_log( LOG_LEVEL_DEBUG, "%10s%25s", item->host, item->key ); servaddr_in.sin_family=AF_INET; if(item->useip==1) { hp=gethostbyname(item->ip); } else { hp=gethostbyname(item->host); } if(hp==NULL) { zabbix_log( LOG_LEVEL_WARNING, "gethostbyname() failed" ); return NETWORK_ERROR; } servaddr_in.sin_addr.s_addr=((struct in_addr *)(hp->h_addr))->s_addr; servaddr_in.sin_port=htons(item->port); s=socket(AF_INET,SOCK_STREAM,0); if(CONFIG_NOTIMEWAIT == 1) { ling.l_onoff=1; ling.l_linger=0; if(setsockopt(s,SOL_SOCKET,SO_LINGER,&ling,sizeof(ling))==-1) { zabbix_log(LOG_LEVEL_WARNING, "Cannot setsockopt SO_LINGER [%s]", strerror(errno)); } } if(s==0) { zabbix_log(LOG_LEVEL_WARNING, "Cannot create socket [%s]", strerror(errno)); return FAIL; } myaddr_in.sin_family = AF_INET; myaddr_in.sin_port=0; myaddr_in.sin_addr.s_addr=INADDR_ANY; if( connect(s,(struct sockaddr *)&servaddr_in,sizeof(struct sockaddr_in)) == -1 ) { switch (errno) { case EINTR: zabbix_log( LOG_LEVEL_WARNING, "Timeout while connecting to [%s]",item->host ); break; case EHOSTUNREACH: zabbix_log( LOG_LEVEL_WARNING, "No route to host [%s]",item->host ); break; default: zabbix_log( LOG_LEVEL_WARNING, "Cannot connect to [%s] [%s]",item->host, strerror(errno)); } close(s); return NETWORK_ERROR; } sprintf(c,"%s\n",item->key); if( sendto(s,c,strlen(c),0,(struct sockaddr *)&servaddr_in,sizeof(struct sockaddr_in)) == -1 ) { switch (errno) { case EINTR: zabbix_log( LOG_LEVEL_WARNING, "Timeout while sending data to [%s]",item->host ); break; default: zabbix_log( LOG_LEVEL_WARNING, "Error while sending data to [%s] [%s]",item->host, strerror(errno)); } close(s); return FAIL; } i=sizeof(struct sockaddr_in); i=recvfrom(s,c,MAX_STRING_LEN,0,(struct sockaddr *)&servaddr_in,&i); if(i == -1) { switch (errno) { case EINTR: zabbix_log( LOG_LEVEL_WARNING, "Timeout while receiving data from [%s]",item->host ); break; case ECONNRESET: close(s); return NETWORK_ERROR; default: zabbix_log( LOG_LEVEL_WARNING, "Error while receiving data from [%s] [%s]",item->host, strerror(errno)); } close(s); return FAIL; } if( close(s)!=0 ) { zabbix_log(LOG_LEVEL_WARNING, "Problem with close [%s]", strerror(errno)); } c[i-1]=0; zabbix_log(LOG_LEVEL_DEBUG, "Got string:%10s", c ); *result=strtod(c,&e); if( (*result==0) && (c==e) && (item->value_type==0) ) { zabbix_log( LOG_LEVEL_WARNING, "Got empty string from [%s]. Parameter [%s]",item->host, item->key); zabbix_log( LOG_LEVEL_WARNING, "Assuming that agent dropped connection because of access permissions"); return NETWORK_ERROR; } if( *result<0 ) { if( cmp_double(*result,NOTSUPPORTED) == 0) { zabbix_log(LOG_LEVEL_DEBUG, "NOTSUPPORTED1 [%s]", c ); return NOTSUPPORTED; } } strncpy(result_str,c,MAX_STRING_LEN); zabbix_log(LOG_LEVEL_DEBUG, "RESULT_STR [%s]", c ); return SUCCEED; } int get_value(double *result,char *result_str,DB_ITEM *item) { int res=FAIL; struct sigaction phan; phan.sa_handler = &signal_handler; sigemptyset(&phan.sa_mask); phan.sa_flags = 0; sigaction(SIGALRM, &phan, NULL); alarm(CONFIG_TIMEOUT); if(item->type == ITEM_TYPE_ZABBIX) { res=get_value_zabbix(result,result_str,item); } else if(item->type == ITEM_TYPE_SNMP) { #ifdef HAVE_UCD_SNMP_UCD_SNMP_CONFIG_H res=get_value_SNMPv1(result,result_str,item); #else zabbix_log(LOG_LEVEL_WARNING, "Support of SNMP parameters was no compiled in"); res=NOTSUPPORTED; #endif } else { zabbix_log(LOG_LEVEL_WARNING, "Not supported item type:%d",item->type); res=NOTSUPPORTED; } alarm(0); return res; } int get_minnextcheck(int now) { char sql[MAX_STRING_LEN+1]; DB_RESULT *result; int res; /* Host status 0 == MONITORED 1 == NOT MONITORED 2 == UNREACHABLE */ #ifdef TESTTEST sprintf(sql,"select count(*),min(nextcheck) from items i,hosts h where i.status=0 and (h.status=0 or (h.status=2 and h.disable_until<%d)) and h.hostid=i.hostid and i.status=0 and h.hostid%%%d=%d and i.key_<>'%s'",now,CONFIG_SUCKERD_FORKS-2,sucker_num-2,SERVER_STATUS_KEY); #else sprintf(sql,"select count(*),min(nextcheck) from items i,hosts h where i.status=0 and (h.status=0 or (h.status=2 and h.disable_until<%d)) and h.hostid=i.hostid and i.status=0 and i.itemid%%%d=%d and i.key_<>'%s'",now,CONFIG_SUCKERD_FORKS-2,sucker_num-2,SERVER_STATUS_KEY); #endif result = DBselect(sql); if( DBnum_rows(result) == 0) { zabbix_log(LOG_LEVEL_DEBUG, "No items to update for minnextcheck."); res = FAIL; } else { if( atoi(DBget_field(result,0,0)) == 0) { res = FAIL; } else { res = atoi(DBget_field(result,0,1)); } } DBfree_result(result); return res; } /* Update special host's item - "status" */ void update_key_status(int hostid,int host_status) { char sql[MAX_STRING_LEN+1]; char value_str[MAX_STRING_LEN+1]; char *s; DB_ITEM item; DB_RESULT *result; zabbix_log(LOG_LEVEL_DEBUG, "In update_key_status()"); sprintf(sql,"select i.itemid,i.key_,h.host,h.port,i.delay,i.description,i.nextcheck,i.type,i.snmp_community,i.snmp_oid,h.useip,h.ip,i.history,i.lastvalue,i.prevvalue,i.hostid,h.status,i.value_type from items i,hosts h where h.hostid=i.hostid and h.hostid=%d and i.key_='%s'", hostid,SERVER_STATUS_KEY); result = DBselect(sql); if( DBnum_rows(result) == 0) { zabbix_log( LOG_LEVEL_DEBUG, "No items to update."); } else { item.itemid=atoi(DBget_field(result,0,0)); item.key=DBget_field(result,0,1); item.host=DBget_field(result,0,2); item.port=atoi(DBget_field(result,0,3)); item.delay=atoi(DBget_field(result,0,4)); item.description=DBget_field(result,0,5); item.nextcheck=atoi(DBget_field(result,0,6)); item.type=atoi(DBget_field(result,0,7)); item.snmp_community=DBget_field(result,0,8); item.snmp_oid=DBget_field(result,0,9); item.useip=atoi(DBget_field(result,0,10)); item.ip=DBget_field(result,0,11); item.history=atoi(DBget_field(result,0,12)); s=DBget_field(result,0,13); if(s==NULL) { item.lastvalue_null=1; } else { item.lastvalue_null=0; item.lastvalue_str=s; item.lastvalue=atof(s); } s=DBget_field(result,0,14); if(s==NULL) { item.prevvalue_null=1; } else { item.prevvalue_null=0; item.prevvalue_str=s; item.prevvalue=atof(s); } item.hostid=atoi(DBget_field(result,0,15)); item.value_type=atoi(DBget_field(result,0,17)); sprintf(value_str,"%d",host_status); process_new_value(&item,value_str); update_triggers(0, 1, item.itemid, 0 ); } DBfree_result(result); } int get_values(void) { double value; char value_str[MAX_STRING_LEN+1]; char sql[MAX_STRING_LEN+1]; DB_RESULT *result; int i; int now; int res; DB_ITEM item; char *s; int host_status; now = time(NULL); #ifdef TESTTEST sprintf(sql,"select i.itemid,i.key_,h.host,h.port,i.delay,i.description,i.nextcheck,i.type,i.snmp_community,i.snmp_oid,h.useip,h.ip,i.history,i.lastvalue,i.prevvalue,i.hostid,h.status,i.value_type from items i,hosts h where i.nextcheck<=%d and i.status=0 and (h.status=0 or (h.status=2 and h.disable_until<=%d)) and h.hostid=i.hostid and h.hostid%%%d=%d and i.key_<>'%s' order by i.nextcheck", now, now, CONFIG_SUCKERD_FORKS-2,sucker_num-2,SERVER_STATUS_KEY); #else sprintf(sql,"select i.itemid,i.key_,h.host,h.port,i.delay,i.description,i.nextcheck,i.type,i.snmp_community,i.snmp_oid,h.useip,h.ip,i.history,i.lastvalue,i.prevvalue,i.hostid,h.status,i.value_type from items i,hosts h where i.nextcheck<=%d and i.status=0 and (h.status=0 or (h.status=2 and h.disable_until<=%d)) and h.hostid=i.hostid and i.itemid%%%d=%d and i.key_<>'%s' order by i.nextcheck", now, now, CONFIG_SUCKERD_FORKS-2,sucker_num-2,SERVER_STATUS_KEY); #endif result = DBselect(sql); for(i=0;i0) { if(sleeptime > SUCKER_DELAY) { sleeptime = SUCKER_DELAY; } zabbix_log( LOG_LEVEL_DEBUG, "Sleeping for %d seconds", sleeptime ); #ifdef HAVE_FUNCTION_SETPROCTITLE setproctitle("sucker [sleeping for %d seconds]", sleeptime); #endif sleep( sleeptime ); } else { zabbix_log( LOG_LEVEL_DEBUG, "No sleeping" ); } } } int main(int argc, char **argv) { int i; pid_t pid; struct sigaction phan; init_config(); daemon_init(); phan.sa_handler = &signal_handler; /* set up sig handler using sigaction() */ sigemptyset(&phan.sa_mask); phan.sa_flags = 0; sigaction(SIGINT, &phan, NULL); sigaction(SIGQUIT, &phan, NULL); sigaction(SIGTERM, &phan, NULL); sigaction(SIGCHLD, &phan, NULL); if(CONFIG_LOG_FILE == NULL) { zabbix_open_log(LOG_TYPE_SYSLOG,CONFIG_LOG_LEVEL,NULL); } else { zabbix_open_log(LOG_TYPE_FILE,CONFIG_LOG_LEVEL,CONFIG_LOG_FILE); } create_pid_file(); zabbix_log( LOG_LEVEL_WARNING, "zabbix_suckerd started"); /* Need to set trigger status to UNKNOWN since last run */ DBconnect(CONFIG_DBHOST, CONFIG_DBNAME, CONFIG_DBUSER, CONFIG_DBPASSWORD, CONFIG_DBSOCKET); DBupdate_triggers_status_after_restart(); DBclose(); pids=calloc(CONFIG_SUCKERD_FORKS-1,sizeof(pid_t)); for(i=1;i