From 0d5d42c52228964d76996c0e58fdf69258436716 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 4 Apr 2008 16:57:25 +0000 Subject: an initial, somewhat working, tester for the mail functionality --- plugins/ommail/ommail.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 212 insertions(+), 3 deletions(-) (limited to 'plugins/ommail/ommail.c') diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c index 57de7fc0..4da4f58c 100644 --- a/plugins/ommail/ommail.c +++ b/plugins/ommail/ommail.c @@ -33,9 +33,10 @@ #include #include #include +#include #include -#include -#include +#include +#include #include "syslogd.h" #include "syslogd-types.h" #include "srUtils.h" @@ -63,6 +64,9 @@ typedef struct _instanceData { uchar *pszFrom; uchar *pszTo; uchar *pszSubject; + char RcvBuf[1024]; /* buffer for receiving server responses */ + size_t lenRcvBuf; + size_t iRcvBuf; /* current index into the rcvBuf (buf empty if iRcvBuf == lenRcvBuf) */ int sock; /* socket to this server (most important when we do multiple msgs per mail) */ } smtp; } md; /* mode-specific data */ @@ -104,6 +108,197 @@ CODESTARTdbgPrintInstInfo ENDdbgPrintInstInfo +/* TCP support code, should probably be moved to net.c or some place else... -- rgerhards, 2008-04-04 */ + +/* "receive" a character from the remote server. A single character + * is returned. Returns RS_RET_NO_MORE_DATA if the server has closed + * the connection and RS_RET_IO_ERROR if something goes wrong. This + * is a blocking read. + * rgerhards, 2008-04-04 + */ +static rsRetVal +getRcvChar(instanceData *pData, char *pC) +{ + DEFiRet; + ssize_t lenBuf; + assert(pData != NULL); + + if(pData->md.smtp.iRcvBuf == pData->md.smtp.lenRcvBuf) { /* buffer empty? */ + /* yes, we need to read the next server response */ + do { + lenBuf = recv(pData->md.smtp.sock, pData->md.smtp.RcvBuf, sizeof(pData->md.smtp.RcvBuf), 0); + if(lenBuf == 0) { + ABORT_FINALIZE(RS_RET_NO_MORE_DATA); + } else if(lenBuf < 0) { + if(errno != EAGAIN) { + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + } else { + /* good read */ + pData->md.smtp.iRcvBuf = 0; + pData->md.smtp.lenRcvBuf = lenBuf; + } + + } while(lenBuf < 1); + } + + /* when we reach this point, we have a non-empty buffer */ + *pC = pData->md.smtp.RcvBuf[pData->md.smtp.iRcvBuf++]; + +finalize_it: + RETiRet; +} + + +#if 0 +/* Initialize TCP socket (for sender), new socket is returned in + * pSock if all goes well. + */ +static rsRetVal +CreateSocket(struct addrinfo *addrDest, int *pSock) +{ + DEFiRet; + int fd; + struct addrinfo *r; + char errStr[1024]; + + r = addrDest; + + while(r != NULL) { + fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); + if(fd != -1) { + if(connect(fd, r->ai_addr, r->ai_addrlen) != 0) { + dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + } else { + *pSock = fd; + FINALIZE; + } + close(fd); + } else { + dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + } + r = r->ai_next; + } + + dbgprintf("no working socket could be obtained"); + iRet = RS_RET_NO_SOCKET; + +finalize_it: + RETiRet; +} +#endif + + +/* open a connection to the mail server + * rgerhards, 2008-04-04 + */ +static rsRetVal +serverConnect(instanceData *pData) +{ + struct addrinfo *res = NULL; + struct addrinfo hints; + char errStr[1024]; + + DEFiRet; + assert(pData != NULL); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* TODO: make configurable! */ + hints.ai_socktype = SOCK_STREAM; + if(getaddrinfo((char*)pData->md.smtp.pszSrv, (char*)pData->md.smtp.pszSrvPort, &hints, &res) != 0) { + dbgprintf("error %d in getaddrinfo\n", errno); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + + if((pData->md.smtp.sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { + dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + + if(connect(pData->md.smtp.sock, res->ai_addr, res->ai_addrlen) != 0) { + dbgprintf("create tcp connection failed, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr))); + ABORT_FINALIZE(RS_RET_IO_ERROR); + } + +finalize_it: + if(res != NULL) + freeaddrinfo(res); + + if(iRet != RS_RET_OK) { + if(pData->md.smtp.sock != -1) { + close(pData->md.smtp.sock); + pData->md.smtp.sock = -1; + } + } + + RETiRet; +} + + + +/* send text to the server, blocking send */ +static rsRetVal +Send(int sock, char *msg, size_t len) +{ + DEFiRet; + size_t offsBuf = 0; + ssize_t lenSend; + + assert(msg != NULL); + + if(len == 0) /* it's valid, but does not make much sense ;) */ + FINALIZE; + + do { + lenSend = send(sock, msg + offsBuf, len - offsBuf, 0); + dbgprintf("TCP sent %ld bytes, requested %ld\n", (long) lenSend, (long) len); + + if(lenSend == -1) { + if(errno != EAGAIN) { + dbgprintf("message not (tcp)send, errno %d", errno); + ABORT_FINALIZE(RS_RET_TCP_SEND_ERROR); + } + } else if(lenSend != (ssize_t) len) { + offsBuf += len; /* on to next round... */ + } else { + FINALIZE; + } + } while(1); + +finalize_it: + RETiRet; +} + + +/* send a message via SMTP + * TODO: care about the result codes, we can't do it that blindly ;) + * rgerhards, 2008-04-04 + */ +static rsRetVal +sendSMTP(instanceData *pData, uchar *body) +{ + DEFiRet; + + assert(pData != NULL); + + CHKiRet(serverConnect(pData)); + CHKiRet(Send(pData->md.smtp.sock, "HELO\r\n", 6)); + CHKiRet(Send(pData->md.smtp.sock, "MAIL FROM: \r\n", sizeof("MAIL FROM: \r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, "RCPT TO: \r\n", sizeof("RCPT TO: \r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, "DATA\r\n", sizeof("DATA\r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, body, strlen((char*) body))); + CHKiRet(Send(pData->md.smtp.sock, "\r\n.\r\n", sizeof("\r\n.\r\n") - 1)); + CHKiRet(Send(pData->md.smtp.sock, "QUIT\r\n", sizeof("QUIT\r\n") - 1)); + + close(pData->md.smtp.sock); + pData->md.smtp.sock = -1; + +finalize_it: + RETiRet; +} + + + /* connect to server * rgerhards, 2008-04-04 */ @@ -111,6 +306,10 @@ static rsRetVal doConnect(instanceData *pData) { DEFiRet; + iRet = serverConnect(pData); + if(iRet == RS_RET_IO_ERROR) + iRet = RS_RET_SUSPENDED; + RETiRet; } @@ -131,7 +330,7 @@ CODESTARTdoAction /* forward */ iRet = sendSMTP(pData, ppString[0]); - if(iRet != RELP_RET_OK) { + if(iRet != RS_RET_OK) { /* error! */ dbgprintf("error sending mail, suspending\n"); iRet = RS_RET_SUSPENDED; @@ -154,6 +353,16 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) if((iRet = createInstance(&pData)) != RS_RET_OK) FINALIZE; + //pData->md.smtp.pszSrv = "172.19.2.10"; + pData->md.smtp.pszSrv = "172.19.0.6"; + pData->md.smtp.pszSrvPort = "25"; + pData->md.smtp.pszFrom = "rgerhards@adiscon.com"; + pData->md.smtp.pszTo = "rgerhards@adiscon.com"; + pData->md.smtp.pszSubject = "rsyslog test message"; + + /* process template */ + CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) "RSYSLOG_TraditionalForwardFormat")); + /* TODO: do we need to call freeInstance if we failed - this is a general question for * all output modules. I'll address it later as the interface evolves. rgerhards, 2007-07-25 */ -- cgit