예제 #1
0
파일: modules.c 프로젝트: DooDleZzz/rsyslog
/* Prepare a module for unloading.
 * This is currently a dummy, to be filled when we have a plug-in
 * interface - rgerhards, 2007-08-09
 * rgerhards, 2007-11-21:
 * When this function is called, all instance-data must already have
 * been destroyed. In the case of output modules, this happens when the
 * rule set is being destroyed. When we implement other module types, we
 * need to think how we handle it there (and if we have any instance data).
 * rgerhards, 2008-03-10: reject unload request if the module has a reference
 * count > 0.
 */
static rsRetVal
modPrepareUnload(modInfo_t *pThis)
{
	DEFiRet;
	void *pModCookie;

	assert(pThis != NULL);

	if(pThis->uRefCnt > 0) {
		dbgprintf("rejecting unload of module '%s' because it has a refcount of %d\n",
			  pThis->pszName, pThis->uRefCnt);
		ABORT_FINALIZE(RS_RET_MODULE_STILL_REFERENCED);
	}

	CHKiRet(pThis->modGetID(&pModCookie));
	pThis->modExit(); /* tell the module to get ready for unload */
	CHKiRet(unregCfSysLineHdlrs4Owner(pModCookie));

finalize_it:
	RETiRet;
}
예제 #2
0
파일: net.c 프로젝트: vii5ard/rsyslog
/* sets the correct allow root pointer based on provided type
 * rgerhards, 2008-12-01
 */
static rsRetVal
setAllowRoot(struct AllowedSenders **ppAllowRoot, uchar *pszType)
{
	DEFiRet;

	if(!strcmp((char*)pszType, "UDP"))
		*ppAllowRoot = pAllowedSenders_UDP;
	else if(!strcmp((char*)pszType, "TCP"))
		*ppAllowRoot = pAllowedSenders_TCP;
#ifdef USE_GSSAPI
	else if(!strcmp((char*)pszType, "GSS"))
		*ppAllowRoot = pAllowedSenders_GSS;
#endif
	else {
		dbgprintf("program error: invalid allowed sender ID '%s', denying...\n", pszType);
		ABORT_FINALIZE(RS_RET_CODE_ERR); /* everything is invalid for an invalid type */
	}

finalize_it:
	RETiRet;
}
예제 #3
0
파일: statsobj.c 프로젝트: Whissi/rsyslog
/* add a counter to an object
 * ctrName is duplicated, caller must free it if requried
 * NOTE: The counter is READ-ONLY and MUST NOT be modified (most
 * importantly, it must not be initialized, so the caller must
 * ensure the counter is properly initialized before AddCounter()
 * is called.
 */
static rsRetVal
addManagedCounter(statsobj_t *pThis, const uchar *ctrName, statsCtrType_t ctrType, int8_t flags, void *pCtr,
ctr_t **entryRef, int8_t linked)
{
	ctr_t *ctr;
	DEFiRet;

	*entryRef = NULL;

	CHKmalloc(ctr = calloc(1, sizeof(ctr_t)));
	ctr->next = NULL;
	ctr->prev = NULL;
	if((ctr->name = ustrdup(ctrName)) == NULL) {
		DBGPRINTF("addCounter: OOM in strdup()\n");
		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
	}
	ctr->flags = flags;
	ctr->ctrType = ctrType;
	switch(ctrType) {
	case ctrType_IntCtr:
		ctr->val.pIntCtr = (intctr_t*) pCtr;
		break;
	case ctrType_Int:
		ctr->val.pInt = (int*) pCtr;
		break;
	}
	if (linked) {
		addCtrToList(pThis, ctr);
	}
	*entryRef = ctr;

finalize_it:
	if (iRet != RS_RET_OK) {
		if (ctr != NULL) {
			free(ctr->name);
			free(ctr);
		}
	}
	RETiRet;
}
예제 #4
0
static rsRetVal
doLastMessageRepeatedNTimes(ratelimit_t *ratelimit, smsg_t *pMsg, smsg_t **ppRepMsg)
{
	int bNeedUnlockMutex = 0;
	DEFiRet;

	if(ratelimit->bThreadSafe) {
		pthread_mutex_lock(&ratelimit->mut);
		bNeedUnlockMutex = 1;
	}

	if( ratelimit->pMsg != NULL &&
	    getMSGLen(pMsg) == getMSGLen(ratelimit->pMsg) &&
	    !ustrcmp(getMSG(pMsg), getMSG(ratelimit->pMsg)) &&
	    !strcmp(getHOSTNAME(pMsg), getHOSTNAME(ratelimit->pMsg)) &&
	    !strcmp(getPROCID(pMsg, LOCK_MUTEX), getPROCID(ratelimit->pMsg, LOCK_MUTEX)) &&
	    !strcmp(getAPPNAME(pMsg, LOCK_MUTEX), getAPPNAME(ratelimit->pMsg, LOCK_MUTEX))) {
		ratelimit->nsupp++;
		DBGPRINTF("msg repeated %d times\n", ratelimit->nsupp);
		/* use current message, so we have the new timestamp
		 * (means we need to discard previous one) */
		msgDestruct(&ratelimit->pMsg);
		ratelimit->pMsg = pMsg;
		ABORT_FINALIZE(RS_RET_DISCARDMSG);
	} else {/* new message, do "repeat processing" & save it */
		if(ratelimit->pMsg != NULL) {
			if(ratelimit->nsupp > 0) {
				*ppRepMsg = ratelimitGenRepMsg(ratelimit);
				ratelimit->nsupp = 0;
			}
			msgDestruct(&ratelimit->pMsg);
		}
		ratelimit->pMsg = MsgAddRef(pMsg);
	}

finalize_it:
	if(bNeedUnlockMutex)
		pthread_mutex_unlock(&ratelimit->mut);
	RETiRet;
}
예제 #5
0
/* init function (must be called once) */
rsRetVal
dnscacheInit(void)
{
    DEFiRet;
    if((dnsCache.ht = create_hashtable(100, hash_from_key_fn, key_equals_fn,
                                       (void(*)(void*))entryDestruct)) == NULL) {
        DBGPRINTF("dnscache: error creating hash table!\n");
        ABORT_FINALIZE(RS_RET_ERR); // TODO: make this degrade, but run!
    }
    dnsCache.nEntries = 0;
    pthread_rwlock_init(&dnsCache.rwlock, NULL);
    CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */
    CHKiRet(objUse(glbl, CORE_COMPONENT));
    CHKiRet(objUse(errmsg, CORE_COMPONENT));
    CHKiRet(objUse(prop, CORE_COMPONENT));

    prop.Construct(&staticErrValue);
    prop.SetString(staticErrValue, (uchar*)"???", 3);
    prop.ConstructFinalize(staticErrValue);
finalize_it:
    RETiRet;
}
예제 #6
0
/* TODO: handle multiple blocks
 * test-read END record; if present, store offset, else unbounded (current active block)
 * when decrypting, check if bound is reached. If yes, split into two blocks, get new IV for
 * second one.
 */
rsRetVal
rsgcryDecrypt(gcryfile pF, uchar *buf, size_t *len)
{
	gcry_error_t gcryError;
	DEFiRet;
	
	if(pF->bytesToBlkEnd != -1)
		pF->bytesToBlkEnd -= *len;
	gcryError = gcry_cipher_decrypt(pF->chd, buf, *len, NULL, 0);
	if(gcryError) {
		DBGPRINTF("gcry_cipher_decrypt failed:  %s/%s\n",
			gcry_strsource(gcryError),
			gcry_strerror(gcryError));
		ABORT_FINALIZE(RS_RET_ERR);
	}
	removePadding(buf, len);
	// TODO: remove dbgprintf once things are sufficently stable -- rgerhards, 2013-05-16
	dbgprintf("libgcry: decrypted, bytesToBlkEnd %lld, buffer is now '%50.50s'\n", (long long) pF->bytesToBlkEnd, buf);

finalize_it:
	RETiRet;
}
예제 #7
0
파일: net.c 프로젝트: vii5ard/rsyslog
/* Problem with the warnings: they seem to stem back from the way the API is structured */
static rsRetVal
getIFIPAddr(uchar *szif, int family, uchar *pszbuf, int lenBuf)
{
	struct ifaddrs * ifaddrs = NULL;
	struct ifaddrs * ifa;
	void * pAddr;
	DEFiRet;

 	if(getifaddrs(&ifaddrs) != 0) {
		ABORT_FINALIZE(RS_RET_ERR);
	}

	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
		if(strcmp(ifa->ifa_name, (char*)szif))
			continue;
		if(   (family == AF_INET6 || family == AF_UNSPEC)
		   && ifa->ifa_addr->sa_family == AF_INET6) {
			pAddr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
			inet_ntop(AF_INET6, pAddr, (char*)pszbuf, lenBuf);
			break;
		} else if(/*   (family == AF_INET || family == AF_UNSPEC)
		         &&*/ ifa->ifa_addr->sa_family == AF_INET) {
			pAddr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
			inet_ntop(AF_INET, pAddr, (char*)pszbuf, lenBuf);
			break;
		} 
	}

	if(ifaddrs != NULL)
		freeifaddrs(ifaddrs);

	if(ifa == NULL)
		iRet = RS_RET_NOT_FOUND;

finalize_it:
	RETiRet;

}
예제 #8
0
/* construct from CStr object. only the counted string is
 * copied, not the szString.
 * rgerhards 2005-10-18
 */
rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom)
{
	DEFiRet;
	cstr_t *pThis;

	assert(ppThis != NULL);
	rsCHECKVALIDOBJECT(pFrom, OIDrsCStr);

	CHKiRet(rsCStrConstruct(&pThis));

	pThis->iBufSize = pThis->iStrLen = pFrom->iStrLen;
	if((pThis->pBuf = (uchar*) MALLOC(sizeof(uchar) * pThis->iStrLen)) == NULL) {
		RSFREEOBJ(pThis);
		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
	}

	/* copy properties */
	memcpy(pThis->pBuf, pFrom->pBuf, pThis->iStrLen);

	*ppThis = pThis;
finalize_it:
	RETiRet;
}
예제 #9
0
/* construct from sz string
 * rgerhards 2005-09-15
 */
rsRetVal rsCStrConstructFromszStr(cstr_t **ppThis, uchar *sz)
{
	DEFiRet;
	cstr_t *pThis;

	assert(ppThis != NULL);

	CHKiRet(rsCStrConstruct(&pThis));

	pThis->iBufSize = pThis->iStrLen = strlen((char *) sz);
	if((pThis->pBuf = (uchar*) MALLOC(sizeof(uchar) * pThis->iStrLen)) == NULL) {
		RSFREEOBJ(pThis);
		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
	}

	/* we do NOT need to copy the \0! */
	memcpy(pThis->pBuf, sz, pThis->iStrLen);

	*ppThis = pThis;

finalize_it:
	RETiRet;
}
예제 #10
0
/* find an entry in the unacked list and provide it to the caller. The entry is handed
 * over to the caller and removed from the queue of unacked entries. It is the caller's
 * duty to destruct the sendbuf when it is done with it.
 * rgerhards, 20080-03-20
 */
relpRetVal
relpSessGetUnacked(relpSess_t *pThis, relpSendbuf_t **ppSendbuf, relpTxnr_t txnr)
{
	relpSessUnacked_t *pUnackedEtry;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);
	assert(ppSendbuf != NULL);
	
	for(  pUnackedEtry = pThis->pUnackedLstRoot
	    ; pUnackedEtry != NULL && pUnackedEtry->pSendbuf->txnr != txnr
	    ; pUnackedEtry = pUnackedEtry->pNext)
	   	/*JUST SKIP*/;

	if(pUnackedEtry == NULL)
		ABORT_FINALIZE(RELP_RET_NOT_FOUND);

	*ppSendbuf = pUnackedEtry->pSendbuf;
	relpSessDelUnacked(pThis, pUnackedEtry);

finalize_it:
	LEAVE_RELPFUNC;
}
예제 #11
0
eiWriteIV(gcryfile gf, const uchar *const iv)
{
	static const char hexchars[16] =
	   {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
	unsigned iSrc, iDst;
	char hex[4096];
	DEFiRet;

	if(gf->blkLength > sizeof(hex)/2) {
		DBGPRINTF("eiWriteIV: crypto block len way too large, aborting "
			  "write");
		ABORT_FINALIZE(RS_RET_ERR);
	}

	for(iSrc = iDst = 0 ; iSrc < gf->blkLength ; ++iSrc) {
		hex[iDst++] = hexchars[iv[iSrc]>>4];
		hex[iDst++] = hexchars[iv[iSrc]&0x0f];
	}

	iRet = eiWriteRec(gf, "IV:", 3, hex, gf->blkLength*2);
finalize_it:
	RETiRet;
}
예제 #12
0
파일: vm.c 프로젝트: DooDleZzz/rsyslog
/* find a function inside the function registry
 * The caller provides a cstr_t with the function name and receives
 * a function pointer back. If no function is found, an RS_RET_UNKNW_FUNC
 * error is returned. So if the function returns with RS_RET_OK, the caller
 * can savely assume the function pointer is valid.
 * rgerhards, 2009-04-06
 */
static rsRetVal
findRSFunction(cstr_t *pcsName, prsf_t *prsf)
{
	rsf_entry_t *pEntry;
	rsf_entry_t *pFound;
	DEFiRet;

	assert(prsf != NULL);

	/* find function by list walkthrough.  */
	pFound = NULL;
	for(pEntry = funcRegRoot ; pEntry != NULL && pFound == NULL ; pEntry = pEntry->pNext)
		if(!rsCStrCStrCmp(pEntry->pName, pcsName))
			pFound = pEntry;

	if(pFound == NULL)
		ABORT_FINALIZE(RS_RET_UNKNW_FUNC);

	*prsf = pFound->rsf;

finalize_it:
	RETiRet;
}
예제 #13
0
/* construct from es_str_t string
 * rgerhards 2010-12-03
 */
rsRetVal
cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str)
{
	DEFiRet;
	cstr_t *pThis;

	CHKiRet(rsCStrConstruct(&pThis));

	pThis->iStrLen = es_strlen(str);
	pThis->iBufSize = pThis->iStrLen + 1;
	if((pThis->pBuf = (uchar*) MALLOC(pThis->iBufSize)) == NULL) {
		RSFREEOBJ(pThis);
		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
	}

	/* we do NOT need to copy the \0! */
	memcpy(pThis->pBuf, es_getBufAddr(str), pThis->iStrLen);

	*ppThis = pThis;

finalize_it:
	RETiRet;
}
예제 #14
0
파일: cfsysline.c 프로젝트: Werkov/rsyslog
/* extract a username and return its uid.
 * rgerhards, 2007-07-17
 */
static rsRetVal doGetUID(uchar **pp, rsRetVal (*pSetHdlr)(void*, uid_t), void *pVal)
{
	struct passwd *ppwBuf;
	struct passwd pwBuf;
	DEFiRet;
	uchar szName[256];
	char stringBuf[2048];	/* I hope this is large enough... */

	assert(pp != NULL);
	assert(*pp != NULL);

	if(getSubString(pp, (char*) szName, sizeof(szName), ' ')  != 0) {
		errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract user name");
		ABORT_FINALIZE(RS_RET_NOT_FOUND);
	}

	getpwnam_r((char*)szName, &pwBuf, stringBuf, sizeof(stringBuf), &ppwBuf);

	if(ppwBuf == NULL) {
		errmsg.LogError(0, RS_RET_NOT_FOUND, "ID for user '%s' could not be found or error", (char*)szName);
		iRet = RS_RET_NOT_FOUND;
	} else {
		if(pSetHdlr == NULL) {
			/* we should set value directly to var */
			*((uid_t*)pVal) = ppwBuf->pw_uid;
		} else {
			/* we set value via a set function */
			CHKiRet(pSetHdlr(pVal, ppwBuf->pw_uid));
		}
		dbgprintf("uid %d obtained for user '%s'\n", (int) ppwBuf->pw_uid, szName);
	}

	skipWhiteSpace(pp); /* skip over any whitespace */

finalize_it:
	RETiRet;
}
예제 #15
0
/** Construct a RELP sess instance
 *  the pSrv parameter may be set to NULL if the session object is for a client.
 */
relpRetVal
relpSessConstruct(relpSess_t **ppThis, relpEngine_t *pEngine, relpSrv_t *pSrv)
{
	relpSess_t *pThis;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	RELPOBJ_assert(pEngine, Engine);

	if((pThis = calloc(1, sizeof(relpSess_t))) == NULL) {
		ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);
	}

	RELP_CORE_CONSTRUCTOR(pThis, Sess);
	pThis->pEngine = pEngine;
	/* use Engine's command enablement states as default */
	pThis->stateCmdSyslog = pEngine->stateCmdSyslog;
	pThis->pSrv = pSrv;
	pThis->txnr = 1; /* txnr start at 1 according to spec */
	pThis->timeout = 10; /* TODO: make configurable */
	pThis->sizeWindow = RELP_DFLT_WINDOW_SIZE; /* TODO: make configurable */
	pThis->maxDataSize = RELP_DFLT_MAX_DATA_SIZE;

	CHKRet(relpSendqConstruct(&pThis->pSendq, pThis->pEngine));
	pthread_mutex_init(&pThis->mutSend, NULL);

	*ppThis = pThis;

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pThis != NULL) {
			relpSessDestruct(&pThis);
		}
	}

	LEAVE_RELPFUNC;
}
예제 #16
0
파일: omlibdbi.c 프로젝트: daemon13/rsyslog
/* The following function writes the current log entry
 * to an established database connection.
 */
rsRetVal writeDB(uchar *psz, instanceData *pData)
{
	DEFiRet;
	dbi_result dbiRes = NULL;

	ASSERT(psz != NULL);
	ASSERT(pData != NULL);

	/* see if we are ready to proceed */
	if(pData->conn == NULL) {
		CHKiRet(initConn(pData, 0));
	}

	/* try insert */
	if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) {
		/* error occured, try to re-init connection and retry */
		closeConn(pData); /* close the current handle */
		CHKiRet(initConn(pData, 0)); /* try to re-open */
		if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) { /* re-try insert */
			/* we failed, giving up for now */
			reportDBError(pData, 0);
			closeConn(pData); /* free ressources */
			ABORT_FINALIZE(RS_RET_SUSPENDED);
		}
	}

finalize_it:
	if(iRet == RS_RET_OK) {
		pData->uLastDBErrno = 0; /* reset error for error supression */
	}

	if(dbiRes != NULL)
		dbi_result_free(dbiRes);

	RETiRet;
}
예제 #17
0
/* llDestroyRootElt - destroy the root element but otherwise
 * keeps this list intact.  -- rgerhards, 2007-08-03
 */
rsRetVal llDestroyRootElt(linkedList_t *pThis)
{
	DEFiRet;
	llElt_t *pPrev;
	
	if(pThis->pRoot == NULL) {
		ABORT_FINALIZE(RS_RET_EMPTY_LIST);
	}

	pPrev = pThis->pRoot;
	if(pPrev->pNext == NULL) {
		/* it was the only list element */
		pThis->pLast = NULL;
		pThis->pRoot = NULL;
	} else {
		/* there are other list elements */
		pThis->pRoot = pPrev->pNext;
	}

	CHKiRet(llDestroyElt(pThis, pPrev));

finalize_it:
	RETiRet;
}
예제 #18
0
/* Send a command to the server.
 * This is a "raw" send function that just sends the command but does not
 * care about the receive loop or session state. This has been put into its
 * own function as some functionality (most importantly session init!) requires
 * handling that is other than the regular command/response mode.
 * rgerhards, 2008-03-19
 */
static relpRetVal
relpSessRawSendCommand(relpSess_t *pThis, unsigned char *pCmd, size_t lenCmd,
		    unsigned char *pData, size_t lenData, relpRetVal (*rspHdlr)(relpSess_t*,relpFrame_t*))
{
	relpSendbuf_t *pSendbuf;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	CHKRet(relpFrameBuildSendbuf(&pSendbuf, pThis->txnr, pCmd, lenCmd, pData, lenData, pThis, rspHdlr));
	pThis->txnr = relpEngineNextTXNR(pThis->txnr);
	/* now send it */
	pThis->pEngine->dbgprint("frame to send: '%s'\n", pSendbuf->pData + (9 - pSendbuf->lenTxnr));
	iRet = relpSendbufSendAll(pSendbuf, pThis, 1);

	if(iRet == RELP_RET_IO_ERR) {
		pThis->pEngine->dbgprint("relp session %p flagged as broken, IO error\n", pThis);
		pThis->sessState = eRelpSessState_BROKEN;
		ABORT_FINALIZE(RELP_RET_SESSION_BROKEN);
	}

finalize_it:
	LEAVE_RELPFUNC;
}
예제 #19
0
파일: lookup.c 프로젝트: schiele/rsyslog
rsRetVal
lookupProcessCnf(struct cnfobj *o)
{
	struct cnfparamvals *pvals;
	lookup_t *lu;
	short i;
	DEFiRet;

	pvals = nvlstGetParams(o->nvlst, &modpblk, NULL);
	if(pvals == NULL) {
		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
	}
	DBGPRINTF("lookupProcessCnf params:\n");
	cnfparamsPrint(&modpblk, pvals);
	
	CHKiRet(lookupNew(&lu));

	for(i = 0 ; i < modpblk.nParams ; ++i) {
		if(!pvals[i].bUsed)
			continue;
		if(!strcmp(modpblk.descr[i].name, "file")) {
			CHKmalloc(lu->filename = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL));
		} else if(!strcmp(modpblk.descr[i].name, "name")) {
			CHKmalloc(lu->name = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL));
		} else {
			dbgprintf("lookup_table: program error, non-handled "
			  "param '%s'\n", modpblk.descr[i].name);
		}
	}
	CHKiRet(lookupReadFile(lu));
	DBGPRINTF("lookup table '%s' loaded from file '%s'\n", lu->name, lu->filename);

finalize_it:
	cnfparamvalsDestruct(pvals, &modpblk);
	RETiRet;
}
예제 #20
0
파일: tcpsrv.c 프로젝트: adruch/rsyslog
static inline rsRetVal
RunSelect(tcpsrv_t *pThis, nsd_epworkset_t workset[], size_t sizeWorkset)
{
	DEFiRet;
	int nfds;
	int i;
	int iWorkset;
	int iTCPSess;
	int bIsReady;
	nssel_t *pSel = NULL;
	rsRetVal localRet;

	ISOBJ_TYPE_assert(pThis, tcpsrv);

	/* this is an endless loop - it is terminated by the framework canelling
	 * this thread. Thus, we also need to instantiate a cancel cleanup handler
	 * to prevent us from leaking anything. -- rgerhards, 20080-04-24
	 */
	pthread_cleanup_push(RunCancelCleanup, (void*) &pSel);
	while(1) {
		CHKiRet(nssel.Construct(&pSel));
		if(pThis->pszDrvrName != NULL)
			CHKiRet(nssel.SetDrvrName(pSel, pThis->pszDrvrName));
		CHKiRet(nssel.ConstructFinalize(pSel));

		/* Add the TCP listen sockets to the list of read descriptors. */
		for(i = 0 ; i < pThis->iLstnCurr ; ++i) {
			CHKiRet(nssel.Add(pSel, pThis->ppLstn[i], NSDSEL_RD));
		}

		/* do the sessions */
		iTCPSess = TCPSessGetNxtSess(pThis, -1);
		while(iTCPSess != -1) {
			/* TODO: access to pNsd is NOT really CLEAN, use method... */
			CHKiRet(nssel.Add(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD));
			/* now get next... */
			iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess);
		}

		/* wait for io to become ready */
		CHKiRet(nssel.Wait(pSel, &nfds));
		if(glbl.GetGlobalInputTermState() == 1)
			break; /* terminate input! */

		iWorkset = 0;
		for(i = 0 ; i < pThis->iLstnCurr ; ++i) {
			if(glbl.GetGlobalInputTermState() == 1)
				ABORT_FINALIZE(RS_RET_FORCE_TERM);
			CHKiRet(nssel.IsReady(pSel, pThis->ppLstn[i], NSDSEL_RD, &bIsReady, &nfds));
			if(bIsReady) {
				workset[iWorkset].id = i;
				workset[iWorkset].pUsr = (void*) pThis->ppLstn; /* this is a flag to indicate listen sock */
				++iWorkset;
				if(iWorkset >= (int) sizeWorkset) {
					processWorkset(pThis, NULL, iWorkset, workset);
					iWorkset = 0;
				}
				//DBGPRINTF("New connect on NSD %p.\n", pThis->ppLstn[i]);
				//SessAccept(pThis, pThis->ppLstnPort[i], &pNewSess, pThis->ppLstn[i]);
				--nfds; /* indicate we have processed one */
			}
		}

		/* now check the sessions */
		iTCPSess = TCPSessGetNxtSess(pThis, -1);
		while(nfds && iTCPSess != -1) {
			if(glbl.GetGlobalInputTermState() == 1)
				ABORT_FINALIZE(RS_RET_FORCE_TERM);
			localRet = nssel.IsReady(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD, &bIsReady, &nfds);
			if(bIsReady || localRet != RS_RET_OK) {
				workset[iWorkset].id = iTCPSess;
				workset[iWorkset].pUsr = (void*) pThis->pSessions[iTCPSess];
				++iWorkset;
				if(iWorkset >= (int) sizeWorkset) {
					processWorkset(pThis, NULL, iWorkset, workset);
					iWorkset = 0;
				}
				--nfds; /* indicate we have processed one */
			}
			iTCPSess = TCPSessGetNxtSess(pThis, iTCPSess);
		}

		if(iWorkset > 0)
			processWorkset(pThis, NULL, iWorkset, workset);

		/* we need to copy back close descriptors */
		CHKiRet(nssel.Destruct(&pSel));
finalize_it: /* this is a very special case - this time only we do not exit the function,
	      * because that would not help us either. So we simply retry it. Let's see
	      * if that actually is a better idea. Exiting the loop wasn't we always
	      * crashed, which made sense (the rest of the engine was not prepared for
	      * that) -- rgerhards, 2008-05-19
	      */
		if(pSel != NULL) { /* cleanup missing? happens during err exit! */
			nssel.Destruct(&pSel);
		}
	}

	/* note that this point is usually not reached */
	pthread_cleanup_pop(1); /* remove cleanup handler */

	RETiRet;
}
예제 #21
0
파일: tcpsrv.c 프로젝트: adruch/rsyslog
/* Accept new TCP connection; make entry in session table. If there
 * is no more space left in the connection table, the new TCP
 * connection is immediately dropped.
 * ppSess has a pointer to the newly created session, if it succeeds.
 * If it does not succeed, no session is created and ppSess is
 * undefined. If the user has provided an OnSessAccept Callback,
 * this one is executed immediately after creation of the 
 * session object, so that it can do its own initialization.
 * rgerhards, 2008-03-02
 */
static rsRetVal
SessAccept(tcpsrv_t *pThis, tcpLstnPortList_t *pLstnInfo, tcps_sess_t **ppSess, netstrm_t *pStrm)
{
	DEFiRet;
	tcps_sess_t *pSess = NULL;
	netstrm_t *pNewStrm = NULL;
	int iSess = -1;
	struct sockaddr_storage *addr;
	uchar *fromHostFQDN = NULL;
	prop_t *fromHostIP;

	ISOBJ_TYPE_assert(pThis, tcpsrv);
	assert(pLstnInfo != NULL);

	CHKiRet(netstrm.AcceptConnReq(pStrm, &pNewStrm));

	/* Add to session list */
	iSess = TCPSessTblFindFreeSpot(pThis);
	if(iSess == -1) {
		errno = 0;
		errmsg.LogError(0, RS_RET_MAX_SESS_REACHED, "too many tcp sessions - dropping incoming request");
		ABORT_FINALIZE(RS_RET_MAX_SESS_REACHED);
	}

	if(pThis->bUseKeepAlive) {
	        CHKiRet(netstrm.SetKeepAliveProbes(pNewStrm, pThis->iKeepAliveProbes));
	        CHKiRet(netstrm.SetKeepAliveTime(pNewStrm, pThis->iKeepAliveTime));
	        CHKiRet(netstrm.SetKeepAliveIntvl(pNewStrm, pThis->iKeepAliveIntvl));
		CHKiRet(netstrm.EnableKeepAlive(pNewStrm));
	}

	/* we found a free spot and can construct our session object */
	CHKiRet(tcps_sess.Construct(&pSess));
	CHKiRet(tcps_sess.SetTcpsrv(pSess, pThis));
	CHKiRet(tcps_sess.SetLstnInfo(pSess, pLstnInfo));
	if(pThis->OnMsgReceive != NULL)
		CHKiRet(tcps_sess.SetOnMsgReceive(pSess, pThis->OnMsgReceive));

	/* get the host name */
	CHKiRet(netstrm.GetRemoteHName(pNewStrm, &fromHostFQDN));
	CHKiRet(netstrm.GetRemoteIP(pNewStrm, &fromHostIP));
	CHKiRet(netstrm.GetRemAddr(pNewStrm, &addr));
	/* TODO: check if we need to strip the domain name here -- rgerhards, 2008-04-24 */

	/* Here we check if a host is permitted to send us messages. If it isn't, we do not further
	 * process the message but log a warning (if we are configured to do this).
	 * rgerhards, 2005-09-26
	 */
	if(!pThis->pIsPermittedHost((struct sockaddr*) addr, (char*) fromHostFQDN, pThis->pUsr, pSess->pUsr)) {
		DBGPRINTF("%s is not an allowed sender\n", fromHostFQDN);
		if(glbl.GetOption_DisallowWarning()) {
			errno = 0;
			errmsg.LogError(0, RS_RET_HOST_NOT_PERMITTED, "TCP message from disallowed sender %s discarded", fromHostFQDN);
		}
		ABORT_FINALIZE(RS_RET_HOST_NOT_PERMITTED);
	}

	/* OK, we have an allowed sender, so let's continue, what
	 * means we can finally fill in the session object.
	 */
	CHKiRet(tcps_sess.SetHost(pSess, fromHostFQDN));
	fromHostFQDN = NULL; /* we handed this string over */
	CHKiRet(tcps_sess.SetHostIP(pSess, fromHostIP));
	CHKiRet(tcps_sess.SetStrm(pSess, pNewStrm));
	pNewStrm = NULL; /* prevent it from being freed in error handler, now done in tcps_sess! */
	CHKiRet(tcps_sess.SetMsgIdx(pSess, 0));
	CHKiRet(tcps_sess.ConstructFinalize(pSess));

	/* check if we need to call our callback */
	if(pThis->pOnSessAccept != NULL) {
		CHKiRet(pThis->pOnSessAccept(pThis, pSess));
	}

	*ppSess = pSess;
	if(!pThis->bUsingEPoll)
		pThis->pSessions[iSess] = pSess;
	pSess = NULL; /* this is now also handed over */

finalize_it:
	if(iRet != RS_RET_OK) {
		if(pSess != NULL)
			tcps_sess.Destruct(&pSess);
		if(pNewStrm != NULL)
			netstrm.Destruct(&pNewStrm);
		free(fromHostFQDN);
	}

	RETiRet;
}
예제 #22
0
/**
 * Parse a TIMESTAMP-3164. The pTime parameter
 * is guranteed to be updated only if a new valid timestamp
 * could be obtained (restriction added 2008-09-16 by rgerhards). This
 * also means the caller *must* provide a valid (probably current) 
 * timstamp in pTime when calling this function. a 3164 timestamp contains
 * only partial information and only that partial information is updated.
 * So the "output timestamp" is a valid timestamp only if the "input
 * timestamp" was valid, too. The is actually an optimization, as it
 * permits us to use a pre-aquired timestamp and thus avoids to do
 * a (costly) time() call. Thanks to David Lang for insisting on
 * time() call reduction ;).
 * This method now also checks the maximum string length it is passed.
 * If a *valid* timestamp is found, the string length is decremented
 * by the number of characters processed. If it is not a valid timestamp,
 * the length is kept unmodified. -- rgerhards, 2009-09-23
 */
static rsRetVal
ParseTIMESTAMP3164(struct syslogTime *pTime, uchar** ppszTS, int *pLenStr)
{
	/* variables to temporarily hold time information while we parse */
	int month;
	int day;
	int year = 0; /* 0 means no year provided */
	int hour; /* 24 hour clock */
	int minute;
	int second;
	/* end variables to temporarily hold time information while we parse */
	int lenStr;
	uchar *pszTS;
	DEFiRet;

	assert(ppszTS != NULL);
	pszTS = *ppszTS;
	assert(pszTS != NULL);
	assert(pTime != NULL);
	assert(pLenStr != NULL);
	lenStr = *pLenStr;

	/* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec),
	 * we may see the following character sequences occur:
	 *
	 * J(an/u(n/l)), Feb, Ma(r/y), A(pr/ug), Sep, Oct, Nov, Dec
	 *
	 * We will use this for parsing, as it probably is the
	 * fastest way to parse it.
	 *
	 * 2009-08-17: we now do case-insensitive comparisons, as some devices obviously do not
	 * obey to the RFC-specified case. As we need to guess in any case, we can ignore case
	 * in the first place -- rgerhards
	 *
	 * 2005-07-18, well sometimes it pays to be a bit more verbose, even in C...
	 * Fixed a bug that lead to invalid detection of the data. The issue was that
	 * we had an if(++pszTS == 'x') inside of some of the consturcts below. However,
	 * there were also some elseifs (doing the same ++), which than obviously did not
	 * check the orginal character but the next one. Now removed the ++ and put it
	 * into the statements below. Was a really nasty bug... I didn't detect it before
	 * june, when it first manifested. This also lead to invalid parsing of the rest
	 * of the message, as the time stamp was not detected to be correct. - rgerhards
	 */
	if(lenStr < 3)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	switch(*pszTS++)
	{
	case 'j':
	case 'J':
		if(*pszTS == 'a' || *pszTS == 'A') {
			++pszTS;
			if(*pszTS == 'n' || *pszTS == 'N') {
				++pszTS;
				month = 1;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else if(*pszTS == 'u' || *pszTS == 'U') {
			++pszTS;
			if(*pszTS == 'n' || *pszTS == 'N') {
				++pszTS;
				month = 6;
			} else if(*pszTS == 'l' || *pszTS == 'L') {
				++pszTS;
				month = 7;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	case 'f':
	case 'F':
		if(*pszTS == 'e' || *pszTS == 'E') {
			++pszTS;
			if(*pszTS == 'b' || *pszTS == 'B') {
				++pszTS;
				month = 2;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	case 'm':
	case 'M':
		if(*pszTS == 'a' || *pszTS == 'A') {
			++pszTS;
			if(*pszTS == 'r' || *pszTS == 'R') {
				++pszTS;
				month = 3;
			} else if(*pszTS == 'y' || *pszTS == 'Y') {
				++pszTS;
				month = 5;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	case 'a':
	case 'A':
		if(*pszTS == 'p' || *pszTS == 'P') {
			++pszTS;
			if(*pszTS == 'r' || *pszTS == 'R') {
				++pszTS;
				month = 4;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else if(*pszTS == 'u' || *pszTS == 'U') {
			++pszTS;
			if(*pszTS == 'g' || *pszTS == 'G') {
				++pszTS;
				month = 8;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	case 's':
	case 'S':
		if(*pszTS == 'e' || *pszTS == 'E') {
			++pszTS;
			if(*pszTS == 'p' || *pszTS == 'P') {
				++pszTS;
				month = 9;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	case 'o':
	case 'O':
		if(*pszTS == 'c' || *pszTS == 'C') {
			++pszTS;
			if(*pszTS == 't' || *pszTS == 'T') {
				++pszTS;
				month = 10;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	case 'n':
	case 'N':
		if(*pszTS == 'o' || *pszTS == 'O') {
			++pszTS;
			if(*pszTS == 'v' || *pszTS == 'V') {
				++pszTS;
				month = 11;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	case 'd':
	case 'D':
		if(*pszTS == 'e' || *pszTS == 'E') {
			++pszTS;
			if(*pszTS == 'c' || *pszTS == 'C') {
				++pszTS;
				month = 12;
			} else
				ABORT_FINALIZE(RS_RET_INVLD_TIME);
		} else
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		break;
	default:
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	}

	lenStr -= 3;

	/* done month */

	if(lenStr == 0 || *pszTS++ != ' ')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;

	/* we accept a slightly malformed timestamp when receiving. This is
	 * we accept one-digit days
	 */
	if(*pszTS == ' ') {
		--lenStr;
		++pszTS;
	}

	day = srSLMGParseInt32(&pszTS, &lenStr);
	if(day < 1 || day > 31)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(lenStr == 0 || *pszTS++ != ' ')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;

	/* time part */
	hour = srSLMGParseInt32(&pszTS, &lenStr);
	if(hour > 1970 && hour < 2100) {
		/* if so, we assume this actually is a year. This is a format found
		 * e.g. in Cisco devices.
		 * (if you read this 2100+ trying to fix a bug, congratulate me
		 * to how long the code survived - me no longer ;)) -- rgerhards, 2008-11-18
		 */
		year = hour;

		/* re-query the hour, this time it must be valid */
		if(lenStr == 0 || *pszTS++ != ' ')
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		--lenStr;
		hour = srSLMGParseInt32(&pszTS, &lenStr);
	}

	if(hour < 0 || hour > 23)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(lenStr == 0 || *pszTS++ != ':')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;
	minute = srSLMGParseInt32(&pszTS, &lenStr);
	if(minute < 0 || minute > 59)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(lenStr == 0 || *pszTS++ != ':')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;
	second = srSLMGParseInt32(&pszTS, &lenStr);
	if(second < 0 || second > 60)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	/* we provide support for an extra ":" after the date. While this is an
	 * invalid format, it occurs frequently enough (e.g. with Cisco devices)
	 * to permit it as a valid case. -- rgerhards, 2008-09-12
	 */
	if(lenStr > 0 && *pszTS == ':') {
		++pszTS; /* just skip past it */
		--lenStr;
	}
	if(lenStr > 0) {
		if(*pszTS != ' ') /* if it is not a space, it can not be a "good" time - 2010-02-22 rgerhards */
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		++pszTS; /* just skip past it */
		--lenStr;
	}

	/* we had success, so update parse pointer and caller-provided timestamp
	 * fields we do not have are not updated in the caller's timestamp. This
	 * is the reason why the caller must pass in a correct timestamp.
	 */
	*ppszTS = pszTS; /* provide updated parse position back to caller */
	pTime->timeType = 1;
	pTime->month = month;
	if(year > 0)
		pTime->year = year; /* persist year if detected */
	pTime->day = day;
	pTime->hour = hour;
	pTime->minute = minute;
	pTime->second = second;
 	pTime->secfracPrecision = 0;
	pTime->secfrac = 0;
	*pLenStr = lenStr;

finalize_it:
	RETiRet;
}
예제 #23
0
/**
 * Parse a TIMESTAMP-3339.
 * updates the parse pointer position. The pTime parameter
 * is guranteed to be updated only if a new valid timestamp
 * could be obtained (restriction added 2008-09-16 by rgerhards).
 * This method now also checks the maximum string length it is passed.
 * If a *valid* timestamp is found, the string length is decremented
 * by the number of characters processed. If it is not a valid timestamp,
 * the length is kept unmodified. -- rgerhards, 2009-09-23
 */
static rsRetVal
ParseTIMESTAMP3339(struct syslogTime *pTime, uchar** ppszTS, int *pLenStr)
{
	uchar *pszTS = *ppszTS;
	/* variables to temporarily hold time information while we parse */
	int year;
	int month;
	int day;
	int hour; /* 24 hour clock */
	int minute;
	int second;
	int secfrac;	/* fractional seconds (must be 32 bit!) */
	int secfracPrecision;
	char OffsetMode;	/* UTC offset + or - */
	char OffsetHour;	/* UTC offset in hours */
	int OffsetMinute;	/* UTC offset in minutes */
	int lenStr;
	/* end variables to temporarily hold time information while we parse */
	DEFiRet;

	assert(pTime != NULL);
	assert(ppszTS != NULL);
	assert(pszTS != NULL);

	lenStr = *pLenStr;
	year = srSLMGParseInt32(&pszTS, &lenStr);

	/* We take the liberty to accept slightly malformed timestamps e.g. in 
	 * the format of 2003-9-1T1:0:0. This doesn't hurt on receiving. Of course,
	 * with the current state of affairs, we would never run into this code
	 * here because at postion 11, there is no "T" in such cases ;)
	 */
	if(lenStr == 0 || *pszTS++ != '-')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;
	month = srSLMGParseInt32(&pszTS, &lenStr);
	if(month < 1 || month > 12)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(lenStr == 0 || *pszTS++ != '-')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;
	day = srSLMGParseInt32(&pszTS, &lenStr);
	if(day < 1 || day > 31)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(lenStr == 0 || *pszTS++ != 'T')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;

	hour = srSLMGParseInt32(&pszTS, &lenStr);
	if(hour < 0 || hour > 23)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(lenStr == 0 || *pszTS++ != ':')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;
	minute = srSLMGParseInt32(&pszTS, &lenStr);
	if(minute < 0 || minute > 59)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(lenStr == 0 || *pszTS++ != ':')
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	--lenStr;
	second = srSLMGParseInt32(&pszTS, &lenStr);
	if(second < 0 || second > 60)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	/* Now let's see if we have secfrac */
	if(lenStr > 0 && *pszTS == '.') {
		--lenStr;
		uchar *pszStart = ++pszTS;
		secfrac = srSLMGParseInt32(&pszTS, &lenStr);
		secfracPrecision = (int) (pszTS - pszStart);
	} else {
		secfracPrecision = 0;
		secfrac = 0;
	}

	/* check the timezone */
	if(lenStr == 0)
		ABORT_FINALIZE(RS_RET_INVLD_TIME);

	if(*pszTS == 'Z') {
		--lenStr;
		pszTS++; /* eat Z */
		OffsetMode = 'Z';
		OffsetHour = 0;
		OffsetMinute = 0;
	} else if((*pszTS == '+') || (*pszTS == '-')) {
		OffsetMode = *pszTS;
		--lenStr;
		pszTS++;

		OffsetHour = srSLMGParseInt32(&pszTS, &lenStr);
		if(OffsetHour < 0 || OffsetHour > 23)
			ABORT_FINALIZE(RS_RET_INVLD_TIME);

		if(lenStr == 0 || *pszTS != ':')
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		--lenStr;
		pszTS++;
		OffsetMinute = srSLMGParseInt32(&pszTS, &lenStr);
		if(OffsetMinute < 0 || OffsetMinute > 59)
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
	} else {
		/* there MUST be TZ information */
		ABORT_FINALIZE(RS_RET_INVLD_TIME);
	}

	/* OK, we actually have a 3339 timestamp, so let's indicated this */
	if(lenStr > 0) {
		if(*pszTS != ' ') /* if it is not a space, it can not be a "good" time - 2010-02-22 rgerhards */
			ABORT_FINALIZE(RS_RET_INVLD_TIME);
		++pszTS; /* just skip past it */
		--lenStr;
	}

	/* we had success, so update parse pointer and caller-provided timestamp */
	*ppszTS = pszTS;
	pTime->timeType = 2;
	pTime->year = year;
	pTime->month = month;
	pTime->day = day;
	pTime->hour = hour;
	pTime->minute = minute;
	pTime->second = second;
	pTime->secfrac = secfrac;
	pTime->secfracPrecision = secfracPrecision;
	pTime->OffsetMode = OffsetMode;
	pTime->OffsetHour = OffsetHour;
	pTime->OffsetMinute = OffsetMinute;
	*pLenStr = lenStr;

finalize_it:
	RETiRet;
}
예제 #24
0
파일: omsnmp.c 프로젝트: Xat59/rsyslog
static rsRetVal omsnmp_sendsnmp(wrkrInstanceData_t *pWrkrData, uchar *psz)
{
	DEFiRet;

	netsnmp_pdu    *pdu = NULL;
	oid             enterpriseoid[MAX_OID_LEN];
	size_t          enterpriseoidlen = MAX_OID_LEN;
	oid				oidSyslogMessage[MAX_OID_LEN];
	size_t			oLen = MAX_OID_LEN;
	int             status;
	char            *trap = NULL;
	const char		*strErr = NULL;
	instanceData *pData;

	pData = pWrkrData->pData;
	/* Init SNMP Session if necessary */
	if (pWrkrData->snmpsession == NULL) {
		CHKiRet(omsnmp_initSession(pWrkrData));
	}
	
	/* String should not be NULL */
	ASSERT(psz != NULL);
	dbgprintf( "omsnmp_sendsnmp: ENTER - Syslogmessage = '%s'\n", (char*)psz);

	/* If SNMP Version1 is configured !*/
	if(pWrkrData->snmpsession->version == SNMP_VERSION_1) {
		pdu = snmp_pdu_create(SNMP_MSG_TRAP);

		/* Set enterprise */
		if(!snmp_parse_oid(pData->szEnterpriseOID == NULL ? "1.3.6.1.4.1.3.1.1" : (char*)pData->szEnterpriseOID,
				   enterpriseoid, &enterpriseoidlen )) {
			strErr = snmp_api_errstring(snmp_errno);
			errmsg.LogError(0, RS_RET_DISABLE_ACTION, "omsnmp_sendsnmp: Parsing EnterpriseOID "
					"failed '%s' with error '%s' \n", pData->szSyslogMessageOID, strErr);
			ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
		}
		pdu->enterprise = (oid *) MALLOC(enterpriseoidlen * sizeof(oid));
		memcpy(pdu->enterprise, enterpriseoid, enterpriseoidlen * sizeof(oid));
		pdu->enterprise_length = enterpriseoidlen;

		/* Set Traptype */
		pdu->trap_type = pData->iTrapType; 
		
		/* Set SpecificType */
		pdu->specific_type = pData->iSpecificType;

		/* Set Updtime */
		pdu->time = get_uptime();
	}
	/* If SNMP Version2c is configured !*/
	else if (pWrkrData->snmpsession->version == SNMP_VERSION_2c) 
	{
		long sysuptime;
		char csysuptime[20];
		
		/* Create PDU */
		pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
		
		/* Set uptime */
		sysuptime = get_uptime();
		snprintf( csysuptime, sizeof(csysuptime) , "%ld", sysuptime);
		trap = csysuptime;
		snmp_add_var(pdu, objid_sysuptime, sizeof(objid_sysuptime) / sizeof(oid), 't', trap);

		/* Now set the SyslogMessage Trap OID */
		if ( snmp_add_var(pdu, objid_snmptrap, sizeof(objid_snmptrap) / sizeof(oid), 'o',
			pData->szSnmpTrapOID == NULL ?  "1.3.6.1.4.1.19406.1.2.1" : (char*) pData->szSnmpTrapOID
			) != 0) {
			strErr = snmp_api_errstring(snmp_errno);
			errmsg.LogError(0, RS_RET_DISABLE_ACTION, "omsnmp_sendsnmp: Adding trap OID failed '%s' with error '%s' \n", pData->szSnmpTrapOID, strErr);
			ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
		}
	}

	/* SET TRAP PARAMETER for SyslogMessage! */
/*	dbgprintf( "omsnmp_sendsnmp: SyslogMessage '%s'\n", psz );*/

	/* First create new OID object */
	if (snmp_parse_oid(pData->szSyslogMessageOID == NULL ?
			    "1.3.6.1.4.1.19406.1.1.2.1" : (char*)pData->szSyslogMessageOID,
				oidSyslogMessage, &oLen)) {
		int iErrCode = snmp_add_var(pdu, oidSyslogMessage, oLen, 's', (char*) psz);
		if (iErrCode) {
			const char *str = snmp_api_errstring(iErrCode);
			errmsg.LogError(0, RS_RET_DISABLE_ACTION,  "omsnmp_sendsnmp: Invalid SyslogMessage OID, error code '%d' - '%s'\n", iErrCode, str );
			ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
		}
	} else {
		strErr = snmp_api_errstring(snmp_errno);
		errmsg.LogError(0, RS_RET_DISABLE_ACTION, "omsnmp_sendsnmp: Parsing SyslogMessageOID failed '%s' with error '%s' \n", pData->szSyslogMessageOID, strErr);

		ABORT_FINALIZE(RS_RET_DISABLE_ACTION);
	}

	/* Send the TRAP */
	status = snmp_send(pWrkrData->snmpsession, pdu) == 0;
	if (status)
	{
		/* Debug Output! */
		int iErrorCode = pWrkrData->snmpsession->s_snmp_errno;
		errmsg.LogError(0, RS_RET_SUSPENDED,  "omsnmp_sendsnmp: snmp_send failed error '%d', Description='%s'\n", iErrorCode*(-1), api_errors[iErrorCode*(-1)]);

		/* Clear Session */
		omsnmp_exitSession(pWrkrData);

		ABORT_FINALIZE(RS_RET_SUSPENDED);
	}

finalize_it:
	if(iRet != RS_RET_OK) {
		if(pdu != NULL) {
			snmp_free_pdu(pdu);
		}
	}

	dbgprintf( "omsnmp_sendsnmp: LEAVE\n");
	RETiRet;
}
예제 #25
0
파일: imczmq.c 프로젝트: dpocock/rsyslog
static rsRetVal rcvData(){
	DEFiRet;
	
	if(!listenerList) {
		listenerList = zlist_new();
		if(!listenerList) {
			errmsg.LogError(0, NO_ERRCODE, "could not allocate list");
			ABORT_FINALIZE(RS_RET_ERR);
		}
	}

	zactor_t *authActor;
	zcert_t *serverCert;

	if(runModConf->authenticator == 1) {
		authActor = zactor_new(zauth, NULL);
		zstr_sendx(authActor, "CURVE", runModConf->clientCertPath, NULL);
		zsock_wait(authActor);
	} 

	instanceConf_t *inst;
	for(inst = runModConf->root; inst != NULL; inst=inst->next) {
		CHKiRet(addListener(inst));
	}
	
	zpoller_t *poller = zpoller_new(NULL);
	if(!poller) {
		errmsg.LogError(0, NO_ERRCODE, "could not create poller");
			ABORT_FINALIZE(RS_RET_ERR);
	}
	DBGPRINTF("imczmq: created poller\n");

	struct listener_t *pData;

	pData = zlist_first(listenerList);
	if(!pData) {
		errmsg.LogError(0, NO_ERRCODE, "imczmq: no listeners were "
						"started, input not activated.\n");
		ABORT_FINALIZE(RS_RET_NO_RUN);
	}

	while(pData) {
		int rc = zpoller_add(poller, pData->sock);
		if(rc != 0) {
			errmsg.LogError(0, NO_ERRCODE, "imczmq: could not add "
						"socket to poller, input not activated.\n");
			ABORT_FINALIZE(RS_RET_NO_RUN);
		}
		pData = zlist_next(listenerList);
	}

	zframe_t *frame;
	zsock_t *which = (zsock_t *)zpoller_wait(poller, -1);
	while(which) {
		if (zpoller_terminated(poller)) {
				break;
		}
		pData = zlist_first(listenerList);
		while(pData->sock != which) {
			pData = zlist_next(listenerList);
		}
	
		if(which == pData->sock) {
			DBGPRINTF("imczmq: found matching socket\n");
		}

		frame = zframe_recv(which);
		char *buf = zframe_strdup(frame);

		if(buf == NULL) {
			DBGPRINTF("imczmq: null buffer\n");
			continue;
		}
		smsg_t *pMsg;
		if(msgConstruct(&pMsg) == RS_RET_OK) {
			MsgSetRawMsg(pMsg, buf, strlen(buf));
			MsgSetInputName(pMsg, s_namep);
			MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
			MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp());
			MsgSetRcvFromIP(pMsg, glbl.GetLocalHostIP());
			MsgSetMSGoffs(pMsg, 0);
			MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY);
			MsgSetRuleset(pMsg, pData->ruleset);
			pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME;
			submitMsg2(pMsg);
		}

		free(buf);
		which = (zsock_t *)zpoller_wait(poller, -1);
	}
finalize_it:
	zframe_destroy(&frame);
	zpoller_destroy(&poller);
	pData = zlist_first(listenerList);
	while(pData) {
		zsock_destroy(&pData->sock);
		free(pData->ruleset);
		pData = zlist_next(listenerList);
	}
	zlist_destroy(&listenerList);
	zactor_destroy(&authActor);
	zcert_destroy(&serverCert);
	RETiRet;
}
예제 #26
0
파일: lookup.c 프로젝트: schiele/rsyslog
/* note: widely-deployed json_c 0.9 does NOT support incremental
 * parsing. In order to keep compatible with e.g. Ubuntu 12.04LTS,
 * we read the file into one big memory buffer and parse it at once.
 * While this is not very elegant, it will not pose any real issue
 * for "reasonable" lookup tables (and "unreasonably" large ones
 * will probably have other issues as well...).
 */
static rsRetVal
lookupReadFile(lookup_t *pThis)
{
	struct json_tokener *tokener = NULL;
	struct json_object *json = NULL;
	int eno;
	char errStr[1024];
	char *iobuf = NULL;
	int fd;
	ssize_t nread;
	struct stat sb;
	DEFiRet;


	if(stat((char*)pThis->filename, &sb) == -1) {
		eno = errno;
		errmsg.LogError(0, RS_RET_FILE_NOT_FOUND,
			"lookup table file '%s' stat failed: %s",
			pThis->filename, rs_strerror_r(eno, errStr, sizeof(errStr)));
		ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
	}

	CHKmalloc(iobuf = malloc(sb.st_size));

	if((fd = open((const char*) pThis->filename, O_RDONLY)) == -1) {
		eno = errno;
		errmsg.LogError(0, RS_RET_FILE_NOT_FOUND,
			"lookup table file '%s' could not be opened: %s",
			pThis->filename, rs_strerror_r(eno, errStr, sizeof(errStr)));
		ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
	}

	tokener = json_tokener_new();
	nread = read(fd, iobuf, sb.st_size);
	if(nread != (ssize_t) sb.st_size) {
		eno = errno;
		errmsg.LogError(0, RS_RET_READ_ERR,
			"lookup table file '%s' read error: %s",
			pThis->filename, rs_strerror_r(eno, errStr, sizeof(errStr)));
		ABORT_FINALIZE(RS_RET_READ_ERR);
	}

	json = json_tokener_parse_ex(tokener, iobuf, sb.st_size);
	if(json == NULL) {
		errmsg.LogError(0, RS_RET_JSON_PARSE_ERR,
			"lookup table file '%s' json parsing error",
			pThis->filename);
		ABORT_FINALIZE(RS_RET_JSON_PARSE_ERR);
	}
	free(iobuf); /* early free to sever resources*/
	iobuf = NULL; /* make sure no double-free */

	/* got json object, now populate our own in-memory structure */
	CHKiRet(lookupBuildTable(pThis, json));

finalize_it:
	free(iobuf);
	if(tokener != NULL)
		json_tokener_free(tokener);
	if(json != NULL)
		json_object_put(json);
	RETiRet;
}
예제 #27
0
파일: offers.c 프로젝트: davidelang/librelp
/* construct an offers list from the offers contained in a frame. The frame's
 * Read Next pointer must be positioned at the first character of the offer.
 * rgerhards, 2008-03-25
 */
relpRetVal
relpOffersConstructFromFrame(relpOffers_t **ppOffers, relpFrame_t *pFrame)
{
	relpOffers_t *pOffers = NULL;
	relpOffer_t *pOffer;
	relpRetVal localRet;
	unsigned char c;
	size_t iName;
	size_t iVal;
	unsigned char szFeatNam[RELP_MAX_OFFER_FEATURENAME+1];
	unsigned char szFeatVal[RELP_MAX_OFFER_FEATUREVALUE+1];

	ENTER_RELPFUNC;
	assert(ppOffers != NULL);
	RELPOBJ_assert(pFrame, Frame);

	CHKRet(relpOffersConstruct(&pOffers, pFrame->pEngine));

	/* now process the command data */

	localRet = relpFrameGetNextC(pFrame, &c);
	while(localRet == RELP_RET_OK) {
		/* command name */
		iName = 0;
		while(iName < RELP_MAX_OFFER_FEATURENAME && c != '=' && localRet == RELP_RET_OK) {
			szFeatNam[iName++] = c;
			localRet = relpFrameGetNextC(pFrame, &c);
		}
		szFeatNam[iName] = '\0'; /* space is reserved for this! */
		CHKRet(relpOfferAdd(&pOffer, szFeatNam, pOffers));

		/* and now process the values (if any) */
		while(localRet == RELP_RET_OK && c != '\n') {
			localRet = relpFrameGetNextC(pFrame, &c); /* eat the "=" or "," */
			iVal = 0;
			while(   iVal < RELP_MAX_OFFER_FEATUREVALUE && localRet == RELP_RET_OK
			      && c != ',' && c != '\n' ) {
				szFeatVal[iVal++] = c;
				localRet = relpFrameGetNextC(pFrame, &c);
			}
			if(iVal > 0) { /* only set feature if one is actually given */
				szFeatVal[iVal] = '\0'; /* space is reserved for this */
				CHKRet(relpOfferValueAdd(szFeatVal, 0, pOffer));
			}
		}

		if(localRet == RELP_RET_OK && c == '\n')
			localRet = relpFrameGetNextC(pFrame, &c); /* eat '\n' */

	}

	if(localRet != RELP_RET_END_OF_DATA)
		ABORT_FINALIZE(localRet);

	*ppOffers = pOffers;

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pOffers != NULL)
			relpOffersDestruct(&pOffers);
	}

	LEAVE_RELPFUNC;
}
예제 #28
0
파일: offers.c 프로젝트: davidelang/librelp
/* create as string with the complete offers. The string is dynamically
 * allocated and passed to the caller. The caller is responsible for
 * freeing it. This function always allocates a sufficiently large
 * string (TODO: ensure that!). A string my be prepended to the offers
 * block (this is for rsp status). If that is not desired, the param
 * must be NULL, in which case its length is simply ignored (suggest to use
 * 0 in that case).
 * rgerhards, 2008-03-24
 */
relpRetVal
relpOffersToString(relpOffers_t *pThis, unsigned char *pszHdr, size_t lenHdr,
		   unsigned char **ppszOffers, size_t *plenStr)
{
	unsigned char *pszOffers = NULL;
	size_t iStr;
	size_t currSize;
	size_t iAlloc;
	relpOffer_t *pOffer;
	relpOfferValue_t *pOfferVal;

	ENTER_RELPFUNC;
	assert(ppszOffers != NULL);
	RELPOBJ_assert(pThis, Offers);

	if(pszHdr != NULL && lenHdr > 4096)
		iAlloc = 4096 + lenHdr;
	else
		iAlloc = 4096;

	if((pszOffers = malloc(iAlloc)) == NULL) {
		ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);
	}

	currSize = iAlloc;
	iAlloc = 4096;

	/* check if we need to prepend anything */
	if(pszHdr == NULL) {
		iStr = 0; /* no, start at the beginning */
	} else {
		memcpy((char*)pszOffers, (char*)pszHdr, lenHdr);
		iStr = lenHdr;
	}

	for(pOffer = pThis->pRoot ; pOffer != NULL ; pOffer = pOffer->pNext) {
		/* we use -3 in the realloc-guard ifs so that we have space for constants following! */
		if(currSize - iStr - 3 < strlen((char*)pOffer->szName)) {
			if((pszOffers = realloc(pszOffers, currSize + iAlloc)) == NULL) {
				ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);
				currSize += iAlloc;
			}
		}
		strcpy((char*)pszOffers+iStr, (char*)pOffer->szName);
		iStr += strlen((char*)pOffer->szName);
		pszOffers[iStr++] = '=';
		for(pOfferVal = pOffer->pValueRoot ; pOfferVal != NULL ; pOfferVal = pOfferVal->pNext) {
			if(currSize - iStr - 3 < strlen((char*)pOfferVal->szVal)) {
				if((pszOffers = realloc(pszOffers, currSize + iAlloc)) == NULL) {
					ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);
					currSize += iAlloc;
				}
			}
			strcpy((char*)pszOffers+iStr, (char*)pOfferVal->szVal);
			iStr += strlen((char*)pOfferVal->szVal);
			if(pOfferVal->pNext != NULL)
				pszOffers[iStr++] = ',';
		}
		if(pOffer->pNext != NULL)
			pszOffers[iStr++] = '\n';
	}

	*ppszOffers = pszOffers;
	*plenStr = iStr;

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pszOffers != NULL)
			free(pszOffers);
	}

	LEAVE_RELPFUNC;
}
예제 #29
0
파일: dnscache.c 프로젝트: Whissi/rsyslog
resolveAddr(struct sockaddr_storage *addr, dnscache_entry_t *etry)
{
	DEFiRet;
	int error;
	sigset_t omask, nmask;
	struct addrinfo hints, *res;
	char szIP[80]; /* large enough for IPv6 */
	char fqdnBuf[NI_MAXHOST];
	rs_size_t fqdnLen;
	rs_size_t i;
	
	error = mygetnameinfo((struct sockaddr *)addr, SALEN((struct sockaddr *)addr),
			    (char*) szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST);
	if(error) {
		dbgprintf("Malformed from address %s\n", gai_strerror(error));
		ABORT_FINALIZE(RS_RET_INVALID_SOURCE);
	}

	if(!glbl.GetDisableDNS()) {
		sigemptyset(&nmask);
		sigaddset(&nmask, SIGHUP);
		pthread_sigmask(SIG_BLOCK, &nmask, &omask);

		error = mygetnameinfo((struct sockaddr *)addr, SALEN((struct sockaddr *) addr),
				    fqdnBuf, NI_MAXHOST, NULL, 0, NI_NAMEREQD);

		if(error == 0) {
			memset (&hints, 0, sizeof (struct addrinfo));
			hints.ai_flags = AI_NUMERICHOST;

			/* we now do a lookup once again. This one should fail,
			 * because we should not have obtained a non-numeric address. If
			 * we got a numeric one, someone messed with DNS!
			 */
			if(getaddrinfo (fqdnBuf, NULL, &hints, &res) == 0) {
				uchar szErrMsg[1024];
				freeaddrinfo (res);
				/* OK, we know we have evil. The question now is what to do about
				 * it. One the one hand, the message might probably be intended
				 * to harm us. On the other hand, losing the message may also harm us.
				 * Thus, the behaviour is controlled by the $DropMsgsWithMaliciousDnsPTRRecords
				 * option. If it tells us we should discard, we do so, else we proceed,
				 * but log an error message together with it.
				 * time being, we simply drop the name we obtained and use the IP - that one
				 * is OK in any way. We do also log the error message. rgerhards, 2007-07-16
		 		 */
		 		if(glbl.GetDropMalPTRMsgs() == 1) {
					snprintf((char*)szErrMsg, sizeof(szErrMsg),
						 "Malicious PTR record, message dropped "
						 "IP = \"%s\" HOST = \"%s\"",
						 szIP, fqdnBuf);
					LogError(0, RS_RET_MALICIOUS_ENTITY, "%s", szErrMsg);
					pthread_sigmask(SIG_SETMASK, &omask, NULL);
					ABORT_FINALIZE(RS_RET_MALICIOUS_ENTITY);
				}

				/* Please note: we deal with a malicous entry. Thus, we have crafted
				 * the snprintf() below so that all text is in front of the entry - maybe
				 * it contains characters that make the message unreadable
				 * (OK, I admit this is more or less impossible, but I am paranoid...)
				 * rgerhards, 2007-07-16
				 */
				snprintf((char*)szErrMsg, sizeof(szErrMsg),
					 "Malicious PTR record (message accepted, but used IP "
					 "instead of PTR name: IP = \"%s\" HOST = \"%s\"",
					 szIP, fqdnBuf);
				LogError(0, NO_ERRCODE, "%s", szErrMsg);

				error = 1; /* that will trigger using IP address below. */
			} else {/* we have a valid entry, so let's create the respective properties */
				fqdnLen = strlen(fqdnBuf);
				prop.CreateStringProp(&etry->fqdn, (uchar*)fqdnBuf, fqdnLen);
				for(i = 0 ; i < fqdnLen ; ++i)
					fqdnBuf[i] = tolower(fqdnBuf[i]);
				prop.CreateStringProp(&etry->fqdnLowerCase, (uchar*)fqdnBuf, fqdnLen);
			}
		}
		pthread_sigmask(SIG_SETMASK, &omask, NULL);
	}


finalize_it:
	if(iRet != RS_RET_OK) {
		strcpy(szIP, "?error.obtaining.ip?");
		error = 1; /* trigger hostname copies below! */
	}

	/* we need to create the inputName property (only once during our lifetime) */
	prop.CreateStringProp(&etry->ip, (uchar*)szIP, strlen(szIP));

	if(error || glbl.GetDisableDNS()) {
		dbgprintf("Host name for your address (%s) unknown\n", szIP);
		prop.AddRef(etry->ip);
		etry->fqdn = etry->ip;
		prop.AddRef(etry->ip);
		etry->fqdnLowerCase = etry->ip;
	}

	setLocalHostName(etry);

	RETiRet;
}
예제 #30
0
파일: parse.c 프로젝트: fastly/rsyslog
rsRetVal parsAddrWithBits(rsParsObj *pThis, struct NetAddr **pIP, int *pBits)
{
	register uchar *pC;
	uchar *pszIP;
	uchar *pszTmp;
	struct addrinfo hints, *res = NULL;
	cstr_t *pCStr;
	DEFiRet;

	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
	assert(pIP != NULL);
	assert(pBits != NULL);

	CHKiRet(cstrConstruct(&pCStr));

	parsSkipWhitespace(pThis);
	pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;

	/* we parse everything until either '/', ',' or
	 * whitespace. Validity will be checked down below.
	 */
	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
	      && *pC != '/' && *pC != ',' && !isspace((int)*pC)) {
		if((iRet = cstrAppendChar(pCStr, *pC)) != RS_RET_OK) {
			cstrDestruct (&pCStr);
			FINALIZE;
		}
		++pThis->iCurrPos;
		++pC;
	}
	
	/* We got the string, let's finish it...  */
	if((iRet = cstrFinalize(pCStr)) != RS_RET_OK) {
		cstrDestruct(&pCStr);
		FINALIZE;
	}

	/* now we have the string and must check/convert it to
	 * an NetAddr structure.
	 */	
  	CHKiRet(cstrConvSzStrAndDestruct(pCStr, &pszIP, 0));

	*pIP = calloc(1, sizeof(struct NetAddr));
	
	if (*((char*)pszIP) == '[') {
		pszTmp = (uchar*)strchr ((char*)pszIP, ']');
		if (pszTmp == NULL) {
			free (pszIP);
			ABORT_FINALIZE(RS_RET_INVALID_IP);
		}
		*pszTmp = '\0';

		memset (&hints, 0, sizeof (struct addrinfo));
		hints.ai_family = AF_INET6;
#		ifdef AI_ADDRCONFIG
			hints.ai_flags  = AI_ADDRCONFIG | AI_NUMERICHOST;
#		else
			hints.ai_flags  = AI_NUMERICHOST;
#		endif
		
		switch(getaddrinfo ((char*)pszIP+1, NULL, &hints, &res)) {
		case 0: 
			(*pIP)->addr.NetAddr = MALLOC (res->ai_addrlen);
			memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen);
			freeaddrinfo (res);
			break;
		case EAI_NONAME:
			F_SET((*pIP)->flags, ADDR_NAME|ADDR_PRI6);
			(*pIP)->addr.HostWildcard = strdup ((const char*)pszIP+1);
			break;
		default:
			free (pszIP);
			free (*pIP);
			ABORT_FINALIZE(RS_RET_ERR);
		}
		
		if(*pC == '/') {
			/* mask bits follow, let's parse them! */
			++pThis->iCurrPos; /* eat slash */
			if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) {
				free (pszIP);
				free (*pIP);
				FINALIZE;
			}
			/* we need to refresh pointer (changed by parsInt()) */
			pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
		} else {
			/* no slash, so we assume a single host (/128) */
			*pBits = 128;
		}
	} else { /* now parse IPv4 */
		memset (&hints, 0, sizeof (struct addrinfo));
		hints.ai_family = AF_INET;
#		ifdef AI_ADDRCONFIG
			hints.ai_flags  = AI_ADDRCONFIG | AI_NUMERICHOST;
#		else
			hints.ai_flags  = AI_NUMERICHOST;
#		endif
		
		switch(getaddrinfo ((char*)pszIP, NULL, &hints, &res)) {
		case 0: 
			(*pIP)->addr.NetAddr = MALLOC (res->ai_addrlen);
			memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen);
			freeaddrinfo (res);
			break;
		case EAI_NONAME:
			F_SET((*pIP)->flags, ADDR_NAME);
			(*pIP)->addr.HostWildcard = strdup ((const char*)pszIP);
			break;
		default:
			free (pszIP);
			free (*pIP);
			ABORT_FINALIZE(RS_RET_ERR);
		}
			
		if(*pC == '/') {
			/* mask bits follow, let's parse them! */
			++pThis->iCurrPos; /* eat slash */
			if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) {
				free (pszIP);
				free (*pIP);
				FINALIZE;
			}
			/* we need to refresh pointer (changed by parsInt()) */
			pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
		} else {
			/* no slash, so we assume a single host (/32) */
			*pBits = 32;
		}
	}
	free(pszIP); /* no longer needed */

	/* skip to next processable character */
	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
	      && (*pC == ',' || isspace((int)*pC))) {
		++pThis->iCurrPos;
		++pC;
	}

	iRet = RS_RET_OK;

finalize_it:
	RETiRet;
}