www.pudn.com > Firewall_PNE_3_3.zip > syslogcLib.c, change:2009-03-16,size:16680b


/* syslogcLib.c - BSD syslog protocol client library */

/* Copyright 2004-2005 Wind River Systems, Inc. */
#include "copyright_wrs.h"

/*
modification history
--------------------
01d,09sep05,svk  Reformat parameter comments
01c,13jul04,myz  move common header files to fw.h
01b,27feb04,myz  make syslogcBinToAscStrConvert() a local function
01a,08sep03,myz  written
*/

/*
DESCRIPTION

This library implements the client side of the BSD syslog protocol RFC 3164. 
This protocol provides a transport to allow a machine to send event 
notification messages across IP networks to event message collectors - also 
known as syslog servers.

*/

#include "fw.h"
#include "ioLib.h"
#include "hostLib.h"
#include "sockLib.h"
#include "wrn/firewall/syslogcLib.h"

/* local macros */

/* constant and default value definitions */

#define TEMP_HOST_NAME_LEN    100
#define DFT_TAGID_LEN         32
#define SYSLOG_MSG_MAX_LEN    1024
#define DFT_HOST_NAME_LEN     40

/* various special values related to the syslog message format */

#define FIELD_DELIMITER        ' ' 
#define PRI_PART_LEADING_CHAR  '<'
#define PRI_PART_ENDING_CHAR   '>'
#define ASCII_ZERO  0x30
#define ASCII_a     0x60

/* indication of the type of the input data */

#define MDATA_TYPE   0x10    /* input data contained in mbuf */
#define BDATA_TYPE   0x20    /* input data in a binray buffer */
#define CDATA_TYPE   0x30    /* input data as NULL terminated string */

/* Macros for generic calculation */

#define BYTE_MS4BITS(x) (((x) >> 4) & 0x0f)
#define BYTE_LS4BITS(x) ((x) & 0x0f)
#define MIN(x,y)   ((x) > (y)? (y): (x))

/* typedefs */

/* locals */

LOCAL struct in_addr dftServerIpAddr;
LOCAL char  clientHostName[DFT_HOST_NAME_LEN];
LOCAL int   clientFd = 0;
LOCAL BOOL  syslogcLibInitDone = FALSE;
LOCAL char * monthStr[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
                           "Aug","Sep","Oct","Nov","Dec"};

/* local function prototypes */

LOCAL STATUS syslogMsgSend (void *, int, char *, UINT16, ULONG,int);
LOCAL int mdataToSyslogBuf (M_BLK_ID,int, char *, int);
LOCAL int num100LessToAsc (int, char *);
LOCAL int timestampStrGet(char *);
LOCAL int syslogcBinToAscStrConvert (UINT8 *, int, char *, int);

/******************************************************************************
*
* syslogcLibInit - initialize the syslog client module
*
* This routine saves the default syslog server IP address if provided and
* creates a client side UDP socket bound to the default syslog port. 
* Both the UDP socket and the server IP address will be used in the sending
* routines.
*
* RETURNS: socket file descriptor or ERROR if fails
*
*/
int syslogcLibInit 
    (
    char * pServer    /* default syslog server IP address, NULL terminated*/
    )
    {
    struct sockaddr_in  sin;
    int sFd;

    if (syslogcLibInitDone == TRUE)
        return clientFd;

    /* validate the destination parameter */

    if (pServer == NULL)
        {
	dftServerIpAddr.s_addr = 0;
        }
    else
	{
	if (((dftServerIpAddr.s_addr = inet_addr(pServer)) == ERROR) &&
	    ((dftServerIpAddr.s_addr = hostGetByName(pServer)) == ERROR))
	    {
	    dftServerIpAddr.s_addr = 0;
	    perror("syslogcLibInit,unknown default syslog server name");
	    }
	}

    /* create the client socket */

    bzero ((char *)&sin, sizeof (sin));

    if ((sFd = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR)
        {
        perror("syslogcLibInit, syslog socket creation fail");
        return ERROR;
        }

    /* bind the socket to the default port as recommeded by RFC3164 */

    sin.sin_family = AF_INET;
    sin.sin_len    = sizeof(sin);
    sin.sin_port   = htons(SYSLOGC_DEFAULT_PORT);
    sin.sin_addr.s_addr = INADDR_ANY;

    if (bind(sFd, (struct sockaddr *)&sin, sizeof(sin)) == ERROR)
        {
        perror("syslogcLibInit, syslog sokcet bind fail");
        close(sFd);
        return ERROR;
        }

    /* get the client's host name used as ID in syslog message */

    bzero(clientHostName,DFT_HOST_NAME_LEN);

    if (gethostname(clientHostName,DFT_HOST_NAME_LEN - 1) == ERROR)
	strcpy(clientHostName,"Un-defined host name");

    clientFd = sFd;
    syslogcLibInitDone = TRUE;

    return sFd;
    }

/*****************************************************************************
*
* syslogcShutdown - close and clean up the syslog client module
*
* This routine disables the syslog client and reclaims the resource. The
* syslogcLibInit() should be called again in order to restart the syslog client.
*
* RETURNS: NONE
*/

void syslogcShutdown (void)
    {
    if (syslogcLibInitDone == TRUE)
	{
        close(clientFd);

	syslogcLibInitDone = FALSE;
	}
    }

/******************************************************************************
*
* syslogcMdataSend - send the data in mbuf chain to the syslog server
*
* This routine sends the data in mbuf chain up to the maximum limit per syslog
* message to the syslog server.
*
* RETURNS: OK or ERROR
*/

STATUS syslogcMdataSend
    (
    M_BLK_ID pMblk, /* point to the mbuf */
    int pktLogLen,  /* the number of bytes of the packet to be logged */
    char * pMsgId,  /* The message ID string, optional */ 
    UINT16 code,    /* syslog facility and severity code, default used if 0 */
    ULONG  serverIpAddr /* binary server IP address in network byte order, */ 
                        /* default used if value is 0 */ 
    )
    {
    if (syslogcLibInitDone == FALSE)
	return ERROR;

    return syslogMsgSend((void *)pMblk,pktLogLen,pMsgId,code,
			 serverIpAddr,MDATA_TYPE);
    }

/******************************************************************************
*
* syslogcBinDataSend - send a block of binary data to the syslog server
*
* This routine sends a block of binary data to the syslog server
*
* RETURNS: OK or ERROR
*/

STATUS syslogcBinDataSend
    (
    UINT8 * pData,  /* point to the data stream */
    int    len,     /* length of the data stream */
    char * pMsgId,  /* The message ID string, optional. */
    UINT16 code,    /* syslog facility and severity code, default used if 0 */
    ULONG  serverIpAddr /* binary server IP address in network byte order,  */
                        /* default used if value is 0 */ 
    )
    {
    if (syslogcLibInitDone == FALSE)
	return ERROR;

    return syslogMsgSend((void *)pData,len,pMsgId,code,
			 serverIpAddr, BDATA_TYPE);
    }

/******************************************************************************
*
* syslogcStringSend - send a string of character data to the syslog server
*
* This routine sends a string of character data to the syslog server
*
* RETURNS: OK or ERROR
*/

STATUS syslogcStringSend
    (
    char * pStr,    /* point to the NULL terminated string */
    UINT16 code,    /* syslog facility and severity code, default used if 0 */
    ULONG  serverIpAddr /* binary server IP address in network byte order, */
                        /* default used if value is 0 */ 
    )
    {
    if (syslogcLibInitDone == FALSE)
	return ERROR;

    return syslogMsgSend((void *)pStr,0,NULL,code,
			 serverIpAddr,CDATA_TYPE);
    }

/******************************************************************************
*
* syslogMsgSend - Send a message to the syslog server
*
* This routine composes a syslog format message and sends to the syslog server
* specified in the init routine. 
*
* RETURNS: OK or ERROR
*
*/
LOCAL STATUS syslogMsgSend
    (
    void * pData,     /* point to the data message */
    int    dataLen,   /* length of the message */
    char * pMsgIdStr, /* message Id string */
    UINT16 code,    /* syslog facility and severity code, default used if 0 */
    ULONG  serverIpAddr,
    int    dataType
    )
    {
    char * pLogMsg;
    int cnt = 0;
    int remainder;
    int digit;
    char * pTmp;
    int len;
    struct sockaddr_in serverSockAddr;
    UINT8   fCode;  /* syslog facility code */
    UINT8   sCode;  /* syslog severity code */
   
    /* safety check */

    if (pData == NULL)
        return ERROR;

    fCode = (code >> 8) & 0xff;
    sCode = (UINT8)(code & 0xff);

    /* check facility code, use default if not specified or invalid */

    if (fCode > SYSLOGC_LOCAL7)
	fCode = SYSLOGC_USER_LEVEL_MSG;

    /* check severity code, use default if not specified or invalid */

    if (sCode > SYSLOGC_SEVERITY_DEBUG)
        sCode = SYSLOGC_SEVERITY_INFORMATIONAL;

    if (serverIpAddr == 0 && dftServerIpAddr.s_addr == 0)
        {
        /* syslog server IP address is not specified  */

        return ERROR;
        }
    
    if (!serverIpAddr)
        serverIpAddr = dftServerIpAddr.s_addr;
 
    /* initialize the server address structure */

    serverSockAddr.sin_family      = AF_INET;
    serverSockAddr.sin_len         = sizeof(serverSockAddr);
    serverSockAddr.sin_port        = htons(SYSLOGC_DEFAULT_PORT);
    serverSockAddr.sin_addr.s_addr = serverIpAddr;

    /* malloc a buffer to compose the syslog message */

    if ((pLogMsg = malloc(SYSLOG_MSG_MAX_LEN)) == NULL)
        {
        printf("ERROR: slogcMsgSend: fail to allocate the memory\n");
        return ERROR;
        }

    /* compose the PRI part */

    pLogMsg[cnt++] = PRI_PART_LEADING_CHAR;   /* leading character */
    
    /* priority value = facility number * 8 + severity number */

    remainder = fCode * 8 + sCode;  /* priority value */

    /* extract the 100th digit and convert to ASCII value*/

    digit = remainder/100;     
    if (digit)
        {     
        remainder = remainder - (digit * 100);
        pLogMsg[cnt++] = digit + ASCII_ZERO;
        }

    /* convert 100 less number */
    
    cnt += num100LessToAsc(remainder,&pLogMsg[cnt]);

    pLogMsg[cnt++] = PRI_PART_ENDING_CHAR;  /* ending character for PRI part */

    /* compose the Header part, immediately follow the PRI part
     * The Header consists of two field timerstamp and host name
     * Each field should be followed by a space character
     */

    /* first the timestamp */

    cnt += timestampStrGet(&pLogMsg[cnt]);
    pLogMsg[cnt++] = FIELD_DELIMITER;   

    /* host name */

    bcopy(clientHostName,&pLogMsg[cnt],strlen(clientHostName));
    cnt += strlen(clientHostName);
    pLogMsg[cnt++] = FIELD_DELIMITER; 

    /* The final part, the MSG part consists of two fields TAG and CONTENT.
     * TAG, max 32 chars, CONTENT, the first char should be non-alphanumeric
     * signifying the end of TAG. There is no ending delimiter to the whole
     * MSG part
     */

    /* Use task name as the  process Id */

    pTmp = taskName(taskIdSelf());

    if (pTmp)
	{
        len = MIN(strlen(pTmp),DFT_TAGID_LEN);
        bcopy(pTmp,&pLogMsg[cnt],len);
        cnt += len;
	pLogMsg[cnt++] = ':';
        pLogMsg[cnt++] = ' ';
	}

    if (pMsgIdStr != NULL)
        {
        len = MIN(strlen(pMsgIdStr),SYSLOG_MSG_MAX_LEN - cnt - 1);
        bcopy(pMsgIdStr,&pLogMsg[cnt],len);
        cnt += len;
        }

    pLogMsg[cnt++] = ' ';

    switch (dataType)
        {
        case MDATA_TYPE:
            cnt += mdataToSyslogBuf((M_BLK_ID)pData,dataLen,
                                    &pLogMsg[cnt],
                                    SYSLOG_MSG_MAX_LEN - cnt);
            break;

        case BDATA_TYPE:
            cnt += syslogcBinToAscStrConvert((UINT8 *)pData,
                                    dataLen,
                                    &pLogMsg[cnt],
                                    SYSLOG_MSG_MAX_LEN - cnt);
            break;

        case CDATA_TYPE:
            {
            int copyLen;

            copyLen = MIN(strlen((char *)pData), (SYSLOG_MSG_MAX_LEN - cnt));
 
            bcopy((char *)pData,&pLogMsg[cnt],copyLen);
            cnt += copyLen;
	    }
            break;

        default:
            printf("ERROR type 0x%x not supported\n",dataType);
        }

    /* now send the message to the server */

    if (sendto (clientFd,(caddr_t)pLogMsg,cnt,0, 
	(struct sockaddr *)&serverSockAddr,sizeof(serverSockAddr)) == ERROR)
        {
        free(pLogMsg);
        perror("syslogMsgSend sendto fail");
        return (ERROR);
        }
 
    free(pLogMsg);
    return OK;
    }

/******************************************************************************
*
* syslogcBinToAscStrConvert - Convert binary data to the ASCII format
*
* RETURN: number of ASCII bytes written to buffer
*/

LOCAL int syslogcBinToAscStrConvert
    (
    UINT8 * pData,   /* point to a block of data */
    int     dataLen, /* data length */
    char *  pBuf,    /* buffer to store converted ASCII value */
    int     bufLen   /* length of the buffer */
    )
    {
    int i;
    int cnt = 0;
    int copyLen;

    /* make sure not write beyond the buffer limit */

    copyLen = MIN(dataLen, bufLen/3);

    for (i = 0; i < copyLen; i++)
        {
        /* the most significant 4 bits */

        if (BYTE_MS4BITS(pData[i]) > 9)
            pBuf[cnt++] = BYTE_MS4BITS(pData[i]) - 9 + ASCII_a;
        else
            pBuf[cnt++] = BYTE_MS4BITS(pData[i]) + ASCII_ZERO;

        /* the least significant 4 bits */

        if (BYTE_LS4BITS(pData[i]) > 9)
            pBuf[cnt++] = BYTE_LS4BITS(pData[i]) - 9 + ASCII_a;
        else
            pBuf[cnt++] = BYTE_LS4BITS(pData[i]) + ASCII_ZERO;

        /* the space char */

        pBuf[cnt++] = ' ';
        }
    return cnt;
    }

/******************************************************************************
*
* mdataToSyslogBuf - Convert data in mbuf into ASCII format in syslog buffer
*
* RETURNS: number of bytes of the buffer consumed 
*/

LOCAL int mdataToSyslogBuf 
    (
    M_BLK_ID pMblk, /* point to the mbuf chain */
    int pktLogLen,  /* number of the bytes of the packet to be sent */ 
    char * pBuf,    /* the buffer to take the converted ASCII data */
    int    bufLen   /* the maxium length of the buffer */
    )
    {
    int mdataLen;
    int copyLen;
    UINT8 * pData;
    int cnt = 0;

    /* each 8 bit binary data consumes 3 bytes(data + space) of ASCII buffer */

    if (pktLogLen)
        copyLen = MIN(pktLogLen,pMblk->m_pkthdr.len);
    else
	copyLen = pMblk->m_pkthdr.len;

    copyLen = MIN(copyLen, (bufLen/3)); 

    /* now copy the packet data */

    while (pMblk != NULL)
        {
        mdataLen = MIN(pMblk->mBlkHdr.mLen,  copyLen); 

        pData = (UINT8 *)pMblk->mBlkHdr.mData;

        cnt += syslogcBinToAscStrConvert(pData,mdataLen,&pBuf[cnt],bufLen-cnt);

        copyLen -= mdataLen;

        if (copyLen <= 0)
            break;

        pMblk   = pMblk->mBlkHdr.mNext;
        }
    return cnt;
    }

/******************************************************************************
*
* timestampStrGet - Get the syslog format timestamp string 
*
* This routine retrieves the timestamp information from the local clock using
* clockLib function clock_gettime. It assumes the clock has been setup and 
* running.
* 
* RETURNS: the length of  the timestamp string
*/

LOCAL int timestampStrGet 
    (
    char * pBuf  /* buffer to store the timestamp string */
    )
    {
    int cnt = 0;
    UINT32 timeSec = 0;
    int digit;
    struct timespec ts;
    struct tm timeFields;

    if (_clockRealtime.timeBase.tv_sec)
        {
        clock_gettime(CLOCK_REALTIME,&ts);
        timeSec = ts.tv_sec;
        }

    if (!timeSec)
	return cnt;

    localtime_r((time_t *)&timeSec,&timeFields);

    /* month field */

    strcpy(pBuf,monthStr[timeFields.tm_mon]);
    cnt += strlen(monthStr[timeFields.tm_mon]);
    
    pBuf[cnt++] = FIELD_DELIMITER;

    /* day field */
    
    if (timeFields.tm_mday < 10)
        pBuf[cnt++] = ' ';
    else
        {
        digit = timeFields.tm_mday / 10;
        timeFields.tm_mday = timeFields.tm_mday - (digit * 10);
        pBuf[cnt++] = digit + ASCII_ZERO;
        }

    pBuf[cnt++] = timeFields.tm_mday + ASCII_ZERO;
    pBuf[cnt++] = FIELD_DELIMITER;

    /* hour field */

    cnt += num100LessToAsc(timeFields.tm_hour,&pBuf[cnt]);
    pBuf[cnt++] = ':';
 
    /* minute field */
    
    cnt += num100LessToAsc(timeFields.tm_min,&pBuf[cnt]);
    pBuf[cnt++] = ':';

    /* second field */
    
    cnt += num100LessToAsc(timeFields.tm_sec,&pBuf[cnt]);

    return cnt;
    }

/******************************************************************************
*
* num100LessToAsc - Convert numeric values less than 100 to the ASCII value
*
* RETURN: number of bytes of the ASCII data
*/

LOCAL int num100LessToAsc 
    (
    int number,  /* numeric value */
    char * pBuf  /* buffer to store the converted ASCII data */
    )
    {
    int digit;
    int cnt = 0;

    digit = number / 10;
    pBuf[cnt++] = digit + ASCII_ZERO;
    number = number - digit * 10;
    pBuf[cnt++] = number + ASCII_ZERO;

    return cnt;
    }